cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sunxi.c (23685B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Allwinner sun4i MUSB Glue Layer
      4 *
      5 * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
      6 *
      7 * Based on code from
      8 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
      9 */
     10
     11#include <linux/clk.h>
     12#include <linux/err.h>
     13#include <linux/extcon.h>
     14#include <linux/io.h>
     15#include <linux/kernel.h>
     16#include <linux/module.h>
     17#include <linux/of.h>
     18#include <linux/phy/phy-sun4i-usb.h>
     19#include <linux/platform_device.h>
     20#include <linux/reset.h>
     21#include <linux/soc/sunxi/sunxi_sram.h>
     22#include <linux/usb/musb.h>
     23#include <linux/usb/of.h>
     24#include <linux/usb/usb_phy_generic.h>
     25#include <linux/workqueue.h>
     26#include "musb_core.h"
     27
     28/*
     29 * Register offsets, note sunxi musb has a different layout then most
     30 * musb implementations, we translate the layout in musb_readb & friends.
     31 */
     32#define SUNXI_MUSB_POWER			0x0040
     33#define SUNXI_MUSB_DEVCTL			0x0041
     34#define SUNXI_MUSB_INDEX			0x0042
     35#define SUNXI_MUSB_VEND0			0x0043
     36#define SUNXI_MUSB_INTRTX			0x0044
     37#define SUNXI_MUSB_INTRRX			0x0046
     38#define SUNXI_MUSB_INTRTXE			0x0048
     39#define SUNXI_MUSB_INTRRXE			0x004a
     40#define SUNXI_MUSB_INTRUSB			0x004c
     41#define SUNXI_MUSB_INTRUSBE			0x0050
     42#define SUNXI_MUSB_FRAME			0x0054
     43#define SUNXI_MUSB_TXFIFOSZ			0x0090
     44#define SUNXI_MUSB_TXFIFOADD			0x0092
     45#define SUNXI_MUSB_RXFIFOSZ			0x0094
     46#define SUNXI_MUSB_RXFIFOADD			0x0096
     47#define SUNXI_MUSB_FADDR			0x0098
     48#define SUNXI_MUSB_TXFUNCADDR			0x0098
     49#define SUNXI_MUSB_TXHUBADDR			0x009a
     50#define SUNXI_MUSB_TXHUBPORT			0x009b
     51#define SUNXI_MUSB_RXFUNCADDR			0x009c
     52#define SUNXI_MUSB_RXHUBADDR			0x009e
     53#define SUNXI_MUSB_RXHUBPORT			0x009f
     54#define SUNXI_MUSB_CONFIGDATA			0x00c0
     55
     56/* VEND0 bits */
     57#define SUNXI_MUSB_VEND0_PIO_MODE		0
     58
     59/* flags */
     60#define SUNXI_MUSB_FL_ENABLED			0
     61#define SUNXI_MUSB_FL_HOSTMODE			1
     62#define SUNXI_MUSB_FL_HOSTMODE_PEND		2
     63#define SUNXI_MUSB_FL_VBUS_ON			3
     64#define SUNXI_MUSB_FL_PHY_ON			4
     65#define SUNXI_MUSB_FL_HAS_SRAM			5
     66#define SUNXI_MUSB_FL_HAS_RESET			6
     67#define SUNXI_MUSB_FL_NO_CONFIGDATA		7
     68#define SUNXI_MUSB_FL_PHY_MODE_PEND		8
     69
     70/* Our read/write methods need access and do not get passed in a musb ref :| */
     71static struct musb *sunxi_musb;
     72
     73struct sunxi_glue {
     74	struct device		*dev;
     75	struct musb		*musb;
     76	struct platform_device	*musb_pdev;
     77	struct clk		*clk;
     78	struct reset_control	*rst;
     79	struct phy		*phy;
     80	struct platform_device	*usb_phy;
     81	struct usb_phy		*xceiv;
     82	enum phy_mode		phy_mode;
     83	unsigned long		flags;
     84	struct work_struct	work;
     85	struct extcon_dev	*extcon;
     86	struct notifier_block	host_nb;
     87};
     88
     89/* phy_power_on / off may sleep, so we use a workqueue  */
     90static void sunxi_musb_work(struct work_struct *work)
     91{
     92	struct sunxi_glue *glue = container_of(work, struct sunxi_glue, work);
     93	bool vbus_on, phy_on;
     94
     95	if (!test_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags))
     96		return;
     97
     98	if (test_and_clear_bit(SUNXI_MUSB_FL_HOSTMODE_PEND, &glue->flags)) {
     99		struct musb *musb = glue->musb;
    100		unsigned long flags;
    101		u8 devctl;
    102
    103		spin_lock_irqsave(&musb->lock, flags);
    104
    105		devctl = readb(musb->mregs + SUNXI_MUSB_DEVCTL);
    106		if (test_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags)) {
    107			set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
    108			musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
    109			MUSB_HST_MODE(musb);
    110			devctl |= MUSB_DEVCTL_SESSION;
    111		} else {
    112			clear_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
    113			musb->xceiv->otg->state = OTG_STATE_B_IDLE;
    114			MUSB_DEV_MODE(musb);
    115			devctl &= ~MUSB_DEVCTL_SESSION;
    116		}
    117		writeb(devctl, musb->mregs + SUNXI_MUSB_DEVCTL);
    118
    119		spin_unlock_irqrestore(&musb->lock, flags);
    120	}
    121
    122	vbus_on = test_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
    123	phy_on = test_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags);
    124
    125	if (phy_on != vbus_on) {
    126		if (vbus_on) {
    127			phy_power_on(glue->phy);
    128			set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags);
    129		} else {
    130			phy_power_off(glue->phy);
    131			clear_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags);
    132		}
    133	}
    134
    135	if (test_and_clear_bit(SUNXI_MUSB_FL_PHY_MODE_PEND, &glue->flags))
    136		phy_set_mode(glue->phy, glue->phy_mode);
    137}
    138
    139static void sunxi_musb_set_vbus(struct musb *musb, int is_on)
    140{
    141	struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
    142
    143	if (is_on) {
    144		set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
    145		musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
    146	} else {
    147		clear_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
    148	}
    149
    150	schedule_work(&glue->work);
    151}
    152
    153static void sunxi_musb_pre_root_reset_end(struct musb *musb)
    154{
    155	struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
    156
    157	sun4i_usb_phy_set_squelch_detect(glue->phy, false);
    158}
    159
    160static void sunxi_musb_post_root_reset_end(struct musb *musb)
    161{
    162	struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
    163
    164	sun4i_usb_phy_set_squelch_detect(glue->phy, true);
    165}
    166
    167static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci)
    168{
    169	struct musb *musb = __hci;
    170	unsigned long flags;
    171
    172	spin_lock_irqsave(&musb->lock, flags);
    173
    174	musb->int_usb = readb(musb->mregs + SUNXI_MUSB_INTRUSB);
    175	if (musb->int_usb)
    176		writeb(musb->int_usb, musb->mregs + SUNXI_MUSB_INTRUSB);
    177
    178	if ((musb->int_usb & MUSB_INTR_RESET) && !is_host_active(musb)) {
    179		/* ep0 FADDR must be 0 when (re)entering peripheral mode */
    180		musb_ep_select(musb->mregs, 0);
    181		musb_writeb(musb->mregs, MUSB_FADDR, 0);
    182	}
    183
    184	musb->int_tx = readw(musb->mregs + SUNXI_MUSB_INTRTX);
    185	if (musb->int_tx)
    186		writew(musb->int_tx, musb->mregs + SUNXI_MUSB_INTRTX);
    187
    188	musb->int_rx = readw(musb->mregs + SUNXI_MUSB_INTRRX);
    189	if (musb->int_rx)
    190		writew(musb->int_rx, musb->mregs + SUNXI_MUSB_INTRRX);
    191
    192	musb_interrupt(musb);
    193
    194	spin_unlock_irqrestore(&musb->lock, flags);
    195
    196	return IRQ_HANDLED;
    197}
    198
    199static int sunxi_musb_host_notifier(struct notifier_block *nb,
    200				    unsigned long event, void *ptr)
    201{
    202	struct sunxi_glue *glue = container_of(nb, struct sunxi_glue, host_nb);
    203
    204	if (event)
    205		set_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags);
    206	else
    207		clear_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags);
    208
    209	set_bit(SUNXI_MUSB_FL_HOSTMODE_PEND, &glue->flags);
    210	schedule_work(&glue->work);
    211
    212	return NOTIFY_DONE;
    213}
    214
    215static int sunxi_musb_init(struct musb *musb)
    216{
    217	struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
    218	int ret;
    219
    220	sunxi_musb = musb;
    221	musb->phy = glue->phy;
    222	musb->xceiv = glue->xceiv;
    223
    224	if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags)) {
    225		ret = sunxi_sram_claim(musb->controller->parent);
    226		if (ret)
    227			return ret;
    228	}
    229
    230	ret = clk_prepare_enable(glue->clk);
    231	if (ret)
    232		goto error_sram_release;
    233
    234	if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) {
    235		ret = reset_control_deassert(glue->rst);
    236		if (ret)
    237			goto error_clk_disable;
    238	}
    239
    240	writeb(SUNXI_MUSB_VEND0_PIO_MODE, musb->mregs + SUNXI_MUSB_VEND0);
    241
    242	/* Register notifier before calling phy_init() */
    243	ret = devm_extcon_register_notifier(glue->dev, glue->extcon,
    244					EXTCON_USB_HOST, &glue->host_nb);
    245	if (ret)
    246		goto error_reset_assert;
    247
    248	ret = phy_init(glue->phy);
    249	if (ret)
    250		goto error_reset_assert;
    251
    252	musb->isr = sunxi_musb_interrupt;
    253
    254	/* Stop the musb-core from doing runtime pm (not supported on sunxi) */
    255	pm_runtime_get(musb->controller);
    256
    257	return 0;
    258
    259error_reset_assert:
    260	if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags))
    261		reset_control_assert(glue->rst);
    262error_clk_disable:
    263	clk_disable_unprepare(glue->clk);
    264error_sram_release:
    265	if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags))
    266		sunxi_sram_release(musb->controller->parent);
    267	return ret;
    268}
    269
    270static int sunxi_musb_exit(struct musb *musb)
    271{
    272	struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
    273
    274	pm_runtime_put(musb->controller);
    275
    276	cancel_work_sync(&glue->work);
    277	if (test_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags))
    278		phy_power_off(glue->phy);
    279
    280	phy_exit(glue->phy);
    281
    282	if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags))
    283		reset_control_assert(glue->rst);
    284
    285	clk_disable_unprepare(glue->clk);
    286	if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags))
    287		sunxi_sram_release(musb->controller->parent);
    288
    289	devm_usb_put_phy(glue->dev, glue->xceiv);
    290
    291	return 0;
    292}
    293
    294static void sunxi_musb_enable(struct musb *musb)
    295{
    296	struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
    297
    298	glue->musb = musb;
    299
    300	/* musb_core does not call us in a balanced manner */
    301	if (test_and_set_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags))
    302		return;
    303
    304	schedule_work(&glue->work);
    305}
    306
    307static void sunxi_musb_disable(struct musb *musb)
    308{
    309	struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
    310
    311	clear_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags);
    312}
    313
    314static struct dma_controller *
    315sunxi_musb_dma_controller_create(struct musb *musb, void __iomem *base)
    316{
    317	return NULL;
    318}
    319
    320static void sunxi_musb_dma_controller_destroy(struct dma_controller *c)
    321{
    322}
    323
    324static int sunxi_musb_set_mode(struct musb *musb, u8 mode)
    325{
    326	struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
    327	enum phy_mode new_mode;
    328
    329	switch (mode) {
    330	case MUSB_HOST:
    331		new_mode = PHY_MODE_USB_HOST;
    332		break;
    333	case MUSB_PERIPHERAL:
    334		new_mode = PHY_MODE_USB_DEVICE;
    335		break;
    336	case MUSB_OTG:
    337		new_mode = PHY_MODE_USB_OTG;
    338		break;
    339	default:
    340		dev_err(musb->controller->parent,
    341			"Error requested mode not supported by this kernel\n");
    342		return -EINVAL;
    343	}
    344
    345	if (glue->phy_mode == new_mode)
    346		return 0;
    347
    348	if (musb->port_mode != MUSB_OTG) {
    349		dev_err(musb->controller->parent,
    350			"Error changing modes is only supported in dual role mode\n");
    351		return -EINVAL;
    352	}
    353
    354	if (musb->port1_status & USB_PORT_STAT_ENABLE)
    355		musb_root_disconnect(musb);
    356
    357	/*
    358	 * phy_set_mode may sleep, and we're called with a spinlock held,
    359	 * so let sunxi_musb_work deal with it.
    360	 */
    361	glue->phy_mode = new_mode;
    362	set_bit(SUNXI_MUSB_FL_PHY_MODE_PEND, &glue->flags);
    363	schedule_work(&glue->work);
    364
    365	return 0;
    366}
    367
    368static int sunxi_musb_recover(struct musb *musb)
    369{
    370	struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
    371
    372	/*
    373	 * Schedule a phy_set_mode with the current glue->phy_mode value,
    374	 * this will force end the current session.
    375	 */
    376	set_bit(SUNXI_MUSB_FL_PHY_MODE_PEND, &glue->flags);
    377	schedule_work(&glue->work);
    378
    379	return 0;
    380}
    381
    382/*
    383 * sunxi musb register layout
    384 * 0x00 - 0x17	fifo regs, 1 long per fifo
    385 * 0x40 - 0x57	generic control regs (power - frame)
    386 * 0x80 - 0x8f	ep control regs (addressed through hw_ep->regs, indexed)
    387 * 0x90 - 0x97	fifo control regs (indexed)
    388 * 0x98 - 0x9f	multipoint / busctl regs (indexed)
    389 * 0xc0		configdata reg
    390 */
    391
    392static u32 sunxi_musb_fifo_offset(u8 epnum)
    393{
    394	return (epnum * 4);
    395}
    396
    397static u32 sunxi_musb_ep_offset(u8 epnum, u16 offset)
    398{
    399	WARN_ONCE(offset != 0,
    400		  "sunxi_musb_ep_offset called with non 0 offset\n");
    401
    402	return 0x80; /* indexed, so ignore epnum */
    403}
    404
    405static u32 sunxi_musb_busctl_offset(u8 epnum, u16 offset)
    406{
    407	return SUNXI_MUSB_TXFUNCADDR + offset;
    408}
    409
    410static u8 sunxi_musb_readb(void __iomem *addr, u32 offset)
    411{
    412	struct sunxi_glue *glue;
    413
    414	if (addr == sunxi_musb->mregs) {
    415		/* generic control or fifo control reg access */
    416		switch (offset) {
    417		case MUSB_FADDR:
    418			return readb(addr + SUNXI_MUSB_FADDR);
    419		case MUSB_POWER:
    420			return readb(addr + SUNXI_MUSB_POWER);
    421		case MUSB_INTRUSB:
    422			return readb(addr + SUNXI_MUSB_INTRUSB);
    423		case MUSB_INTRUSBE:
    424			return readb(addr + SUNXI_MUSB_INTRUSBE);
    425		case MUSB_INDEX:
    426			return readb(addr + SUNXI_MUSB_INDEX);
    427		case MUSB_TESTMODE:
    428			return 0; /* No testmode on sunxi */
    429		case MUSB_DEVCTL:
    430			return readb(addr + SUNXI_MUSB_DEVCTL);
    431		case MUSB_TXFIFOSZ:
    432			return readb(addr + SUNXI_MUSB_TXFIFOSZ);
    433		case MUSB_RXFIFOSZ:
    434			return readb(addr + SUNXI_MUSB_RXFIFOSZ);
    435		case MUSB_CONFIGDATA + 0x10: /* See musb_read_configdata() */
    436			glue = dev_get_drvdata(sunxi_musb->controller->parent);
    437			/* A33 saves a reg, and we get to hardcode this */
    438			if (test_bit(SUNXI_MUSB_FL_NO_CONFIGDATA,
    439				     &glue->flags))
    440				return 0xde;
    441
    442			return readb(addr + SUNXI_MUSB_CONFIGDATA);
    443		case MUSB_ULPI_BUSCONTROL:
    444			dev_warn(sunxi_musb->controller->parent,
    445				"sunxi-musb does not have ULPI bus control register\n");
    446			return 0;
    447		/* Offset for these is fixed by sunxi_musb_busctl_offset() */
    448		case SUNXI_MUSB_TXFUNCADDR:
    449		case SUNXI_MUSB_TXHUBADDR:
    450		case SUNXI_MUSB_TXHUBPORT:
    451		case SUNXI_MUSB_RXFUNCADDR:
    452		case SUNXI_MUSB_RXHUBADDR:
    453		case SUNXI_MUSB_RXHUBPORT:
    454			/* multipoint / busctl reg access */
    455			return readb(addr + offset);
    456		default:
    457			dev_err(sunxi_musb->controller->parent,
    458				"Error unknown readb offset %u\n", offset);
    459			return 0;
    460		}
    461	} else if (addr == (sunxi_musb->mregs + 0x80)) {
    462		/* ep control reg access */
    463		/* sunxi has a 2 byte hole before the txtype register */
    464		if (offset >= MUSB_TXTYPE)
    465			offset += 2;
    466		return readb(addr + offset);
    467	}
    468
    469	dev_err(sunxi_musb->controller->parent,
    470		"Error unknown readb at 0x%x bytes offset\n",
    471		(int)(addr - sunxi_musb->mregs));
    472	return 0;
    473}
    474
    475static void sunxi_musb_writeb(void __iomem *addr, unsigned offset, u8 data)
    476{
    477	if (addr == sunxi_musb->mregs) {
    478		/* generic control or fifo control reg access */
    479		switch (offset) {
    480		case MUSB_FADDR:
    481			return writeb(data, addr + SUNXI_MUSB_FADDR);
    482		case MUSB_POWER:
    483			return writeb(data, addr + SUNXI_MUSB_POWER);
    484		case MUSB_INTRUSB:
    485			return writeb(data, addr + SUNXI_MUSB_INTRUSB);
    486		case MUSB_INTRUSBE:
    487			return writeb(data, addr + SUNXI_MUSB_INTRUSBE);
    488		case MUSB_INDEX:
    489			return writeb(data, addr + SUNXI_MUSB_INDEX);
    490		case MUSB_TESTMODE:
    491			if (data)
    492				dev_warn(sunxi_musb->controller->parent,
    493					"sunxi-musb does not have testmode\n");
    494			return;
    495		case MUSB_DEVCTL:
    496			return writeb(data, addr + SUNXI_MUSB_DEVCTL);
    497		case MUSB_TXFIFOSZ:
    498			return writeb(data, addr + SUNXI_MUSB_TXFIFOSZ);
    499		case MUSB_RXFIFOSZ:
    500			return writeb(data, addr + SUNXI_MUSB_RXFIFOSZ);
    501		case MUSB_ULPI_BUSCONTROL:
    502			dev_warn(sunxi_musb->controller->parent,
    503				"sunxi-musb does not have ULPI bus control register\n");
    504			return;
    505		/* Offset for these is fixed by sunxi_musb_busctl_offset() */
    506		case SUNXI_MUSB_TXFUNCADDR:
    507		case SUNXI_MUSB_TXHUBADDR:
    508		case SUNXI_MUSB_TXHUBPORT:
    509		case SUNXI_MUSB_RXFUNCADDR:
    510		case SUNXI_MUSB_RXHUBADDR:
    511		case SUNXI_MUSB_RXHUBPORT:
    512			/* multipoint / busctl reg access */
    513			return writeb(data, addr + offset);
    514		default:
    515			dev_err(sunxi_musb->controller->parent,
    516				"Error unknown writeb offset %u\n", offset);
    517			return;
    518		}
    519	} else if (addr == (sunxi_musb->mregs + 0x80)) {
    520		/* ep control reg access */
    521		if (offset >= MUSB_TXTYPE)
    522			offset += 2;
    523		return writeb(data, addr + offset);
    524	}
    525
    526	dev_err(sunxi_musb->controller->parent,
    527		"Error unknown writeb at 0x%x bytes offset\n",
    528		(int)(addr - sunxi_musb->mregs));
    529}
    530
    531static u16 sunxi_musb_readw(void __iomem *addr, u32 offset)
    532{
    533	if (addr == sunxi_musb->mregs) {
    534		/* generic control or fifo control reg access */
    535		switch (offset) {
    536		case MUSB_INTRTX:
    537			return readw(addr + SUNXI_MUSB_INTRTX);
    538		case MUSB_INTRRX:
    539			return readw(addr + SUNXI_MUSB_INTRRX);
    540		case MUSB_INTRTXE:
    541			return readw(addr + SUNXI_MUSB_INTRTXE);
    542		case MUSB_INTRRXE:
    543			return readw(addr + SUNXI_MUSB_INTRRXE);
    544		case MUSB_FRAME:
    545			return readw(addr + SUNXI_MUSB_FRAME);
    546		case MUSB_TXFIFOADD:
    547			return readw(addr + SUNXI_MUSB_TXFIFOADD);
    548		case MUSB_RXFIFOADD:
    549			return readw(addr + SUNXI_MUSB_RXFIFOADD);
    550		case MUSB_HWVERS:
    551			return 0; /* sunxi musb version is not known */
    552		default:
    553			dev_err(sunxi_musb->controller->parent,
    554				"Error unknown readw offset %u\n", offset);
    555			return 0;
    556		}
    557	} else if (addr == (sunxi_musb->mregs + 0x80)) {
    558		/* ep control reg access */
    559		return readw(addr + offset);
    560	}
    561
    562	dev_err(sunxi_musb->controller->parent,
    563		"Error unknown readw at 0x%x bytes offset\n",
    564		(int)(addr - sunxi_musb->mregs));
    565	return 0;
    566}
    567
    568static void sunxi_musb_writew(void __iomem *addr, unsigned offset, u16 data)
    569{
    570	if (addr == sunxi_musb->mregs) {
    571		/* generic control or fifo control reg access */
    572		switch (offset) {
    573		case MUSB_INTRTX:
    574			return writew(data, addr + SUNXI_MUSB_INTRTX);
    575		case MUSB_INTRRX:
    576			return writew(data, addr + SUNXI_MUSB_INTRRX);
    577		case MUSB_INTRTXE:
    578			return writew(data, addr + SUNXI_MUSB_INTRTXE);
    579		case MUSB_INTRRXE:
    580			return writew(data, addr + SUNXI_MUSB_INTRRXE);
    581		case MUSB_FRAME:
    582			return writew(data, addr + SUNXI_MUSB_FRAME);
    583		case MUSB_TXFIFOADD:
    584			return writew(data, addr + SUNXI_MUSB_TXFIFOADD);
    585		case MUSB_RXFIFOADD:
    586			return writew(data, addr + SUNXI_MUSB_RXFIFOADD);
    587		default:
    588			dev_err(sunxi_musb->controller->parent,
    589				"Error unknown writew offset %u\n", offset);
    590			return;
    591		}
    592	} else if (addr == (sunxi_musb->mregs + 0x80)) {
    593		/* ep control reg access */
    594		return writew(data, addr + offset);
    595	}
    596
    597	dev_err(sunxi_musb->controller->parent,
    598		"Error unknown writew at 0x%x bytes offset\n",
    599		(int)(addr - sunxi_musb->mregs));
    600}
    601
    602static const struct musb_platform_ops sunxi_musb_ops = {
    603	.quirks		= MUSB_INDEXED_EP,
    604	.init		= sunxi_musb_init,
    605	.exit		= sunxi_musb_exit,
    606	.enable		= sunxi_musb_enable,
    607	.disable	= sunxi_musb_disable,
    608	.fifo_offset	= sunxi_musb_fifo_offset,
    609	.ep_offset	= sunxi_musb_ep_offset,
    610	.busctl_offset	= sunxi_musb_busctl_offset,
    611	.readb		= sunxi_musb_readb,
    612	.writeb		= sunxi_musb_writeb,
    613	.readw		= sunxi_musb_readw,
    614	.writew		= sunxi_musb_writew,
    615	.dma_init	= sunxi_musb_dma_controller_create,
    616	.dma_exit	= sunxi_musb_dma_controller_destroy,
    617	.set_mode	= sunxi_musb_set_mode,
    618	.recover	= sunxi_musb_recover,
    619	.set_vbus	= sunxi_musb_set_vbus,
    620	.pre_root_reset_end = sunxi_musb_pre_root_reset_end,
    621	.post_root_reset_end = sunxi_musb_post_root_reset_end,
    622};
    623
    624/* Allwinner OTG supports up to 5 endpoints */
    625#define SUNXI_MUSB_MAX_EP_NUM	6
    626#define SUNXI_MUSB_RAM_BITS	11
    627
    628static struct musb_fifo_cfg sunxi_musb_mode_cfg[] = {
    629	MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512),
    630	MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512),
    631	MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512),
    632	MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512),
    633	MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512),
    634	MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512),
    635	MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512),
    636	MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512),
    637	MUSB_EP_FIFO_SINGLE(5, FIFO_TX, 512),
    638	MUSB_EP_FIFO_SINGLE(5, FIFO_RX, 512),
    639};
    640
    641/* H3/V3s OTG supports only 4 endpoints */
    642#define SUNXI_MUSB_MAX_EP_NUM_H3	5
    643
    644static struct musb_fifo_cfg sunxi_musb_mode_cfg_h3[] = {
    645	MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512),
    646	MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512),
    647	MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512),
    648	MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512),
    649	MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512),
    650	MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512),
    651	MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512),
    652	MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512),
    653};
    654
    655static const struct musb_hdrc_config sunxi_musb_hdrc_config = {
    656	.fifo_cfg       = sunxi_musb_mode_cfg,
    657	.fifo_cfg_size  = ARRAY_SIZE(sunxi_musb_mode_cfg),
    658	.multipoint	= true,
    659	.dyn_fifo	= true,
    660	.num_eps	= SUNXI_MUSB_MAX_EP_NUM,
    661	.ram_bits	= SUNXI_MUSB_RAM_BITS,
    662};
    663
    664static struct musb_hdrc_config sunxi_musb_hdrc_config_h3 = {
    665	.fifo_cfg       = sunxi_musb_mode_cfg_h3,
    666	.fifo_cfg_size  = ARRAY_SIZE(sunxi_musb_mode_cfg_h3),
    667	.multipoint	= true,
    668	.dyn_fifo	= true,
    669	.num_eps	= SUNXI_MUSB_MAX_EP_NUM_H3,
    670	.ram_bits	= SUNXI_MUSB_RAM_BITS,
    671};
    672
    673
    674static int sunxi_musb_probe(struct platform_device *pdev)
    675{
    676	struct musb_hdrc_platform_data	pdata;
    677	struct platform_device_info	pinfo;
    678	struct sunxi_glue		*glue;
    679	struct device_node		*np = pdev->dev.of_node;
    680	int ret;
    681
    682	if (!np) {
    683		dev_err(&pdev->dev, "Error no device tree node found\n");
    684		return -EINVAL;
    685	}
    686
    687	glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
    688	if (!glue)
    689		return -ENOMEM;
    690
    691	memset(&pdata, 0, sizeof(pdata));
    692	switch (usb_get_dr_mode(&pdev->dev)) {
    693#if defined CONFIG_USB_MUSB_DUAL_ROLE || defined CONFIG_USB_MUSB_HOST
    694	case USB_DR_MODE_HOST:
    695		pdata.mode = MUSB_HOST;
    696		glue->phy_mode = PHY_MODE_USB_HOST;
    697		break;
    698#endif
    699#if defined CONFIG_USB_MUSB_DUAL_ROLE || defined CONFIG_USB_MUSB_GADGET
    700	case USB_DR_MODE_PERIPHERAL:
    701		pdata.mode = MUSB_PERIPHERAL;
    702		glue->phy_mode = PHY_MODE_USB_DEVICE;
    703		break;
    704#endif
    705#ifdef CONFIG_USB_MUSB_DUAL_ROLE
    706	case USB_DR_MODE_OTG:
    707		pdata.mode = MUSB_OTG;
    708		glue->phy_mode = PHY_MODE_USB_OTG;
    709		break;
    710#endif
    711	default:
    712		dev_err(&pdev->dev, "Invalid or missing 'dr_mode' property\n");
    713		return -EINVAL;
    714	}
    715	pdata.platform_ops	= &sunxi_musb_ops;
    716	if (!of_device_is_compatible(np, "allwinner,sun8i-h3-musb"))
    717		pdata.config = &sunxi_musb_hdrc_config;
    718	else
    719		pdata.config = &sunxi_musb_hdrc_config_h3;
    720
    721	glue->dev = &pdev->dev;
    722	INIT_WORK(&glue->work, sunxi_musb_work);
    723	glue->host_nb.notifier_call = sunxi_musb_host_notifier;
    724
    725	if (of_device_is_compatible(np, "allwinner,sun4i-a10-musb"))
    726		set_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags);
    727
    728	if (of_device_is_compatible(np, "allwinner,sun6i-a31-musb"))
    729		set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags);
    730
    731	if (of_device_is_compatible(np, "allwinner,sun8i-a33-musb") ||
    732	    of_device_is_compatible(np, "allwinner,sun8i-h3-musb")) {
    733		set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags);
    734		set_bit(SUNXI_MUSB_FL_NO_CONFIGDATA, &glue->flags);
    735	}
    736
    737	glue->clk = devm_clk_get(&pdev->dev, NULL);
    738	if (IS_ERR(glue->clk)) {
    739		dev_err(&pdev->dev, "Error getting clock: %ld\n",
    740			PTR_ERR(glue->clk));
    741		return PTR_ERR(glue->clk);
    742	}
    743
    744	if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) {
    745		glue->rst = devm_reset_control_get(&pdev->dev, NULL);
    746		if (IS_ERR(glue->rst)) {
    747			if (PTR_ERR(glue->rst) == -EPROBE_DEFER)
    748				return -EPROBE_DEFER;
    749			dev_err(&pdev->dev, "Error getting reset %ld\n",
    750				PTR_ERR(glue->rst));
    751			return PTR_ERR(glue->rst);
    752		}
    753	}
    754
    755	glue->extcon = extcon_get_edev_by_phandle(&pdev->dev, 0);
    756	if (IS_ERR(glue->extcon)) {
    757		if (PTR_ERR(glue->extcon) == -EPROBE_DEFER)
    758			return -EPROBE_DEFER;
    759		dev_err(&pdev->dev, "Invalid or missing extcon\n");
    760		return PTR_ERR(glue->extcon);
    761	}
    762
    763	glue->phy = devm_phy_get(&pdev->dev, "usb");
    764	if (IS_ERR(glue->phy)) {
    765		if (PTR_ERR(glue->phy) == -EPROBE_DEFER)
    766			return -EPROBE_DEFER;
    767		dev_err(&pdev->dev, "Error getting phy %ld\n",
    768			PTR_ERR(glue->phy));
    769		return PTR_ERR(glue->phy);
    770	}
    771
    772	glue->usb_phy = usb_phy_generic_register();
    773	if (IS_ERR(glue->usb_phy)) {
    774		dev_err(&pdev->dev, "Error registering usb-phy %ld\n",
    775			PTR_ERR(glue->usb_phy));
    776		return PTR_ERR(glue->usb_phy);
    777	}
    778
    779	glue->xceiv = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
    780	if (IS_ERR(glue->xceiv)) {
    781		ret = PTR_ERR(glue->xceiv);
    782		dev_err(&pdev->dev, "Error getting usb-phy %d\n", ret);
    783		goto err_unregister_usb_phy;
    784	}
    785
    786	platform_set_drvdata(pdev, glue);
    787
    788	memset(&pinfo, 0, sizeof(pinfo));
    789	pinfo.name	 = "musb-hdrc";
    790	pinfo.id	= PLATFORM_DEVID_AUTO;
    791	pinfo.parent	= &pdev->dev;
    792	pinfo.fwnode	= of_fwnode_handle(pdev->dev.of_node);
    793	pinfo.of_node_reused = true;
    794	pinfo.res	= pdev->resource;
    795	pinfo.num_res	= pdev->num_resources;
    796	pinfo.data	= &pdata;
    797	pinfo.size_data = sizeof(pdata);
    798
    799	glue->musb_pdev = platform_device_register_full(&pinfo);
    800	if (IS_ERR(glue->musb_pdev)) {
    801		ret = PTR_ERR(glue->musb_pdev);
    802		dev_err(&pdev->dev, "Error registering musb dev: %d\n", ret);
    803		goto err_unregister_usb_phy;
    804	}
    805
    806	return 0;
    807
    808err_unregister_usb_phy:
    809	usb_phy_generic_unregister(glue->usb_phy);
    810	return ret;
    811}
    812
    813static int sunxi_musb_remove(struct platform_device *pdev)
    814{
    815	struct sunxi_glue *glue = platform_get_drvdata(pdev);
    816	struct platform_device *usb_phy = glue->usb_phy;
    817
    818	platform_device_unregister(glue->musb_pdev);
    819	usb_phy_generic_unregister(usb_phy);
    820
    821	return 0;
    822}
    823
    824static const struct of_device_id sunxi_musb_match[] = {
    825	{ .compatible = "allwinner,sun4i-a10-musb", },
    826	{ .compatible = "allwinner,sun6i-a31-musb", },
    827	{ .compatible = "allwinner,sun8i-a33-musb", },
    828	{ .compatible = "allwinner,sun8i-h3-musb", },
    829	{}
    830};
    831MODULE_DEVICE_TABLE(of, sunxi_musb_match);
    832
    833static struct platform_driver sunxi_musb_driver = {
    834	.probe = sunxi_musb_probe,
    835	.remove = sunxi_musb_remove,
    836	.driver = {
    837		.name = "musb-sunxi",
    838		.of_match_table = sunxi_musb_match,
    839	},
    840};
    841module_platform_driver(sunxi_musb_driver);
    842
    843MODULE_DESCRIPTION("Allwinner sunxi MUSB Glue Layer");
    844MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
    845MODULE_LICENSE("GPL v2");