| /* |
| * arch/arm/plat-ambarella/misc/atag.c |
| * |
| * Author: Anthony Ginger <hfjiang@ambarella.com> |
| * |
| * Copyright (C) 2004-2010, Ambarella, Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| * |
| */ |
| |
| #include <linux/kernel.h> |
| #include <linux/init.h> |
| #include <linux/bootmem.h> |
| #include <linux/dma-mapping.h> |
| #include <linux/module.h> |
| |
| #include <asm/page.h> |
| #include <asm/io.h> |
| #include <asm/setup.h> |
| #include <asm/mach/map.h> |
| |
| #include <mach/hardware.h> |
| #include <mach/board.h> |
| #include <plat/debug.h> |
| #include <hal/hal.h> |
| |
| /* ==========================================================================*/ |
| u32 ambarella_debug_level = AMBA_DEBUG_NULL; |
| EXPORT_SYMBOL(ambarella_debug_level); |
| |
| u32 ambarella_debug_info = 0; |
| EXPORT_SYMBOL(ambarella_debug_info); |
| |
| u32 ambarella_boot_splash_logo = 0; |
| EXPORT_SYMBOL(ambarella_boot_splash_logo); |
| |
| unsigned long ambarella_debug_lookup_name(const char *name) |
| { |
| return module_kallsyms_lookup_name(name); |
| } |
| EXPORT_SYMBOL(ambarella_debug_lookup_name); |
| |
| /* ==========================================================================*/ |
| static int __init parse_eth0_tag_mac(const struct tag *tag) |
| { |
| u32 high, low; |
| |
| high = tag->u.serialnr.high; |
| low = tag->u.serialnr.low; |
| |
| ambarella_board_generic.eth0_mac[0] = (low >> 0); |
| ambarella_board_generic.eth0_mac[1] = (low >> 8); |
| ambarella_board_generic.eth0_mac[2] = (low >> 16); |
| ambarella_board_generic.eth0_mac[3] = (low >> 24); |
| ambarella_board_generic.eth0_mac[4] = (high >> 0); |
| ambarella_board_generic.eth0_mac[5] = (high >> 8); |
| return 0; |
| } |
| __tagtable(ATAG_AMBARELLA_ETH0, parse_eth0_tag_mac); |
| |
| static int __init parse_eth1_tag_mac(const struct tag *tag) |
| { |
| u32 high, low; |
| |
| high = tag->u.serialnr.high; |
| low = tag->u.serialnr.low; |
| |
| ambarella_board_generic.eth1_mac[0] = (low >> 0); |
| ambarella_board_generic.eth1_mac[1] = (low >> 8); |
| ambarella_board_generic.eth1_mac[2] = (low >> 16); |
| ambarella_board_generic.eth1_mac[3] = (low >> 24); |
| ambarella_board_generic.eth1_mac[4] = (high >> 0); |
| ambarella_board_generic.eth1_mac[5] = (high >> 8); |
| return 0; |
| } |
| __tagtable(ATAG_AMBARELLA_ETH1, parse_eth1_tag_mac); |
| |
| static int __init parse_wifi0_tag_mac(const struct tag *tag) |
| { |
| u32 high, low; |
| |
| high = tag->u.serialnr.high; |
| low = tag->u.serialnr.low; |
| |
| ambarella_board_generic.wifi0_mac[0] = (low >> 0); |
| ambarella_board_generic.wifi0_mac[1] = (low >> 8); |
| ambarella_board_generic.wifi0_mac[2] = (low >> 16); |
| ambarella_board_generic.wifi0_mac[3] = (low >> 24); |
| ambarella_board_generic.wifi0_mac[4] = (high >> 0); |
| ambarella_board_generic.wifi0_mac[5] = (high >> 8); |
| return 0; |
| } |
| __tagtable(ATAG_AMBARELLA_WIFI0, parse_wifi0_tag_mac); |
| |
| static int __init parse_wifi1_tag_mac(const struct tag *tag) |
| { |
| u32 high, low; |
| |
| high = tag->u.serialnr.high; |
| low = tag->u.serialnr.low; |
| |
| ambarella_board_generic.wifi1_mac[0] = (low >> 0); |
| ambarella_board_generic.wifi1_mac[1] = (low >> 8); |
| ambarella_board_generic.wifi1_mac[2] = (low >> 16); |
| ambarella_board_generic.wifi1_mac[3] = (low >> 24); |
| ambarella_board_generic.wifi1_mac[4] = (high >> 0); |
| ambarella_board_generic.wifi1_mac[5] = (high >> 8); |
| return 0; |
| } |
| __tagtable(ATAG_AMBARELLA_WIFI1, parse_wifi1_tag_mac); |
| |
| static int __init parse_usb_eth0_tag_mac(const struct tag *tag) |
| { |
| u32 high, low; |
| |
| high = tag->u.serialnr.high; |
| low = tag->u.serialnr.low; |
| |
| ambarella_board_generic.usb_eth0_mac[0] = (low >> 0); |
| ambarella_board_generic.usb_eth0_mac[1] = (low >> 8); |
| ambarella_board_generic.usb_eth0_mac[2] = (low >> 16); |
| ambarella_board_generic.usb_eth0_mac[3] = (low >> 24); |
| ambarella_board_generic.usb_eth0_mac[4] = (high >> 0); |
| ambarella_board_generic.usb_eth0_mac[5] = (high >> 8); |
| return 0; |
| } |
| __tagtable(ATAG_AMBARELLA_USB_ETH0, parse_usb_eth0_tag_mac); |
| |
| static int __init parse_usb_eth1_tag_mac(const struct tag *tag) |
| { |
| u32 high, low; |
| |
| high = tag->u.serialnr.high; |
| low = tag->u.serialnr.low; |
| |
| ambarella_board_generic.usb_eth1_mac[0] = (low >> 0); |
| ambarella_board_generic.usb_eth1_mac[1] = (low >> 8); |
| ambarella_board_generic.usb_eth1_mac[2] = (low >> 16); |
| ambarella_board_generic.usb_eth1_mac[3] = (low >> 24); |
| ambarella_board_generic.usb_eth1_mac[4] = (high >> 0); |
| ambarella_board_generic.usb_eth1_mac[5] = (high >> 8); |
| return 0; |
| } |
| __tagtable(ATAG_AMBARELLA_USB_ETH1, parse_usb_eth1_tag_mac); |
| |
| /* ==========================================================================*/ |
| #define AMBARELLA_IO_DESC_AHB_ID 0 |
| #define AMBARELLA_IO_DESC_APB_ID 1 |
| #define AMBARELLA_IO_DESC_PPM_ID 2 |
| #define AMBARELLA_IO_DESC_BSB_ID 3 |
| #define AMBARELLA_IO_DESC_DSP_ID 4 |
| #if defined(CONFIG_PLAT_AMBARELLA_SUPPORT_MMAP_NEW) |
| #define AMBARELLA_IO_DESC_DRAMC_ID (AMBARELLA_IO_DESC_DSP_ID + 1) |
| #define AMBARELLA_IO_DESC_CRYPT_ID (AMBARELLA_IO_DESC_DSP_ID + 2) |
| #if defined(CONFIG_PLAT_AMBARELLA_SUPPORT_MMAP_NEW_CORTEX_EXT) |
| #define AMBARELLA_IO_DESC_AXI_ID (AMBARELLA_IO_DESC_DSP_ID + 3) |
| #define AMBARELLA_IO_DESC_DDD_ID (AMBARELLA_IO_DESC_DSP_ID + 4) |
| #endif |
| #endif |
| |
| struct ambarella_mem_map_desc { |
| char name[32]; |
| struct map_desc io_desc; |
| }; |
| static struct ambarella_mem_map_desc ambarella_io_desc[] = { |
| [AMBARELLA_IO_DESC_AHB_ID] = { |
| .name = "AHB", |
| .io_desc = { |
| .virtual= AHB_BASE, |
| .pfn = __phys_to_pfn(AHB_PHYS_BASE), |
| .length = AHB_SIZE, |
| #if defined(CONFIG_PLAT_AMBARELLA_ADD_REGISTER_LOCK) |
| .type = MT_DEVICE_NONSHARED, |
| #else |
| .type = MT_DEVICE, |
| #endif |
| }, |
| }, |
| [AMBARELLA_IO_DESC_APB_ID] = { |
| .name = "APB", |
| .io_desc = { |
| .virtual= APB_BASE, |
| .pfn = __phys_to_pfn(APB_PHYS_BASE), |
| .length = APB_SIZE, |
| #if defined(CONFIG_PLAT_AMBARELLA_ADD_REGISTER_LOCK) |
| .type = MT_DEVICE_NONSHARED, |
| #else |
| .type = MT_DEVICE, |
| #endif |
| }, |
| }, |
| [AMBARELLA_IO_DESC_PPM_ID] = { |
| .name = "PPM", /*Private Physical Memory*/ |
| .io_desc = { |
| .virtual= NOLINUX_MEM_V_START, |
| .pfn = __phys_to_pfn(DEFAULT_MEM_START), |
| .length = CONFIG_AMBARELLA_PPM_SIZE, |
| .type = MT_MEMORY, |
| }, |
| }, |
| [AMBARELLA_IO_DESC_BSB_ID] = { |
| .name = "BSB", /*Bit Stream Buffer*/ |
| .io_desc = { |
| .virtual= DEFAULT_BSB_BASE, |
| .pfn = __phys_to_pfn(DEFAULT_BSB_START), |
| .length = DEFAULT_BSB_SIZE, |
| .type = MT_MEMORY, |
| }, |
| }, |
| [AMBARELLA_IO_DESC_DSP_ID] = { |
| .name = "DSP", |
| .io_desc = { |
| .virtual= DEFAULT_DSP_BASE, |
| .pfn = __phys_to_pfn(DEFAULT_DSP_START), |
| .length = DEFAULT_DSP_SIZE, |
| .type = MT_MEMORY, |
| }, |
| }, |
| #if defined(CONFIG_PLAT_AMBARELLA_SUPPORT_MMAP_NEW) |
| [AMBARELLA_IO_DESC_DRAMC_ID] = { |
| .name = "DRAMC", |
| .io_desc = { |
| .virtual= DRAMC_BASE, |
| .pfn = __phys_to_pfn(DRAMC_PHYS_BASE), |
| .length = DRAMC_SIZE, |
| #if defined(CONFIG_PLAT_AMBARELLA_ADD_REGISTER_LOCK) |
| .type = MT_DEVICE_NONSHARED, |
| #else |
| .type = MT_DEVICE, |
| #endif |
| }, |
| }, |
| [AMBARELLA_IO_DESC_CRYPT_ID] = { |
| .name = "CRYPT", |
| .io_desc = { |
| .virtual= CRYPT_BASE, |
| .pfn = __phys_to_pfn(CRYPT_PHYS_BASE), |
| .length = CRYPT_SIZE, |
| #if defined(CONFIG_PLAT_AMBARELLA_ADD_REGISTER_LOCK) |
| .type = MT_DEVICE_NONSHARED, |
| #else |
| .type = MT_DEVICE, |
| #endif |
| }, |
| }, |
| #if defined(CONFIG_PLAT_AMBARELLA_SUPPORT_MMAP_NEW_CORTEX_EXT) |
| [AMBARELLA_IO_DESC_AXI_ID] = { |
| .name = "AXI", |
| .io_desc = { |
| .virtual= AXI_BASE, |
| .pfn = __phys_to_pfn(AXI_PHYS_BASE), |
| .length = AXI_SIZE, |
| .type = MT_DEVICE, |
| }, |
| }, |
| [AMBARELLA_IO_DESC_DDD_ID] = { |
| .name = "DDD", |
| .io_desc = { |
| .virtual= DDD_BASE, |
| .pfn = __phys_to_pfn(DDD_PHYS_BASE), |
| .length = DDD_SIZE, |
| .type = MT_DEVICE, |
| }, |
| }, |
| #endif |
| #endif |
| }; |
| |
| #if defined(CONFIG_PLAT_AMBARELLA_SUPPORT_HAL) |
| static struct ambarella_mem_hal_desc ambarella_hal_info = { |
| .physaddr = DEFAULT_HAL_START, |
| .size = DEFAULT_HAL_SIZE, |
| .virtual = DEFAULT_HAL_BASE, |
| .remapped = 0, |
| .inited = 0, |
| }; |
| DEFINE_SPINLOCK(ambarella_hal_info_lock); |
| unsigned long ambarella_hal_info_lock_flags; |
| #endif |
| |
| static struct ambarella_mem_rev_desc ambarella_bst_info = { |
| .physaddr = DEFAULT_BST_START, |
| .size = DEFAULT_BST_SIZE, |
| }; |
| |
| void __init ambarella_map_io(void) |
| { |
| int i; |
| u32 iop, ios, iov; |
| #if defined(CONFIG_PLAT_AMBARELLA_SUPPORT_HAL) |
| u32 halp, hals, halv; |
| unsigned int hal_type = 0; |
| int bhal_mapped = 0; |
| struct map_desc hal_desc; |
| |
| spin_lock_irqsave(&ambarella_hal_info_lock, |
| ambarella_hal_info_lock_flags); |
| halp = ambarella_hal_info.physaddr; |
| hals = ambarella_hal_info.size; |
| halv = ambarella_hal_info.virtual; |
| spin_unlock_irqrestore(&ambarella_hal_info_lock, |
| ambarella_hal_info_lock_flags); |
| #endif |
| |
| for (i = 0; i < ARRAY_SIZE(ambarella_io_desc); i++) { |
| iop = __pfn_to_phys(ambarella_io_desc[i].io_desc.pfn); |
| ios = ambarella_io_desc[i].io_desc.length; |
| iov = ambarella_io_desc[i].io_desc.virtual; |
| if (ios > 0) { |
| iotable_init(&(ambarella_io_desc[i].io_desc), 1); |
| pr_info("Ambarella: %s\t= 0x%08x[0x%08x],0x%08x %d\n", |
| ambarella_io_desc[i].name, iop, iov, ios, |
| ambarella_io_desc[i].io_desc.type); |
| #if defined(CONFIG_PLAT_AMBARELLA_SUPPORT_HAL) |
| if ((halv >= iov) && ((halv + hals) <= (iov + ios))) { |
| bhal_mapped = 1; |
| hal_type = ambarella_io_desc[i].io_desc.type; |
| } |
| #endif |
| } |
| } |
| |
| if (ambarella_io_desc[AMBARELLA_IO_DESC_PPM_ID].io_desc.length == 0) { |
| iov = __phys_to_virt(DEFAULT_MEM_START); |
| ios = SZ_1M; |
| ambarella_io_desc[AMBARELLA_IO_DESC_PPM_ID].io_desc.virtual = |
| iov; |
| ambarella_io_desc[AMBARELLA_IO_DESC_PPM_ID].io_desc.length = |
| ios; |
| ambarella_io_desc[AMBARELLA_IO_DESC_PPM_ID].io_desc.pfn = |
| __phys_to_pfn(DEFAULT_MEM_START); |
| #if defined(CONFIG_PLAT_AMBARELLA_SUPPORT_HAL) |
| if ((halv >= iov) && ((halv + hals) <= (iov + ios))) { |
| bhal_mapped = 1; |
| hal_type = MT_MEMORY; |
| } |
| #endif |
| } |
| |
| #if defined(CONFIG_PLAT_AMBARELLA_SUPPORT_HAL) |
| spin_lock_irqsave(&ambarella_hal_info_lock, |
| ambarella_hal_info_lock_flags); |
| if (!bhal_mapped) { |
| if (!ambarella_hal_info.remapped) { |
| hal_desc.virtual = halv; |
| hal_desc.pfn = __phys_to_pfn(halp); |
| hal_desc.length = hals; |
| hal_desc.type = MT_MEMORY; |
| iotable_init(&hal_desc, 1); |
| bhal_mapped = 1; |
| hal_type = hal_desc.type; |
| ambarella_hal_info.remapped = bhal_mapped; |
| } else { |
| hal_type = MT_MEMORY; |
| } |
| } else { |
| ambarella_hal_info.remapped = bhal_mapped; |
| } |
| if (ambarella_hal_info.remapped) |
| pr_info("Ambarella: HAL\t= 0x%08x[0x%08x],0x%08x %d\n", |
| halp, halv, hals, hal_type); |
| else |
| pr_info("Ambarella: HAL\t= 0x%08x[0x%08x],0x%08x Map Fail!\n", |
| halp, halv, hals); |
| spin_unlock_irqrestore(&ambarella_hal_info_lock, |
| ambarella_hal_info_lock_flags); |
| #endif |
| } |
| |
| /* ==========================================================================*/ |
| static int __init dsp_mem_check(u32 start, u32 size) |
| { |
| u32 vstart; |
| u32 tmp; |
| |
| if ((start & MEM_MAP_CHECK_MASK) || (start < DEFAULT_MEM_START)) { |
| pr_err("Ambarella: Bad DSP mem start 0x%08x\n", start); |
| return -EINVAL; |
| } |
| |
| if (size & MEM_MAP_CHECK_MASK) { |
| pr_err("Ambarella: Bad DSP mem size 0x%08x\n", size); |
| return -EINVAL; |
| } |
| |
| vstart = (start - DEFAULT_MEM_START) + NOLINUX_MEM_V_START; |
| if (vstart < VMALLOC_END) { |
| pr_err("Ambarella: Bad DSP virtual 0x%08x\n", vstart); |
| return -EINVAL; |
| } |
| if (vstart >= (NOLINUX_MEM_V_START + NOLINUX_MEM_V_SIZE)) { |
| tmp = vstart - NOLINUX_MEM_V_SIZE; |
| if (tmp < NOLINUX_MEM_V_START) { |
| tmp = NOLINUX_MEM_V_START; |
| } |
| pr_info("%s: Change DSP start form 0x%08x to 0x%08x\n", |
| __func__, vstart, tmp); |
| vstart = tmp; |
| } |
| if ((vstart + size) > (NOLINUX_MEM_V_START + NOLINUX_MEM_V_SIZE)) { |
| tmp = (NOLINUX_MEM_V_START + NOLINUX_MEM_V_SIZE) - vstart; |
| pr_info("%s: Change DSP size form 0x%08x to 0x%08x\n", |
| __func__, size, tmp); |
| size = tmp; |
| } |
| |
| ambarella_io_desc[AMBARELLA_IO_DESC_DSP_ID].io_desc.virtual = vstart; |
| ambarella_io_desc[AMBARELLA_IO_DESC_DSP_ID].io_desc.pfn = |
| __phys_to_pfn(start); |
| ambarella_io_desc[AMBARELLA_IO_DESC_DSP_ID].io_desc.length = size; |
| |
| return 0; |
| } |
| |
| static int __init early_dsp(char *p) |
| { |
| unsigned long start = 0; |
| unsigned long size = 0; |
| char *endp; |
| |
| start = memparse(p, &endp); |
| if (*endp == ',') |
| size = memparse(endp + 1, NULL); |
| |
| return dsp_mem_check(start, size); |
| } |
| early_param("dsp", early_dsp); |
| |
| static int __init parse_mem_tag_dsp(const struct tag *tag) |
| { |
| return dsp_mem_check(tag->u.mem.start, tag->u.mem.size); |
| } |
| __tagtable(ATAG_AMBARELLA_DSP, parse_mem_tag_dsp); |
| |
| /* ==========================================================================*/ |
| static int __init bsb_mem_check(u32 start, u32 size) |
| { |
| u32 vstart; |
| u32 tmp; |
| |
| if ((start & MEM_MAP_CHECK_MASK) || (start < DEFAULT_MEM_START)) { |
| pr_err("Ambarella: Bad BSB mem start 0x%08x\n", start); |
| return -EINVAL; |
| } |
| |
| if (size & MEM_MAP_CHECK_MASK) { |
| pr_err("Ambarella: Bad BSB mem size 0x%08x\n", size); |
| return -EINVAL; |
| } |
| |
| vstart = (start - DEFAULT_MEM_START) + NOLINUX_MEM_V_START; |
| if (vstart < VMALLOC_END) { |
| pr_err("Ambarella: Bad BSB virtual 0x%08x\n", vstart); |
| return -EINVAL; |
| } |
| if (vstart >= (NOLINUX_MEM_V_START + NOLINUX_MEM_V_SIZE)) { |
| tmp = vstart - NOLINUX_MEM_V_SIZE; |
| if (tmp < NOLINUX_MEM_V_START) { |
| tmp = NOLINUX_MEM_V_START; |
| } |
| pr_info("%s: Change DSP start form 0x%08x to 0x%08x\n", |
| __func__, vstart, tmp); |
| vstart = tmp; |
| } |
| if ((vstart + size) > (NOLINUX_MEM_V_START + NOLINUX_MEM_V_SIZE)) { |
| tmp = (NOLINUX_MEM_V_START + NOLINUX_MEM_V_SIZE) - vstart; |
| pr_info("%s: Change DSP size form 0x%08x to 0x%08x\n", |
| __func__, size, tmp); |
| size = tmp; |
| } |
| |
| ambarella_io_desc[AMBARELLA_IO_DESC_BSB_ID].io_desc.virtual = vstart; |
| ambarella_io_desc[AMBARELLA_IO_DESC_BSB_ID].io_desc.pfn = |
| __phys_to_pfn(start); |
| ambarella_io_desc[AMBARELLA_IO_DESC_BSB_ID].io_desc.length = size; |
| |
| high_memory = __va(__pfn_to_phys(__phys_to_pfn(start))); |
| |
| return 0; |
| } |
| |
| static int __init early_bsb(char *p) |
| { |
| unsigned long start = 0; |
| unsigned long size = 0; |
| char *endp; |
| |
| start = memparse(p, &endp); |
| if (*endp == ',') |
| size = memparse(endp + 1, NULL); |
| |
| return bsb_mem_check(start, size); |
| } |
| early_param("bsb", early_bsb); |
| |
| /* ==========================================================================*/ |
| static int __init parse_mem_tag_bsb(const struct tag *tag) |
| { |
| return bsb_mem_check(tag->u.mem.start, tag->u.mem.size); |
| } |
| __tagtable(ATAG_AMBARELLA_BSB, parse_mem_tag_bsb); |
| |
| static int __init parse_mem_tag_bst(const struct tag *tag) |
| { |
| ambarella_bst_info.physaddr = tag->u.mem.start; |
| ambarella_bst_info.size = tag->u.mem.size; |
| |
| return 0; |
| } |
| __tagtable(ATAG_AMBARELLA_BST, parse_mem_tag_bst); |
| |
| u32 get_ambarella_ppm_phys(void) |
| { |
| return __pfn_to_phys( |
| ambarella_io_desc[AMBARELLA_IO_DESC_PPM_ID].io_desc.pfn); |
| } |
| EXPORT_SYMBOL(get_ambarella_ppm_phys); |
| |
| u32 get_ambarella_ppm_virt(void) |
| { |
| return ambarella_io_desc[AMBARELLA_IO_DESC_PPM_ID].io_desc.virtual; |
| } |
| EXPORT_SYMBOL(get_ambarella_ppm_virt); |
| |
| u32 get_ambarella_ppm_size(void) |
| { |
| return ambarella_io_desc[AMBARELLA_IO_DESC_PPM_ID].io_desc.length; |
| } |
| EXPORT_SYMBOL(get_ambarella_ppm_size); |
| |
| u32 get_ambarella_bsbmem_phys(void) |
| { |
| return __pfn_to_phys( |
| ambarella_io_desc[AMBARELLA_IO_DESC_BSB_ID].io_desc.pfn); |
| } |
| EXPORT_SYMBOL(get_ambarella_bsbmem_phys); |
| |
| u32 get_ambarella_bsbmem_virt(void) |
| { |
| return ambarella_io_desc[AMBARELLA_IO_DESC_BSB_ID].io_desc.virtual; |
| } |
| EXPORT_SYMBOL(get_ambarella_bsbmem_virt); |
| |
| u32 get_ambarella_bsbmem_size(void) |
| { |
| return ambarella_io_desc[AMBARELLA_IO_DESC_BSB_ID].io_desc.length; |
| } |
| EXPORT_SYMBOL(get_ambarella_bsbmem_size); |
| |
| u32 get_ambarella_dspmem_phys(void) |
| { |
| return __pfn_to_phys( |
| ambarella_io_desc[AMBARELLA_IO_DESC_DSP_ID].io_desc.pfn); |
| } |
| EXPORT_SYMBOL(get_ambarella_dspmem_phys); |
| |
| u32 get_ambarella_dspmem_virt(void) |
| { |
| return ambarella_io_desc[AMBARELLA_IO_DESC_DSP_ID].io_desc.virtual; |
| } |
| EXPORT_SYMBOL(get_ambarella_dspmem_virt); |
| |
| u32 get_ambarella_dspmem_size(void) |
| { |
| return ambarella_io_desc[AMBARELLA_IO_DESC_DSP_ID].io_desc.length; |
| } |
| EXPORT_SYMBOL(get_ambarella_dspmem_size); |
| |
| u32 get_ambarella_bstmem_info(u32 *bstadd, u32 *bstsize) |
| { |
| if ((ambarella_bst_info.size == 0) || |
| (ambarella_bst_info.physaddr < get_ambarella_ppm_phys()) || |
| ((ambarella_bst_info.physaddr + ambarella_bst_info.size) > |
| (get_ambarella_ppm_phys() + get_ambarella_ppm_size()))) |
| return AMB_BST_INVALID; |
| |
| *bstadd = ambarella_bst_info.physaddr; |
| *bstsize = ambarella_bst_info.size; |
| |
| return AMB_BST_MAGIC; |
| } |
| EXPORT_SYMBOL(get_ambarella_bstmem_info); |
| |
| u32 *get_ambarella_bstmem_head(void) |
| { |
| u32 *pstart_address = NULL; |
| u32 *phead_address = NULL; |
| u32 offset = 0; |
| u32 valid = 0; |
| |
| if (ambarella_bst_info.size == 0) |
| return (u32 *)AMB_BST_INVALID; |
| |
| pstart_address = (u32 *)ambarella_phys_to_virt( |
| ambarella_bst_info.physaddr); |
| for (phead_address = |
| &pstart_address[(ambarella_bst_info.size >> 2) - 1]; |
| phead_address > pstart_address; phead_address--) { |
| if (*phead_address == AMB_BST_MAGIC) { |
| valid = 1; |
| break; |
| } |
| } |
| for (; phead_address > pstart_address; phead_address--) { |
| if (*phead_address != AMB_BST_MAGIC) { |
| offset = *phead_address; |
| break; |
| } |
| } |
| if ((offset == 0) || (valid == 0)) |
| return (u32 *)AMB_BST_INVALID; |
| |
| phead_address -= (offset >> 2); |
| |
| return phead_address; |
| } |
| EXPORT_SYMBOL(get_ambarella_bstmem_head); |
| |
| u32 ambarella_phys_to_virt(u32 paddr) |
| { |
| int i; |
| u32 phystart; |
| u32 phylength; |
| u32 phyoffset; |
| u32 vstart; |
| |
| for (i = 0; i < ARRAY_SIZE(ambarella_io_desc); i++) { |
| phystart = __pfn_to_phys(ambarella_io_desc[i].io_desc.pfn); |
| phylength = ambarella_io_desc[i].io_desc.length; |
| vstart = ambarella_io_desc[i].io_desc.virtual; |
| if ((paddr >= phystart) && (paddr < (phystart + phylength))) { |
| phyoffset = paddr - phystart; |
| return (vstart + phyoffset); |
| } |
| } |
| |
| return __phys_to_virt(paddr); |
| } |
| EXPORT_SYMBOL(ambarella_phys_to_virt); |
| |
| u32 ambarella_virt_to_phys(u32 vaddr) |
| { |
| int i; |
| u32 phystart; |
| u32 vlength; |
| u32 voffset; |
| u32 vstart; |
| |
| for (i = 0; i < ARRAY_SIZE(ambarella_io_desc); i++) { |
| phystart = __pfn_to_phys(ambarella_io_desc[i].io_desc.pfn); |
| vlength = ambarella_io_desc[i].io_desc.length; |
| vstart = ambarella_io_desc[i].io_desc.virtual; |
| if ((vaddr >= vstart) && (vaddr < (vstart + vlength))) { |
| voffset = vaddr - vstart; |
| return (phystart + voffset); |
| } |
| } |
| |
| return __virt_to_phys(vaddr); |
| } |
| EXPORT_SYMBOL(ambarella_virt_to_phys); |
| |
| u32 get_ambarella_ahb_phys(void) |
| { |
| return __pfn_to_phys( |
| ambarella_io_desc[AMBARELLA_IO_DESC_AHB_ID].io_desc.pfn); |
| } |
| EXPORT_SYMBOL(get_ambarella_ahb_phys); |
| |
| u32 get_ambarella_ahb_virt(void) |
| { |
| return ambarella_io_desc[AMBARELLA_IO_DESC_AHB_ID].io_desc.virtual; |
| } |
| EXPORT_SYMBOL(get_ambarella_ahb_virt); |
| |
| u32 get_ambarella_ahb_size(void) |
| { |
| return ambarella_io_desc[AMBARELLA_IO_DESC_AHB_ID].io_desc.length; |
| } |
| EXPORT_SYMBOL(get_ambarella_ahb_size); |
| |
| u32 get_ambarella_apb_phys(void) |
| { |
| return __pfn_to_phys( |
| ambarella_io_desc[AMBARELLA_IO_DESC_APB_ID].io_desc.pfn); |
| } |
| EXPORT_SYMBOL(get_ambarella_apb_phys); |
| |
| u32 get_ambarella_apb_virt(void) |
| { |
| return ambarella_io_desc[AMBARELLA_IO_DESC_APB_ID].io_desc.virtual; |
| } |
| EXPORT_SYMBOL(get_ambarella_apb_virt); |
| |
| u32 get_ambarella_apb_size(void) |
| { |
| return ambarella_io_desc[AMBARELLA_IO_DESC_APB_ID].io_desc.length; |
| } |
| EXPORT_SYMBOL(get_ambarella_apb_size); |
| |
| /* ==========================================================================*/ |
| static struct ambarella_mem_rev_info ambarella_reserve_mem_info = { |
| .counter = 0, |
| }; |
| |
| static int __init reserve_mem_check(u32 start, u32 size) |
| { |
| u32 index; |
| |
| if ((start & MEM_MAP_CHECK_MASK) || (start < PHYS_OFFSET)) { |
| pr_err("Ambarella: Bad revmem start 0x%08x\n", start); |
| return -EINVAL; |
| } |
| |
| if (size & MEM_MAP_CHECK_MASK) { |
| pr_err("Ambarella: Bad revmem size 0x%08x\n", size); |
| return -EINVAL; |
| } |
| |
| index = ambarella_reserve_mem_info.counter; |
| if (index < MEMORY_RESERVE_MAX_NR) { |
| ambarella_reserve_mem_info.desc[index].physaddr = start; |
| ambarella_reserve_mem_info.desc[index].size = size; |
| ambarella_reserve_mem_info.counter++; |
| } else { |
| pr_err("Ambarella: too much revmem %d!\n", index); |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| static int __init early_revmem(char *p) |
| { |
| unsigned long start = 0; |
| unsigned long size = 0; |
| char *endp; |
| |
| start = memparse(p, &endp); |
| if (*endp == ',') |
| size = memparse(endp + 1, NULL); |
| |
| return reserve_mem_check(start, size); |
| } |
| early_param("revmem", early_revmem); |
| |
| static int __init parse_mem_tag_revmem(const struct tag *tag) |
| { |
| return reserve_mem_check(tag->u.mem.start, tag->u.mem.size); |
| } |
| __tagtable(ATAG_AMBARELLA_REVMEM, parse_mem_tag_revmem); |
| |
| u32 get_ambarella_mem_rev_info(struct ambarella_mem_rev_info *pinfo) |
| { |
| int i; |
| u32 revp, revs; |
| |
| if (ambarella_reserve_mem_info.counter) |
| pr_info("Ambarella Reserve Memory:\n"); |
| |
| for (i = 0; i < ambarella_reserve_mem_info.counter; i++) { |
| revp = ambarella_reserve_mem_info.desc[i].physaddr; |
| revs = ambarella_reserve_mem_info.desc[i].size; |
| pr_info("\t%02d:\t0x%08x[0x%08x]\tNormal\n", i, revp, revs); |
| } |
| |
| *pinfo = ambarella_reserve_mem_info; |
| |
| return 0; |
| } |
| EXPORT_SYMBOL(get_ambarella_mem_rev_info); |
| |
| /* ==========================================================================*/ |
| #if defined(CONFIG_PLAT_AMBARELLA_SUPPORT_HAL) |
| |
| static int __init hal_mem_check(u32 pstart, u32 size, u32 vstart) |
| { |
| if ((pstart & MEM_MAP_CHECK_MASK) || (pstart < DEFAULT_MEM_START)) { |
| pr_err("Ambarella: Bad HAL pstart 0x%08x\n", pstart); |
| return -EINVAL; |
| } |
| |
| if (vstart & MEM_MAP_CHECK_MASK) { |
| pr_err("Ambarella: Bad HAL vstart 0x%08x\n", vstart); |
| return -EINVAL; |
| } |
| |
| spin_lock_irqsave(&ambarella_hal_info_lock, |
| ambarella_hal_info_lock_flags); |
| ambarella_hal_info.physaddr = pstart; |
| ambarella_hal_info.size = size; |
| ambarella_hal_info.virtual = vstart; |
| spin_unlock_irqrestore(&ambarella_hal_info_lock, |
| ambarella_hal_info_lock_flags); |
| |
| return 0; |
| } |
| |
| static int __init early_hal(char *p) |
| { |
| unsigned long pstart = 0; |
| unsigned long size = 0; |
| unsigned long vstart = 0; |
| char *endp; |
| |
| pstart = memparse(p, &endp); |
| if (*endp == ',') |
| vstart = memparse(endp + 1, &endp); |
| if (*endp == ',') |
| size = memparse(endp + 1, NULL); |
| |
| return hal_mem_check(pstart, size, vstart); |
| } |
| early_param("hal", early_hal); |
| |
| static int __init parse_mem_tag_hal(const struct tag *tag) |
| { |
| return hal_mem_check(tag->u.ramdisk.start, |
| tag->u.ramdisk.size, tag->u.ramdisk.flags); |
| } |
| __tagtable(ATAG_AMBARELLA_HAL, parse_mem_tag_hal); |
| |
| void *ambarella_hal_get_vp(void) |
| { |
| u32 hal_vp; |
| |
| spin_lock_irqsave(&ambarella_hal_info_lock, |
| ambarella_hal_info_lock_flags); |
| if (unlikely((!ambarella_hal_info.remapped))) { |
| pr_err("%s: remap HAL first!\n", __func__); |
| BUG(); |
| } |
| |
| if (unlikely((!ambarella_hal_info.inited))) { |
| amb_hal_success_t retval; |
| |
| #if defined(CONFIG_PLAT_AMBARELLA_SUPPORT_MMAP_NEW) |
| retval = amb_set_peripherals_base_address( |
| (void *)ambarella_hal_info.virtual, |
| (void *)APB_BASE, (void *)AHB_BASE, |
| (void *)DRAMC_BASE); |
| #else |
| retval = amb_set_peripherals_base_address( |
| (void *)ambarella_hal_info.virtual, |
| (void *)APB_BASE, (void *)AHB_BASE); |
| #endif |
| BUG_ON(retval != AMB_HAL_SUCCESS); |
| ambarella_hal_info.inited = 1; |
| } |
| |
| hal_vp = ambarella_hal_info.virtual; |
| spin_unlock_irqrestore(&ambarella_hal_info_lock, |
| ambarella_hal_info_lock_flags); |
| |
| return (void *)hal_vp; |
| } |
| EXPORT_SYMBOL(ambarella_hal_get_vp); |
| |
| u32 ambarella_hal_get_size(void) |
| { |
| u32 hal_size; |
| |
| spin_lock_irqsave(&ambarella_hal_info_lock, |
| ambarella_hal_info_lock_flags); |
| hal_size = ambarella_hal_info.size; |
| spin_unlock_irqrestore(&ambarella_hal_info_lock, |
| ambarella_hal_info_lock_flags); |
| return hal_size; |
| } |
| EXPORT_SYMBOL(ambarella_hal_get_size); |
| |
| void ambarella_hal_set_invalid(void) |
| { |
| spin_lock_irqsave(&ambarella_hal_info_lock, |
| ambarella_hal_info_lock_flags); |
| ambarella_hal_info.inited = 0; |
| spin_unlock_irqrestore(&ambarella_hal_info_lock, |
| ambarella_hal_info_lock_flags); |
| } |
| #endif |
| |
| int arch_pfn_is_nosave(unsigned long pfn) |
| { |
| int i; |
| unsigned long nosave_begin_pfn; |
| unsigned long nosave_end_pfn; |
| |
| nosave_begin_pfn = |
| ambarella_io_desc[AMBARELLA_IO_DESC_PPM_ID].io_desc.pfn; |
| nosave_end_pfn = PFN_PHYS(nosave_begin_pfn) + |
| ambarella_io_desc[AMBARELLA_IO_DESC_PPM_ID].io_desc.length; |
| nosave_end_pfn = PFN_UP(nosave_end_pfn); |
| |
| if ((pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn)) |
| return 1; |
| |
| for (i = 0; i < ambarella_reserve_mem_info.counter; i++) { |
| nosave_begin_pfn = __phys_to_pfn( |
| ambarella_reserve_mem_info.desc[i].physaddr); |
| nosave_end_pfn = __phys_to_pfn( |
| ambarella_reserve_mem_info.desc[i].physaddr + |
| ambarella_reserve_mem_info.desc[i].size); |
| if ((pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn)) |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| /* ==========================================================================*/ |
| static int __init early_boot_splash_logo(char *p) |
| { |
| ambarella_boot_splash_logo = 1; |
| return 0; |
| } |
| early_param("boot_splash_logo_on", early_boot_splash_logo); |
| |