aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/gemini/patches-4.19/0018-ARM-dts-Add-the-FOTG210-USB-host-to-Gemini-boards.patch
blob: 83d993b1f93bcea915c1881c6a711a766ad320ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
From 1ff9a279dbeb0034929042faef186ce934474c2b Mon Sep 17 00:00:00 2001
From: Linus Walleij <linus.walleij@linaro.org>
Date: Fri, 21 Apr 2017 20:50:22 +0200
Subject: [PATCH 18/18] ARM: dts: Add the FOTG210 USB host to Gemini boards

This adds the FOTG210 USB host controller to the Gemini
device trees. In the main SoC DTSI it is flagged as disabled
and then it is selectively enabled on the devices that utilize
it.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ChangeLog v1->v2:
- Rebased to kernel v4.19-rc1
- Drop pinctrl-0 handle from the second USB port
- Add comment on how to deal with the USB pin control
---
 arch/arm/boot/dts/gemini-dlink-dir-685.dts |  8 ++++++
 arch/arm/boot/dts/gemini-nas4220b.dts      |  8 ++++++
 arch/arm/boot/dts/gemini-rut1xx.dts        | 20 ++++++++++++++
 arch/arm/boot/dts/gemini-sl93512r.dts      |  8 ++++++
 arch/arm/boot/dts/gemini-sq201.dts         |  8 ++++++
 arch/arm/boot/dts/gemini-wbd111.dts        |  8 ++++++
 arch/arm/boot/dts/gemini-wbd222.dts        |  8 ++++++
 arch/arm/boot/dts/gemini.dtsi              | 32 ++++++++++++++++++++++
 8 files changed, 100 insertions(+)

--- a/arch/arm/boot/dts/gemini-dlink-dir-685.dts
+++ b/arch/arm/boot/dts/gemini-dlink-dir-685.dts
@@ -452,5 +452,13 @@
 				};
 			};
 		};
+
+		usb@68000000 {
+			status = "okay";
+		};
+
+		usb@69000000 {
+			status = "okay";
+		};
 	};
 };
--- a/arch/arm/boot/dts/gemini-nas4220b.dts
+++ b/arch/arm/boot/dts/gemini-nas4220b.dts
@@ -204,5 +204,13 @@
 		ata@63400000 {
 			status = "okay";
 		};
+
+		usb@68000000 {
+			status = "okay";
+		};
+
+		usb@69000000 {
+			status = "okay";
+		};
 	};
 };
--- a/arch/arm/boot/dts/gemini-rut1xx.dts
+++ b/arch/arm/boot/dts/gemini-rut1xx.dts
@@ -124,5 +124,25 @@
 				/* Not used in this platform */
 			};
 		};
+
+		ethernet@60000000 {
+			status = "okay";
+
+			ethernet-port@0 {
+				phy-mode = "rgmii";
+				phy-handle = <&phy0>;
+			};
+			ethernet-port@1 {
+				/* Not used in this platform */
+			};
+		};
+
+		usb@68000000 {
+			status = "okay";
+		};
+
+		usb@69000000 {
+			status = "okay";
+		};
 	};
 };
--- a/arch/arm/boot/dts/gemini-sl93512r.dts
+++ b/arch/arm/boot/dts/gemini-sl93512r.dts
@@ -324,5 +324,13 @@
 		ata@63400000 {
 			status = "okay";
 		};
+
+		usb@68000000 {
+			status = "okay";
+		};
+
+		usb@69000000 {
+			status = "okay";
+		};
 	};
 };
--- a/arch/arm/boot/dts/gemini-sq201.dts
+++ b/arch/arm/boot/dts/gemini-sq201.dts
@@ -292,5 +292,13 @@
 		ata@63000000 {
 			status = "okay";
 		};
+
+		usb@68000000 {
+			status = "okay";
+		};
+
+		usb@69000000 {
+			status = "okay";
+		};
 	};
 };
--- a/arch/arm/boot/dts/gemini-wbd111.dts
+++ b/arch/arm/boot/dts/gemini-wbd111.dts
@@ -171,5 +171,13 @@
 				/* Not used in this platform */
 			};
 		};
+
+		usb@68000000 {
+			status = "okay";
+		};
+
+		usb@69000000 {
+			status = "okay";
+		};
 	};
 };
--- a/arch/arm/boot/dts/gemini-wbd222.dts
+++ b/arch/arm/boot/dts/gemini-wbd222.dts
@@ -183,5 +183,13 @@
 				phy-handle = <&phy1>;
 			};
 		};
+
+		usb@68000000 {
+			status = "okay";
+		};
+
+		usb@69000000 {
+			status = "okay";
+		};
 	};
 };
--- a/arch/arm/boot/dts/gemini.dtsi
+++ b/arch/arm/boot/dts/gemini.dtsi
@@ -409,5 +409,37 @@
 			#size-cells = <0>;
 			status = "disabled";
 		};
+
+		usb@68000000 {
+			compatible = "cortina,gemini-usb", "faraday,fotg210";
+			reg = <0x68000000 0x1000>;
+			interrupts = <10 IRQ_TYPE_LEVEL_HIGH>;
+			resets = <&syscon GEMINI_RESET_USB0>;
+			clocks = <&syscon GEMINI_CLK_GATE_USB0>;
+			clock-names = "PCLK";
+			/*
+			 * This will claim pins for USB0 and USB1 at the same
+			 * time as they are using some common pins. If you for
+			 * some reason have a system using USB1 at 96000000 but
+			 * NOT using USB0 at 68000000 you wll have to add the
+			 * usb_default_pins to the USB controller at 96000000
+			 * in your .dts for the board.
+			 */
+			pinctrl-names = "default";
+			pinctrl-0 = <&usb_default_pins>;
+			syscon = <&syscon>;
+			status = "disabled";
+		};
+
+		usb@69000000 {
+			compatible = "cortina,gemini-usb", "faraday,fotg210";
+			reg = <0x69000000 0x1000>;
+			interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
+			resets = <&syscon GEMINI_RESET_USB1>;
+			clocks = <&syscon GEMINI_CLK_GATE_USB1>;
+			clock-names = "PCLK";
+			syscon = <&syscon>;
+			status = "disabled";
+		};
 	};
 };
ass="kt">unsigned char pl081_id[] = { 0x81, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 }; static void pl080_update(pl080_state *s) { if ((s->tc_int & s->tc_mask) || (s->err_int & s->err_mask)) pic_set_irq_new(s->pic, s->irq, 1); else pic_set_irq_new(s->pic, s->irq, 1); } static void pl080_run(pl080_state *s) { int c; int flow; pl080_channel *ch; int swidth; int dwidth; int xsize; int n; int src_id; int dest_id; int size; char buff[4]; uint32_t req; s->tc_mask = 0; for (c = 0; c < s->nchannels; c++) { if (s->chan[c].conf & PL080_CCONF_ITC) s->tc_mask |= 1 << c; if (s->chan[c].conf & PL080_CCONF_IE) s->err_mask |= 1 << c; } if ((s->conf & PL080_CONF_E) == 0) return; cpu_abort(cpu_single_env, "DMA active\n"); /* If we are already in the middle of a DMA operation then indicate that there may be new DMA requests and return immediately. */ if (s->running) { s->running++; return; } s->running = 1; while (s->running) { for (c = 0; c < s->nchannels; c++) { ch = &s->chan[c]; again: /* Test if thiws channel has any pending DMA requests. */ if ((ch->conf & (PL080_CCONF_H | PL080_CCONF_E)) != PL080_CCONF_E) continue; flow = (ch->conf >> 11) & 7; if (flow >= 4) { cpu_abort(cpu_single_env, "pl080_run: Peripheral flow control not implemented\n"); } src_id = (ch->conf >> 1) & 0x1f; dest_id = (ch->conf >> 6) & 0x1f; size = ch->ctrl & 0xfff; req = s->req_single | s->req_burst; switch (flow) { case 0: break; case 1: if ((req & (1u << dest_id)) == 0) size = 0; break; case 2: if ((req & (1u << src_id)) == 0) size = 0; break; case 3: if ((req & (1u << src_id)) == 0 || (req & (1u << dest_id)) == 0) size = 0; break; } if (!size) continue; /* Transfer one element. */ /* ??? Should transfer multiple elements for a burst request. */ /* ??? Unclear what the proper behavior is when source and destination widths are different. */ swidth = 1 << ((ch->ctrl >> 18) & 7); dwidth = 1 << ((ch->ctrl >> 21) & 7); for (n = 0; n < dwidth; n+= swidth) { cpu_physical_memory_read(ch->src, buff + n, swidth); if (ch->ctrl & PL080_CCTRL_SI) ch->src += swidth; } xsize = (dwidth < swidth) ? swidth : dwidth; /* ??? This may pad the value incorrectly for dwidth < 32. */ for (n = 0; n < xsize; n += dwidth) { cpu_physical_memory_write(ch->dest + n, buff + n, dwidth); if (ch->ctrl & PL080_CCTRL_DI) ch->dest += swidth; } size--; ch->ctrl = (ch->ctrl & 0xfffff000) | size; if (size == 0) { /* Transfer complete. */ if (ch->lli) { ch->src = ldl_phys(ch->lli); ch->dest = ldl_phys(ch->lli + 4); ch->ctrl = ldl_phys(ch->lli + 12); ch->lli = ldl_phys(ch->lli + 8); } else { ch->conf &= ~PL080_CCONF_E; } if (ch->ctrl & PL080_CCTRL_I) { s->tc_int |= 1 << c; } } goto again; } if (--s->running) s->running = 1; } } static uint32_t pl080_read(void *opaque, target_phys_addr_t offset) { pl080_state *s = (pl080_state *)opaque; uint32_t i; uint32_t mask; offset -= s->base; if (offset >= 0xfe0 && offset < 0x1000) { if (s->nchannels == 8) { return pl080_id[(offset - 0xfe0) >> 2]; } else { return pl081_id[(offset - 0xfe0) >> 2]; } } if (offset >= 0x100 && offset < 0x200) { i = (offset & 0xe0) >> 5; if (i >= s->nchannels) goto bad_offset; switch (offset >> 2) { case 0: /* SrcAddr */ return s->chan[i].src; case 1: /* DestAddr */ return s->chan[i].dest; case 2: /* LLI */ return s->chan[i].lli; case 3: /* Control */ return s->chan[i].ctrl; case 4: /* Configuration */ return s->chan[i].conf; default: goto bad_offset; } } switch (offset >> 2) { case 0: /* IntStatus */ return (s->tc_int & s->tc_mask) | (s->err_int & s->err_mask); case 1: /* IntTCStatus */ return (s->tc_int & s->tc_mask); case 3: /* IntErrorStatus */ return (s->err_int & s->err_mask); case 5: /* RawIntTCStatus */ return s->tc_int; case 6: /* RawIntErrorStatus */ return s->err_int; case 7: /* EnbldChns */ mask = 0; for (i = 0; i < s->nchannels; i++) { if (s->chan[i].conf & PL080_CCONF_E) mask |= 1 << i; } return mask; case 8: /* SoftBReq */ case 9: /* SoftSReq */ case 10: /* SoftLBReq */ case 11: /* SoftLSReq */ /* ??? Implement these. */ return 0; case 12: /* Configuration */ return s->conf; case 13: /* Sync */ return s->sync; default: bad_offset: cpu_abort(cpu_single_env, "pl080_read: Bad offset %x\n", offset); return 0; } } static void pl080_write(void *opaque, target_phys_addr_t offset, uint32_t value) { pl080_state *s = (pl080_state *)opaque; int i; offset -= s->base; if (offset >= 0x100 && offset < 0x200) { i = (offset & 0xe0) >> 5; if (i >= s->nchannels) goto bad_offset; switch (offset >> 2) { case 0: /* SrcAddr */ s->chan[i].src = value; break; case 1: /* DestAddr */ s->chan[i].dest = value; break; case 2: /* LLI */ s->chan[i].lli = value; break; case 3: /* Control */ s->chan[i].ctrl = value; break; case 4: /* Configuration */ s->chan[i].conf = value; pl080_run(s); break; } } switch (offset >> 2) { case 2: /* IntTCClear */ s->tc_int &= ~value; break; case 4: /* IntErrorClear */ s->err_int &= ~value; break; case 8: /* SoftBReq */ case 9: /* SoftSReq */ case 10: /* SoftLBReq */ case 11: /* SoftLSReq */ /* ??? Implement these. */ cpu_abort(cpu_single_env, "pl080_write: Soft DMA not implemented\n"); break; case 12: /* Configuration */ s->conf = value; if (s->conf & (PL080_CONF_M1 | PL080_CONF_M1)) { cpu_abort(cpu_single_env, "pl080_write: Big-endian DMA not implemented\n"); } pl080_run(s); break; case 13: /* Sync */ s->sync = value; break; default: bad_offset: cpu_abort(cpu_single_env, "pl080_write: Bad offset %x\n", offset); } pl080_update(s); } static CPUReadMemoryFunc *pl080_readfn[] = { pl080_read, pl080_read, pl080_read }; static CPUWriteMemoryFunc *pl080_writefn[] = { pl080_write, pl080_write, pl080_write }; /* The PL080 and PL081 are the same except for the number of channels they implement (8 and 2 respectively). */ void *pl080_init(uint32_t base, void *pic, int irq, int nchannels) { int iomemtype; pl080_state *s; s = (pl080_state *)qemu_mallocz(sizeof(pl080_state)); iomemtype = cpu_register_io_memory(0, pl080_readfn, pl080_writefn, s); cpu_register_physical_memory(base, 0x00000fff, iomemtype); s->base = base; s->pic = pic; s->irq = irq; s->nchannels = nchannels; /* ??? Save/restore. */ return s; }