1/* 2 * Ralink RT305x SoC platform device registration 3 * 4 * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org> 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 as published 8 * by the Free Software Foundation. 9 */ 10 11#include <linux/kernel.h> 12#include <linux/platform_device.h> 13#include <linux/err.h> 14#include <linux/clk.h> 15#include <linux/mtd/mtd.h> 16#include <linux/mtd/physmap.h> 17#include <linux/spi/spi.h> 18#include <linux/rt2x00_platform.h> 19#include <linux/delay.h> 20#include <linux/dma-mapping.h> 21 22#include <asm/addrspace.h> 23 24#include <asm/mach-ralink/rt305x.h> 25#include <asm/mach-ralink/rt305x_regs.h> 26#include "devices.h" 27 28#include <ramips_eth_platform.h> 29#include <rt305x_esw_platform.h> 30#include <rt3883_ehci_platform.h> 31#include <rt3883_ohci_platform.h> 32 33static struct resource rt305x_flash0_resources[] = { 34 { 35 .flags = IORESOURCE_MEM, 36 .start = KSEG1ADDR(RT305X_FLASH0_BASE), 37 .end = KSEG1ADDR(RT305X_FLASH0_BASE) + 38 RT305X_FLASH0_SIZE - 1, 39 }, 40}; 41 42struct physmap_flash_data rt305x_flash0_data; 43static struct platform_device rt305x_flash0_device = { 44 .name = "physmap-flash", 45 .resource = rt305x_flash0_resources, 46 .num_resources = ARRAY_SIZE(rt305x_flash0_resources), 47 .dev = { 48 .platform_data = &rt305x_flash0_data, 49 }, 50}; 51 52static struct resource rt305x_flash1_resources[] = { 53 { 54 .flags = IORESOURCE_MEM, 55 .start = KSEG1ADDR(RT305X_FLASH1_BASE), 56 .end = KSEG1ADDR(RT305X_FLASH1_BASE) + 57 RT305X_FLASH1_SIZE - 1, 58 }, 59}; 60 61struct physmap_flash_data rt305x_flash1_data; 62static struct platform_device rt305x_flash1_device = { 63 .name = "physmap-flash", 64 .resource = rt305x_flash1_resources, 65 .num_resources = ARRAY_SIZE(rt305x_flash1_resources), 66 .dev = { 67 .platform_data = &rt305x_flash1_data, 68 }, 69}; 70 71static int rt305x_flash_instance __initdata; 72void __init rt305x_register_flash(unsigned int id) 73{ 74 struct platform_device *pdev; 75 struct physmap_flash_data *pdata; 76 u32 t; 77 int reg; 78 79 switch (id) { 80 case 0: 81 pdev = &rt305x_flash0_device; 82 reg = MEMC_REG_FLASH_CFG0; 83 break; 84 case 1: 85 pdev = &rt305x_flash1_device; 86 reg = MEMC_REG_FLASH_CFG1; 87 break; 88 default: 89 return; 90 } 91 92 t = rt305x_memc_rr(reg); 93 t = (t >> FLASH_CFG_WIDTH_SHIFT) & FLASH_CFG_WIDTH_MASK; 94 95 pdata = pdev->dev.platform_data; 96 switch (t) { 97 case FLASH_CFG_WIDTH_8BIT: 98 pdata->width = 1; 99 break; 100 case FLASH_CFG_WIDTH_16BIT: 101 pdata->width = 2; 102 break; 103 case FLASH_CFG_WIDTH_32BIT: 104 pdata->width = 4; 105 break; 106 default: 107 printk(KERN_ERR "RT305x: flash bank%u witdh is invalid\n", id); 108 return; 109 } 110 111 pdev->id = rt305x_flash_instance; 112 113 platform_device_register(pdev); 114 rt305x_flash_instance++; 115} 116 117static void rt305x_fe_reset(void) 118{ 119 rt305x_sysc_wr(RT305X_RESET_FE, SYSC_REG_RESET_CTRL); 120 rt305x_sysc_wr(0, SYSC_REG_RESET_CTRL); 121} 122 123static struct resource rt305x_eth_resources[] = { 124 { 125 .start = RT305X_FE_BASE, 126 .end = RT305X_FE_BASE + PAGE_SIZE - 1, 127 .flags = IORESOURCE_MEM, 128 }, { 129 .start = RT305X_CPU_IRQ_FE, 130 .end = RT305X_CPU_IRQ_FE, 131 .flags = IORESOURCE_IRQ, 132 }, 133}; 134 135static struct ramips_eth_platform_data ramips_eth_data = { 136 .mac = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }, 137 .reset_fe = rt305x_fe_reset, 138 .min_pkt_len = 64, 139}; 140 141static struct platform_device rt305x_eth_device = { 142 .name = "ramips_eth", 143 .resource = rt305x_eth_resources, 144 .num_resources = ARRAY_SIZE(rt305x_eth_resources), 145 .dev = { 146 .platform_data = &ramips_eth_data, 147 } 148}; 149 150static struct resource rt305x_esw_resources[] = { 151 { 152 .start = RT305X_SWITCH_BASE, 153 .end = RT305X_SWITCH_BASE + PAGE_SIZE - 1, 154 .flags = IORESOURCE_MEM, 155 }, 156}; 157 158struct rt305x_esw_platform_data rt305x_esw_data = { 159 /* All ports are LAN ports. */ 160 .vlan_config = RT305X_ESW_VLAN_CONFIG_NONE, 161 .reg_initval_fct2 = 0x00d6500c, 162 /* 163 * ext phy base addr 31, enable port 5 polling, rx/tx clock skew 1, 164 * turbo mii off, rgmi 3.3v off 165 * port5: disabled 166 * port6: enabled, gige, full-duplex, rx/tx-flow-control 167 */ 168 .reg_initval_fpa2 = 0x3f502b28, 169}; 170 171static struct platform_device rt305x_esw_device = { 172 .name = "rt305x-esw", 173 .resource = rt305x_esw_resources, 174 .num_resources = ARRAY_SIZE(rt305x_esw_resources), 175 .dev = { 176 .platform_data = &rt305x_esw_data, 177 } 178}; 179 180void __init rt305x_register_ethernet(void) 181{ 182 struct clk *clk; 183 184 clk = clk_get(NULL, "sys"); 185 if (IS_ERR(clk)) 186 panic("unable to get SYS clock, err=%ld", PTR_ERR(clk)); 187 188 ramips_eth_data.sys_freq = clk_get_rate(clk); 189 190 platform_device_register(&rt305x_esw_device); 191 platform_device_register(&rt305x_eth_device); 192} 193 194static struct resource rt305x_wifi_resources[] = { 195 { 196 .start = RT305X_WMAC_BASE, 197 .end = RT305X_WMAC_BASE + 0x3FFFF, 198 .flags = IORESOURCE_MEM, 199 }, { 200 .start = RT305X_CPU_IRQ_WNIC, 201 .end = RT305X_CPU_IRQ_WNIC, 202 .flags = IORESOURCE_IRQ, 203 }, 204}; 205 206static struct rt2x00_platform_data rt305x_wifi_data; 207static struct platform_device rt305x_wifi_device = { 208 .name = "rt2800_wmac", 209 .resource = rt305x_wifi_resources, 210 .num_resources = ARRAY_SIZE(rt305x_wifi_resources), 211 .dev = { 212 .platform_data = &rt305x_wifi_data, 213 } 214}; 215 216void __init rt305x_register_wifi(void) 217{ 218 u32 t; 219 rt305x_wifi_data.eeprom_file_name = "RT305X.eeprom"; 220 221 if (soc_is_rt3352() || soc_is_rt5350()) { 222 t = rt305x_sysc_rr(SYSC_REG_SYSTEM_CONFIG); 223 t &= RT3352_SYSCFG0_XTAL_SEL; 224 if (!t) 225 rt305x_wifi_data.clk_is_20mhz = 1; 226 } 227 platform_device_register(&rt305x_wifi_device); 228} 229 230static struct resource rt305x_wdt_resources[] = { 231 { 232 .start = RT305X_TIMER_BASE, 233 .end = RT305X_TIMER_BASE + RT305X_TIMER_SIZE - 1, 234 .flags = IORESOURCE_MEM, 235 }, 236}; 237 238static struct platform_device rt305x_wdt_device = { 239 .name = "ramips-wdt", 240 .id = -1, 241 .resource = rt305x_wdt_resources, 242 .num_resources = ARRAY_SIZE(rt305x_wdt_resources), 243}; 244 245void __init rt305x_register_wdt(void) 246{ 247 u32 t; 248 249 /* enable WDT reset output on pin SRAM_CS_N */ 250 t = rt305x_sysc_rr(SYSC_REG_SYSTEM_CONFIG); 251 t |= RT305X_SYSCFG_SRAM_CS0_MODE_WDT << 252 RT305X_SYSCFG_SRAM_CS0_MODE_SHIFT; 253 rt305x_sysc_wr(t, SYSC_REG_SYSTEM_CONFIG); 254 255 platform_device_register(&rt305x_wdt_device); 256} 257 258static struct resource rt305x_spi_resources[] = { 259 { 260 .flags = IORESOURCE_MEM, 261 .start = RT305X_SPI_BASE, 262 .end = RT305X_SPI_BASE + RT305X_SPI_SIZE - 1, 263 }, 264}; 265 266static struct platform_device rt305x_spi_device = { 267 .name = "ramips-spi", 268 .id = 0, 269 .resource = rt305x_spi_resources, 270 .num_resources = ARRAY_SIZE(rt305x_spi_resources), 271}; 272 273void __init rt305x_register_spi(struct spi_board_info *info, int n) 274{ 275 spi_register_board_info(info, n); 276 platform_device_register(&rt305x_spi_device); 277} 278 279static struct resource rt305x_dwc_otg_resources[] = { 280 { 281 .start = RT305X_OTG_BASE, 282 .end = RT305X_OTG_BASE + 0x3FFFF, 283 .flags = IORESOURCE_MEM, 284 }, { 285 .start = RT305X_INTC_IRQ_OTG, 286 .end = RT305X_INTC_IRQ_OTG, 287 .flags = IORESOURCE_IRQ, 288 }, 289}; 290 291static struct platform_device rt305x_dwc_otg_device = { 292 .name = "dwc_otg", 293 .resource = rt305x_dwc_otg_resources, 294 .num_resources = ARRAY_SIZE(rt305x_dwc_otg_resources), 295 .dev = { 296 .platform_data = NULL, 297 } 298}; 299 300static atomic_t rt3352_usb_use_count = ATOMIC_INIT(0); 301 302static void rt3352_usb_host_start(void) 303{ 304 u32 t; 305 306 if (atomic_inc_return(&rt3352_usb_use_count) != 1) 307 return; 308 309 t = rt305x_sysc_rr(RT3352_SYSC_REG_USB_PS); 310 311 /* enable clock for port0's and port1's phys */ 312 t = rt305x_sysc_rr(RT3352_SYSC_REG_CLKCFG1); 313 t = t | RT3352_CLKCFG1_UPHY0_CLK_EN | RT3352_CLKCFG1_UPHY1_CLK_EN; 314 rt305x_sysc_wr(t, RT3352_SYSC_REG_CLKCFG1); 315 mdelay(500); 316 317 /* pull USBHOST and USBDEV out from reset */ 318 t = rt305x_sysc_rr(RT3352_SYSC_REG_RSTCTRL); 319 t &= ~(RT3352_RSTCTRL_UHST | RT3352_RSTCTRL_UDEV); 320 rt305x_sysc_wr(t, RT3352_SYSC_REG_RSTCTRL); 321 mdelay(500); 322 323 /* enable host mode */ 324 t = rt305x_sysc_rr(RT3352_SYSC_REG_SYSCFG1); 325 t |= RT3352_SYSCFG1_USB0_HOST_MODE; 326 rt305x_sysc_wr(t, RT3352_SYSC_REG_SYSCFG1); 327 328 t = rt305x_sysc_rr(RT3352_SYSC_REG_USB_PS); 329} 330 331static void rt3352_usb_host_stop(void) 332{ 333 u32 t; 334 335 if (atomic_dec_return(&rt3352_usb_use_count) != 0) 336 return; 337 338 /* put USBHOST and USBDEV into reset */ 339 t = rt305x_sysc_rr(RT3352_SYSC_REG_RSTCTRL); 340 t |= RT3352_RSTCTRL_UHST | RT3352_RSTCTRL_UDEV; 341 rt305x_sysc_wr(t, RT3352_SYSC_REG_RSTCTRL); 342 udelay(10000); 343 344 /* disable clock for port0's and port1's phys*/ 345 t = rt305x_sysc_rr(RT3352_SYSC_REG_CLKCFG1); 346 t &= ~(RT3352_CLKCFG1_UPHY0_CLK_EN | RT3352_CLKCFG1_UPHY1_CLK_EN); 347 rt305x_sysc_wr(t, RT3352_SYSC_REG_CLKCFG1); 348 udelay(10000); 349} 350 351static struct rt3883_ehci_platform_data rt3352_ehci_data = { 352 .start_hw = rt3352_usb_host_start, 353 .stop_hw = rt3352_usb_host_stop, 354}; 355 356static struct resource rt3352_ehci_resources[] = { 357 { 358 .start = RT3352_EHCI_BASE, 359 .end = RT3352_EHCI_BASE + RT3352_EHCI_SIZE - 1, 360 .flags = IORESOURCE_MEM, 361 }, { 362 .start = RT305X_INTC_IRQ_OTG, 363 .end = RT305X_INTC_IRQ_OTG, 364 .flags = IORESOURCE_IRQ, 365 }, 366}; 367 368static u64 rt3352_ehci_dmamask = DMA_BIT_MASK(32); 369static struct platform_device rt3352_ehci_device = { 370 .name = "rt3883-ehci", 371 .id = -1, 372 .resource = rt3352_ehci_resources, 373 .num_resources = ARRAY_SIZE(rt3352_ehci_resources), 374 .dev = { 375 .dma_mask = &rt3352_ehci_dmamask, 376 .coherent_dma_mask = DMA_BIT_MASK(32), 377 .platform_data = &rt3352_ehci_data, 378 }, 379}; 380 381static struct resource rt3352_ohci_resources[] = { 382 { 383 .start = RT3352_OHCI_BASE, 384 .end = RT3352_OHCI_BASE + RT3352_OHCI_SIZE - 1, 385 .flags = IORESOURCE_MEM, 386 }, { 387 .start = RT305X_INTC_IRQ_OTG, 388 .end = RT305X_INTC_IRQ_OTG, 389 .flags = IORESOURCE_IRQ, 390 }, 391}; 392 393static struct rt3883_ohci_platform_data rt3352_ohci_data = { 394 .start_hw = rt3352_usb_host_start, 395 .stop_hw = rt3352_usb_host_stop, 396}; 397 398static u64 rt3352_ohci_dmamask = DMA_BIT_MASK(32); 399static struct platform_device rt3352_ohci_device = { 400 .name = "rt3883-ohci", 401 .id = -1, 402 .resource = rt3352_ohci_resources, 403 .num_resources = ARRAY_SIZE(rt3352_ohci_resources), 404 .dev = { 405 .dma_mask = &rt3352_ohci_dmamask, 406 .coherent_dma_mask = DMA_BIT_MASK(32), 407 .platform_data = &rt3352_ohci_data, 408 }, 409}; 410 411void __init rt305x_register_usb(void) 412{ 413 if (soc_is_rt305x() || soc_is_rt3350()) { 414 platform_device_register(&rt305x_dwc_otg_device); 415 } else if (soc_is_rt3352() || soc_is_rt5350()) { 416 platform_device_register(&rt3352_ehci_device); 417 platform_device_register(&rt3352_ohci_device); 418 } else { 419 BUG(); 420 } 421} 422