Commit | Line | Data |
---|---|---|
ccb7cc74 KM |
1 | /* |
2 | * r8a7778 processor support | |
3 | * | |
4 | * Copyright (C) 2013 Renesas Solutions Corp. | |
5 | * Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | |
52421914 | 6 | * Copyright (C) 2013 Cogent Embedded, Inc. |
ccb7cc74 KM |
7 | * |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; version 2 of the License. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | */ | |
21 | ||
22 | #include <linux/kernel.h> | |
23 | #include <linux/io.h> | |
24 | #include <linux/irqchip/arm-gic.h> | |
25 | #include <linux/of.h> | |
26 | #include <linux/of_platform.h> | |
39ca2283 | 27 | #include <linux/platform_data/gpio-rcar.h> |
3a42fa20 | 28 | #include <linux/platform_data/irq-renesas-intc-irqpin.h> |
ccb7cc74 KM |
29 | #include <linux/platform_device.h> |
30 | #include <linux/irqchip.h> | |
db331fc8 | 31 | #include <linux/serial_sci.h> |
ccb7cc74 | 32 | #include <linux/sh_timer.h> |
02474a41 SS |
33 | #include <linux/pm_runtime.h> |
34 | #include <linux/usb/phy.h> | |
35 | #include <linux/usb/hcd.h> | |
36 | #include <linux/usb/ehci_pdriver.h> | |
37 | #include <linux/usb/ohci_pdriver.h> | |
38 | #include <linux/dma-mapping.h> | |
ccb7cc74 KM |
39 | #include <mach/irqs.h> |
40 | #include <mach/r8a7778.h> | |
41 | #include <mach/common.h> | |
42 | #include <asm/mach/arch.h> | |
43 | #include <asm/hardware/cache-l2x0.h> | |
44 | ||
db331fc8 KM |
45 | /* SCIF */ |
46 | #define SCIF_INFO(baseaddr, irq) \ | |
47 | { \ | |
48 | .mapbase = baseaddr, \ | |
49 | .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP, \ | |
50 | .scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1, \ | |
51 | .scbrr_algo_id = SCBRR_ALGO_2, \ | |
52 | .type = PORT_SCIF, \ | |
53 | .irqs = SCIx_IRQ_MUXED(irq), \ | |
54 | } | |
55 | ||
c9031fbb | 56 | static struct plat_sci_port scif_platform_data[] __initdata = { |
db331fc8 KM |
57 | SCIF_INFO(0xffe40000, gic_iid(0x66)), |
58 | SCIF_INFO(0xffe41000, gic_iid(0x67)), | |
59 | SCIF_INFO(0xffe42000, gic_iid(0x68)), | |
60 | SCIF_INFO(0xffe43000, gic_iid(0x69)), | |
61 | SCIF_INFO(0xffe44000, gic_iid(0x6a)), | |
62 | SCIF_INFO(0xffe45000, gic_iid(0x6b)), | |
63 | }; | |
64 | ||
ccb7cc74 | 65 | /* TMU */ |
c9031fbb | 66 | static struct resource sh_tmu0_resources[] __initdata = { |
ccb7cc74 KM |
67 | DEFINE_RES_MEM(0xffd80008, 12), |
68 | DEFINE_RES_IRQ(gic_iid(0x40)), | |
69 | }; | |
70 | ||
c9031fbb | 71 | static struct sh_timer_config sh_tmu0_platform_data __initdata = { |
ccb7cc74 KM |
72 | .name = "TMU00", |
73 | .channel_offset = 0x4, | |
74 | .timer_bit = 0, | |
75 | .clockevent_rating = 200, | |
76 | }; | |
77 | ||
c9031fbb | 78 | static struct resource sh_tmu1_resources[] __initdata = { |
ccb7cc74 KM |
79 | DEFINE_RES_MEM(0xffd80014, 12), |
80 | DEFINE_RES_IRQ(gic_iid(0x41)), | |
81 | }; | |
82 | ||
c9031fbb | 83 | static struct sh_timer_config sh_tmu1_platform_data __initdata = { |
ccb7cc74 KM |
84 | .name = "TMU01", |
85 | .channel_offset = 0x10, | |
86 | .timer_bit = 1, | |
87 | .clocksource_rating = 200, | |
88 | }; | |
89 | ||
81484487 KM |
90 | #define r8a7778_register_tmu(idx) \ |
91 | platform_device_register_resndata( \ | |
92 | &platform_bus, "sh_tmu", idx, \ | |
93 | sh_tmu##idx##_resources, \ | |
94 | ARRAY_SIZE(sh_tmu##idx##_resources), \ | |
95 | &sh_tmu##idx##_platform_data, \ | |
96 | sizeof(sh_tmu##idx##_platform_data)) | |
ccb7cc74 | 97 | |
02474a41 SS |
98 | /* USB */ |
99 | static struct usb_phy *phy; | |
100 | ||
101 | static int usb_power_on(struct platform_device *pdev) | |
102 | { | |
103 | if (IS_ERR(phy)) | |
104 | return PTR_ERR(phy); | |
105 | ||
106 | pm_runtime_enable(&pdev->dev); | |
107 | pm_runtime_get_sync(&pdev->dev); | |
108 | ||
109 | usb_phy_init(phy); | |
110 | ||
111 | return 0; | |
112 | } | |
113 | ||
114 | static void usb_power_off(struct platform_device *pdev) | |
115 | { | |
116 | if (IS_ERR(phy)) | |
117 | return; | |
118 | ||
119 | usb_phy_shutdown(phy); | |
120 | ||
121 | pm_runtime_put_sync(&pdev->dev); | |
122 | pm_runtime_disable(&pdev->dev); | |
123 | } | |
124 | ||
125 | static int ehci_init_internal_buffer(struct usb_hcd *hcd) | |
126 | { | |
127 | /* | |
128 | * Below are recommended values from the datasheet; | |
129 | * see [USB :: Setting of EHCI Internal Buffer]. | |
130 | */ | |
131 | /* EHCI IP internal buffer setting */ | |
132 | iowrite32(0x00ff0040, hcd->regs + 0x0094); | |
133 | /* EHCI IP internal buffer enable */ | |
134 | iowrite32(0x00000001, hcd->regs + 0x009C); | |
135 | ||
136 | return 0; | |
137 | } | |
138 | ||
139 | static struct usb_ehci_pdata ehci_pdata __initdata = { | |
140 | .power_on = usb_power_on, | |
141 | .power_off = usb_power_off, | |
142 | .power_suspend = usb_power_off, | |
143 | .pre_setup = ehci_init_internal_buffer, | |
144 | }; | |
145 | ||
146 | static struct resource ehci_resources[] __initdata = { | |
147 | DEFINE_RES_MEM(0xffe70000, 0x400), | |
148 | DEFINE_RES_IRQ(gic_iid(0x4c)), | |
149 | }; | |
150 | ||
151 | static struct usb_ohci_pdata ohci_pdata __initdata = { | |
152 | .power_on = usb_power_on, | |
153 | .power_off = usb_power_off, | |
154 | .power_suspend = usb_power_off, | |
155 | }; | |
156 | ||
157 | static struct resource ohci_resources[] __initdata = { | |
158 | DEFINE_RES_MEM(0xffe70400, 0x400), | |
159 | DEFINE_RES_IRQ(gic_iid(0x4c)), | |
160 | }; | |
161 | ||
162 | #define USB_PLATFORM_INFO(hci) \ | |
163 | static struct platform_device_info hci##_info __initdata = { \ | |
164 | .parent = &platform_bus, \ | |
165 | .name = #hci "-platform", \ | |
166 | .id = -1, \ | |
167 | .res = hci##_resources, \ | |
168 | .num_res = ARRAY_SIZE(hci##_resources), \ | |
169 | .data = &hci##_pdata, \ | |
170 | .size_data = sizeof(hci##_pdata), \ | |
171 | .dma_mask = DMA_BIT_MASK(32), \ | |
172 | } | |
173 | ||
174 | USB_PLATFORM_INFO(ehci); | |
175 | USB_PLATFORM_INFO(ohci); | |
176 | ||
734e02f8 | 177 | /* Ether */ |
c9031fbb | 178 | static struct resource ether_resources[] __initdata = { |
734e02f8 KM |
179 | DEFINE_RES_MEM(0xfde00000, 0x400), |
180 | DEFINE_RES_IRQ(gic_iid(0x89)), | |
181 | }; | |
182 | ||
183 | void __init r8a7778_add_ether_device(struct sh_eth_plat_data *pdata) | |
184 | { | |
c02f8469 | 185 | platform_device_register_resndata(&platform_bus, "r8a777x-ether", -1, |
734e02f8 KM |
186 | ether_resources, |
187 | ARRAY_SIZE(ether_resources), | |
188 | pdata, sizeof(*pdata)); | |
189 | } | |
190 | ||
39ca2283 | 191 | /* PFC/GPIO */ |
c9031fbb | 192 | static struct resource pfc_resources[] __initdata = { |
369b00bb KM |
193 | DEFINE_RES_MEM(0xfffc0000, 0x118), |
194 | }; | |
195 | ||
39ca2283 | 196 | #define R8A7778_GPIO(idx) \ |
c9031fbb | 197 | static struct resource r8a7778_gpio##idx##_resources[] __initdata = { \ |
39ca2283 KM |
198 | DEFINE_RES_MEM(0xffc40000 + 0x1000 * (idx), 0x30), \ |
199 | DEFINE_RES_IRQ(gic_iid(0x87)), \ | |
200 | }; \ | |
201 | \ | |
c9031fbb | 202 | static struct gpio_rcar_config r8a7778_gpio##idx##_platform_data __initdata = { \ |
39ca2283 KM |
203 | .gpio_base = 32 * (idx), \ |
204 | .irq_base = GPIO_IRQ_BASE(idx), \ | |
205 | .number_of_pins = 32, \ | |
206 | .pctl_name = "pfc-r8a7778", \ | |
207 | } | |
208 | ||
209 | R8A7778_GPIO(0); | |
210 | R8A7778_GPIO(1); | |
211 | R8A7778_GPIO(2); | |
212 | R8A7778_GPIO(3); | |
213 | R8A7778_GPIO(4); | |
214 | ||
215 | #define r8a7778_register_gpio(idx) \ | |
216 | platform_device_register_resndata( \ | |
217 | &platform_bus, "gpio_rcar", idx, \ | |
218 | r8a7778_gpio##idx##_resources, \ | |
219 | ARRAY_SIZE(r8a7778_gpio##idx##_resources), \ | |
220 | &r8a7778_gpio##idx##_platform_data, \ | |
221 | sizeof(r8a7778_gpio##idx##_platform_data)) | |
222 | ||
369b00bb KM |
223 | void __init r8a7778_pinmux_init(void) |
224 | { | |
225 | platform_device_register_simple( | |
226 | "pfc-r8a7778", -1, | |
227 | pfc_resources, | |
228 | ARRAY_SIZE(pfc_resources)); | |
39ca2283 KM |
229 | |
230 | r8a7778_register_gpio(0); | |
231 | r8a7778_register_gpio(1); | |
232 | r8a7778_register_gpio(2); | |
233 | r8a7778_register_gpio(3); | |
234 | r8a7778_register_gpio(4); | |
ae8b378f SH |
235 | }; |
236 | ||
46b9a092 KM |
237 | /* I2C */ |
238 | static struct resource i2c_resources[] __initdata = { | |
239 | /* I2C0 */ | |
240 | DEFINE_RES_MEM(0xffc70000, 0x1000), | |
241 | DEFINE_RES_IRQ(gic_iid(0x63)), | |
242 | /* I2C1 */ | |
243 | DEFINE_RES_MEM(0xffc71000, 0x1000), | |
244 | DEFINE_RES_IRQ(gic_iid(0x6e)), | |
245 | /* I2C2 */ | |
246 | DEFINE_RES_MEM(0xffc72000, 0x1000), | |
247 | DEFINE_RES_IRQ(gic_iid(0x6c)), | |
248 | /* I2C3 */ | |
249 | DEFINE_RES_MEM(0xffc73000, 0x1000), | |
250 | DEFINE_RES_IRQ(gic_iid(0x6d)), | |
251 | }; | |
252 | ||
1fd4eecd | 253 | static void __init r8a7778_register_i2c(int id) |
46b9a092 KM |
254 | { |
255 | BUG_ON(id < 0 || id > 3); | |
256 | ||
257 | platform_device_register_simple( | |
258 | "i2c-rcar", id, | |
259 | i2c_resources + (2 * id), 2); | |
260 | } | |
261 | ||
8b89797f KM |
262 | /* HSPI */ |
263 | static struct resource hspi_resources[] __initdata = { | |
264 | /* HSPI0 */ | |
265 | DEFINE_RES_MEM(0xfffc7000, 0x18), | |
266 | DEFINE_RES_IRQ(gic_iid(0x5f)), | |
267 | /* HSPI1 */ | |
268 | DEFINE_RES_MEM(0xfffc8000, 0x18), | |
269 | DEFINE_RES_IRQ(gic_iid(0x74)), | |
270 | /* HSPI2 */ | |
271 | DEFINE_RES_MEM(0xfffc6000, 0x18), | |
272 | DEFINE_RES_IRQ(gic_iid(0x75)), | |
273 | }; | |
274 | ||
275 | void __init r8a7778_add_hspi_device(int id) | |
276 | { | |
277 | BUG_ON(id < 0 || id > 2); | |
278 | ||
279 | platform_device_register_simple( | |
280 | "sh-hspi", id, | |
281 | hspi_resources + (2 * id), 2); | |
282 | } | |
283 | ||
cfa66a81 | 284 | void __init r8a7778_add_dt_devices(void) |
ccb7cc74 KM |
285 | { |
286 | int i; | |
287 | ||
288 | #ifdef CONFIG_CACHE_L2X0 | |
289 | void __iomem *base = ioremap_nocache(0xf0100000, 0x1000); | |
290 | if (base) { | |
291 | /* | |
292 | * Early BRESP enable, Shared attribute override enable, 64K*16way | |
293 | * don't call iounmap(base) | |
294 | */ | |
295 | l2x0_init(base, 0x40470000, 0x82000fff); | |
296 | } | |
297 | #endif | |
298 | ||
db331fc8 KM |
299 | for (i = 0; i < ARRAY_SIZE(scif_platform_data); i++) |
300 | platform_device_register_data(&platform_bus, "sh-sci", i, | |
301 | &scif_platform_data[i], | |
302 | sizeof(struct plat_sci_port)); | |
303 | ||
81484487 KM |
304 | r8a7778_register_tmu(0); |
305 | r8a7778_register_tmu(1); | |
ccb7cc74 KM |
306 | } |
307 | ||
cfa66a81 KM |
308 | void __init r8a7778_add_standard_devices(void) |
309 | { | |
310 | r8a7778_add_dt_devices(); | |
1fd4eecd KM |
311 | r8a7778_register_i2c(0); |
312 | r8a7778_register_i2c(1); | |
313 | r8a7778_register_i2c(2); | |
314 | r8a7778_register_i2c(3); | |
cfa66a81 KM |
315 | } |
316 | ||
02474a41 SS |
317 | void __init r8a7778_init_late(void) |
318 | { | |
319 | phy = usb_get_phy(USB_PHY_TYPE_USB2); | |
320 | ||
321 | platform_device_register_full(&ehci_info); | |
322 | platform_device_register_full(&ohci_info); | |
323 | } | |
324 | ||
c9031fbb | 325 | static struct renesas_intc_irqpin_config irqpin_platform_data __initdata = { |
3a42fa20 KM |
326 | .irq_base = irq_pin(0), /* IRQ0 -> IRQ3 */ |
327 | .sense_bitfield_width = 2, | |
328 | }; | |
329 | ||
c9031fbb | 330 | static struct resource irqpin_resources[] __initdata = { |
3a42fa20 KM |
331 | DEFINE_RES_MEM(0xfe78001c, 4), /* ICR1 */ |
332 | DEFINE_RES_MEM(0xfe780010, 4), /* INTPRI */ | |
333 | DEFINE_RES_MEM(0xfe780024, 4), /* INTREQ */ | |
334 | DEFINE_RES_MEM(0xfe780044, 4), /* INTMSK0 */ | |
335 | DEFINE_RES_MEM(0xfe780064, 4), /* INTMSKCLR0 */ | |
336 | DEFINE_RES_IRQ(gic_iid(0x3b)), /* IRQ0 */ | |
337 | DEFINE_RES_IRQ(gic_iid(0x3c)), /* IRQ1 */ | |
338 | DEFINE_RES_IRQ(gic_iid(0x3d)), /* IRQ2 */ | |
339 | DEFINE_RES_IRQ(gic_iid(0x3e)), /* IRQ3 */ | |
340 | }; | |
341 | ||
342 | void __init r8a7778_init_irq_extpin(int irlm) | |
343 | { | |
344 | void __iomem *icr0 = ioremap_nocache(0xfe780000, PAGE_SIZE); | |
345 | unsigned long tmp; | |
346 | ||
347 | if (!icr0) { | |
348 | pr_warn("r8a7778: unable to setup external irq pin mode\n"); | |
349 | return; | |
350 | } | |
351 | ||
352 | tmp = ioread32(icr0); | |
353 | if (irlm) | |
354 | tmp |= 1 << 23; /* IRQ0 -> IRQ3 as individual pins */ | |
355 | else | |
356 | tmp &= ~(1 << 23); /* IRL mode - not supported */ | |
357 | tmp |= (1 << 21); /* LVLMODE = 1 */ | |
358 | iowrite32(tmp, icr0); | |
359 | iounmap(icr0); | |
360 | ||
361 | if (irlm) | |
362 | platform_device_register_resndata( | |
363 | &platform_bus, "renesas_intc_irqpin", -1, | |
364 | irqpin_resources, ARRAY_SIZE(irqpin_resources), | |
365 | &irqpin_platform_data, sizeof(irqpin_platform_data)); | |
366 | } | |
367 | ||
54aa4c48 KM |
368 | void __init r8a7778_init_delay(void) |
369 | { | |
370 | shmobile_setup_delay(800, 1, 3); /* Cortex-A9 @ 800MHz */ | |
371 | } | |
372 | ||
373 | #ifdef CONFIG_USE_OF | |
ccb7cc74 KM |
374 | #define INT2SMSKCR0 0x82288 /* 0xfe782288 */ |
375 | #define INT2SMSKCR1 0x8228c /* 0xfe78228c */ | |
376 | ||
377 | #define INT2NTSR0 0x00018 /* 0xfe700018 */ | |
378 | #define INT2NTSR1 0x0002c /* 0xfe70002c */ | |
54aa4c48 | 379 | void __init r8a7778_init_irq_dt(void) |
ccb7cc74 KM |
380 | { |
381 | void __iomem *base = ioremap_nocache(0xfe700000, 0x00100000); | |
382 | ||
383 | BUG_ON(!base); | |
384 | ||
54aa4c48 KM |
385 | irqchip_init(); |
386 | ||
ccb7cc74 KM |
387 | /* route all interrupts to ARM */ |
388 | __raw_writel(0x73ffffff, base + INT2NTSR0); | |
389 | __raw_writel(0xffffffff, base + INT2NTSR1); | |
390 | ||
391 | /* unmask all known interrupts in INTCS2 */ | |
392 | __raw_writel(0x08330773, base + INT2SMSKCR0); | |
393 | __raw_writel(0x00311110, base + INT2SMSKCR1); | |
394 | ||
395 | iounmap(base); | |
396 | } | |
397 | ||
ccb7cc74 KM |
398 | static const char *r8a7778_compat_dt[] __initdata = { |
399 | "renesas,r8a7778", | |
400 | NULL, | |
401 | }; | |
402 | ||
403 | DT_MACHINE_START(R8A7778_DT, "Generic R8A7778 (Flattened Device Tree)") | |
404 | .init_early = r8a7778_init_delay, | |
405 | .init_irq = r8a7778_init_irq_dt, | |
ccb7cc74 KM |
406 | .init_time = shmobile_timer_init, |
407 | .dt_compat = r8a7778_compat_dt, | |
02474a41 | 408 | .init_late = r8a7778_init_late, |
ccb7cc74 KM |
409 | MACHINE_END |
410 | ||
411 | #endif /* CONFIG_USE_OF */ |