[adm8668] add support for on-board EHCI controller
[openwrt.git] / target / linux / adm8668 / files / arch / mips / adm8668 / platform.c
1 /*
2  * Infineon/ADMTek 8668 (WildPass) platform devices support
3  *
4  * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us>
5  * Copyright (C) 2012 Florian Fainelli <florian@openwrt.org>
6  *
7  * This file is subject to the terms and conditions of the GNU General Public
8  * License.  See the file "COPYING" in the main directory of this archive
9  * for more details.
10  */
11
12 #include <linux/init.h>
13 #include <linux/kernel.h>
14 #include <linux/platform_device.h>
15 #include <linux/platform_data/tulip.h>
16 #include <linux/usb/ehci_pdriver.h>
17 #include <linux/mtd/physmap.h>
18 #include <linux/mtd/partitions.h>
19 #include <linux/pci.h>
20 #include <linux/slab.h>
21 #include <linux/ioport.h>
22 #include <linux/amba/bus.h>
23 #include <linux/amba/serial.h>
24
25 #include <asm/reboot.h>
26 #include <asm/time.h>
27 #include <asm/addrspace.h>
28 #include <asm/bootinfo.h>
29 #include <asm/io.h>
30 #include <adm8668.h>
31
32 #define ADM8868_UBOOT_ENV               0x20000
33 #define ADM8868_UBOOT_WAN_MAC           0x5ac
34 #define ADM8868_UBOOT_LAN_MAC           0x404
35
36 static void adm8668_uart_set_mctrl(struct amba_device *dev,
37                                         void __iomem *base,
38                                         unsigned int mcrtl)
39 {
40 }
41
42 static struct amba_pl010_data adm8668_uart0_data = {
43         .set_mctrl = adm8668_uart_set_mctrl,
44 };
45
46 static struct amba_device adm8668_uart0_device = {
47         .dev = {
48                 .init_name      = "apb:uart0",
49                 .platform_data  = &adm8668_uart0_data,
50         },
51         .res = {
52                 .start          = ADM8668_UART0_BASE,
53                 .end            = ADM8668_UART0_BASE + 0xF,
54                 .flags          = IORESOURCE_MEM,
55         },
56         .irq = {
57                 INT_LVL_UART0,
58                 -1
59         },
60         .periphid = 0x0041010,
61 };
62
63 static struct resource eth0_resources[] = {
64         {
65                 .start          = ADM8668_LAN_BASE,
66                 .end            = ADM8668_LAN_BASE + 256,
67                 .flags          = IORESOURCE_MEM,
68         },
69         {
70                 .start          = INT_LVL_LAN,
71                 .flags          = IORESOURCE_IRQ,
72         },
73 };
74
75 static struct tulip_platform_data eth0_pdata = {
76         .chip_id        = ADM8668,
77 };
78
79 static struct platform_device adm8668_eth0_device = {
80         .name           = "tulip",
81         .id             = 0,
82         .resource       = eth0_resources,
83         .num_resources  = ARRAY_SIZE(eth0_resources),
84         .dev.platform_data = &eth0_pdata,
85 };
86
87 static struct resource eth1_resources[] = {
88         {
89                 .start          = ADM8668_WAN_BASE,
90                 .end            = ADM8668_WAN_BASE + 256,
91                 .flags          = IORESOURCE_MEM,
92         },
93         {
94                 .start          = INT_LVL_WAN,
95                 .flags          = IORESOURCE_IRQ,
96         },
97 };
98
99 static struct tulip_platform_data eth1_pdata = {
100         .chip_id        = ADM8668,
101 };
102
103 static struct platform_device adm8668_eth1_device = {
104         .name           = "tulip",
105         .id             = 1,
106         .resource       = eth1_resources,
107         .num_resources  = ARRAY_SIZE(eth1_resources),
108         .dev.platform_data = &eth1_pdata,
109 };
110
111 static const char *nor_probe_types[] = { "adm8668part", NULL };
112
113 static struct physmap_flash_data nor_flash_data = {
114         .width                  = 2,
115         .part_probe_types       = nor_probe_types,
116 };
117
118 static struct resource nor_resources[] = {
119         {
120                 .start  = ADM8668_SMEM1_BASE,
121                 .end    = ADM8668_SMEM1_BASE + 0x800000 - 1,
122                 .flags  = IORESOURCE_MEM,
123         },
124 };
125
126 static struct platform_device adm8668_nor_device = {
127         .name           = "physmap-flash",
128         .id             = -1,
129         .resource       = nor_resources,
130         .num_resources  = ARRAY_SIZE(nor_resources),
131         .dev.platform_data = &nor_flash_data,
132 };
133
134 static struct resource usb_resources[] = {
135         {
136                 .start  = ADM8668_USB_BASE,
137                 .end    = ADM8668_USB_BASE + 0x1FFFFF,
138                 .flags  = IORESOURCE_MEM,
139         },
140         {
141                 .start  = INT_LVL_USB,
142                 .end    = INT_LVL_USB,
143                 .flags  = IORESOURCE_IRQ,
144         },
145 };
146
147 static struct usb_ehci_pdata usb_pdata = {
148         .caps_offset    = 0x100,
149         .has_tt         = 1,
150         .port_power_off = 1,
151 };
152
153 static struct platform_device adm8668_usb_device = {
154         .name           = "ehci-platform",
155         .id             = -1,
156         .resource       = usb_resources,
157         .num_resources  = ARRAY_SIZE(usb_resources),
158         .dev.platform_data = &usb_pdata,
159 };
160
161 static struct platform_device *adm8668_devs[] = {
162         &adm8668_eth0_device,
163         &adm8668_eth1_device,
164         &adm8668_nor_device,
165         &adm8668_usb_device,
166 };
167
168 static void adm8668_fetch_mac(int unit)
169 {
170         u8 *mac;
171         u32 offset;
172         struct tulip_platform_data *pdata;
173
174         switch (unit) {
175         case -1:
176         case 0:
177                 offset = ADM8868_UBOOT_LAN_MAC;
178                 pdata = &eth0_pdata;
179                 break;
180         case 1:
181                 offset = ADM8868_UBOOT_WAN_MAC;
182                 pdata = &eth1_pdata;
183                 break;
184         default:
185                 pr_err("unsupported ethernet unit: %d\n", unit);
186                 return;
187         }
188
189         mac = (u8 *)(KSEG1ADDR(ADM8668_SMEM1_BASE) + ADM8868_UBOOT_ENV + offset);
190
191         memcpy(pdata->mac, mac, sizeof(pdata->mac));
192 }
193
194 static void adm8668_ehci_workaround(void)
195 {
196         u32 chipid;
197
198         chipid = ADM8668_CONFIG_REG(ADM8668_CR0);
199         ADM8668_CONFIG_REG(ADM8668_CR66) = 0x0C1600D9;
200
201         if (chipid == 0x86880001)
202                 return;
203
204         ADM8668_CONFIG_REG(ADM8668_CR66) &= ~(3 << 20);
205         ADM8668_CONFIG_REG(ADM8668_CR66) |= (1 << 20);
206         pr_info("ADM8668: applied USB workaround\n");
207 }
208
209
210 int __devinit adm8668_devs_register(void)
211 {
212         int ret;
213
214         ret = amba_device_register(&adm8668_uart0_device, &iomem_resource);
215         if (ret)
216                 panic("failed to register AMBA UART");
217
218         adm8668_fetch_mac(0);
219         adm8668_fetch_mac(1);
220         adm8668_ehci_workaround();
221
222         return platform_add_devices(adm8668_devs, ARRAY_SIZE(adm8668_devs));
223 }
224 arch_initcall(adm8668_devs_register);