/* * (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 /* Ethernet MAC resources ------------------------------------------------- */ static struct stm_pad_config stx7100_ethernet_pad_configs[] = { [stx7100_ethernet_mode_mii] = { .gpios_num = 1, .gpios = (struct stm_pad_gpio []) { /* Claimed only when config->ext_clk == 0 */ STM_PAD_PIO_OUT_NAMED(3, 7, 1, "PHYCLK"), }, .sysconfs_num = 3, .sysconfs = (struct stm_pad_sysconf []) { /* DVO_ETH_PAD_DISABLE and ETH_IF_ON */ STM_PAD_SYS_CFG(7, 16, 17, 3), /* RMII_MODE */ STM_PAD_SYS_CFG(7, 18, 18, 0), /* * PHY_CLK_EXT: PHY external clock * 0: PHY clock is provided by STx7109 * 1: PHY clock is provided by an external source * Value assigned in stx7100_configure_ethernet() */ STM_PAD_SYS_CFG(7, 19, 19, -1), }, }, [stx7100_ethernet_mode_rmii] = { .gpios_num = 1, .gpios = (struct stm_pad_gpio []) { /* Claimed only when config->ext_clk == 0 */ STM_PAD_PIO_OUT_NAMED(3, 7, 1, "PHYCLK"), }, .sysconfs_num = 3, .sysconfs = (struct stm_pad_sysconf []) { /* DVO_ETH_PAD_DISABLE and ETH_IF_ON */ STM_PAD_SYS_CFG(7, 16, 17, 3), /* RMII_MODE */ STM_PAD_SYS_CFG(7, 18, 18, 1), /* PHY_CLK_EXT */ STM_PAD_SYS_CFG(7, 19, 19, -1), }, }, }; static void stx7100_ethernet_fix_mac_speed(void *bsp_priv, unsigned int speed) { struct sysconf_field *mac_speed_sel = bsp_priv; sysconf_write(mac_speed_sel, (speed == SPEED_100) ? 1 : 0); } static struct plat_stmmacenet_data stx7100_ethernet_platform_data = { /* .pbl is set in stx7100_configure_ethernet() */ .has_gmac = 0, .enh_desc = 0, .fix_mac_speed = stx7100_ethernet_fix_mac_speed, .init = &stmmac_claim_resource, }; static struct platform_device stx7100_ethernet_device = { .name = "stmmaceth", .id = 0, .num_resources = 2, .resource = (struct resource[]) { STM_PLAT_RESOURCE_MEM(0x18110000, 0x10000), STM_PLAT_RESOURCE_IRQ_NAMED("macirq", 133, -1), }, .dev.platform_data = &stx7100_ethernet_platform_data, }; void __init stx7100_configure_ethernet(struct stx7100_ethernet_config *config) { static int configured; struct stx7100_ethernet_config default_config; struct stm_pad_config *pad_config; int interface; /* 7100 doesn't have a MAC */ if (cpu_data->type == CPU_STX7100) return; BUG_ON(configured); configured = 1; if (!config) config = &default_config; pad_config = &stx7100_ethernet_pad_configs[config->mode]; switch (config->mode) { case stx7100_ethernet_mode_mii: if (config->ext_clk) stm_pad_set_pio_ignored(pad_config, "PHYCLK"); interface = PHY_INTERFACE_MODE_MII; break; case stx7100_ethernet_mode_rmii: if (config->ext_clk) stm_pad_set_pio_in(pad_config, "PHYCLK", -1); interface = PHY_INTERFACE_MODE_RMII; break; default: BUG(); break; } pad_config->sysconfs[2].value = (config->ext_clk ? 1 : 0); stx7100_ethernet_platform_data.custom_cfg = (void *) pad_config; stx7100_ethernet_platform_data.interface = interface; stx7100_ethernet_platform_data.bus_id = config->phy_bus; stx7100_ethernet_platform_data.phy_addr = config->phy_addr; stx7100_ethernet_platform_data.mdio_bus_data = config->mdio_bus_data; /* MAC_SPEED_SEL */ stx7100_ethernet_platform_data.bsp_priv = sysconf_claim(SYS_CFG, 7, 20, 20, "stmmac"); /* Configure the ethernet MAC PBL depending on the cut of the chip */ stx7100_ethernet_platform_data.pbl = (cpu_data->cut_major == 1) ? 1 : 32; platform_device_register(&stx7100_ethernet_device); } /* USB resources ---------------------------------------------------------- */ static int stx7100_usb_oc_gpio = -EINVAL; static int stx7100_usb_pwr_gpio = -EINVAL; static int stx7100_usb_pad_claim(struct stm_pad_state *state, void *priv) { /* Work around for USB over-current detection chip being * active low, and the 710x being active high. * * This test is wrong for 7100 cut 3.0 (which needs the work * around), but as we can't reliably determine the minor * revision number, hard luck, this works for most people. */ if ((cpu_data->type == CPU_STX7109 && cpu_data->cut_major < 2) || (cpu_data->type == CPU_STX7100 && cpu_data->cut_major < 3)) { stx7100_usb_oc_gpio = stm_pad_gpio_request_output(state, "OC", 0); BUG_ON(stx7100_usb_oc_gpio == STM_GPIO_INVALID); } /* * There have been two changes to the USB power enable signal: * * - 7100 upto and including cut 3.0 and 7109 1.0 generated an * active high enables signal. From 7100 cut 3.1 and 7109 cut 2.0 * the signal changed to active low. * * - The 710x ref board (mb442) has always used power distribution * chips which have active high enables signals (on rev A and B * this was a TI TPS2052, rev C used the ST equivalent a ST2052). * However rev A and B had a pull up on the enables signal, while * rev C changed this to a pull down. * * The net effect of all this is that the easiest way to drive * this signal is ignore the USB hardware and drive it as a PIO * pin. * * (Note the USB over current input on the 710x changed from active * high to low at the same cuts, but board revs A and B had a resistor * option to select an inverted output from the TPS2052, so no * software work around is required.) */ stx7100_usb_pwr_gpio = stm_pad_gpio_request_output(state, "PWR", 1); BUG_ON(stx7100_usb_pwr_gpio == STM_GPIO_INVALID); return 0; } static void stx7100_usb_pad_release(struct stm_pad_state *state, void *priv) { if (gpio_is_valid(stx7100_usb_oc_gpio)) stm_pad_gpio_free(state, stx7100_usb_oc_gpio); if (gpio_is_valid(stx7100_usb_pwr_gpio)) stm_pad_gpio_free(state, stx7100_usb_pwr_gpio); } #define USB_PWR "USB_PWR" static void stx7100_usb_power(struct stm_device_state *device_state, enum stm_device_power_state power) { stm_device_sysconf_write(device_state, USB_PWR, (power == stm_device_power_on) ? 0 : 1); mdelay(30); } static struct stm_plat_usb_data stx7100_usb_platform_data = { .flags = STM_PLAT_USB_FLAGS_STRAP_8BIT | STM_PLAT_USB_FLAGS_STRAP_PLL | STM_PLAT_USB_FLAGS_OPC_MSGSIZE_CHUNKSIZE, .device_config = &(struct stm_device_config){ .pad_config = &(struct stm_pad_config) { .gpios_num = 2, .gpios = (struct stm_pad_gpio []) { STM_PAD_PIO_IN_NAMED(5, 6, -1, "OC"), STM_PAD_PIO_OUT_NAMED(5, 7, 1, "PWR"), }, .custom_claim = stx7100_usb_pad_claim, .custom_release = stx7100_usb_pad_release, .sysconfs_num = 1, .sysconfs = (struct stm_pad_sysconf []) { /* USB_AT */ STM_PAD_SYS_CFG(2, 1, 1, 0), }, }, .sysconfs_num = 1, .sysconfs = (struct stm_device_sysconf []) { STM_DEVICE_SYS_CFG(2, 4, 5, USB_PWR), }, .power = stx7100_usb_power, }, }; static u64 stx7100_usb_dma_mask = DMA_BIT_MASK(32); static struct platform_device stx7100_usb_device = { .name = "stm-usb", .id = 0, .dev = { .dma_mask = &stx7100_usb_dma_mask, .coherent_dma_mask = DMA_BIT_MASK(32), .platform_data = &stx7100_usb_platform_data, }, .num_resources = 6, .resource = (struct resource[]) { STM_PLAT_RESOURCE_MEM_NAMED("ehci", 0x191ffe00, 0x100), STM_PLAT_RESOURCE_IRQ_NAMED("ehci", 169, -1), STM_PLAT_RESOURCE_MEM_NAMED("ohci", 0x191ffc00, 0x100), STM_PLAT_RESOURCE_IRQ_NAMED("ohci", 168, -1), STM_PLAT_RESOURCE_MEM_NAMED("wrapper", 0x19100000, 0x100), STM_PLAT_RESOURCE_MEM_NAMED("protocol", 0x191fff00, 0x100), }, }; void __init stx7100_configure_usb(void) { static int configured; BUG_ON(configured); configured = 1; platform_device_register(&stx7100_usb_device); } /* MiPHY resources -------------------------------------------------------- */ static struct stm_plat_miphy_dummy_data stx7100_miphy_dummy_platform_data = { .miphy_first = 0, .miphy_count = 1, .miphy_modes = (enum miphy_mode[1]) {SATA_MODE}, }; static struct platform_device stx7100_miphy_dummy_device = { .name = "stm-miphy-dummy", .id = 0, .num_resources = 0, .dev = { .platform_data = &stx7100_miphy_dummy_platform_data, } }; static int __init stx7100_miphy_postcore_setup(void) { return platform_device_register(&stx7100_miphy_dummy_device); } postcore_initcall(stx7100_miphy_postcore_setup); /* SATA resources --------------------------------------------------------- */ static struct stm_plat_sata_data stx7100_sata_platform_data = { /* filled in stx7100_configure_sata() */ .device_config = &(struct stm_device_config){}, }; static struct platform_device stx7100_sata_device = { .name = "sata-stm", .id = -1, .dev.platform_data = &stx7100_sata_platform_data, .num_resources = 2, .resource = (struct resource[]) { STM_PLAT_RESOURCE_MEM(0x19209000, 0x1000), STM_PLAT_RESOURCE_IRQ(170, -1), }, }; void __init stx7100_configure_sata(void) { static int configured; BUG_ON(configured); configured = 1; if (cpu_data->type == CPU_STX7100 && cpu_data->cut_major == 1) { /* 7100 cut 1.x */ stx7100_sata_platform_data.phy_init = 0x0013704A; } else { /* 7100 cut 2.x and cut 3.x and 7109 */ stx7100_sata_platform_data.phy_init = 0x388fc; } if ((cpu_data->type == CPU_STX7109 && cpu_data->cut_major == 1) || cpu_data->type == CPU_STX7100) { stx7100_sata_platform_data.only_32bit = 1; stx7100_sata_platform_data.pc_glue_logic_init = 0x1ff; } else { stx7100_sata_platform_data.only_32bit = 0; stx7100_sata_platform_data.pc_glue_logic_init = 0x100ff; } platform_device_register(&stx7100_sata_device); }