1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Allwinner SUNXI "glue layer" 4 * 5 * Copyright �� 2015 Hans de Goede <hdegoede@redhat.com> 6 * Copyright �� 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> 7 * 8 * Based on the sw_usb "Allwinner OTG Dual Role Controller" code. 9 * Copyright 2007-2012 (C) Allwinner Technology Co., Ltd. 10 * javen <javen@allwinnertech.com> 11 * 12 * Based on the DA8xx "glue layer" code. 13 * Copyright (c) 2008-2009 MontaVista Software, Inc. <source@mvista.com> 14 * Copyright (C) 2005-2006 by Texas Instruments 15 * 16 * This file is part of the Inventra Controller Driver for Linux. 17 */ 18#include <common.h> 19#include <clk.h> 20#include <dm.h> 21#include <generic-phy.h> 22#include <log.h> 23#include <malloc.h> 24#include <phy-sun4i-usb.h> 25#include <reset.h> 26#include <asm/arch/cpu.h> 27#include <asm/arch/clock.h> 28#include <dm/device_compat.h> 29#include <dm/lists.h> 30#include <dm/root.h> 31#include <linux/bitops.h> 32#include <linux/delay.h> 33#include <linux/printk.h> 34#include <linux/usb/musb.h> 35#include "linux-compat.h" 36#include "musb_core.h" 37#include "musb_uboot.h" 38 39/****************************************************************************** 40 ****************************************************************************** 41 * From the Allwinner driver 42 ****************************************************************************** 43 ******************************************************************************/ 44 45/****************************************************************************** 46 * From include/sunxi_usb_bsp.h 47 ******************************************************************************/ 48 49/* reg offsets */ 50#define USBC_REG_o_ISCR 0x0400 51#define USBC_REG_o_PHYCTL 0x0404 52#define USBC_REG_o_PHYBIST 0x0408 53#define USBC_REG_o_PHYTUNE 0x040c 54 55#define USBC_REG_o_VEND0 0x0043 56 57/* Interface Status and Control */ 58#define USBC_BP_ISCR_VBUS_VALID_FROM_DATA 30 59#define USBC_BP_ISCR_VBUS_VALID_FROM_VBUS 29 60#define USBC_BP_ISCR_EXT_ID_STATUS 28 61#define USBC_BP_ISCR_EXT_DM_STATUS 27 62#define USBC_BP_ISCR_EXT_DP_STATUS 26 63#define USBC_BP_ISCR_MERGED_VBUS_STATUS 25 64#define USBC_BP_ISCR_MERGED_ID_STATUS 24 65 66#define USBC_BP_ISCR_ID_PULLUP_EN 17 67#define USBC_BP_ISCR_DPDM_PULLUP_EN 16 68#define USBC_BP_ISCR_FORCE_ID 14 69#define USBC_BP_ISCR_FORCE_VBUS_VALID 12 70#define USBC_BP_ISCR_VBUS_VALID_SRC 10 71 72#define USBC_BP_ISCR_HOSC_EN 7 73#define USBC_BP_ISCR_VBUS_CHANGE_DETECT 6 74#define USBC_BP_ISCR_ID_CHANGE_DETECT 5 75#define USBC_BP_ISCR_DPDM_CHANGE_DETECT 4 76#define USBC_BP_ISCR_IRQ_ENABLE 3 77#define USBC_BP_ISCR_VBUS_CHANGE_DETECT_EN 2 78#define USBC_BP_ISCR_ID_CHANGE_DETECT_EN 1 79#define USBC_BP_ISCR_DPDM_CHANGE_DETECT_EN 0 80 81/****************************************************************************** 82 * From usbc/usbc.c 83 ******************************************************************************/ 84 85struct sunxi_musb_config { 86 struct musb_hdrc_config *config; 87}; 88 89struct sunxi_glue { 90 struct musb_host_data mdata; 91 struct clk clk; 92 struct reset_ctl rst; 93 struct sunxi_musb_config *cfg; 94 struct device dev; 95 struct phy phy; 96}; 97#define to_sunxi_glue(d) container_of(d, struct sunxi_glue, dev) 98 99static u32 USBC_WakeUp_ClearChangeDetect(u32 reg_val) 100{ 101 u32 temp = reg_val; 102 103 temp &= ~BIT(USBC_BP_ISCR_VBUS_CHANGE_DETECT); 104 temp &= ~BIT(USBC_BP_ISCR_ID_CHANGE_DETECT); 105 temp &= ~BIT(USBC_BP_ISCR_DPDM_CHANGE_DETECT); 106 107 return temp; 108} 109 110static void USBC_EnableIdPullUp(__iomem void *base) 111{ 112 u32 reg_val; 113 114 reg_val = musb_readl(base, USBC_REG_o_ISCR); 115 reg_val |= BIT(USBC_BP_ISCR_ID_PULLUP_EN); 116 reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 117 musb_writel(base, USBC_REG_o_ISCR, reg_val); 118} 119 120static void USBC_EnableDpDmPullUp(__iomem void *base) 121{ 122 u32 reg_val; 123 124 reg_val = musb_readl(base, USBC_REG_o_ISCR); 125 reg_val |= BIT(USBC_BP_ISCR_DPDM_PULLUP_EN); 126 reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 127 musb_writel(base, USBC_REG_o_ISCR, reg_val); 128} 129 130static void USBC_ForceIdToLow(__iomem void *base) 131{ 132 u32 reg_val; 133 134 reg_val = musb_readl(base, USBC_REG_o_ISCR); 135 reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID); 136 reg_val |= (0x02 << USBC_BP_ISCR_FORCE_ID); 137 reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 138 musb_writel(base, USBC_REG_o_ISCR, reg_val); 139} 140 141static void USBC_ForceIdToHigh(__iomem void *base) 142{ 143 u32 reg_val; 144 145 reg_val = musb_readl(base, USBC_REG_o_ISCR); 146 reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID); 147 reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID); 148 reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 149 musb_writel(base, USBC_REG_o_ISCR, reg_val); 150} 151 152static void USBC_ForceVbusValidToLow(__iomem void *base) 153{ 154 u32 reg_val; 155 156 reg_val = musb_readl(base, USBC_REG_o_ISCR); 157 reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID); 158 reg_val |= (0x02 << USBC_BP_ISCR_FORCE_VBUS_VALID); 159 reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 160 musb_writel(base, USBC_REG_o_ISCR, reg_val); 161} 162 163static void USBC_ForceVbusValidToHigh(__iomem void *base) 164{ 165 u32 reg_val; 166 167 reg_val = musb_readl(base, USBC_REG_o_ISCR); 168 reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID); 169 reg_val |= (0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID); 170 reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 171 musb_writel(base, USBC_REG_o_ISCR, reg_val); 172} 173 174static void USBC_ConfigFIFO_Base(void) 175{ 176 u32 reg_value; 177 178 /* config usb fifo, 8kb mode */ 179 reg_value = readl(SUNXI_SRAMC_BASE + 0x04); 180 reg_value &= ~(0x03 << 0); 181 reg_value |= BIT(0); 182 writel(reg_value, SUNXI_SRAMC_BASE + 0x04); 183} 184 185/****************************************************************************** 186 * Needed for the DFU polling magic 187 ******************************************************************************/ 188 189static u8 last_int_usb; 190 191bool dfu_usb_get_reset(void) 192{ 193 return !!(last_int_usb & MUSB_INTR_RESET); 194} 195 196/****************************************************************************** 197 * MUSB Glue code 198 ******************************************************************************/ 199 200static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci) 201{ 202 struct musb *musb = __hci; 203 irqreturn_t retval = IRQ_NONE; 204 205 /* read and flush interrupts */ 206 musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); 207 last_int_usb = musb->int_usb; 208 if (musb->int_usb) 209 musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb); 210 musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); 211 if (musb->int_tx) 212 musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx); 213 musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); 214 if (musb->int_rx) 215 musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx); 216 217 if (musb->int_usb || musb->int_tx || musb->int_rx) 218 retval |= musb_interrupt(musb); 219 220 return retval; 221} 222 223/* musb_core does not call enable / disable in a balanced manner <sigh> */ 224static bool enabled = false; 225 226static int sunxi_musb_enable(struct musb *musb) 227{ 228 struct sunxi_glue *glue = to_sunxi_glue(musb->controller); 229 int ret; 230 231 pr_debug("%s():\n", __func__); 232 233 musb_ep_select(musb->mregs, 0); 234 musb_writeb(musb->mregs, MUSB_FADDR, 0); 235 236 if (enabled) 237 return 0; 238 239 /* select PIO mode */ 240 musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0); 241 242 if (is_host_enabled(musb)) { 243 ret = sun4i_usb_phy_id_detect(&glue->phy); 244 if (ret == 1) { 245 printf("No host cable detected: "); 246 return -ENODEV; 247 } 248 249 ret = generic_phy_power_on(&glue->phy); 250 if (ret) { 251 pr_debug("failed to power on USB PHY\n"); 252 return ret; 253 } 254 } 255 256 USBC_ForceVbusValidToHigh(musb->mregs); 257 258 enabled = true; 259 return 0; 260} 261 262static void sunxi_musb_disable(struct musb *musb) 263{ 264 struct sunxi_glue *glue = to_sunxi_glue(musb->controller); 265 int ret; 266 267 pr_debug("%s():\n", __func__); 268 269 if (!enabled) 270 return; 271 272 if (is_host_enabled(musb)) { 273 ret = generic_phy_power_off(&glue->phy); 274 if (ret) { 275 pr_debug("failed to power off USB PHY\n"); 276 return; 277 } 278 } 279 280 USBC_ForceVbusValidToLow(musb->mregs); 281 mdelay(200); /* Wait for the current session to timeout */ 282 283 enabled = false; 284} 285 286static int sunxi_musb_init(struct musb *musb) 287{ 288 struct sunxi_glue *glue = to_sunxi_glue(musb->controller); 289 int ret; 290 291 pr_debug("%s():\n", __func__); 292 293 ret = clk_enable(&glue->clk); 294 if (ret) { 295 dev_err(musb->controller, "failed to enable clock\n"); 296 return ret; 297 } 298 299 if (reset_valid(&glue->rst)) { 300 ret = reset_deassert(&glue->rst); 301 if (ret) { 302 dev_err(musb->controller, "failed to deassert reset\n"); 303 goto err_clk; 304 } 305 } 306 307 ret = generic_phy_init(&glue->phy); 308 if (ret) { 309 dev_dbg(musb->controller, "failed to init USB PHY\n"); 310 goto err_rst; 311 } 312 313 musb->isr = sunxi_musb_interrupt; 314 315 USBC_ConfigFIFO_Base(); 316 USBC_EnableDpDmPullUp(musb->mregs); 317 USBC_EnableIdPullUp(musb->mregs); 318 319 if (is_host_enabled(musb)) { 320 /* Host mode */ 321 USBC_ForceIdToLow(musb->mregs); 322 } else { 323 /* Peripheral mode */ 324 USBC_ForceIdToHigh(musb->mregs); 325 } 326 USBC_ForceVbusValidToHigh(musb->mregs); 327 328 return 0; 329 330err_rst: 331 if (reset_valid(&glue->rst)) 332 reset_assert(&glue->rst); 333err_clk: 334 clk_disable(&glue->clk); 335 return ret; 336} 337 338static int sunxi_musb_exit(struct musb *musb) 339{ 340 struct sunxi_glue *glue = to_sunxi_glue(musb->controller); 341 int ret = 0; 342 343 if (generic_phy_valid(&glue->phy)) { 344 ret = generic_phy_exit(&glue->phy); 345 if (ret) { 346 dev_dbg(musb->controller, 347 "failed to power off usb phy\n"); 348 return ret; 349 } 350 } 351 352 if (reset_valid(&glue->rst)) 353 reset_assert(&glue->rst); 354 clk_disable(&glue->clk); 355 356 return 0; 357} 358 359static void sunxi_musb_pre_root_reset_end(struct musb *musb) 360{ 361 struct sunxi_glue *glue = to_sunxi_glue(musb->controller); 362 363 sun4i_usb_phy_set_squelch_detect(&glue->phy, false); 364} 365 366static void sunxi_musb_post_root_reset_end(struct musb *musb) 367{ 368 struct sunxi_glue *glue = to_sunxi_glue(musb->controller); 369 370 sun4i_usb_phy_set_squelch_detect(&glue->phy, true); 371} 372 373static const struct musb_platform_ops sunxi_musb_ops = { 374 .init = sunxi_musb_init, 375 .exit = sunxi_musb_exit, 376 .enable = sunxi_musb_enable, 377 .disable = sunxi_musb_disable, 378 .pre_root_reset_end = sunxi_musb_pre_root_reset_end, 379 .post_root_reset_end = sunxi_musb_post_root_reset_end, 380}; 381 382/* Allwinner OTG supports up to 5 endpoints */ 383#define SUNXI_MUSB_MAX_EP_NUM 6 384#define SUNXI_MUSB_RAM_BITS 11 385 386static struct musb_fifo_cfg sunxi_musb_mode_cfg[] = { 387 MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512), 388 MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512), 389 MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512), 390 MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512), 391 MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512), 392 MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512), 393 MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512), 394 MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512), 395 MUSB_EP_FIFO_SINGLE(5, FIFO_TX, 512), 396 MUSB_EP_FIFO_SINGLE(5, FIFO_RX, 512), 397}; 398 399/* H3/V3s OTG supports only 4 endpoints */ 400#define SUNXI_MUSB_MAX_EP_NUM_H3 5 401 402static struct musb_fifo_cfg sunxi_musb_mode_cfg_h3[] = { 403 MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512), 404 MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512), 405 MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512), 406 MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512), 407 MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512), 408 MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512), 409 MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512), 410 MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512), 411}; 412 413static struct musb_hdrc_config musb_config = { 414 .fifo_cfg = sunxi_musb_mode_cfg, 415 .fifo_cfg_size = ARRAY_SIZE(sunxi_musb_mode_cfg), 416 .multipoint = true, 417 .dyn_fifo = true, 418 .num_eps = SUNXI_MUSB_MAX_EP_NUM, 419 .ram_bits = SUNXI_MUSB_RAM_BITS, 420}; 421 422static struct musb_hdrc_config musb_config_h3 = { 423 .fifo_cfg = sunxi_musb_mode_cfg_h3, 424 .fifo_cfg_size = ARRAY_SIZE(sunxi_musb_mode_cfg_h3), 425 .multipoint = true, 426 .dyn_fifo = true, 427 .soft_con = true, 428 .num_eps = SUNXI_MUSB_MAX_EP_NUM_H3, 429 .ram_bits = SUNXI_MUSB_RAM_BITS, 430}; 431 432static int musb_usb_probe(struct udevice *dev) 433{ 434 struct sunxi_glue *glue = dev_get_priv(dev); 435 struct musb_host_data *host = &glue->mdata; 436 struct musb_hdrc_platform_data pdata; 437 void *base = dev_read_addr_ptr(dev); 438 int ret; 439 440#ifdef CONFIG_USB_MUSB_HOST 441 struct usb_bus_priv *priv = dev_get_uclass_priv(dev); 442#endif 443 444 if (!base) 445 return -EINVAL; 446 447 glue->cfg = (struct sunxi_musb_config *)dev_get_driver_data(dev); 448 if (!glue->cfg) 449 return -EINVAL; 450 451 ret = clk_get_by_index(dev, 0, &glue->clk); 452 if (ret) { 453 dev_err(dev, "failed to get clock\n"); 454 return ret; 455 } 456 457 ret = reset_get_by_index(dev, 0, &glue->rst); 458 if (ret && ret != -ENOENT) { 459 dev_err(dev, "failed to get reset\n"); 460 return ret; 461 } 462 463 ret = generic_phy_get_by_name(dev, "usb", &glue->phy); 464 if (ret) { 465 pr_err("failed to get usb PHY\n"); 466 return ret; 467 } 468 469 memset(&pdata, 0, sizeof(pdata)); 470 pdata.power = 250; 471 pdata.platform_ops = &sunxi_musb_ops; 472 pdata.config = glue->cfg->config; 473 474#ifdef CONFIG_USB_MUSB_HOST 475 priv->desc_before_addr = true; 476 477 pdata.mode = MUSB_HOST; 478 host->host = musb_init_controller(&pdata, &glue->dev, base); 479 if (!host->host) 480 return -EIO; 481 482 ret = musb_lowlevel_init(host); 483 if (!ret) 484 printf("Allwinner mUSB OTG (Host)\n"); 485#else 486 pdata.mode = MUSB_PERIPHERAL; 487 host->host = musb_register(&pdata, &glue->dev, base); 488 if (IS_ERR_OR_NULL(host->host)) 489 return -EIO; 490 491 printf("Allwinner mUSB OTG (Peripheral)\n"); 492#endif 493 494 return ret; 495} 496 497static int musb_usb_remove(struct udevice *dev) 498{ 499 struct sunxi_glue *glue = dev_get_priv(dev); 500 struct musb_host_data *host = &glue->mdata; 501 502 musb_stop(host->host); 503 free(host->host); 504 host->host = NULL; 505 506 return 0; 507} 508 509/* 510 * The Linux driver has a config struct, its fields mapping to this driver 511 * like this: 512 * .hdrc_config: 513 * sunxi_musb_hdrc_config_5eps => musb_config 514 * sunxi_musb_hdrc_config_4eps => musb_config_h3 515 * .has_sram: always enabled, ideally no-op on SoCs not using it 516 * .has_reset: automatically detected from DT 517 * .no_configdata: handled via Kconfig's CONFIG_USB_MUSB_FIXED_CONFIGDATA 518 */ 519static const struct sunxi_musb_config sun4i_a10_cfg = { 520 .config = &musb_config, 521}; 522 523static const struct sunxi_musb_config sun6i_a31_cfg = { 524 .config = &musb_config, 525}; 526 527static const struct sunxi_musb_config sun8i_h3_cfg = { 528 .config = &musb_config_h3, 529}; 530 531static const struct sunxi_musb_config suniv_f1c100s_cfg = { 532 .config = &musb_config, 533}; 534 535static const struct udevice_id sunxi_musb_ids[] = { 536 { .compatible = "allwinner,sun4i-a10-musb", 537 .data = (ulong)&sun4i_a10_cfg }, 538 { .compatible = "allwinner,sun6i-a31-musb", 539 .data = (ulong)&sun6i_a31_cfg }, 540 { .compatible = "allwinner,sun8i-a33-musb", 541 .data = (ulong)&sun6i_a31_cfg }, 542 { .compatible = "allwinner,sun8i-h3-musb", 543 .data = (ulong)&sun8i_h3_cfg }, 544 { .compatible = "allwinner,suniv-f1c100s-musb", 545 .data = (ulong)&suniv_f1c100s_cfg }, 546 { } 547}; 548 549U_BOOT_DRIVER(usb_musb) = { 550 .name = "sunxi-musb", 551#ifdef CONFIG_USB_MUSB_HOST 552 .id = UCLASS_USB, 553#else 554 .id = UCLASS_USB_GADGET_GENERIC, 555#endif 556 .of_match = sunxi_musb_ids, 557 .probe = musb_usb_probe, 558 .remove = musb_usb_remove, 559#ifdef CONFIG_USB_MUSB_HOST 560 .ops = &musb_usb_ops, 561#endif 562 .plat_auto = sizeof(struct usb_plat), 563 .priv_auto = sizeof(struct sunxi_glue), 564}; 565