exynos5_usb_phy.c revision 269702
1139749Simp/*- 240024Sgibbs * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> 340024Sgibbs * All rights reserved. 440024Sgibbs * 540024Sgibbs * Redistribution and use in source and binary forms, with or without 640024Sgibbs * modification, are permitted provided that the following conditions 740024Sgibbs * are met: 840024Sgibbs * 1. Redistributions of source code must retain the above copyright 956979Sgibbs * notice, this list of conditions and the following disclaimer. 1040024Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1140024Sgibbs * notice, this list of conditions and the following disclaimer in the 1240024Sgibbs * documentation and/or other materials provided with the distribution. 1340024Sgibbs * 1440024Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1540024Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1640024Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1740024Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18119418Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19119418Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20119418Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2140024Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2240024Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2356979Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2456979Sgibbs * SUCH DAMAGE. 2556979Sgibbs */ 2640024Sgibbs 2756979Sgibbs/* 2856979Sgibbs * DWC3 USB 3.0 DRD (dual role device) PHY 2956979Sgibbs */ 3056979Sgibbs 3156979Sgibbs#include <sys/cdefs.h> 3256979Sgibbs__FBSDID("$FreeBSD: head/sys/arm/samsung/exynos/exynos5_usb_phy.c 269702 2014-08-08 06:29:30Z nwhitehorn $"); 3356979Sgibbs 3456979Sgibbs#include <sys/param.h> 3556979Sgibbs#include <sys/systm.h> 3656979Sgibbs#include <sys/bus.h> 3756979Sgibbs#include <sys/kernel.h> 3856979Sgibbs#include <sys/module.h> 3956979Sgibbs#include <sys/malloc.h> 4056979Sgibbs#include <sys/rman.h> 4156979Sgibbs#include <sys/timeet.h> 4256979Sgibbs#include <sys/timetc.h> 4356979Sgibbs#include <sys/watchdog.h> 4456979Sgibbs#include <sys/gpio.h> 4556979Sgibbs 4656979Sgibbs#include <dev/ofw/openfirm.h> 4756979Sgibbs#include <dev/ofw/ofw_bus.h> 4856979Sgibbs#include <dev/ofw/ofw_bus_subr.h> 4956979Sgibbs 5056979Sgibbs#include <machine/bus.h> 5156979Sgibbs#include <machine/cpu.h> 5256979Sgibbs#include <machine/intr.h> 5356979Sgibbs 5456979Sgibbs#include <arm/samsung/exynos/exynos5_common.h> 5556979Sgibbs#include <arm/samsung/exynos/exynos5_pmu.h> 5656979Sgibbs 5756979Sgibbs#include "gpio_if.h" 5856979Sgibbs 5956979Sgibbs#define USB_DRD_LINKSYSTEM 0x04 6056979Sgibbs#define LINKSYSTEM_FLADJ_MASK (0x3f << 1) 6156979Sgibbs#define LINKSYSTEM_FLADJ(x) ((x) << 1) 6256979Sgibbs#define LINKSYSTEM_XHCI_VERSION_CTRL (1 << 27) 6356979Sgibbs#define USB_DRD_PHYUTMI 0x08 6456979Sgibbs#define PHYUTMI_OTGDISABLE (1 << 6) 6556979Sgibbs#define PHYUTMI_FORCESUSPEND (1 << 1) 6656979Sgibbs#define PHYUTMI_FORCESLEEP (1 << 0) 6756979Sgibbs#define USB_DRD_PHYPIPE 0x0c 6856979Sgibbs#define USB_DRD_PHYCLKRST 0x10 6956979Sgibbs#define PHYCLKRST_PORTRESET (1 << 1) 7056979Sgibbs#define PHYCLKRST_COMMONONN (1 << 0) 7156979Sgibbs#define PHYCLKRST_EN_UTMISUSPEND (1 << 31) 7256979Sgibbs#define PHYCLKRST_SSC_REFCLKSEL_MASK (0xff << 23) 7356979Sgibbs#define PHYCLKRST_SSC_REFCLKSEL(x) ((x) << 23) 7456979Sgibbs#define PHYCLKRST_SSC_RANGE_MASK (0x03 << 21) 7556979Sgibbs#define PHYCLKRST_SSC_RANGE(x) ((x) << 21) 7656979Sgibbs#define PHYCLKRST_SSC_EN (1 << 20) 7756979Sgibbs#define PHYCLKRST_REF_SSP_EN (1 << 19) 7856979Sgibbs#define PHYCLKRST_REF_CLKDIV2 (1 << 18) 7956979Sgibbs#define PHYCLKRST_MPLL_MLTPR_MASK (0x7f << 11) 8056979Sgibbs#define PHYCLKRST_MPLL_MLTPR_100MHZ (0x19 << 11) 8156979Sgibbs#define PHYCLKRST_MPLL_MLTPR_50M (0x32 << 11) 8256979Sgibbs#define PHYCLKRST_MPLL_MLTPR_24MHZ (0x68 << 11) 8356979Sgibbs#define PHYCLKRST_MPLL_MLTPR_20MHZ (0x7d << 11) 8456979Sgibbs#define PHYCLKRST_MPLL_MLTPR_19200KHZ (0x02 << 11) 8556979Sgibbs#define PHYCLKRST_FSEL_UTMI_MASK (0x7 << 5) 8656979Sgibbs#define PHYCLKRST_FSEL_PIPE_MASK (0x7 << 8) 8756979Sgibbs#define PHYCLKRST_FSEL(x) ((x) << 5) 8856979Sgibbs#define PHYCLKRST_FSEL_9MHZ6 0x0 8956979Sgibbs#define PHYCLKRST_FSEL_10MHZ 0x1 9056979Sgibbs#define PHYCLKRST_FSEL_12MHZ 0x2 9156979Sgibbs#define PHYCLKRST_FSEL_19MHZ2 0x3 9256979Sgibbs#define PHYCLKRST_FSEL_20MHZ 0x4 9356979Sgibbs#define PHYCLKRST_FSEL_24MHZ 0x5 9456979Sgibbs#define PHYCLKRST_FSEL_50MHZ 0x7 9556979Sgibbs#define PHYCLKRST_RETENABLEN (1 << 4) 9656979Sgibbs#define PHYCLKRST_REFCLKSEL_MASK (0x03 << 2) 9756979Sgibbs#define PHYCLKRST_REFCLKSEL_PAD_REFCLK (0x2 << 2) 9856979Sgibbs#define PHYCLKRST_REFCLKSEL_EXT_REFCLK (0x3 << 2) 9956979Sgibbs#define USB_DRD_PHYREG0 0x14 10056979Sgibbs#define USB_DRD_PHYREG1 0x18 10156979Sgibbs#define USB_DRD_PHYPARAM0 0x1c 10256979Sgibbs#define PHYPARAM0_REF_USE_PAD (1 << 31) 10356979Sgibbs#define PHYPARAM0_REF_LOSLEVEL_MASK (0x1f << 26) 10456979Sgibbs#define PHYPARAM0_REF_LOSLEVEL (0x9 << 26) 10556979Sgibbs#define USB_DRD_PHYPARAM1 0x20 10656979Sgibbs#define PHYPARAM1_PCS_TXDEEMPH_MASK (0x1f << 0) 10756979Sgibbs#define PHYPARAM1_PCS_TXDEEMPH (0x1c) 10856979Sgibbs#define USB_DRD_PHYTERM 0x24 10956979Sgibbs#define USB_DRD_PHYTEST 0x28 11056979Sgibbs#define PHYTEST_POWERDOWN_SSP (1 << 3) 11156979Sgibbs#define PHYTEST_POWERDOWN_HSP (1 << 2) 11256979Sgibbs#define USB_DRD_PHYADP 0x2c 11356979Sgibbs#define USB_DRD_PHYUTMICLKSEL 0x30 11456979Sgibbs#define PHYUTMICLKSEL_UTMI_CLKSEL (1 << 2) 11556979Sgibbs#define USB_DRD_PHYRESUME 0x34 11656979Sgibbs#define USB_DRD_LINKPORT 0x44 11756979Sgibbs 11856979Sgibbsstruct usb_phy_softc { 11956979Sgibbs struct resource *res[1]; 12056979Sgibbs bus_space_tag_t bst; 12156979Sgibbs bus_space_handle_t bsh; 12256979Sgibbs device_t dev; 12356979Sgibbs}; 12456979Sgibbs 12556979Sgibbsstatic struct resource_spec usb_phy_spec[] = { 12656979Sgibbs { SYS_RES_MEMORY, 0, RF_ACTIVE }, 12756979Sgibbs { -1, 0 } 12856979Sgibbs}; 12956979Sgibbs 13056979Sgibbsstatic int 13156979Sgibbsusb_phy_probe(device_t dev) 13256979Sgibbs{ 13356979Sgibbs 13456979Sgibbs if (!ofw_bus_status_okay(dev)) 13556979Sgibbs return (ENXIO); 13656979Sgibbs 13756979Sgibbs if (!ofw_bus_is_compatible(dev, "samsung,exynos5420-usbdrd-phy")) 13856979Sgibbs return (ENXIO); 13956979Sgibbs 14056979Sgibbs device_set_desc(dev, "Samsung Exynos 5 USB PHY"); 14156979Sgibbs return (BUS_PROBE_DEFAULT); 14256979Sgibbs} 14356979Sgibbs 14456979Sgibbsstatic int 14556979Sgibbsvbus_on(struct usb_phy_softc *sc) 14656979Sgibbs{ 14756979Sgibbs pcell_t dts_value[3]; 14856979Sgibbs device_t gpio_dev; 14956979Sgibbs phandle_t node; 15056979Sgibbs pcell_t pin; 15156979Sgibbs int len; 15256979Sgibbs 15356979Sgibbs if ((node = ofw_bus_get_node(sc->dev)) == -1) 15456979Sgibbs return (-1); 15556979Sgibbs 15656979Sgibbs /* Power pin */ 15756979Sgibbs if ((len = OF_getproplen(node, "vbus-supply")) <= 0) 15856979Sgibbs return (-1); 15956979Sgibbs OF_getencprop(node, "vbus-supply", dts_value, len); 16056979Sgibbs pin = dts_value[0]; 16156979Sgibbs 16256979Sgibbs gpio_dev = devclass_get_device(devclass_find("gpio"), 0); 16356979Sgibbs if (gpio_dev == NULL) { 16456979Sgibbs device_printf(sc->dev, "cant find gpio_dev\n"); 16556979Sgibbs return (1); 16656979Sgibbs } 16756979Sgibbs 16856979Sgibbs GPIO_PIN_SETFLAGS(gpio_dev, pin, GPIO_PIN_OUTPUT); 16956979Sgibbs GPIO_PIN_SET(gpio_dev, pin, GPIO_PIN_HIGH); 17056979Sgibbs 17156979Sgibbs return (0); 17256979Sgibbs} 17356979Sgibbs 17456979Sgibbsstatic int 17556979Sgibbsusb3_phy_init(struct usb_phy_softc *sc) 17656979Sgibbs{ 17756979Sgibbs int reg; 17856979Sgibbs 17956979Sgibbs /* Reset USB 3.0 PHY */ 18056979Sgibbs WRITE4(sc, USB_DRD_PHYREG0, 0); 18156979Sgibbs 18256979Sgibbs reg = READ4(sc, USB_DRD_PHYPARAM0); 18356979Sgibbs /* PHY CLK src */ 18456979Sgibbs reg &= ~(PHYPARAM0_REF_USE_PAD); 18556979Sgibbs reg &= ~(PHYPARAM0_REF_LOSLEVEL_MASK); 18656979Sgibbs reg |= (PHYPARAM0_REF_LOSLEVEL); 18756979Sgibbs WRITE4(sc, USB_DRD_PHYPARAM0, reg); 18856979Sgibbs WRITE4(sc, USB_DRD_PHYRESUME, 0); 18956979Sgibbs 19056979Sgibbs reg = (LINKSYSTEM_XHCI_VERSION_CTRL | 19156979Sgibbs LINKSYSTEM_FLADJ(0x20)); 19256979Sgibbs WRITE4(sc, USB_DRD_LINKSYSTEM, reg); 19356979Sgibbs 19456979Sgibbs reg = READ4(sc, USB_DRD_PHYPARAM1); 19556979Sgibbs reg &= ~(PHYPARAM1_PCS_TXDEEMPH_MASK); 19656979Sgibbs reg |= (PHYPARAM1_PCS_TXDEEMPH); 19756979Sgibbs WRITE4(sc, USB_DRD_PHYPARAM1, reg); 19856979Sgibbs 19956979Sgibbs reg = READ4(sc, USB_DRD_PHYUTMICLKSEL); 20056979Sgibbs reg |= (PHYUTMICLKSEL_UTMI_CLKSEL); 20156979Sgibbs WRITE4(sc, USB_DRD_PHYUTMICLKSEL, reg); 20256979Sgibbs 20356979Sgibbs reg = READ4(sc, USB_DRD_PHYTEST); 20456979Sgibbs reg &= ~(PHYTEST_POWERDOWN_HSP); 20556979Sgibbs reg &= ~(PHYTEST_POWERDOWN_SSP); 20656979Sgibbs WRITE4(sc, USB_DRD_PHYTEST, reg); 20756979Sgibbs 20856979Sgibbs WRITE4(sc, USB_DRD_PHYUTMI, PHYUTMI_OTGDISABLE); 20956979Sgibbs 21056979Sgibbs /* Clock */ 21156979Sgibbs reg = (PHYCLKRST_REFCLKSEL_EXT_REFCLK); 21256979Sgibbs reg |= (PHYCLKRST_FSEL(PHYCLKRST_FSEL_24MHZ)); 21356979Sgibbs reg |= (PHYCLKRST_MPLL_MLTPR_24MHZ); 21456979Sgibbs reg |= (PHYCLKRST_SSC_REFCLKSEL(0x88)); 21556979Sgibbs reg |= (PHYCLKRST_RETENABLEN | 21656979Sgibbs PHYCLKRST_REF_SSP_EN | /* Super speed */ 21756979Sgibbs PHYCLKRST_SSC_EN | /* Spread spectrum */ 21856979Sgibbs PHYCLKRST_COMMONONN | 21956979Sgibbs PHYCLKRST_PORTRESET); 22056979Sgibbs 22156979Sgibbs WRITE4(sc, USB_DRD_PHYCLKRST, reg); 22256979Sgibbs DELAY(50000); 22356979Sgibbs reg &= ~PHYCLKRST_PORTRESET; 22456979Sgibbs WRITE4(sc, USB_DRD_PHYCLKRST, reg); 22556979Sgibbs 22656979Sgibbs return (0); 22756979Sgibbs} 22856979Sgibbs 22956979Sgibbsstatic int 23056979Sgibbsusb_phy_attach(device_t dev) 23156979Sgibbs{ 23256979Sgibbs struct usb_phy_softc *sc; 23356979Sgibbs 23456979Sgibbs sc = device_get_softc(dev); 23556979Sgibbs sc->dev = dev; 23656979Sgibbs 23756979Sgibbs if (bus_alloc_resources(dev, usb_phy_spec, sc->res)) { 23856979Sgibbs device_printf(dev, "could not allocate resources\n"); 23956979Sgibbs return (ENXIO); 24056979Sgibbs } 24156979Sgibbs 24256979Sgibbs /* Memory interface */ 24356979Sgibbs sc->bst = rman_get_bustag(sc->res[0]); 24456979Sgibbs sc->bsh = rman_get_bushandle(sc->res[0]); 24556979Sgibbs 24656979Sgibbs vbus_on(sc); 24756979Sgibbs 24856979Sgibbs usbdrd_phy_power_on(); 24956979Sgibbs 25056979Sgibbs DELAY(100); 25156979Sgibbs 25256979Sgibbs usb3_phy_init(sc); 25356979Sgibbs 25456979Sgibbs return (0); 25556979Sgibbs} 25656979Sgibbs 25756979Sgibbsstatic device_method_t usb_phy_methods[] = { 25856979Sgibbs DEVMETHOD(device_probe, usb_phy_probe), 25956979Sgibbs DEVMETHOD(device_attach, usb_phy_attach), 26056979Sgibbs { 0, 0 } 26156979Sgibbs}; 26256979Sgibbs 26356979Sgibbsstatic driver_t usb_phy_driver = { 26456979Sgibbs "usb_phy", 26556979Sgibbs usb_phy_methods, 26656979Sgibbs sizeof(struct usb_phy_softc), 26756979Sgibbs}; 26856979Sgibbs 26956979Sgibbsstatic devclass_t usb_phy_devclass; 27056979Sgibbs 27156979SgibbsDRIVER_MODULE(usb_phy, simplebus, usb_phy_driver, usb_phy_devclass, 0, 0); 27256979Sgibbs