| /* |
| * linux/arch/arm/mach-comcerto/comcerto-2000.c |
| * |
| * Copyright (C) 2011 Mindspeed Technologies, 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/sched.h> |
| #include <linux/mm.h> |
| #include <linux/init.h> |
| #include <linux/memblock.h> |
| #include <linux/antirebootloop.h> |
| |
| #include <asm/setup.h> |
| #include <asm/mach-types.h> |
| #include <asm/io.h> |
| #include <asm/sizes.h> |
| #include <asm/mach/arch.h> |
| #include <asm/mach/map.h> |
| #include <mach/irqs.h> |
| #include <linux/delay.h> |
| #include <asm/pmu.h> |
| #include <mach/dma.h> |
| #include <linux/dma-mapping.h> |
| |
| #include <linux/serial_8250.h> |
| #include <linux/serial_core.h> |
| #include <linux/serial_reg.h> |
| #include <linux/smp.h> |
| #include <linux/uio_driver.h> |
| |
| #include <asm/mach-types.h> |
| #include <asm/smp_twd.h> |
| #include <asm/localtimer.h> |
| |
| #include <asm/mach/time.h> |
| #include <asm/hardware/gic.h> |
| #include <mach/reset.h> |
| |
| #include <mach/hardware.h> |
| #include <asm/hardware/cache-l2x0.h> |
| #include <mach/comcerto-2000.h> |
| #include <linux/ahci_platform.h> |
| #include <mach/serdes-c2000.h> |
| #include <linux/clockchips.h> |
| #include <linux/clk.h> |
| #include <mach/comcerto-2000/clock.h> |
| #include <mach/comcerto-2000/pm.h> |
| #include <mach/gpio.h> |
| |
| struct c2k_gpio_pin_stat_info c2k_gpio_pin_stat = |
| { |
| .c2k_gpio_pins_0_31 = 0x0, |
| .c2k_gpio_pins_32_63 = 0x0, |
| }; |
| |
| #ifdef CONFIG_CACHE_L2X0 |
| void __iomem *l2cache_base; |
| #endif |
| |
| /*********************************************************** |
| * Virtual address Mapping * |
| * * |
| ***********************************************************/ |
| |
| static struct map_desc comcerto_io_desc[] __initdata = |
| { |
| #ifdef CONFIG_COMCERTO_MSP |
| { |
| .virtual = COMCERTO_MSP_VADDR, |
| .pfn = __phys_to_pfn(COMCERTO_MSP_DDR_BASE), |
| .length = COMCERTO_MSP_DDR_SIZE_CB, |
| .type = MT_MSP |
| }, |
| { |
| .virtual = (COMCERTO_MSP_VADDR + COMCERTO_MSP_DDR_SIZE_CB), |
| .pfn = __phys_to_pfn(COMCERTO_MSP_DDR_BASE + COMCERTO_MSP_DDR_SIZE_CB), |
| .length = COMCERTO_MSP_DDR_SIZE_NCNB, |
| .type = MT_MSP_NCNB |
| }, |
| { |
| .virtual = COMCERTO_PFE_VADDR, |
| .pfn = __phys_to_pfn(COMCERTO_PFE_DDR_BASE), |
| .length = COMCERTO_PFE_DDR_SIZE, |
| .type = MT_DEVICE |
| }, |
| { |
| .virtual = COMCERTO_PFE_AXI_VADDR, |
| .pfn = __phys_to_pfn(COMCERTO_AXI_PFE_BASE), |
| .length = COMCERTO_AXI_PFE_SIZE, |
| .type = MT_DEVICE |
| }, |
| #endif /* CONFIG_COMCERTO_MSP */ |
| #if defined(CONFIG_PCI) |
| { |
| .virtual = COMCERTO_AXI_PCIe0_VADDR_BASE, |
| .pfn = __phys_to_pfn(COMCERTO_AXI_PCIe0_BASE), |
| .length = SZ_16M, |
| .type = MT_DEVICE |
| }, |
| { |
| .virtual = COMCERTO_AXI_PCIe1_VADDR_BASE, |
| .pfn = __phys_to_pfn(COMCERTO_AXI_PCIe1_BASE), |
| .length = SZ_16M, |
| .type = MT_DEVICE |
| }, |
| #endif |
| { |
| .virtual = COMCERTO_SCU_VADDR, |
| .pfn = __phys_to_pfn(COMCERTO_SCU_BASE), |
| .length = SZ_128K, |
| .type = MT_DEVICE |
| }, |
| { |
| .virtual = IRAM_MEMORY_VADDR, |
| .pfn = __phys_to_pfn(COMCERTO_AXI_IRAM_BASE), |
| .length = IRAM_MEMORY_SIZE, |
| .type = MT_DEVICE |
| }, |
| { |
| .virtual = COMCERTO_APB_VADDR, |
| .pfn = __phys_to_pfn(COMCERTO_AXI_APB_BASE), |
| .length = COMCERTO_APB_SIZE, |
| .type = MT_DEVICE |
| }, |
| { |
| .virtual = COMCERTO_AXI_UART_SPI_VADDR, |
| .pfn = __phys_to_pfn(COMCERTO_AXI_UART_SPI_BASE), |
| .length = COMCERTO_AXI_UART_SPI_SIZE, |
| .type = MT_DEVICE |
| }, |
| { |
| .virtual = COMCERTO_DECT_VADDR, |
| .pfn = __phys_to_pfn(COMCERTO_AXI_DECT_BASE), |
| .length = 2 * SZ_1M, |
| .type = MT_DEVICE |
| }, |
| { |
| .virtual = COMCERTO_SEMA_VADDR, |
| .pfn = __phys_to_pfn(COMCERTO_AXI_SEMA_BASE), |
| .length = SZ_16M, |
| .type = MT_DEVICE |
| }, |
| }; |
| |
| #if defined(CONFIG_COMCERTO_64K_PAGES) |
| #define PFE_DMA_SIZE (4 * SZ_1M) |
| #else |
| #define PFE_DMA_SIZE (16 * SZ_1M) |
| #endif |
| |
| #define DSPG_DECT_CSS_DMA_SIZE (10 * SZ_1M) |
| |
| void __init device_map_io(void) |
| { |
| unsigned long size = PFE_DMA_SIZE; |
| |
| #if defined(CONFIG_DSPG_DECT_CSS) |
| size += DSPG_DECT_CSS_DMA_SIZE; |
| #endif |
| |
| iotable_init(comcerto_io_desc, ARRAY_SIZE(comcerto_io_desc)); |
| |
| /* Increase consistent DMA zone size */ |
| init_consistent_dma_size(size); |
| } |
| |
| |
| void __init device_irq_init(void) |
| { |
| gic_init(0, SGI_IRQ(1), (void *)COMCERTO_GIC_DIST_VADDR, (void *)COMCERTO_GIC_CPU_VADDR); |
| } |
| |
| /************************************************************************ |
| * GPIO |
| ************************************************************************/ |
| static __init void gpio_init(void) |
| { |
| |
| #if defined(CONFIG_COMCERTO_UART1_SUPPORT) |
| writel(readl(COMCERTO_GPIO_MISC_PIN_SELECT) & ~0x3, COMCERTO_GPIO_MISC_PIN_SELECT); |
| #endif |
| |
| #if defined(CONFIG_COMCERTO_UART0_SUPPORT) |
| writel((readl(COMCERTO_GPIO_PIN_SELECT_REG) & ~UART0_GPIO) | UART0_BUS, COMCERTO_GPIO_PIN_SELECT_REG); |
| c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= UART0_GPIO_PIN; /* GPIOs 8 to 11 are used for UART0 */ |
| #endif |
| |
| /* |
| * Configure each GPIO to be Output or Input |
| * When Input, Configure to be Input, IRQ |
| * When Input IRQ, Configure to be IRQ Rising Edge or IRQ falling Edge |
| */ |
| |
| /*[FIXME]: GPIO Output, others are input*/ |
| __raw_writel(__raw_readl(COMCERTO_GPIO_OE_REG) | COMCERTO_OUTPUT_GPIO, COMCERTO_GPIO_OE_REG); |
| |
| /* |
| * Default GPIO IRQ Configuration. Enable specific IRQs in the |
| * board-*.c file |
| */ |
| __raw_writel(0, COMCERTO_GPIO_INT_CFG_REG); |
| |
| /* [FIXME]: Are pins GPIO or pins used by another block*/ |
| //__raw_writel(COMCERTO_GPIO_PIN_USAGE, COMCERTO_GPIO_IOCTRL_REG); |
| } |
| |
| /************************************************************************ |
| * Expansion Bus |
| ************************************************************************/ |
| |
| /*This variable is provided by the board file*/ |
| extern int comcerto_exp_values[5][7]; |
| |
| static __init void exp_bus_init(void) |
| { |
| int cs; |
| u32 cs_enable; |
| unsigned int axi_clk, clk_div; |
| struct clk *clk_axi; |
| |
| /*First, Reset the Expansion block*/ |
| __raw_writel(0x1, COMCERTO_EXP_SW_RST_R); |
| |
| while (readl(COMCERTO_EXP_SW_RST_R) & 0x1) ; |
| |
| /* Clock divider configuration, get the AXI clock first |
| * AXI clock will be used for refernce count , as exp bus |
| * also have a dependancy with AXI. |
| */ |
| clk_axi = clk_get(NULL,"axi"); |
| |
| if (IS_ERR(clk_axi)) { |
| pr_err("comcerto_Device_init: Unable to obtain axi clock: %ld\n",PTR_ERR(clk_axi)); |
| } |
| |
| /*Enable the AXI clock */ |
| if (clk_enable(clk_axi)){ |
| pr_err("%s: Unable to enable axi clock:\n",__func__); |
| } |
| |
| /* Get the AXI clock rate in HZ */ |
| axi_clk = clk_get_rate(clk_axi); |
| /* Round divider up */ |
| clk_div = (axi_clk + COMCERTO_EXPCLK - 1) / COMCERTO_EXPCLK; |
| |
| __raw_writel(clk_div, COMCERTO_EXP_CLOCK_DIV_R); |
| |
| cs_enable = 0; |
| for (cs = 0; cs < 5; cs++) { |
| /*configure only enabled CS */ |
| { |
| if (comcerto_exp_values[cs][0] == 1) |
| cs_enable |= EXP_CSx_EN(cs); |
| |
| /*mode configuration*/ |
| __raw_writel(comcerto_exp_values[cs][3], COMCERTO_EXP_CSx_CFG_R(cs)); |
| |
| /*Chip select Base configuration (start of address space)*/ |
| __raw_writel(comcerto_exp_values[cs][1], COMCERTO_EXP_CSx_BASE_R(cs)); |
| |
| /*Chip select Segment size configuration (end of address space)*/ |
| __raw_writel(comcerto_exp_values[cs][2], COMCERTO_EXP_CSx_SEG_R(cs)); |
| |
| /*Chip select timing configuration*/ |
| __raw_writel(comcerto_exp_values[cs][4], COMCERTO_EXP_CSx_TMG1_R(cs)); |
| __raw_writel(comcerto_exp_values[cs][5], COMCERTO_EXP_CSx_TMG2_R(cs)); |
| __raw_writel(comcerto_exp_values[cs][6], COMCERTO_EXP_CSx_TMG3_R(cs)); |
| } |
| } |
| |
| /*Chip Select activation*/ |
| __raw_writel(EXP_CLK_EN | cs_enable, COMCERTO_EXP_CS_EN_R); |
| } |
| |
| static u32 armv7_aux_ctrl_read(void) |
| { |
| u32 val; |
| |
| asm volatile ("mrc p15, 0, %0, c1, c0, 1" : "=r"(val)); |
| |
| printk(KERN_INFO "ARMv7 AUX CTRL(%d): %#x\n", smp_processor_id(), val); |
| |
| return val; |
| } |
| |
| static void armv7_aux_ctrl_write(u32 val) |
| { |
| printk(KERN_INFO "ARMv7 AUX CTRL(%d): %#x\n", smp_processor_id(), val); |
| asm volatile ("mcr p15, 0, %0, c1, c0, 1" : : "r"(val)); |
| } |
| |
| static void armv7_aux_ctrl_setup(void *info) |
| { |
| u32 aux_ctrl; |
| unsigned long flags; |
| |
| local_irq_save(flags); |
| |
| aux_ctrl = armv7_aux_ctrl_read(); |
| |
| #ifdef CONFIG_PL310_FULL_LINE_OF_ZERO |
| aux_ctrl |= (1 << 3); |
| #endif |
| |
| #ifdef CONFIG_PL310_EXCLUSIVE_CACHE |
| aux_ctrl |= (1 << 7); |
| #endif |
| |
| armv7_aux_ctrl_write(aux_ctrl); |
| |
| local_irq_restore(flags); |
| } |
| |
| #ifdef CONFIG_CACHE_L2X0 |
| void l2x0_latency(u32 tag_ram_setup_lat, u32 tag_ram_rd_lat, u32 tag_ram_wr_lat, u32 data_ram_setup_lat, u32 data_ram_rd_lat, u32 data_ram_wr_lat) |
| { |
| u32 val; |
| |
| val = ((tag_ram_wr_lat - 1) << COMCERTO_L2CC_WR_LAT_SHIFT) | ((tag_ram_rd_lat - 1) << COMCERTO_L2CC_RD_LAT_SHIFT) | (tag_ram_setup_lat - 1); |
| writel(val, l2cache_base + L2X0_TAG_LATENCY_CTRL); |
| |
| val = ((data_ram_wr_lat - 1) << COMCERTO_L2CC_WR_LAT_SHIFT) | ((data_ram_rd_lat - 1) << COMCERTO_L2CC_RD_LAT_SHIFT) | (data_ram_setup_lat - 1); |
| writel(val, l2cache_base + L2X0_DATA_LATENCY_CTRL); |
| } |
| |
| void comcerto_l2cc_init(void) |
| { |
| unsigned int aux_val, aux_mask; |
| unsigned int associativity, waysize; |
| #ifdef CONFIG_L2X0_INSTRUCTION_ONLY |
| int i; |
| #endif |
| |
| |
| l2cache_base = (void *)COMCERTO_L310_VADDR; |
| BUG_ON(!l2cache_base); |
| |
| /* Set Latency of L2CC to minimum (i.e. 1 cycle) */ |
| l2x0_latency(1, 1, 1, 1, 1, 1); |
| |
| /* Set L2 address filtering, use L2CC M1 port for DDR accesses */ |
| writel(0x80000000, l2cache_base + L2X0_ADDR_FILTER_END); |
| writel(0x00000000 | L2X0_ADDR_FILTER_EN, l2cache_base + L2X0_ADDR_FILTER_START); |
| |
| associativity = (COMCERTO_L2CC_ASSOCIATIVITY_8WAY << COMCERTO_L2CC_ASSOCIATIVITY_SHIFT) & COMCERTO_L2CC_ASSOCIATIVITY_MASK; |
| waysize = (COMCERTO_L2CC_ASSOCIATIVITY_32KB << COMCERTO_L2CC_WAYSIZE_SHIFT) & COMCERTO_L2CC_WAYSIZE_MASK; |
| aux_val = associativity | waysize; |
| aux_mask = (COMCERTO_L2CC_ASSOCIATIVITY_MASK | COMCERTO_L2CC_WAYSIZE_MASK); |
| |
| /* Shareable attribute override enable */ |
| /* This prevents the cache from changing "normal memory/non-cacheable" accesses to |
| "normal memory/cacheable/writethrough no read/write allocate"*/ |
| aux_val |= (1 << 22); |
| aux_mask |= (1 << 22); |
| |
| /* Write allocate override, no write allocate */ |
| aux_val |= (1 << 23); |
| aux_mask |= (3 << 23); |
| |
| #ifdef CONFIG_PL310_FULL_LINE_OF_ZERO |
| aux_val |= (1 << 0); |
| aux_mask |= (1 << 0); |
| #endif |
| |
| #ifdef CONFIG_PL310_EARLY_WRITE_RESPONSE |
| aux_val |= (1 << 30); |
| aux_mask |= (1 << 30); |
| #endif |
| |
| #ifdef CONFIG_PL310_STORE_BUFFER_DEVICE_LIMITATION |
| aux_val |= (1 << 11); |
| aux_mask |= (1 << 11); |
| #endif |
| |
| #ifdef CONFIG_PL310_INSTRUCTION_PREFETCH |
| aux_val |= (1 << 29); |
| aux_mask |= (1 << 29); |
| #endif |
| |
| #ifdef CONFIG_PL310_DATA_PREFETCH |
| aux_val |= (1 << 28); |
| aux_mask |= (1 << 28); |
| #endif |
| |
| |
| #ifdef CONFIG_PL310_EXCLUSIVE_CACHE |
| aux_val |= (1 << 12); |
| aux_mask |= (1 << 12); |
| #endif |
| |
| /* L2 8-way associativity with 32KB way size */ |
| l2x0_init(l2cache_base, aux_val, aux_mask); |
| |
| #ifdef CONFIG_L2X0_INSTRUCTION_ONLY |
| for (i = 0; i < 8; i++) |
| writel_relaxed(0xffff, l2cache_base + L2X0_LOCKDOWN_WAY_D_BASE + i * L2X0_LOCKDOWN_STRIDE); |
| |
| outer_flush_all(); |
| #endif |
| |
| armv7_aux_ctrl_setup(NULL); |
| |
| smp_call_function(armv7_aux_ctrl_setup, NULL, 1); |
| } |
| #endif |
| |
| #if defined(CONFIG_COMCERTO_SATA) |
| |
| #define SERDES_PHY1 1 |
| #define SERDES_PHY2 2 |
| |
| static int comcerto_ahci_init(struct device *dev, void __iomem *mmio) |
| { |
| struct serdes_regs_s *p_sata_phy_reg_file; |
| int serdes_regs_size; |
| u32 val; |
| int ref_clk_24; |
| |
| /* Move SATA controller to DDRC2 port */ |
| writel(readl(COMCERTO_GPIO_FABRIC_CTRL_REG) | 0x2, COMCERTO_GPIO_FABRIC_CTRL_REG); |
| |
| val = readl(COMCERTO_GPIO_SYSTEM_CONFIG); |
| ref_clk_24 = val & (BIT_5_MSK|BIT_7_MSK); |
| |
| if(ref_clk_24) |
| { |
| p_sata_phy_reg_file = &sata_phy_reg_file_24[0]; |
| serdes_regs_size = sizeof(sata_phy_reg_file_24); |
| printk(KERN_INFO "SATA Serdes: 24Mhz ref clk\n"); |
| } |
| else |
| { |
| p_sata_phy_reg_file = &sata_phy_reg_file_48[0]; |
| serdes_regs_size = sizeof(sata_phy_reg_file_48); |
| printk(KERN_INFO "SATA Serdes: 48Mhz ref clk\n"); |
| } |
| |
| //Take SATA AXI domain out of reset |
| c2000_block_reset(COMPONENT_AXI_SATA,0); |
| //Bring SATA PMU and OOB out of reset |
| c2000_block_reset(COMPONENT_SATA_PMU,0); |
| c2000_block_reset(COMPONENT_SATA_OOB,0); |
| |
| if ( (val & BOOT_SERDES1_CNF_SATA0) || (!(val & BOOT_SERDES2_CNF_SATA1))) |
| { |
| if (val & BOOT_SERDES1_CNF_SATA0) |
| { |
| //Bring Serdes1 out of reset |
| c2000_block_reset(COMPONENT_SERDES1,0); |
| //Bring SATA0 out of reset |
| c2000_block_reset(COMPONENT_SERDES_SATA0,0); |
| |
| /* Serdes Initialization. */ |
| if( serdes_phy_init(SERDES_PHY1, p_sata_phy_reg_file, |
| serdes_regs_size / sizeof(serdes_regs_t), |
| SD_DEV_TYPE_SATA) ) |
| { |
| printk(KERN_ERR "%s: Failed to initialize serdes1 !!\n", __func__); |
| return -1; |
| } |
| |
| } |
| |
| if (!(val & BOOT_SERDES2_CNF_SATA1)) |
| { |
| //Bring Serdes2 out of reset |
| c2000_block_reset(COMPONENT_SERDES2,0); |
| //Bring SATA1 out of reset |
| c2000_block_reset(COMPONENT_SERDES_SATA1,0); |
| |
| /* Serdes Initialization. */ |
| if( serdes_phy_init(SERDES_PHY2, p_sata_phy_reg_file, |
| serdes_regs_size / sizeof(serdes_regs_t), |
| SD_DEV_TYPE_SATA) ) |
| { |
| printk(KERN_ERR "%s: Failed to initialize serdes2 !!\n", __func__); |
| return -1; |
| } |
| } |
| } else |
| return -1; |
| |
| return 0; |
| } |
| #endif |
| |
| #if defined(CONFIG_COMCERTO_UART0_SUPPORT) || defined(CONFIG_COMCERTO_UART1_SUPPORT) |
| #define UART_DWC_USR 0x1F |
| static int fastuart_handle_irq(struct uart_port *p) |
| { |
| unsigned int iir = p->serial_in(p, UART_IIR); |
| unsigned int dummy; |
| if (serial8250_handle_irq(p, iir)) { |
| return 1; |
| } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { |
| /* Clear the USR */ |
| dummy = p->serial_in(p, UART_DWC_USR); |
| return 1; |
| } |
| |
| return 0; |
| } |
| #endif |
| |
| static struct resource comcerto_pmu_resources[] = { |
| { |
| .start = IRQ_A9_PMU0, |
| .end = IRQ_A9_PMU0, |
| .flags = IORESOURCE_IRQ, |
| }, |
| { |
| .start = IRQ_A9_PMU1, |
| .end = IRQ_A9_PMU1, |
| .flags = IORESOURCE_IRQ, |
| }, |
| }; |
| |
| static struct platform_device comcerto_pmu = { |
| .name = "arm-pmu", |
| .id = ARM_PMU_DEVICE_CPU, |
| .num_resources = ARRAY_SIZE(comcerto_pmu_resources), |
| .resource = comcerto_pmu_resources, |
| }; |
| |
| /* -------------------------------------------------------------------- |
| * Serial interface |
| * -------------------------------------------------------------------- */ |
| #if defined(CONFIG_COMCERTO_UART0_SUPPORT) || defined(CONFIG_COMCERTO_UART1_SUPPORT) |
| static struct plat_serial8250_port comcerto_uart_data[] = { |
| #ifdef CONFIG_COMCERTO_UART1_SUPPORT |
| { |
| .mapbase = COMCERTO_AXI_UART1_BASE, |
| .membase = (void *)COMCERTO_AXI_UART1_VADDR, |
| .irq = IRQ_UART1, |
| .handle_irq = fastuart_handle_irq, |
| .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, |
| .iotype = UPIO_MEM, |
| .regshift = 2, |
| }, |
| #endif |
| #ifdef CONFIG_COMCERTO_UART0_SUPPORT |
| { |
| .mapbase = COMCERTO_AXI_UART0_BASE, |
| .membase = (void *)COMCERTO_AXI_UART0_VADDR, |
| .irq = IRQ_UART0, |
| .handle_irq = fastuart_handle_irq, |
| .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, |
| .iotype = UPIO_MEM, |
| .regshift = 2, |
| }, |
| #endif |
| { |
| .flags = 0, |
| }, |
| }; |
| |
| static struct platform_device comcerto_uart = { |
| .name = "serial8250", |
| .id = PLAT8250_DEV_PLATFORM, |
| .dev = { |
| .platform_data = comcerto_uart_data, |
| }, |
| }; |
| #endif |
| |
| #ifdef CONFIG_COMCERTO_MSP |
| static struct resource comcerto_ved_resources[] = { |
| { |
| .name = "voip", |
| .start = COMCERTO_MSP_DDR_BASE, |
| .end = COMCERTO_MSP_DDR_BASE + COMCERTO_MSP_DDR_SIZE - 1, |
| .flags = IORESOURCE_MEM, |
| }, |
| { |
| .name = "irq", |
| .start = IRQ_PTP0, |
| .flags = IORESOURCE_IRQ, |
| }, |
| }; |
| |
| static struct platform_device comcerto_ved = { |
| .name = "ved", |
| .id = 0, |
| .num_resources = ARRAY_SIZE(comcerto_ved_resources), |
| .resource = comcerto_ved_resources, |
| }; |
| #endif /* CONFIG_COMCERTO_MSP */ |
| |
| |
| /* -------------------------------------------------------------------- |
| * USB 3.0 Host |
| * -------------------------------------------------------------------- */ |
| |
| #if defined(CONFIG_COMCERTO_USB3_SUPPORT) |
| static struct resource comcerto_usb3_resource[] = { |
| [0] = { |
| .start = COMCERTO_AXI_USB3P0_BASE, |
| .end = COMCERTO_AXI_USB3P0_BASE + SZ_8M - 1, |
| .flags = IORESOURCE_MEM, |
| }, |
| [1] = { |
| .start = IRQ_USB3, |
| .end = IRQ_USB3, |
| .flags = IORESOURCE_IRQ, |
| }, |
| }; |
| |
| static u64 comcerto_usb3_dmamask = 0xfffff000; |
| |
| struct platform_device comcerto_device_usb3 = { |
| .name = "xhci-hcd", |
| .id = -1, |
| .resource = comcerto_usb3_resource, |
| .num_resources = ARRAY_SIZE(comcerto_usb3_resource), |
| .dev = { |
| .dma_mask = &comcerto_usb3_dmamask, |
| .coherent_dma_mask = DMA_BIT_MASK(32), |
| }, |
| }; |
| #endif |
| |
| /* -------------------------------------------------------------------- |
| * USB 2.0 Host |
| * -------------------------------------------------------------------- */ |
| |
| #if defined(CONFIG_COMCERTO_USB2_SUPPORT) |
| |
| static u64 comcerto_dwc_otg_dmamask = 0xFFFFFFFF /*DMA_BIT_MASK(32)*/; |
| |
| static struct resource comcerto_dwc_otg_resources[] = { |
| { |
| .start = COMCERTO_AXI_USB2P0_BASE, |
| .end = COMCERTO_AXI_USB2P0_BASE + 0xFFFFFF, |
| .flags = IORESOURCE_MEM, |
| }, { |
| .start = IRQ_USB2, |
| .end = IRQ_USB2, |
| .flags = IORESOURCE_IRQ, |
| }, |
| }; |
| |
| static struct platform_device comcerto_dwc_otg_device = { |
| .name = "dwc_otg", |
| .resource = comcerto_dwc_otg_resources, |
| .num_resources = ARRAY_SIZE(comcerto_dwc_otg_resources), |
| .dev = { |
| .platform_data = NULL, |
| .dma_mask = &comcerto_dwc_otg_dmamask, |
| .coherent_dma_mask = DMA_BIT_MASK(32), |
| } |
| }; |
| #endif |
| |
| #if defined(CONFIG_COMCERTO_SATA) |
| static struct ahci_platform_data comcerto_ahci_pdata = { |
| .init = comcerto_ahci_init, |
| }; |
| |
| static struct resource comcerto_ahci_resource[] = { |
| [0] = { |
| .start = COMCERTO_AXI_SATA_BASE, |
| .end = COMCERTO_AXI_SATA_BASE + SZ_64K - 1, |
| .flags = IORESOURCE_MEM, |
| }, |
| [1] = { |
| .start = IRQ_SATA, |
| .end = IRQ_SATA, |
| .flags = IORESOURCE_IRQ, |
| }, |
| }; |
| |
| static u64 comcerto_ahci_dmamask = DMA_BIT_MASK(32); |
| |
| struct platform_device comcerto_device_ahci = { |
| .name = "ahci", |
| .id = -1, |
| .resource = comcerto_ahci_resource, |
| .num_resources = ARRAY_SIZE(comcerto_ahci_resource), |
| .dev = { |
| .platform_data = &comcerto_ahci_pdata, |
| .dma_mask = &comcerto_ahci_dmamask, |
| .coherent_dma_mask = DMA_BIT_MASK(32), |
| }, |
| }; |
| #endif |
| |
| /* -------------------------------------------------------------------- |
| * XOR Engine |
| * -------------------------------------------------------------------- */ |
| |
| static struct resource comcerto_xor_resource[] = { |
| { |
| .name = "xor base address", |
| .start = COMCERTO_APB_MDMA_BASE, |
| .end = COMCERTO_APB_MDMA_BASE + COMCERTO_APB_MDMA_SIZE - 1, |
| .flags = IORESOURCE_MEM, |
| }, |
| { |
| .name = "IO2M IRQ", |
| .start = IRQ_MDMA_IO2M, |
| .flags = IORESOURCE_IRQ, |
| }, |
| }; |
| |
| static u64 comcerto_xor_dma_mask = DMA_BIT_MASK(32); |
| |
| static struct platform_device comcerto_xor_device = { |
| .name = "comcerto_xor", |
| .id = 0, |
| .dev = { |
| .dma_mask = &comcerto_xor_dma_mask, |
| .coherent_dma_mask = DMA_BIT_MASK(32), |
| }, |
| .num_resources = ARRAY_SIZE(comcerto_xor_resource), |
| .resource = comcerto_xor_resource, |
| }; |
| |
| /* -------------------------------------------------------------------- |
| * Basic C2K MDMA Engine |
| * -------------------------------------------------------------------- */ |
| |
| static struct resource comcerto_dma_resource[] = { |
| { |
| .name = "c2k mdma base address", |
| .start = COMCERTO_APB_MDMA_BASE, |
| .end = COMCERTO_APB_MDMA_BASE + COMCERTO_APB_MDMA_SIZE - 1, |
| .flags = IORESOURCE_MEM, |
| }, |
| { |
| .name = "IO2M IRQ", |
| .start = IRQ_MDMA_IO2M, |
| .flags = IORESOURCE_IRQ, |
| }, |
| }; |
| |
| static u64 comcerto_dma_dma_mask = DMA_BIT_MASK(32); |
| |
| static struct platform_device comcerto_dma_device = { |
| .name = "comcerto_dma", |
| .id = 0, |
| .dev = { |
| .dma_mask = &comcerto_dma_dma_mask, |
| .coherent_dma_mask = DMA_BIT_MASK(32), |
| }, |
| .num_resources = ARRAY_SIZE(comcerto_dma_resource), |
| .resource = comcerto_dma_resource, |
| }; |
| |
| #if defined(CONFIG_COMCERTO_EPAVIS) |
| static u64 comcerto_epavis_cie_dmamask = DMA_BIT_MASK(32); |
| |
| struct platform_device comcerto_device_epavis_cie = { |
| .name = "lc_cie", |
| .id = -1, |
| .dev = { |
| .platform_data = NULL, |
| .dma_mask = &comcerto_epavis_cie_dmamask, |
| .coherent_dma_mask = DMA_BIT_MASK(32), |
| }, |
| }; |
| static u64 comcerto_epavis_decomp_dmamask = DMA_BIT_MASK(32); |
| |
| struct platform_device comcerto_device_epavis_decomp = { |
| .name = "lc_decomp", |
| .id = -1, |
| .dev = { |
| .platform_data = NULL, |
| .dma_mask = &comcerto_epavis_decomp_dmamask, |
| .coherent_dma_mask = DMA_BIT_MASK(32), |
| }, |
| }; |
| #endif |
| |
| #if defined(CONFIG_COMCERTO_CSYS_TPI_CLOCK) |
| struct platform_device comcerto_device_tpi_csys_clk = { |
| .name = "tpi_csys", |
| .id = -1, |
| .dev = { |
| .platform_data = NULL, |
| }, |
| }; |
| #endif |
| |
| int usb3_clk_internal = 1; |
| static int __init get_usb3_clk_mode(char *str) |
| { |
| if (!strcmp(str, "no")) |
| usb3_clk_internal = 0; |
| |
| return 1; |
| } |
| |
| __setup("usb3_internal_clk=", get_usb3_clk_mode); |
| |
| int is_mac_zero(u8 *buf) |
| { |
| unsigned long dm; |
| for (dm = 0; dm < 6; dm++){ |
| if ((*(buf+dm)) != 0) |
| return 1; |
| } |
| return 0; |
| } |
| |
| static int __init mac_addr_atoi(u8 mac_addr[], char *mac_addr_str) |
| { |
| int i, j, k; |
| int str_incr_cnt = 0; |
| |
| if (*mac_addr_str == ',') { |
| *mac_addr_str++; |
| str_incr_cnt++; |
| return str_incr_cnt; |
| } |
| |
| for (i = 0; i < 6; i++) { |
| |
| j = hex_to_bin(*mac_addr_str++); |
| str_incr_cnt++; |
| if (j == -1) |
| return str_incr_cnt; |
| |
| k = hex_to_bin(*mac_addr_str++); |
| str_incr_cnt++; |
| if (k == -1) |
| return str_incr_cnt; |
| |
| mac_addr_str++; |
| str_incr_cnt++; |
| mac_addr[i] = (j << 4) + k; |
| } |
| |
| return str_incr_cnt; |
| } |
| |
| static u8 c2k_mac_addr[3][14]; |
| |
| static void __init mac_addr_setup(char *str) |
| { |
| int str_incr_cnt = 0; |
| |
| if (*str++ != '=' || !*str) /* No mac addr specified */ |
| return; |
| |
| str_incr_cnt = mac_addr_atoi(c2k_mac_addr[0], str); |
| |
| str += str_incr_cnt; |
| |
| str_incr_cnt = mac_addr_atoi(c2k_mac_addr[1], str); |
| |
| str += str_incr_cnt; |
| |
| mac_addr_atoi(c2k_mac_addr[2], str); |
| } |
| __setup("mac_addr", mac_addr_setup); |
| |
| void __init mac_addr_init(struct comcerto_pfe_platform_data * comcerto_pfe_data_ptr) |
| { |
| u8 gem_port_id; |
| |
| for (gem_port_id = 0; gem_port_id < NUM_GEMAC_SUPPORT; gem_port_id++) { |
| if (is_mac_zero(c2k_mac_addr[gem_port_id])) /* If mac is non-zero */ |
| comcerto_pfe_data_ptr->comcerto_eth_pdata[gem_port_id].mac_addr = c2k_mac_addr[gem_port_id]; |
| } |
| |
| } |
| |
| static struct platform_device *comcerto_common_devices[] __initdata = { |
| #if defined(CONFIG_COMCERTO_UART0_SUPPORT) || defined(CONFIG_COMCERTO_UART1_SUPPORT) |
| &comcerto_uart, |
| #endif |
| #ifdef CONFIG_COMCERTO_MSP |
| &comcerto_ved, |
| #endif /* CONFIG_COMCERTO_MSP */ |
| &comcerto_pmu, |
| |
| #if defined(CONFIG_COMCERTO_USB3_SUPPORT) |
| &comcerto_device_usb3, |
| #endif |
| |
| #if defined(CONFIG_COMCERTO_USB2_SUPPORT) |
| &comcerto_dwc_otg_device, |
| #endif |
| |
| #if defined(CONFIG_COMCERTO_SATA) |
| &comcerto_device_ahci, |
| #endif |
| // &comcerto_xor_device, |
| &comcerto_dma_device, |
| #if defined(CONFIG_COMCERTO_EPAVIS) |
| &comcerto_device_epavis_cie, |
| &comcerto_device_epavis_decomp, |
| #endif |
| #if defined(CONFIG_COMCERTO_CSYS_TPI_CLOCK) |
| &comcerto_device_tpi_csys_clk, |
| #endif |
| }; |
| |
| void __init device_init(void) |
| { |
| /* Default value for the bit mask */ |
| unsigned int default_host_utilpe_shared_bitmask = ~(USB2p0_IRQ|WOL_IRQ); |
| struct clk *axi_clk,*ddr_clk,*arm_clk,*l2cc_clk; |
| HAL_clk_div_backup_relocate_table (); |
| system_rev = (readl(COMCERTO_GPIO_DEVICE_ID_REG) >> 24) & 0xf; |
| |
| /* Initialize the reset driver here */ |
| reset_init(); |
| |
| /* Enable the AXI,DDR,A9 susbsystem clock |
| * this is just for s/w use count house keeping. |
| * These clocks will never be disabled from bootloader while |
| * booting. In fact we are keeping this because for these clocks , |
| * we dont have any driver to do a clk_enable. so doing it here. |
| */ |
| |
| /* Get the AXI clk structure */ |
| axi_clk = clk_get(NULL,"axi"); |
| if (IS_ERR(axi_clk)) { |
| pr_err("%s: Unable to obtain AXI clock: %ld\n",__func__,PTR_ERR(axi_clk)); |
| /* System cannot proceed from here */ |
| BUG(); |
| } |
| /* Enable the AXI clk */ |
| if (clk_enable(axi_clk)){ |
| pr_err("%s: Unable to enable AXI clock:\n",__func__); |
| /* System cannot proceed from here */ |
| BUG(); |
| } |
| |
| /* Get the DDR clock structure */ |
| ddr_clk = clk_get(NULL,"ddr"); |
| if (IS_ERR(ddr_clk)) { |
| pr_err("%s: Unable to obtain DDR clock: %ld\n",__func__,PTR_ERR(ddr_clk)); |
| /* System cannot proceed from here */ |
| BUG(); |
| } |
| /* Enable the DDR clk */ |
| if (clk_enable(ddr_clk)){ |
| pr_err("%s: Unable to enable DDR clock:\n",__func__); |
| /* System cannot proceed from here */ |
| BUG(); |
| } |
| |
| /* Get the CPU(A9) clock */ |
| arm_clk = clk_get(NULL,"arm"); |
| if (IS_ERR(arm_clk)) { |
| pr_err("%s: Unable to obtain A9(arm) clock: %ld\n",__func__,PTR_ERR(arm_clk)); |
| /* System cannot proceed from here */ |
| BUG(); |
| } |
| /* Enable the ARM clk */ |
| if (clk_enable(arm_clk)){ |
| pr_err("%s: Unable to enable A9(arm) clock:\n",__func__); |
| /* System cannot proceed from here */ |
| BUG(); |
| } |
| |
| /* Get the L2CC clock */ |
| l2cc_clk = clk_get(NULL,"l2cc"); |
| if (IS_ERR(l2cc_clk)) { |
| pr_err("%s: Unable to obtain L2CC clock: %ld\n",__func__,PTR_ERR(l2cc_clk)); |
| /* L2CC initilization cannot proceed from here */ |
| BUG(); |
| } |
| |
| /* Enable the L2CC clk */ |
| if (clk_enable(l2cc_clk)){ |
| pr_err("%s: Unable to enable L2CC clock:\n",__func__); |
| /* L2CC initilization cannot proceed from here */ |
| BUG(); |
| } |
| |
| #ifdef CONFIG_CACHE_L2X0 |
| comcerto_l2cc_init(); |
| #endif |
| |
| exp_bus_init(); |
| |
| gpio_init(); |
| |
| #ifdef CONFIG_COMCERTO_TDM_CLOCK |
| // [FIXME] Take TDM out of reset |
| //writel(readl(COMCERTO_BLOCK_RESET_REG) | TDM_RST, COMCERTO_BLOCK_RESET_REG); |
| #endif |
| /* Default bit mask is applied here , which will be passed to Util-Pe*/ |
| c2k_pm_bitmask_store(default_host_utilpe_shared_bitmask); |
| |
| platform_add_devices(comcerto_common_devices, ARRAY_SIZE(comcerto_common_devices)); |
| } |
| |
| void __init platform_reserve(void) |
| { |
| /* boot_secondary() in arch/arm/mach-comcerto/platsmp.c uses this range |
| * to store a jump instruction. The second CPU executes this |
| * instruction when it comes out of reset.*/ |
| if (memblock_reserve(0, 0x24) < 0) |
| BUG(); |
| |
| if (memblock_reserve((phys_addr_t) get_antirebootloop_ptr(), |
| PAGE_SIZE) < 0) |
| BUG(); |
| |
| /* Allocate DDR block used by PFE/MSP, the base address is fixed so that util-pe code can |
| be linked at a fixed address */ |
| if (memblock_reserve(COMCERTO_DDR_SHARED_BASE, COMCERTO_DDR_SHARED_SIZE) < 0) |
| BUG(); |
| |
| if (memblock_free(COMCERTO_DDR_SHARED_BASE, COMCERTO_DDR_SHARED_SIZE) < 0) |
| BUG(); |
| |
| if (memblock_remove(COMCERTO_DDR_SHARED_BASE, COMCERTO_DDR_SHARED_SIZE) < 0) |
| BUG(); |
| } |
| |
| phys_addr_t get_antirebootloop_ptr(void) { |
| return COMCERTO_AXI_DDR_BASE + (1 * PAGE_SIZE); |
| } |