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