mtd: sf: Make sf_mtd.c more robust
[platform/kernel/u-boot.git] / drivers / usb / host / ehci-marvell.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2009
4  * Marvell Semiconductor <www.marvell.com>
5  * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
6  */
7
8 #include <common.h>
9 #include <asm/io.h>
10 #include <usb.h>
11 #include "ehci.h"
12 #include <linux/mbus.h>
13 #include <asm/arch/cpu.h>
14 #include <dm.h>
15
16 #if defined(CONFIG_KIRKWOOD)
17 #include <asm/arch/soc.h>
18 #elif defined(CONFIG_ORION5X)
19 #include <asm/arch/orion5x.h>
20 #endif
21
22 DECLARE_GLOBAL_DATA_PTR;
23
24 #define USB_WINDOW_CTRL(i)      (0x320 + ((i) << 4))
25 #define USB_WINDOW_BASE(i)      (0x324 + ((i) << 4))
26 #define USB_TARGET_DRAM         0x0
27
28 #define USB2_SBUSCFG_OFF        0x90
29
30 #define USB_SBUSCFG_BAWR_OFF    0x6
31 #define USB_SBUSCFG_BARD_OFF    0x3
32 #define USB_SBUSCFG_AHBBRST_OFF 0x0
33
34 #define USB_SBUSCFG_BAWR_ALIGN_64B      0x4
35 #define USB_SBUSCFG_BARD_ALIGN_64B      0x4
36 #define USB_SBUSCFG_AHBBRST_INCR16      0x7
37
38 /*
39  * USB 2.0 Bridge Address Decoding registers setup
40  */
41 #ifdef CONFIG_DM_USB
42
43 struct ehci_mvebu_priv {
44         struct ehci_ctrl ehci;
45         fdt_addr_t hcd_base;
46 };
47
48 /*
49  * Once all the older Marvell SoC's (Orion, Kirkwood) are converted
50  * to the common mvebu archticture including the mbus setup, this
51  * will be the only function needed to configure the access windows
52  */
53 static void usb_brg_adrdec_setup(void *base)
54 {
55         const struct mbus_dram_target_info *dram;
56         int i;
57
58         dram = mvebu_mbus_dram_info();
59
60         for (i = 0; i < 4; i++) {
61                 writel(0, base + USB_WINDOW_CTRL(i));
62                 writel(0, base + USB_WINDOW_BASE(i));
63         }
64
65         for (i = 0; i < dram->num_cs; i++) {
66                 const struct mbus_dram_window *cs = dram->cs + i;
67
68                 /* Write size, attributes and target id to control register */
69                 writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) |
70                        (dram->mbus_dram_target_id << 4) | 1,
71                        base + USB_WINDOW_CTRL(i));
72
73                 /* Write base address to base register */
74                 writel(cs->base, base + USB_WINDOW_BASE(i));
75         }
76 }
77
78 static void marvell_ehci_powerup_fixup(struct ehci_ctrl *ctrl,
79                                        uint32_t *status_reg, uint32_t *reg)
80 {
81         struct ehci_mvebu_priv *priv = ctrl->priv;
82
83         /*
84          * Set default value for reg SBUSCFG, which is Control for the AMBA
85          * system bus interface:
86          * BAWR = BARD = 4 : Align rd/wr bursts packets larger than 64 bytes
87          * AHBBRST = 7     : Align AHB burst for packets larger than 64 bytes
88          */
89         writel((USB_SBUSCFG_BAWR_ALIGN_64B << USB_SBUSCFG_BAWR_OFF) |
90                (USB_SBUSCFG_BARD_ALIGN_64B << USB_SBUSCFG_BARD_OFF) |
91                (USB_SBUSCFG_AHBBRST_INCR16 << USB_SBUSCFG_AHBBRST_OFF),
92                priv->hcd_base + USB2_SBUSCFG_OFF);
93
94         mdelay(50);
95 }
96
97 static struct ehci_ops marvell_ehci_ops = {
98         .powerup_fixup  = NULL,
99 };
100
101 static int ehci_mvebu_probe(struct udevice *dev)
102 {
103         struct ehci_mvebu_priv *priv = dev_get_priv(dev);
104         struct ehci_hccr *hccr;
105         struct ehci_hcor *hcor;
106
107         /*
108          * Get the base address for EHCI controller from the device node
109          */
110         priv->hcd_base = devfdt_get_addr(dev);
111         if (priv->hcd_base == FDT_ADDR_T_NONE) {
112                 debug("Can't get the EHCI register base address\n");
113                 return -ENXIO;
114         }
115
116         /*
117          * For SoCs without hlock like Armada3700 we need to program the sbuscfg
118          * reg to guarantee AHB master's burst will not overrun or underrun
119          * the FIFO. Otherwise all USB2 write option will fail.
120          * Also, the address decoder doesn't need to get setup with this
121          * SoC, so don't call usb_brg_adrdec_setup().
122          */
123         if (device_is_compatible(dev, "marvell,armada3700-ehci"))
124                 marvell_ehci_ops.powerup_fixup = marvell_ehci_powerup_fixup;
125         else
126                 usb_brg_adrdec_setup((void *)priv->hcd_base);
127
128         hccr = (struct ehci_hccr *)(priv->hcd_base + 0x100);
129         hcor = (struct ehci_hcor *)
130                 ((uintptr_t)hccr + HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
131
132         debug("ehci-marvell: init hccr %lx and hcor %lx hc_length %ld\n",
133               (uintptr_t)hccr, (uintptr_t)hcor,
134               (uintptr_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
135
136         return ehci_register(dev, hccr, hcor, &marvell_ehci_ops, 0,
137                              USB_INIT_HOST);
138 }
139
140 static const struct udevice_id ehci_usb_ids[] = {
141         { .compatible = "marvell,orion-ehci", },
142         { .compatible = "marvell,armada3700-ehci", },
143         { }
144 };
145
146 U_BOOT_DRIVER(ehci_mvebu) = {
147         .name   = "ehci_mvebu",
148         .id     = UCLASS_USB,
149         .of_match = ehci_usb_ids,
150         .probe = ehci_mvebu_probe,
151         .remove = ehci_deregister,
152         .ops    = &ehci_usb_ops,
153         .platdata_auto_alloc_size = sizeof(struct usb_platdata),
154         .priv_auto_alloc_size = sizeof(struct ehci_mvebu_priv),
155         .flags  = DM_FLAG_ALLOC_PRIV_DMA,
156 };
157
158 #else
159 #define MVUSB_BASE(port)        MVUSB0_BASE
160
161 static void usb_brg_adrdec_setup(int index)
162 {
163         int i;
164         u32 size, base, attrib;
165
166         for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
167
168                 /* Enable DRAM bank */
169                 switch (i) {
170                 case 0:
171                         attrib = MVUSB0_CPU_ATTR_DRAM_CS0;
172                         break;
173                 case 1:
174                         attrib = MVUSB0_CPU_ATTR_DRAM_CS1;
175                         break;
176                 case 2:
177                         attrib = MVUSB0_CPU_ATTR_DRAM_CS2;
178                         break;
179                 case 3:
180                         attrib = MVUSB0_CPU_ATTR_DRAM_CS3;
181                         break;
182                 default:
183                         /* invalide bank, disable access */
184                         attrib = 0;
185                         break;
186                 }
187
188                 size = gd->bd->bi_dram[i].size;
189                 base = gd->bd->bi_dram[i].start;
190                 if ((size) && (attrib))
191                         writel(MVCPU_WIN_CTRL_DATA(size, USB_TARGET_DRAM,
192                                                    attrib, MVCPU_WIN_ENABLE),
193                                 MVUSB0_BASE + USB_WINDOW_CTRL(i));
194                 else
195                         writel(MVCPU_WIN_DISABLE,
196                                MVUSB0_BASE + USB_WINDOW_CTRL(i));
197
198                 writel(base, MVUSB0_BASE + USB_WINDOW_BASE(i));
199         }
200 }
201
202 /*
203  * Create the appropriate control structures to manage
204  * a new EHCI host controller.
205  */
206 int ehci_hcd_init(int index, enum usb_init_type init,
207                 struct ehci_hccr **hccr, struct ehci_hcor **hcor)
208 {
209         usb_brg_adrdec_setup(index);
210
211         *hccr = (struct ehci_hccr *)(MVUSB_BASE(index) + 0x100);
212         *hcor = (struct ehci_hcor *)((uint32_t) *hccr
213                         + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
214
215         debug("ehci-marvell: init hccr %x and hcor %x hc_length %d\n",
216                 (uint32_t)*hccr, (uint32_t)*hcor,
217                 (uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
218
219         return 0;
220 }
221
222 /*
223  * Destroy the appropriate control structures corresponding
224  * the the EHCI host controller.
225  */
226 int ehci_hcd_stop(int index)
227 {
228         return 0;
229 }
230
231 #endif /* CONFIG_DM_USB */