1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * UniPhier Specific Glue Layer for DWC3 4 * 5 * Copyright (C) 2016-2017 Socionext Inc. 6 * Author: Masahiro Yamada <yamada.masahiro@socionext.com> 7 * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> 8 */ 9 10#include <dm.h> 11#include <dm/lists.h> 12#include <linux/bitops.h> 13#include <linux/usb/gadget.h> 14 15#include "core.h" 16#include "gadget.h" 17#include "dwc3-generic.h" 18 19#define UNIPHIER_PRO4_DWC3_RESET 0x40 20#define UNIPHIER_PRO4_DWC3_RESET_XIOMMU BIT(5) 21#define UNIPHIER_PRO4_DWC3_RESET_XLINK BIT(4) 22#define UNIPHIER_PRO4_DWC3_RESET_PHY_SS BIT(2) 23 24#define UNIPHIER_PRO5_DWC3_RESET 0x00 25#define UNIPHIER_PRO5_DWC3_RESET_PHY_S1 BIT(17) 26#define UNIPHIER_PRO5_DWC3_RESET_PHY_S0 BIT(16) 27#define UNIPHIER_PRO5_DWC3_RESET_XLINK BIT(15) 28#define UNIPHIER_PRO5_DWC3_RESET_XIOMMU BIT(14) 29 30#define UNIPHIER_PXS2_DWC3_RESET 0x00 31#define UNIPHIER_PXS2_DWC3_RESET_XLINK BIT(15) 32 33static void uniphier_pro4_dwc3_init(struct udevice *dev, int index, 34 enum usb_dr_mode mode) 35{ 36 struct dwc3_glue_data *glue = dev_get_plat(dev); 37 void *regs = map_physmem(glue->regs, glue->size, MAP_NOCACHE); 38 u32 tmp; 39 40 tmp = readl(regs + UNIPHIER_PRO4_DWC3_RESET); 41 tmp &= ~UNIPHIER_PRO4_DWC3_RESET_PHY_SS; 42 tmp |= UNIPHIER_PRO4_DWC3_RESET_XIOMMU | UNIPHIER_PRO4_DWC3_RESET_XLINK; 43 writel(tmp, regs + UNIPHIER_PRO4_DWC3_RESET); 44 45 unmap_physmem(regs, MAP_NOCACHE); 46} 47 48static void uniphier_pro5_dwc3_init(struct udevice *dev, int index, 49 enum usb_dr_mode mode) 50{ 51 struct dwc3_glue_data *glue = dev_get_plat(dev); 52 void *regs = map_physmem(glue->regs, glue->size, MAP_NOCACHE); 53 u32 tmp; 54 55 tmp = readl(regs + UNIPHIER_PRO5_DWC3_RESET); 56 tmp &= ~(UNIPHIER_PRO5_DWC3_RESET_PHY_S1 | 57 UNIPHIER_PRO5_DWC3_RESET_PHY_S0); 58 tmp |= UNIPHIER_PRO5_DWC3_RESET_XLINK | UNIPHIER_PRO5_DWC3_RESET_XIOMMU; 59 writel(tmp, regs + UNIPHIER_PRO5_DWC3_RESET); 60 61 unmap_physmem(regs, MAP_NOCACHE); 62} 63 64static void uniphier_pxs2_dwc3_init(struct udevice *dev, int index, 65 enum usb_dr_mode mode) 66{ 67 struct dwc3_glue_data *glue = dev_get_plat(dev); 68 void *regs = map_physmem(glue->regs, glue->size, MAP_NOCACHE); 69 u32 tmp; 70 71 tmp = readl(regs + UNIPHIER_PXS2_DWC3_RESET); 72 tmp |= UNIPHIER_PXS2_DWC3_RESET_XLINK; 73 writel(tmp, regs + UNIPHIER_PXS2_DWC3_RESET); 74 75 unmap_physmem(regs, MAP_NOCACHE); 76} 77 78static int dwc3_uniphier_glue_get_ctrl_dev(struct udevice *dev, ofnode *node) 79{ 80 struct udevice *child; 81 const char *name; 82 ofnode subnode; 83 84 /* 85 * "controller reset" belongs to glue logic, and it should be 86 * accessible in .glue_configure() before access to the controller 87 * begins. 88 */ 89 ofnode_for_each_subnode(subnode, dev_ofnode(dev)) { 90 name = ofnode_get_name(subnode); 91 if (!strncmp(name, "reset", 5)) 92 device_bind_driver_to_node(dev, "uniphier-reset", 93 name, subnode, &child); 94 } 95 96 /* Get controller node that is placed separately from the glue node */ 97 *node = ofnode_by_compatible(dev_ofnode(dev->parent), 98 "socionext,uniphier-dwc3"); 99 100 return 0; 101} 102 103static const struct dwc3_glue_ops uniphier_pro4_dwc3_ops = { 104 .glue_get_ctrl_dev = dwc3_uniphier_glue_get_ctrl_dev, 105 .glue_configure = uniphier_pro4_dwc3_init, 106}; 107 108static const struct dwc3_glue_ops uniphier_pro5_dwc3_ops = { 109 .glue_get_ctrl_dev = dwc3_uniphier_glue_get_ctrl_dev, 110 .glue_configure = uniphier_pro5_dwc3_init, 111}; 112 113static const struct dwc3_glue_ops uniphier_pxs2_dwc3_ops = { 114 .glue_get_ctrl_dev = dwc3_uniphier_glue_get_ctrl_dev, 115 .glue_configure = uniphier_pxs2_dwc3_init, 116}; 117 118static const struct udevice_id uniphier_dwc3_match[] = { 119 { 120 .compatible = "socionext,uniphier-pro4-dwc3-glue", 121 .data = (ulong)&uniphier_pro4_dwc3_ops, 122 }, 123 { 124 .compatible = "socionext,uniphier-pro5-dwc3-glue", 125 .data = (ulong)&uniphier_pro5_dwc3_ops, 126 }, 127 { 128 .compatible = "socionext,uniphier-pxs2-dwc3-glue", 129 .data = (ulong)&uniphier_pxs2_dwc3_ops, 130 }, 131 { 132 .compatible = "socionext,uniphier-ld20-dwc3-glue", 133 .data = (ulong)&uniphier_pxs2_dwc3_ops, 134 }, 135 { 136 .compatible = "socionext,uniphier-pxs3-dwc3-glue", 137 .data = (ulong)&uniphier_pxs2_dwc3_ops, 138 }, 139 { 140 .compatible = "socionext,uniphier-nx1-dwc3-glue", 141 .data = (ulong)&uniphier_pxs2_dwc3_ops, 142 }, 143 { /* sentinel */ } 144}; 145 146U_BOOT_DRIVER(dwc3_uniphier_wrapper) = { 147 .name = "uniphier-dwc3", 148 .id = UCLASS_SIMPLE_BUS, 149 .of_match = uniphier_dwc3_match, 150 .bind = dwc3_glue_bind, 151 .probe = dwc3_glue_probe, 152 .remove = dwc3_glue_remove, 153 .plat_auto = sizeof(struct dwc3_glue_data), 154}; 155