1*28a15ef7SHans de Goede /* 2*28a15ef7SHans de Goede * Allwinner SUNXI "glue layer" 3*28a15ef7SHans de Goede * 4*28a15ef7SHans de Goede * Copyright © 2015 Hans de Goede <hdegoede@redhat.com> 5*28a15ef7SHans de Goede * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> 6*28a15ef7SHans de Goede * 7*28a15ef7SHans de Goede * Based on the sw_usb "Allwinner OTG Dual Role Controller" code. 8*28a15ef7SHans de Goede * Copyright 2007-2012 (C) Allwinner Technology Co., Ltd. 9*28a15ef7SHans de Goede * javen <javen@allwinnertech.com> 10*28a15ef7SHans de Goede * 11*28a15ef7SHans de Goede * Based on the DA8xx "glue layer" code. 12*28a15ef7SHans de Goede * Copyright (c) 2008-2009 MontaVista Software, Inc. <source@mvista.com> 13*28a15ef7SHans de Goede * Copyright (C) 2005-2006 by Texas Instruments 14*28a15ef7SHans de Goede * 15*28a15ef7SHans de Goede * This file is part of the Inventra Controller Driver for Linux. 16*28a15ef7SHans de Goede * 17*28a15ef7SHans de Goede * The Inventra Controller Driver for Linux is free software; you 18*28a15ef7SHans de Goede * can redistribute it and/or modify it under the terms of the GNU 19*28a15ef7SHans de Goede * General Public License version 2 as published by the Free Software 20*28a15ef7SHans de Goede * Foundation. 21*28a15ef7SHans de Goede * 22*28a15ef7SHans de Goede */ 23*28a15ef7SHans de Goede #include <common.h> 24*28a15ef7SHans de Goede #include <asm/arch/cpu.h> 25*28a15ef7SHans de Goede #include <asm/arch/usbc.h> 26*28a15ef7SHans de Goede #include "linux-compat.h" 27*28a15ef7SHans de Goede #include "musb_core.h" 28*28a15ef7SHans de Goede 29*28a15ef7SHans de Goede /****************************************************************************** 30*28a15ef7SHans de Goede ****************************************************************************** 31*28a15ef7SHans de Goede * From the Allwinner driver 32*28a15ef7SHans de Goede ****************************************************************************** 33*28a15ef7SHans de Goede ******************************************************************************/ 34*28a15ef7SHans de Goede 35*28a15ef7SHans de Goede /****************************************************************************** 36*28a15ef7SHans de Goede * From include/sunxi_usb_bsp.h 37*28a15ef7SHans de Goede ******************************************************************************/ 38*28a15ef7SHans de Goede 39*28a15ef7SHans de Goede /* reg offsets */ 40*28a15ef7SHans de Goede #define USBC_REG_o_ISCR 0x0400 41*28a15ef7SHans de Goede #define USBC_REG_o_PHYCTL 0x0404 42*28a15ef7SHans de Goede #define USBC_REG_o_PHYBIST 0x0408 43*28a15ef7SHans de Goede #define USBC_REG_o_PHYTUNE 0x040c 44*28a15ef7SHans de Goede 45*28a15ef7SHans de Goede #define USBC_REG_o_VEND0 0x0043 46*28a15ef7SHans de Goede 47*28a15ef7SHans de Goede /* Interface Status and Control */ 48*28a15ef7SHans de Goede #define USBC_BP_ISCR_VBUS_VALID_FROM_DATA 30 49*28a15ef7SHans de Goede #define USBC_BP_ISCR_VBUS_VALID_FROM_VBUS 29 50*28a15ef7SHans de Goede #define USBC_BP_ISCR_EXT_ID_STATUS 28 51*28a15ef7SHans de Goede #define USBC_BP_ISCR_EXT_DM_STATUS 27 52*28a15ef7SHans de Goede #define USBC_BP_ISCR_EXT_DP_STATUS 26 53*28a15ef7SHans de Goede #define USBC_BP_ISCR_MERGED_VBUS_STATUS 25 54*28a15ef7SHans de Goede #define USBC_BP_ISCR_MERGED_ID_STATUS 24 55*28a15ef7SHans de Goede 56*28a15ef7SHans de Goede #define USBC_BP_ISCR_ID_PULLUP_EN 17 57*28a15ef7SHans de Goede #define USBC_BP_ISCR_DPDM_PULLUP_EN 16 58*28a15ef7SHans de Goede #define USBC_BP_ISCR_FORCE_ID 14 59*28a15ef7SHans de Goede #define USBC_BP_ISCR_FORCE_VBUS_VALID 12 60*28a15ef7SHans de Goede #define USBC_BP_ISCR_VBUS_VALID_SRC 10 61*28a15ef7SHans de Goede 62*28a15ef7SHans de Goede #define USBC_BP_ISCR_HOSC_EN 7 63*28a15ef7SHans de Goede #define USBC_BP_ISCR_VBUS_CHANGE_DETECT 6 64*28a15ef7SHans de Goede #define USBC_BP_ISCR_ID_CHANGE_DETECT 5 65*28a15ef7SHans de Goede #define USBC_BP_ISCR_DPDM_CHANGE_DETECT 4 66*28a15ef7SHans de Goede #define USBC_BP_ISCR_IRQ_ENABLE 3 67*28a15ef7SHans de Goede #define USBC_BP_ISCR_VBUS_CHANGE_DETECT_EN 2 68*28a15ef7SHans de Goede #define USBC_BP_ISCR_ID_CHANGE_DETECT_EN 1 69*28a15ef7SHans de Goede #define USBC_BP_ISCR_DPDM_CHANGE_DETECT_EN 0 70*28a15ef7SHans de Goede 71*28a15ef7SHans de Goede /****************************************************************************** 72*28a15ef7SHans de Goede * From usbc/usbc.c 73*28a15ef7SHans de Goede ******************************************************************************/ 74*28a15ef7SHans de Goede 75*28a15ef7SHans de Goede static u32 USBC_WakeUp_ClearChangeDetect(u32 reg_val) 76*28a15ef7SHans de Goede { 77*28a15ef7SHans de Goede u32 temp = reg_val; 78*28a15ef7SHans de Goede 79*28a15ef7SHans de Goede temp &= ~(1 << USBC_BP_ISCR_VBUS_CHANGE_DETECT); 80*28a15ef7SHans de Goede temp &= ~(1 << USBC_BP_ISCR_ID_CHANGE_DETECT); 81*28a15ef7SHans de Goede temp &= ~(1 << USBC_BP_ISCR_DPDM_CHANGE_DETECT); 82*28a15ef7SHans de Goede 83*28a15ef7SHans de Goede return temp; 84*28a15ef7SHans de Goede } 85*28a15ef7SHans de Goede 86*28a15ef7SHans de Goede static void USBC_EnableIdPullUp(__iomem void *base) 87*28a15ef7SHans de Goede { 88*28a15ef7SHans de Goede u32 reg_val; 89*28a15ef7SHans de Goede 90*28a15ef7SHans de Goede reg_val = musb_readl(base, USBC_REG_o_ISCR); 91*28a15ef7SHans de Goede reg_val |= (1 << USBC_BP_ISCR_ID_PULLUP_EN); 92*28a15ef7SHans de Goede reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 93*28a15ef7SHans de Goede musb_writel(base, USBC_REG_o_ISCR, reg_val); 94*28a15ef7SHans de Goede } 95*28a15ef7SHans de Goede 96*28a15ef7SHans de Goede static void USBC_DisableIdPullUp(__iomem void *base) 97*28a15ef7SHans de Goede { 98*28a15ef7SHans de Goede u32 reg_val; 99*28a15ef7SHans de Goede 100*28a15ef7SHans de Goede reg_val = musb_readl(base, USBC_REG_o_ISCR); 101*28a15ef7SHans de Goede reg_val &= ~(1 << USBC_BP_ISCR_ID_PULLUP_EN); 102*28a15ef7SHans de Goede reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 103*28a15ef7SHans de Goede musb_writel(base, USBC_REG_o_ISCR, reg_val); 104*28a15ef7SHans de Goede } 105*28a15ef7SHans de Goede 106*28a15ef7SHans de Goede static void USBC_EnableDpDmPullUp(__iomem void *base) 107*28a15ef7SHans de Goede { 108*28a15ef7SHans de Goede u32 reg_val; 109*28a15ef7SHans de Goede 110*28a15ef7SHans de Goede reg_val = musb_readl(base, USBC_REG_o_ISCR); 111*28a15ef7SHans de Goede reg_val |= (1 << USBC_BP_ISCR_DPDM_PULLUP_EN); 112*28a15ef7SHans de Goede reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 113*28a15ef7SHans de Goede musb_writel(base, USBC_REG_o_ISCR, reg_val); 114*28a15ef7SHans de Goede } 115*28a15ef7SHans de Goede 116*28a15ef7SHans de Goede static void USBC_DisableDpDmPullUp(__iomem void *base) 117*28a15ef7SHans de Goede { 118*28a15ef7SHans de Goede u32 reg_val; 119*28a15ef7SHans de Goede 120*28a15ef7SHans de Goede reg_val = musb_readl(base, USBC_REG_o_ISCR); 121*28a15ef7SHans de Goede reg_val &= ~(1 << USBC_BP_ISCR_DPDM_PULLUP_EN); 122*28a15ef7SHans de Goede reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 123*28a15ef7SHans de Goede musb_writel(base, USBC_REG_o_ISCR, reg_val); 124*28a15ef7SHans de Goede } 125*28a15ef7SHans de Goede 126*28a15ef7SHans de Goede static void USBC_ForceIdToLow(__iomem void *base) 127*28a15ef7SHans de Goede { 128*28a15ef7SHans de Goede u32 reg_val; 129*28a15ef7SHans de Goede 130*28a15ef7SHans de Goede reg_val = musb_readl(base, USBC_REG_o_ISCR); 131*28a15ef7SHans de Goede reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID); 132*28a15ef7SHans de Goede reg_val |= (0x02 << USBC_BP_ISCR_FORCE_ID); 133*28a15ef7SHans de Goede reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 134*28a15ef7SHans de Goede musb_writel(base, USBC_REG_o_ISCR, reg_val); 135*28a15ef7SHans de Goede } 136*28a15ef7SHans de Goede 137*28a15ef7SHans de Goede static void USBC_ForceIdToHigh(__iomem void *base) 138*28a15ef7SHans de Goede { 139*28a15ef7SHans de Goede u32 reg_val; 140*28a15ef7SHans de Goede 141*28a15ef7SHans de Goede reg_val = musb_readl(base, USBC_REG_o_ISCR); 142*28a15ef7SHans de Goede reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID); 143*28a15ef7SHans de Goede reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID); 144*28a15ef7SHans de Goede reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 145*28a15ef7SHans de Goede musb_writel(base, USBC_REG_o_ISCR, reg_val); 146*28a15ef7SHans de Goede } 147*28a15ef7SHans de Goede 148*28a15ef7SHans de Goede static void USBC_ForceVbusValidDisable(__iomem void *base) 149*28a15ef7SHans de Goede { 150*28a15ef7SHans de Goede u32 reg_val; 151*28a15ef7SHans de Goede 152*28a15ef7SHans de Goede reg_val = musb_readl(base, USBC_REG_o_ISCR); 153*28a15ef7SHans de Goede reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID); 154*28a15ef7SHans de Goede reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 155*28a15ef7SHans de Goede musb_writel(base, USBC_REG_o_ISCR, reg_val); 156*28a15ef7SHans de Goede } 157*28a15ef7SHans de Goede 158*28a15ef7SHans de Goede static void USBC_ForceVbusValidToHigh(__iomem void *base) 159*28a15ef7SHans de Goede { 160*28a15ef7SHans de Goede u32 reg_val; 161*28a15ef7SHans de Goede 162*28a15ef7SHans de Goede reg_val = musb_readl(base, USBC_REG_o_ISCR); 163*28a15ef7SHans de Goede reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID); 164*28a15ef7SHans de Goede reg_val |= (0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID); 165*28a15ef7SHans de Goede reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 166*28a15ef7SHans de Goede musb_writel(base, USBC_REG_o_ISCR, reg_val); 167*28a15ef7SHans de Goede } 168*28a15ef7SHans de Goede 169*28a15ef7SHans de Goede static void USBC_ConfigFIFO_Base(void) 170*28a15ef7SHans de Goede { 171*28a15ef7SHans de Goede u32 reg_value; 172*28a15ef7SHans de Goede 173*28a15ef7SHans de Goede /* config usb fifo, 8kb mode */ 174*28a15ef7SHans de Goede reg_value = readl(SUNXI_SRAMC_BASE + 0x04); 175*28a15ef7SHans de Goede reg_value &= ~(0x03 << 0); 176*28a15ef7SHans de Goede reg_value |= (1 << 0); 177*28a15ef7SHans de Goede writel(reg_value, SUNXI_SRAMC_BASE + 0x04); 178*28a15ef7SHans de Goede } 179*28a15ef7SHans de Goede 180*28a15ef7SHans de Goede /****************************************************************************** 181*28a15ef7SHans de Goede * MUSB Glue code 182*28a15ef7SHans de Goede ******************************************************************************/ 183*28a15ef7SHans de Goede 184*28a15ef7SHans de Goede static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci) 185*28a15ef7SHans de Goede { 186*28a15ef7SHans de Goede struct musb *musb = __hci; 187*28a15ef7SHans de Goede irqreturn_t retval = IRQ_NONE; 188*28a15ef7SHans de Goede 189*28a15ef7SHans de Goede /* read and flush interrupts */ 190*28a15ef7SHans de Goede musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); 191*28a15ef7SHans de Goede if (musb->int_usb) 192*28a15ef7SHans de Goede musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb); 193*28a15ef7SHans de Goede musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); 194*28a15ef7SHans de Goede if (musb->int_tx) 195*28a15ef7SHans de Goede musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx); 196*28a15ef7SHans de Goede musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); 197*28a15ef7SHans de Goede if (musb->int_rx) 198*28a15ef7SHans de Goede musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx); 199*28a15ef7SHans de Goede 200*28a15ef7SHans de Goede if (musb->int_usb || musb->int_tx || musb->int_rx) 201*28a15ef7SHans de Goede retval |= musb_interrupt(musb); 202*28a15ef7SHans de Goede 203*28a15ef7SHans de Goede return retval; 204*28a15ef7SHans de Goede } 205*28a15ef7SHans de Goede 206*28a15ef7SHans de Goede static void sunxi_musb_enable(struct musb *musb) 207*28a15ef7SHans de Goede { 208*28a15ef7SHans de Goede pr_debug("%s():\n", __func__); 209*28a15ef7SHans de Goede 210*28a15ef7SHans de Goede /* select PIO mode */ 211*28a15ef7SHans de Goede musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0); 212*28a15ef7SHans de Goede 213*28a15ef7SHans de Goede if (is_host_enabled(musb)) { 214*28a15ef7SHans de Goede /* port power on */ 215*28a15ef7SHans de Goede sunxi_usbc_vbus_enable(0); 216*28a15ef7SHans de Goede } 217*28a15ef7SHans de Goede } 218*28a15ef7SHans de Goede 219*28a15ef7SHans de Goede static void sunxi_musb_disable(struct musb *musb) 220*28a15ef7SHans de Goede { 221*28a15ef7SHans de Goede pr_debug("%s():\n", __func__); 222*28a15ef7SHans de Goede 223*28a15ef7SHans de Goede /* Put the controller back in a pristane state for "usb reset" */ 224*28a15ef7SHans de Goede if (musb->is_active) { 225*28a15ef7SHans de Goede sunxi_usbc_disable(0); 226*28a15ef7SHans de Goede sunxi_usbc_enable(0); 227*28a15ef7SHans de Goede musb->is_active = 0; 228*28a15ef7SHans de Goede } 229*28a15ef7SHans de Goede } 230*28a15ef7SHans de Goede 231*28a15ef7SHans de Goede static int sunxi_musb_init(struct musb *musb) 232*28a15ef7SHans de Goede { 233*28a15ef7SHans de Goede int err; 234*28a15ef7SHans de Goede 235*28a15ef7SHans de Goede pr_debug("%s():\n", __func__); 236*28a15ef7SHans de Goede 237*28a15ef7SHans de Goede err = sunxi_usbc_request_resources(0); 238*28a15ef7SHans de Goede if (err) 239*28a15ef7SHans de Goede return err; 240*28a15ef7SHans de Goede 241*28a15ef7SHans de Goede musb->isr = sunxi_musb_interrupt; 242*28a15ef7SHans de Goede sunxi_usbc_enable(0); 243*28a15ef7SHans de Goede 244*28a15ef7SHans de Goede USBC_ConfigFIFO_Base(); 245*28a15ef7SHans de Goede USBC_EnableDpDmPullUp(musb->mregs); 246*28a15ef7SHans de Goede USBC_EnableIdPullUp(musb->mregs); 247*28a15ef7SHans de Goede 248*28a15ef7SHans de Goede if (is_host_enabled(musb)) { 249*28a15ef7SHans de Goede /* Host mode */ 250*28a15ef7SHans de Goede USBC_ForceIdToLow(musb->mregs); 251*28a15ef7SHans de Goede USBC_ForceVbusValidToHigh(musb->mregs); 252*28a15ef7SHans de Goede } else { 253*28a15ef7SHans de Goede /* Peripheral mode */ 254*28a15ef7SHans de Goede USBC_ForceIdToHigh(musb->mregs); 255*28a15ef7SHans de Goede USBC_ForceVbusValidDisable(musb->mregs); 256*28a15ef7SHans de Goede } 257*28a15ef7SHans de Goede 258*28a15ef7SHans de Goede return 0; 259*28a15ef7SHans de Goede } 260*28a15ef7SHans de Goede 261*28a15ef7SHans de Goede static int sunxi_musb_exit(struct musb *musb) 262*28a15ef7SHans de Goede { 263*28a15ef7SHans de Goede pr_debug("%s():\n", __func__); 264*28a15ef7SHans de Goede 265*28a15ef7SHans de Goede USBC_DisableDpDmPullUp(musb->mregs); 266*28a15ef7SHans de Goede USBC_DisableIdPullUp(musb->mregs); 267*28a15ef7SHans de Goede sunxi_usbc_vbus_disable(0); 268*28a15ef7SHans de Goede sunxi_usbc_disable(0); 269*28a15ef7SHans de Goede 270*28a15ef7SHans de Goede return sunxi_usbc_free_resources(0); 271*28a15ef7SHans de Goede } 272*28a15ef7SHans de Goede 273*28a15ef7SHans de Goede const struct musb_platform_ops sunxi_musb_ops = { 274*28a15ef7SHans de Goede .init = sunxi_musb_init, 275*28a15ef7SHans de Goede .exit = sunxi_musb_exit, 276*28a15ef7SHans de Goede 277*28a15ef7SHans de Goede .enable = sunxi_musb_enable, 278*28a15ef7SHans de Goede .disable = sunxi_musb_disable, 279*28a15ef7SHans de Goede }; 280