/* * (c) 2010 STMicroelectronics Limited * * Author: Pawel Moll * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* EMI resources ---------------------------------------------------------- */ static int __initdata stx7100_emi_bank_configured[EMI_BANKS]; static void stx7100_emi_power(struct stm_device_state *device_state, enum stm_device_power_state power) { int i; int value = (power == stm_device_power_on) ? 0 : 1; stm_device_sysconf_write(device_state, "EMI_PWR", value); for (i = 5; i; --i) { if (stm_device_sysconf_read(device_state, "EMI_ACK") == value) break; mdelay(10); } return; } static struct platform_device stx7100_emi = { .name = "emi", .id = -1, .num_resources = 2, .resource = (struct resource[]) { STM_PLAT_RESOURCE_MEM(0, 64 * 1024 * 1024), STM_PLAT_RESOURCE_MEM(0x1a100000, 0x874), }, .dev.platform_data = &(struct stm_device_config){ .sysconfs_num = 2, .sysconfs = (struct stm_device_sysconf []){ STM_DEVICE_SYS_CFG(32, 1, 1, "EMI_PWR"), STM_DEVICE_SYS_STA(15, 0, 0, "EMI_ACK"), }, .power = stx7100_emi_power, } }; /* PATA resources --------------------------------------------------------- */ /* EMI A21 = CS1 (active low) * EMI A20 = CS0 (active low) * EMI A19 = DA2 * EMI A18 = DA1 * EMI A17 = DA0 */ static struct resource stx7100_pata_resources[] = { /* I/O base: CS1=N, CS0=A */ [0] = STM_PLAT_RESOURCE_MEM(1 << 21, 8 << 17), /* CTL base: CS1=A, CS0=N, DA2=A, DA1=A, DA0=N */ [1] = STM_PLAT_RESOURCE_MEM((1 << 20) + (6 << 17), 4), /* IRQ */ [2] = STM_PLAT_RESOURCE_IRQ(-1, -1), }; static struct platform_device stx7100_pata_device = { .name = "pata_platform", .id = -1, .num_resources = ARRAY_SIZE(stx7100_pata_resources), .resource = stx7100_pata_resources, .dev.platform_data = &(struct pata_platform_info) { .ioport_shift = 17, }, }; void __init stx7100_configure_pata(struct stx7100_pata_config *config) { unsigned long bank_base; if (!config) { BUG(); return; } BUG_ON(config->emi_bank < 0 || config->emi_bank >= EMI_BANKS); BUG_ON(stx7100_emi_bank_configured[config->emi_bank]); stx7100_emi_bank_configured[config->emi_bank] = 1; bank_base = emi_bank_base(config->emi_bank); stx7100_pata_resources[0].start += bank_base; stx7100_pata_resources[0].end += bank_base; stx7100_pata_resources[1].start += bank_base; stx7100_pata_resources[1].end += bank_base; stx7100_pata_resources[2].start = config->irq; stx7100_pata_resources[2].end = config->irq; emi_config_pata(config->emi_bank, config->pc_mode); platform_device_register(&stx7100_pata_device); } /* FDMA resources --------------------------------------------------------- */ static struct stm_plat_fdma_fw_regs stm_fdma_firmware_7100 = { .rev_id = 0x8000 + (0x000 << 2), /* 0x8000 */ .cmd_statn = 0x8000 + (0x010 << 2), /* 0x8040 */ .ptrn = 0x8000 + (0x460 << 2), /* 0x9180 */ .cntn = 0x8000 + (0x462 << 2), /* 0x9188 */ .saddrn = 0x8000 + (0x463 << 2), /* 0x918c */ .daddrn = 0x8000 + (0x464 << 2), /* 0x9190 */ }; static struct stm_plat_fdma_hw stx7100_fdma_hw = { .slim_regs = { .id = 0x0000 + (0x000 << 2), /* 0x0000 */ .ver = 0x0000 + (0x001 << 2), /* 0x0004 */ .en = 0x0000 + (0x002 << 2), /* 0x0008 */ .clk_gate = 0x0000 + (0x003 << 2), /* 0x000c */ }, .dmem = { .offset = 0x8000, .size = 0x600 << 2, /* 1536 * 4 = 6144 */ }, .periph_regs = { .sync_reg = 0x8000 + (0xfe2 << 2), /* 0xbf88 */ .cmd_sta = 0x8000 + (0xff0 << 2), /* 0xbfc0 */ .cmd_set = 0x8000 + (0xff1 << 2), /* 0xbfc4 */ .cmd_clr = 0x8000 + (0xff2 << 2), /* 0xbfc8 */ .cmd_mask = 0x8000 + (0xff3 << 2), /* 0xbfcc */ .int_sta = 0x8000 + (0xff4 << 2), /* 0xbfd0 */ .int_set = 0x8000 + (0xff5 << 2), /* 0xbfd4 */ .int_clr = 0x8000 + (0xff6 << 2), /* 0xbfd8 */ .int_mask = 0x8000 + (0xff7 << 2), /* 0xbfdc */ }, .imem = { .offset = 0xc000, .size = 0xa00 << 2, /* 2560 * 4 = 10240 */ }, }; static struct stm_plat_fdma_data stx7100_fdma_platform_data = { .hw = &stx7100_fdma_hw, .fw = &stm_fdma_firmware_7100, }; static struct stm_plat_fdma_fw_regs stm_fdma_firmware_7109c2 = { .rev_id = 0x8000 + (0x000 << 2), /* 0x8000 */ .cmd_statn = 0x8000 + (0x450 << 2), /* 0x9140 */ .req_ctln = 0x8000 + (0x460 << 2), /* 0x9180 */ .ptrn = 0x8000 + (0x500 << 2), /* 0x9400 */ .cntn = 0x8000 + (0x502 << 2), /* 0x9408 */ .saddrn = 0x8000 + (0x503 << 2), /* 0x940c */ .daddrn = 0x8000 + (0x504 << 2), /* 0x9410 */ }; static struct stm_plat_fdma_hw stx7109c2_fdma_hw = { .slim_regs = { .id = 0x0000 + (0x000 << 2), /* 0x0000 */ .ver = 0x0000 + (0x001 << 2), /* 0x0004 */ .en = 0x0000 + (0x002 << 2), /* 0x0008 */ .clk_gate = 0x0000 + (0x003 << 2), /* 0x000c */ }, .dmem = { .offset = 0x8000, .size = 0x600 << 2, /* 1536 * 4 = 6144 */ }, .periph_regs = { .sync_reg = 0x8000 + (0xfe2 << 2), /* 0xbf88 */ .cmd_sta = 0x8000 + (0xff0 << 2), /* 0xbfc0 */ .cmd_set = 0x8000 + (0xff1 << 2), /* 0xbfc4 */ .cmd_clr = 0x8000 + (0xff2 << 2), /* 0xbfc8 */ .cmd_mask = 0x8000 + (0xff3 << 2), /* 0xbfcc */ .int_sta = 0x8000 + (0xff4 << 2), /* 0xbfd0 */ .int_set = 0x8000 + (0xff5 << 2), /* 0xbfd4 */ .int_clr = 0x8000 + (0xff6 << 2), /* 0xbfd8 */ .int_mask = 0x8000 + (0xff7 << 2), /* 0xbfdc */ }, .imem = { .offset = 0xc000, .size = 0xa00 << 2, /* 2560 * 4 = 10240 */ }, }; static struct stm_plat_fdma_data stx7109c2_fdma_platform_data = { .hw = &stx7109c2_fdma_hw, .fw = &stm_fdma_firmware_7109c2, }; static struct stm_plat_fdma_fw_regs stm_fdma_firmware_7109c3 = { .rev_id = 0x8000 + (0x000 << 2), /* 0x8000 */ .cmd_statn = 0x8000 + (0x450 << 2), /* 0x9140 */ .req_ctln = 0x8000 + (0x460 << 2), /* 0x9180 */ .ptrn = 0x8000 + (0x500 << 2), /* 0x9400 */ .cntn = 0x8000 + (0x502 << 2), /* 0x9408 */ .saddrn = 0x8000 + (0x503 << 2), /* 0x940c */ .daddrn = 0x8000 + (0x504 << 2), /* 0x9410 */ }; static struct stm_plat_fdma_hw stx7109c3_fdma_hw = { .slim_regs = { .id = 0x0000 + (0x000 << 2), /* 0x0000 */ .ver = 0x0000 + (0x001 << 2), /* 0x0004 */ .en = 0x0000 + (0x002 << 2), /* 0x0008 */ .clk_gate = 0x0000 + (0x003 << 2), /* 0x000c */ }, .dmem = { .offset = 0x8000, .size = 0x800 << 2, /* 2048 * 4 = 8192 */ }, .periph_regs = { .sync_reg = 0x8000 + (0xfe2 << 2), /* 0xbf88 */ .cmd_sta = 0x8000 + (0xff0 << 2), /* 0xbfc0 */ .cmd_set = 0x8000 + (0xff1 << 2), /* 0xbfc4 */ .cmd_clr = 0x8000 + (0xff2 << 2), /* 0xbfc8 */ .cmd_mask = 0x8000 + (0xff3 << 2), /* 0xbfcc */ .int_sta = 0x8000 + (0xff4 << 2), /* 0xbfd0 */ .int_set = 0x8000 + (0xff5 << 2), /* 0xbfd4 */ .int_clr = 0x8000 + (0xff6 << 2), /* 0xbfd8 */ .int_mask = 0x8000 + (0xff7 << 2), /* 0xbfdc */ }, .imem = { .offset = 0xc000, .size = 0x1000 << 2, /* 4096 * 4 = 16384 */ }, }; static struct stm_plat_fdma_data stx7109c3_fdma_platform_data = { .hw = &stx7109c3_fdma_hw, .fw = &stm_fdma_firmware_7109c3, }; static struct platform_device stx7100_fdma_device = { .name = "stm-fdma", .id = -1, .num_resources = 2, .resource = (struct resource[2]) { STM_PLAT_RESOURCE_MEM(0x19220000, 0x10000), STM_PLAT_RESOURCE_IRQ(140, -1), }, }; static void stx7100_fdma_setup(void) { switch (cpu_data->type) { case CPU_STX7100: stx7100_fdma_device.dev.platform_data = &stx7100_fdma_platform_data; break; case CPU_STX7109: switch (cpu_data->cut_major) { case 1: BUG(); break; case 2: stx7100_fdma_device.dev.platform_data = &stx7109c2_fdma_platform_data; break; default: stx7100_fdma_device.dev.platform_data = &stx7109c3_fdma_platform_data; break; } break; default: BUG(); break; } } /* Hardware RNG resources ------------------------------------------------- */ static struct platform_device stx7100_rng_hwrandom_device = { .name = "stm-hwrandom", .id = -1, .num_resources = 1, .resource = (struct resource[]) { STM_PLAT_RESOURCE_MEM(0x19250000, 0x1000), } }; static struct platform_device stx7100_rng_devrandom_device = { .name = "stm-rng", .id = -1, .num_resources = 1, .resource = (struct resource[]) { STM_PLAT_RESOURCE_MEM(0x19250000, 0x1000), } }; /* PIO ports resources ---------------------------------------------------- */ static struct platform_device stx7100_pio_devices[] = { [0] = { .name = "stm-gpio", .id = 0, .num_resources = 2, .resource = (struct resource[]) { STM_PLAT_RESOURCE_MEM(0x18020000, 0x100), STM_PLAT_RESOURCE_IRQ(80, -1), }, }, [1] = { .name = "stm-gpio", .id = 1, .num_resources = 2, .resource = (struct resource[]) { STM_PLAT_RESOURCE_MEM(0x18021000, 0x100), STM_PLAT_RESOURCE_IRQ(84, -1), }, }, [2] = { .name = "stm-gpio", .id = 2, .num_resources = 2, .resource = (struct resource[]) { STM_PLAT_RESOURCE_MEM(0x18022000, 0x100), STM_PLAT_RESOURCE_IRQ(88, -1), }, }, [3] = { .name = "stm-gpio", .id = 3, .num_resources = 2, .resource = (struct resource[]) { STM_PLAT_RESOURCE_MEM(0x18023000, 0x100), STM_PLAT_RESOURCE_IRQ(115, -1), }, }, [4] = { .name = "stm-gpio", .id = 4, .num_resources = 2, .resource = (struct resource[]) { STM_PLAT_RESOURCE_MEM(0x18024000, 0x100), STM_PLAT_RESOURCE_IRQ(114, -1), }, }, [5] = { .name = "stm-gpio", .id = 5, .num_resources = 2, .resource = (struct resource[]) { STM_PLAT_RESOURCE_MEM(0x18025000, 0x100), STM_PLAT_RESOURCE_IRQ(113, -1), }, }, }; static int stx7100_pio_config(unsigned gpio, enum stm_pad_gpio_direction direction, int function, void *priv) { switch (direction) { case stm_pad_gpio_direction_in: BUG_ON(function != -1); stm_gpio_direction(gpio, STM_GPIO_DIRECTION_IN); break; case stm_pad_gpio_direction_out: BUG_ON(function < 0); BUG_ON(function > 1); stm_gpio_direction(gpio, function ? STM_GPIO_DIRECTION_ALT_OUT : STM_GPIO_DIRECTION_OUT); break; case stm_pad_gpio_direction_bidir: BUG_ON(function < 0); BUG_ON(function > 1); stm_gpio_direction(gpio, function ? STM_GPIO_DIRECTION_ALT_BIDIR : STM_GPIO_DIRECTION_BIDIR); break; default: BUG(); break; } return 0; } /* sysconf resources ------------------------------------------------------ */ static struct platform_device stx7100_sysconf_device = { .name = "stm-sysconf", .id = -1, .num_resources = 1, .resource = (struct resource[]) { STM_PLAT_RESOURCE_MEM(0x19001000, 0x194), }, .dev.platform_data = &(struct stm_plat_sysconf_data) { .groups_num = 3, .groups = (struct stm_plat_sysconf_group []) { PLAT_SYSCONF_GROUP(SYS_DEV, 0x000), PLAT_SYSCONF_GROUP(SYS_STA, 0x008), PLAT_SYSCONF_GROUP(SYS_CFG, 0x100), }, }, }; /* Early initialisation-----------------------------------------------------*/ /* Initialise devices which are required early in the boot process. */ void __init stx7100_early_device_init(void) { struct sysconf_field *sc; unsigned long devid; unsigned long chip_7109, chip_revision; /* Create a PMB mapping so that the ioremap calls these drivers * will make can be satisfied without having to call get_vm_area * or cause a fault. Its probably also a good for efficiency as * there will be lots of devices in this range. */ ioremap_nocache(0x18000000, 0x04000000); /* Initialise PIO and sysconf drivers */ sysconf_early_init(&stx7100_sysconf_device, 1); stm_gpio_early_init(stx7100_pio_devices, ARRAY_SIZE(stx7100_pio_devices), 176); stm_pad_init(ARRAY_SIZE(stx7100_pio_devices) * STM_GPIO_PINS_PER_PORT, -1, 0, stx7100_pio_config); sc = sysconf_claim(SYS_DEV, 0, 0, 31, "devid"); devid = sysconf_read(sc); chip_7109 = (((devid >> 12) & 0x3ff) == 0x02c); chip_revision = (devid >> 28) + 1; boot_cpu_data.cut_major = chip_revision; printk(KERN_INFO "%s version %ld.x\n", chip_7109 ? "STx7109" : "STx7100", chip_revision); if (chip_7109) { boot_cpu_data.type = CPU_STX7109; sc = sysconf_claim(SYS_STA, 9, 0, 7, "devid"); devid = sysconf_read(sc); printk(KERN_INFO "Chip version %ld.%ld\n", (devid >> 4)+1, devid & 0xf); boot_cpu_data.cut_minor = devid & 0xf; if (devid == 0x24) { /* * See ADCS 8135002 "STI7109 CUT 4.0 CHANGES * VERSUS CUT 3.X" for details of this change. */ printk(KERN_INFO "Setting version to 4.0 to match " "commercial branding\n"); boot_cpu_data.cut_major = 4; boot_cpu_data.cut_minor = 0; } } /* Configure the ST40 RTC to source its clock from clockgenB. * In theory this should be board specific, but so far nobody * has ever done this. */ sc = sysconf_claim(SYS_CFG, 8, 1, 1, "rtc"); sysconf_write(sc, 1); /* We haven't configured the LPC, so the sleep instruction may * do bad things. Thus we disable it here. */ disable_hlt(); } /* Pre-arch initialisation ------------------------------------------------ */ static int __init stx7100_postcore_setup(void) { int i; for (i = 0; i < ARRAY_SIZE(stx7100_pio_devices); i++) platform_device_register(&stx7100_pio_devices[i]); return platform_device_register(&stx7100_emi); } postcore_initcall(stx7100_postcore_setup); /* Late initialisation ---------------------------------------------------- */ static struct platform_device *stx7100_devices[] __initdata = { &stx7100_fdma_device, &stx7100_sysconf_device, &stx7100_rng_hwrandom_device, &stx7100_rng_devrandom_device, }; static int __init stx7100_devices_setup(void) { stx7100_fdma_setup(); return platform_add_devices(stx7100_devices, ARRAY_SIZE(stx7100_devices)); } device_initcall(stx7100_devices_setup);