| /* |
| * 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/types.h> |
| #include <linux/kernel.h> |
| #include <linux/init.h> |
| #include <linux/list.h> |
| #include <linux/device.h> |
| #include <linux/slab.h> |
| #include <linux/string.h> |
| #include <linux/sysdev.h> |
| #include <asm/mach/time.h> |
| #include <linux/clocksource.h> |
| #include <mach/hardware.h> |
| #include <asm/io.h> |
| #include <asm/irq.h> |
| #include <asm/setup.h> |
| #include <asm/mach-types.h> |
| |
| #include <asm/mach/arch.h> |
| #include <asm/mach/flash.h> |
| #include <asm/mach/irq.h> |
| #include <asm/mach/map.h> |
| #include <mach/system.h> |
| |
| #include <linux/tty.h> |
| #include <linux/platform_device.h> |
| #include <linux/serial_core.h> |
| #include <linux/serial.h> |
| #include <linux/serial_8250.h> |
| #include <linux/serial_reg.h> |
| #include <asm/serial.h> |
| #include <plat/cache-feroceon-l2.h> |
| #include <linux/proc_fs.h> |
| #include <linux/mtd/partitions.h> |
| #include <linux/mtd/nand.h> |
| |
| #include <mach/serial.h> |
| |
| #include "ctrlEnv/mvCtrlEnvLib.h" |
| #include "ctrlEnv/mvCtrlEthCompLib.h" |
| #include "ctrlEnv/sys/mvCpuIf.h" |
| #include "cpu/mvCpu.h" |
| #include "boardEnv/mvBoardEnvLib.h" |
| #include "mvDebug.h" |
| #include "mvSysHwConfig.h" |
| #include "pex/mvPexRegs.h" |
| #include "cntmr/mvCntmr.h" |
| #include "gpp/mvGpp.h" |
| #include "plat/gpio.h" |
| #ifdef CONFIG_MTD_NAND_NFC |
| #include "mv_mtd/nand_nfc.h" |
| #endif |
| #if defined(CONFIG_MV_INCLUDE_SDIO) |
| #include "sdmmc/mvSdmmc.h" |
| #include <plat/mvsdio.h> |
| #endif |
| #if defined(CONFIG_MV_INCLUDE_CESA) |
| #include "cesa/mvCesa.h" |
| #endif |
| |
| /* WD */ |
| #include <plat/orion_wdt.h> |
| |
| /* I2C */ |
| #include <linux/i2c.h> |
| #include <linux/mv643xx_i2c.h> |
| #include "ctrlEnv/mvCtrlEnvSpec.h" |
| |
| /* SPI */ |
| #include "mvSysSpiApi.h" |
| |
| |
| /* Eth Phy */ |
| #include "mvSysEthPhyApi.h" |
| |
| extern unsigned int irq_int_type[]; |
| |
| /* for debug putstr */ |
| #include <mach/uncompress.h> |
| static char arr[256]; |
| |
| extern void mv_kw2_cpu_idle_enter_wfi(void); |
| |
| #ifdef MV_INCLUDE_EARLY_PRINTK |
| extern void putstr(const char *ptr); |
| void mv_early_printk(char *fmt,...) |
| { |
| va_list args; |
| va_start(args, fmt); |
| vsprintf(arr,fmt,args); |
| va_end(args); |
| putstr(arr); |
| } |
| #endif |
| |
| |
| extern void __init mv_map_io(void); |
| extern void __init mv_init_irq(void); |
| extern struct sys_timer mv_timer; |
| extern MV_CPU_DEC_WIN* mv_sys_map(void); |
| #if defined(CONFIG_MV_INCLUDE_CESA) |
| extern u32 mv_crypto_base_get(void); |
| #endif |
| unsigned int support_wait_for_interrupt = 0x1; |
| |
| #ifdef CONFIG_MV_PMU_PROC |
| struct proc_dir_entry *mv_pm_proc_entry; |
| #endif /* CONFIG_MV_PMU_PROC */ |
| |
| u32 mvTclk = 166666667; |
| u32 mvSysclk = 200000000; |
| u32 mvIsUsbHost = 1; |
| u32 mod_config = 0; |
| |
| #ifdef CONFIG_MV_INCLUDE_GIG_ETH |
| u8 mvMacAddr[CONFIG_MV_ETH_PORTS_NUM][6]; |
| u16 mvMtu[CONFIG_MV_ETH_PORTS_NUM] = {0}; |
| #endif |
| extern MV_U32 gBoardId; |
| extern unsigned int elf_hwcap; |
| |
| #ifdef CONFIG_MTD_NAND_LNC |
| extern unsigned int mv_nand_ecc; |
| #endif |
| |
| static int noL2 = 0; |
| static int __init noL2_setup(char *__unused) |
| { |
| noL2 = 1; |
| return 1; |
| } |
| __setup("noL2", noL2_setup); |
| |
| |
| static int __init parse_tag_mv_uboot(const struct tag *tag) |
| { |
| unsigned int mvUbootVer = 0; |
| int i = 0; |
| |
| mvUbootVer = tag->u.mv_uboot.uboot_version; |
| mvIsUsbHost = tag->u.mv_uboot.isUsbHost; |
| |
| printk("Using UBoot passing parameters structure: UbootVer:%x\n", mvUbootVer); |
| |
| gBoardId = (mvUbootVer & 0xff); |
| #ifdef CONFIG_MACH_GFLT110 |
| if ((gBoardId != GFLT110_ID) && (gBoardId != GFLT300_ID)) { |
| printk("Unknown boardId from uboot: %x: Defaulting to GFLT110.\n", gBoardId); |
| gBoardId = GFLT110_ID; |
| } |
| #endif |
| printk("Google BoardId: %x\n", mvBoardIdGet()); |
| #ifdef CONFIG_MV_INCLUDE_GIG_ETH |
| for (i = 0; i < CONFIG_MV_ETH_PORTS_NUM; i++) { |
| #if defined (CONFIG_OVERRIDE_ETH_CMDLINE) |
| memset(mvMacAddr[i], 0, 6); |
| mvMtu[i] = 0; |
| #else |
| memcpy(mvMacAddr[i], tag->u.mv_uboot.macAddr[i], 6); |
| mvMtu[i] = tag->u.mv_uboot.mtu[i]; |
| #endif |
| } |
| #endif |
| #ifdef CONFIG_MTD_NAND_LNC |
| /* get NAND ECC type(1-bit or 4-bit) */ |
| if((mvUbootVer >> 8) >= 0x3040c) |
| mv_nand_ecc = tag->u.mv_uboot.nand_ecc; |
| else |
| mv_nand_ecc = 1; /* fallback to 1-bit ECC */ |
| #endif |
| |
| mod_config = tag->u.mv_uboot.mod_bitmask; |
| |
| return 0; |
| } |
| |
| __tagtable(ATAG_MV_UBOOT, parse_tag_mv_uboot); |
| |
| #ifdef CONFIG_MV_INCLUDE_CESA |
| unsigned char* mv_sram_usage_get(int* sram_size_ptr) |
| { |
| int used_size = 0; |
| |
| #if defined(CONFIG_MV_CESA) |
| used_size = sizeof(MV_CESA_SRAM_MAP); |
| #endif |
| |
| if(sram_size_ptr != NULL) |
| *sram_size_ptr = _8K - used_size; |
| |
| return (char *)(mv_crypto_base_get() + used_size); |
| } |
| #endif |
| |
| |
| void print_board_info(void) |
| { |
| char name_buff[50]; |
| printk("\n Marvell Development Board (LSP Version %s_%s)", LSP_VERSION, UPON_SDK_VERSION); |
| |
| mvBoardNameGet(name_buff); |
| printk("-- %s ",name_buff); |
| |
| mvCtrlModelRevNameGet(name_buff); |
| printk(" Soc: %s", name_buff); |
| #if defined(MV_CPU_LE) |
| printk(" LE"); |
| #else |
| printk(" BE"); |
| #endif |
| printk("\n\n"); |
| printk(" Detected Tclk %d and SysClk %d \n",mvTclk, mvSysclk); |
| } |
| |
| /***************************************************************************** |
| * I2C(TWSI) |
| ****************************************************************************/ |
| |
| /* Platform devices list */ |
| |
| static struct mv64xxx_i2c_pdata kw_i2c_pdata = { |
| .freq_m = 12, /* assumes 200 MHz TCLK */ |
| .freq_n = 3, |
| .timeout = 1000, /* Default timeout of 1 second */ |
| }; |
| |
| static struct resource kw_i2c_resources[] = { |
| { |
| .name = "i2c base", |
| .start = INTER_REGS_BASE + MV_TWSI_SLAVE_REGS_OFFSET(0), |
| .end = INTER_REGS_BASE + MV_TWSI_SLAVE_REGS_OFFSET(0) + 0x20 -1, |
| .flags = IORESOURCE_MEM, |
| }, |
| { |
| .name = "i2c irq", |
| .start = TWSI_IRQ_NUM(0), |
| .end = TWSI_IRQ_NUM(0), |
| .flags = IORESOURCE_IRQ, |
| }, |
| }; |
| |
| static struct platform_device kw_i2c = { |
| .name = MV64XXX_I2C_CTLR_NAME, |
| .id = 0, |
| .num_resources = ARRAY_SIZE(kw_i2c_resources), |
| .resource = kw_i2c_resources, |
| .dev = { |
| .platform_data = &kw_i2c_pdata, |
| }, |
| }; |
| |
| #ifdef CONFIG_MTD_NAND_NFC |
| /***************************************************************************** |
| * NAND controller |
| ****************************************************************************/ |
| static struct resource kw2_nfc_resources[] = { |
| { |
| .start = INTER_REGS_BASE + MV_NFC_REGS_OFFSET, |
| .end = INTER_REGS_BASE + MV_NFC_REGS_OFFSET + 0x400 -1, |
| .flags = IORESOURCE_MEM, |
| } |
| }; |
| #endif |
| |
| #if 0 |
| struct mtd_partition nand_parts_info[] = { |
| { .name = "uboot", |
| .offset = 0, |
| .size = 2 * 1024 * 1024 }, |
| { .name = "uimageU", |
| .offset = MTDPART_OFS_NXTBLK, |
| .size = 4 * 1024 * 1024 }, |
| { .name = "rootfsU", |
| .offset = MTDPART_OFS_NXTBLK, |
| .size = MTDPART_SIZ_FULL }, |
| }; |
| int nand_parts_num = 3; |
| #endif |
| |
| struct mtd_partition nand_parts_info[] = { |
| { .name = "uboot", |
| .offset = 0, |
| .size = 2 * 1024 * 1024 }, |
| { .name = "uimageU", |
| .offset = MTDPART_OFS_NXTBLK, |
| .size = 4 * 1024 * 1024 }, |
| { .name = "rootfsU", |
| .offset = MTDPART_OFS_NXTBLK, |
| .size = 94 * 1024 * 1024 }, |
| { .name = "spacer", |
| .offset = MTDPART_OFS_NXTBLK, |
| .size = 2 * 1024 * 1024 }, |
| { .name = "uimageB", |
| .offset = MTDPART_OFS_NXTBLK, |
| .size = 4 * 1024 * 1024 }, |
| { .name = "rootfsB", |
| .offset = MTDPART_OFS_NXTBLK, |
| .size = MTDPART_SIZ_FULL }, |
| }; |
| int nand_parts_num = 6; |
| |
| |
| #ifdef CONFIG_MTD_NAND_NFC |
| static struct nfc_platform_data kw2_nfc_data = { |
| .nfc_width = 8, |
| .num_devs = 1, |
| .num_cs = 1, |
| .use_dma = 0, |
| .ecc_type = MV_NFC_ECC_BCH_2K, |
| .parts = nand_parts_info, |
| .nr_parts = 3, |
| }; |
| |
| static struct platform_device kw2_nfc = { |
| .name = "orion-nfc-hal", |
| .id = 0, |
| .num_resources = ARRAY_SIZE(kw2_nfc_resources), |
| .resource = kw2_nfc_resources, |
| .dev = { |
| .platform_data = &kw2_nfc_data, |
| }, |
| }; |
| #endif |
| |
| /***************************************************************************** |
| * UART |
| ****************************************************************************/ |
| static struct resource mv_uart0_resources[] = { |
| { |
| .start = PORT0_BASE, |
| .end = PORT0_BASE + 0xff, |
| .flags = IORESOURCE_MEM, |
| }, |
| { |
| #ifdef CONFIG_MV_UART_POLLING_MODE |
| .start = 0, |
| .end = 0, |
| #else |
| .start = UART_IRQ_NUM(0), |
| .end = UART_IRQ_NUM(0), |
| #endif |
| .flags = IORESOURCE_IRQ, |
| }, |
| }; |
| |
| #if 0 |
| static struct resource mv_uart1_resources[] = { |
| { |
| .start = PORT1_BASE, |
| .end = PORT1_BASE + 0xff, |
| .flags = IORESOURCE_MEM, |
| }, |
| { |
| .start = UART_IRQ_NUM(1), |
| .end = UART_IRQ_NUM(1), |
| .flags = IORESOURCE_IRQ, |
| }, |
| }; |
| #endif |
| |
| static struct plat_serial8250_port mv_uart0_data[] = { |
| { |
| .mapbase = PORT0_BASE, |
| .membase = (char *)PORT0_BASE, |
| #ifdef CONFIG_MV_UART_POLLING_MODE |
| .irq = 0, //UART_IRQ_NUM(0), |
| #else |
| .irq = UART_IRQ_NUM(0), |
| #endif |
| .flags = UPF_FIXED_TYPE | UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, |
| .iotype = UPIO_DWAPB, |
| .private_data = (void *)0xf101207c, |
| .type = PORT_16550A, |
| .regshift = 2, |
| }, |
| { }, |
| }; |
| |
| static struct plat_serial8250_port mv_uart1_data[] = { |
| { |
| .mapbase = PORT1_BASE, |
| .membase = (char *)PORT1_BASE, |
| .irq = UART_IRQ_NUM(1), |
| .flags = UPF_FIXED_TYPE | UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, |
| .iotype = UPIO_DWAPB, |
| .private_data = (void *)0xf101217c, |
| .type = PORT_16550A, |
| .regshift = 2, |
| }, |
| { }, |
| }; |
| |
| static struct platform_device mv_uart = { |
| .name = "serial8250", |
| .id = PLAT8250_DEV_PLATFORM, |
| .dev = { |
| .platform_data = mv_uart0_data, |
| }, |
| .num_resources = 2, /*ARRAY_SIZE(mv_uart_resources),*/ |
| .resource = mv_uart0_resources, |
| }; |
| |
| |
| static void serial_initialize(void) |
| { |
| mv_uart0_data[0].uartclk = mv_uart1_data[0].uartclk = mvTclk; |
| platform_device_register(&mv_uart); |
| } |
| |
| #if defined(CONFIG_MV_INCLUDE_SDIO) |
| |
| static struct resource mvsdio_resources[] = { |
| [0] = { |
| .start = INTER_REGS_BASE + MV_SDMMC_REGS_OFFSET, |
| .end = INTER_REGS_BASE + MV_SDMMC_REGS_OFFSET + SZ_1K -1, |
| .flags = IORESOURCE_MEM, |
| }, |
| [1] = { |
| .start = SDIO_IRQ_NUM, |
| .end = SDIO_IRQ_NUM, |
| .flags = IORESOURCE_IRQ, |
| }, |
| |
| }; |
| |
| static u64 mvsdio_dmamask = 0xffffffffUL; |
| |
| static struct mvsdio_platform_data mvsdio_data = { |
| .gpio_write_protect = 0, |
| .gpio_card_detect = 0, |
| .dram = NULL, |
| }; |
| |
| static struct platform_device mv_sdio_plat = { |
| .name = "mvsdio", |
| .id = -1, |
| .dev = { |
| .dma_mask = &mvsdio_dmamask, |
| .coherent_dma_mask = 0xffffffff, |
| .platform_data = &mvsdio_data, |
| }, |
| .num_resources = ARRAY_SIZE(mvsdio_resources), |
| .resource = mvsdio_resources, |
| }; |
| |
| |
| #endif /* #if defined(CONFIG_MV_INCLUDE_SDIO) */ |
| |
| #ifdef CONFIG_MV_ETHERNET |
| /***************************************************************************** |
| * Ethernet |
| ****************************************************************************/ |
| #if defined(CONFIG_MV_ETH_LEGACY) |
| static struct platform_device mv88fx_eth = { |
| .name = "mv88fx_eth", |
| .id = 0, |
| .num_resources = 0, |
| }; |
| #elif defined(CONFIG_MV_ETH_NETA) |
| static struct platform_device mv88fx_neta = { |
| .name = "mv88fx_neta", |
| .id = 0, |
| .num_resources = 0, |
| }; |
| #else |
| |
| #error "Ethernet Mode is not defined (should be Legacy or NETA)" |
| |
| #endif /* Ethernet mode: legacy or NETA */ |
| |
| #endif /* CONFIG_MV_ETHERNET */ |
| |
| /***************************************************************************** |
| * WATCHDOG |
| ****************************************************************************/ |
| |
| /* the orion watchdog device data structure */ |
| static struct orion_wdt_platform_data mv_wdt_data = { |
| .tclk = 0, |
| }; |
| |
| /* the watchdog device structure */ |
| static struct platform_device mv_wdt_device = { |
| .name = "orion_wdt", |
| .id = -1, |
| .dev = { |
| .platform_data = &mv_wdt_data, |
| }, |
| .num_resources = 0, |
| }; |
| |
| /* init the watchdog device */ |
| static void __init mv_wdt_init(void) |
| { |
| MV_U32 val; |
| |
| mv_wdt_data.tclk = mvTclk; |
| platform_device_register(&mv_wdt_device); |
| val = mvCntmrRead(WATCHDOG); |
| printk("Orion wdt: %ds remaining\n", val/mvTclk); |
| mvCntmrWrite(WATCHDOG, 0xffffffff); |
| } |
| |
| |
| static void __init kirkwood_l2_init(void) |
| { |
| #ifdef CONFIG_CACHE_FEROCEON_L2_WRITETHROUGH |
| MV_REG_BIT_SET(CPU_L2_CONFIG_REG, 0x10); |
| feroceon_l2_init(1); |
| #else |
| MV_REG_BIT_RESET(CPU_L2_CONFIG_REG, 0x10); |
| feroceon_l2_init(0); |
| #endif |
| } |
| |
| static void __init mv_init(void) |
| { |
| MV_U32 boardId; |
| |
| #ifndef CONFIG_MV_DRAM_DEFAULT_ACCESS_CFG |
| /* Support DRAM access configuration for Avanta-MC only */ |
| if (gBoardId == DB_88F6601_BP_ID || gBoardId == RD_88F6601_MC_ID || |
| gBoardId == RD_88F6601_MC2L_ID || gBoardId == RD_88F6601_SFP_ID) { |
| printk("DRAM access: "); |
| #ifdef CONFIG_MV_DRAM_XBAR_ACCESS_CFG |
| printk("XBAR\n"); |
| #else |
| printk("fast-path\n"); |
| #endif |
| } |
| #endif |
| |
| #ifdef CONFIG_CACHE_FEROCEON_L2 |
| if ((noL2 == 0) && (mvCpuL2Exists() == MV_TRUE)) |
| kirkwood_l2_init(); |
| else |
| printk("No L2-Cache.\n"); |
| #endif |
| |
| /* init the Board environment */ |
| mvBoardEnvInit(); |
| |
| /* init the controller environment */ |
| if (mvCtrlEnvInit()) { |
| printk("Controller env initialization failed.\n"); |
| return; |
| } |
| |
| /* Init the CPU windows setting and the access protection windows. */ |
| if (mvCpuIfInit(mv_sys_map())) { |
| printk("Cpu Interface initialization failed.\n"); |
| return; |
| } |
| |
| /* Init Tclk & SysClk */ |
| mvTclk = mvBoardTclkGet(); |
| mvSysclk = mvBoardSysClkGet(); |
| |
| support_wait_for_interrupt = 1; |
| |
| #ifdef CONFIG_JTAG_DEBUG |
| support_wait_for_interrupt = 0; /* for Lauterbach */ |
| #endif |
| |
| elf_hwcap &= ~HWCAP_JAVA; |
| |
| serial_initialize(); |
| |
| /* At this point, the CPU windows are configured according to default definitions in mvSysHwConfig.h */ |
| /* and cpuAddrWinMap table in mvCpuIf.c. Now it's time to change defaults for each platform. */ |
| mvCpuIfAddDecShow(); |
| |
| print_board_info(); |
| |
| mv_gpio_init(); |
| |
| #ifdef CONFIG_MV_INCLUDE_SPI |
| mvSysSpiInit(0, _16M); |
| #endif |
| |
| /* ETH-PHY */ |
| mvSysEthPhyInit(); |
| |
| /* I2C */ |
| platform_device_register(&kw_i2c); |
| |
| #ifdef CONFIG_MV_PMU_PROC |
| mv_pm_proc_entry = proc_mkdir("mv_pm", NULL); |
| #endif |
| |
| #if defined(CONFIG_MV_INCLUDE_SDIO) |
| if (mvCtrlSdioSupport()) { |
| if (MV_TRUE == mvCtrlPwrClckGet(SDIO_UNIT_ID, 0)) { |
| int irq_detect = mvBoardSDIOGpioPinGet(BOARD_GPP_SDIO_DETECT); |
| MV_UNIT_WIN_INFO addrWinMap[MAX_TARGETS + 1]; |
| |
| if (irq_detect != MV_ERROR) { |
| mvsdio_data.gpio_card_detect = mvBoardSDIOGpioPinGet(BOARD_GPP_SDIO_DETECT); |
| irq_int_type[mvBoardSDIOGpioPinGet(BOARD_GPP_SDIO_DETECT)+IRQ_GPP_START] = GPP_IRQ_TYPE_CHANGE_LEVEL; |
| } |
| |
| if (mvBoardSDIOGpioPinGet(BOARD_GPP_SDIO_WP) != MV_ERROR) |
| mvsdio_data.gpio_write_protect = mvBoardSDIOGpioPinGet(BOARD_GPP_SDIO_WP); |
| |
| if (MV_OK == mvCtrlAddrWinMapBuild(addrWinMap, MAX_TARGETS + 1)) |
| if (MV_OK == mvSdmmcWinInit(addrWinMap)) |
| mvsdio_data.clock = 200000000; //mvBoardTclkGet(); |
| platform_device_register(&mv_sdio_plat); |
| } |
| } |
| #endif |
| |
| #ifdef CONFIG_MV_ETHERNET |
| #if defined(CONFIG_MV_ETH_LEGACY) |
| platform_device_register(&mv88fx_eth); |
| #elif defined(CONFIG_MV_ETH_NETA) |
| mv88fx_neta.dev.platform_data = NULL; |
| platform_device_register(&mv88fx_neta); |
| #endif |
| #endif |
| |
| #ifdef CONFIG_THERMAL_SENSOR_KW2 |
| platform_device_register_simple("KW2Thermal", 0, NULL, 0); |
| #endif |
| |
| #ifdef CONFIG_MTD_NAND_NFC |
| kw2_nfc_data.tclk = mvTclk; |
| platform_device_register(&kw2_nfc); |
| #endif |
| |
| /* Watchdog */ |
| mv_wdt_init(); |
| |
| /* CPU idle driver */ |
| boardId = mvBoardIdGet(); |
| //if (boardId == DB_88F6535_BP_ID || boardId == RD_88F6560_GW_ID) |
| platform_device_register_simple("kw_cpuidle", 0, NULL, 0); |
| |
| pm_power_off = mv_kw2_cpu_idle_enter_wfi; |
| } |
| |
| MACHINE_START(FEROCEON_KW2 ,"Feroceon-KW2") |
| /* MAINTAINER("MARVELL") */ |
| .phys_io = 0xf1000000, |
| .io_pg_offst = ((0xf1000000) >> 18) & 0xfffc, |
| .boot_params = 0x00000100, |
| .map_io = mv_map_io, |
| .init_irq = mv_init_irq, |
| .timer = &mv_timer, |
| .init_machine = mv_init, |
| MACHINE_END |