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

bcma-hcd.c (12540B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Broadcom specific Advanced Microcontroller Bus
      4 * Broadcom USB-core driver (BCMA bus glue)
      5 *
      6 * Copyright 2011-2015 Hauke Mehrtens <hauke@hauke-m.de>
      7 * Copyright 2015 Felix Fietkau <nbd@openwrt.org>
      8 *
      9 * Based on ssb-ohci driver
     10 * Copyright 2007 Michael Buesch <m@bues.ch>
     11 *
     12 * Derived from the OHCI-PCI driver
     13 * Copyright 1999 Roman Weissgaerber
     14 * Copyright 2000-2002 David Brownell
     15 * Copyright 1999 Linus Torvalds
     16 * Copyright 1999 Gregory P. Smith
     17 *
     18 * Derived from the USBcore related parts of Broadcom-SB
     19 * Copyright 2005-2011 Broadcom Corporation
     20 */
     21#include <linux/bcma/bcma.h>
     22#include <linux/delay.h>
     23#include <linux/gpio/consumer.h>
     24#include <linux/platform_device.h>
     25#include <linux/module.h>
     26#include <linux/slab.h>
     27#include <linux/of.h>
     28#include <linux/of_gpio.h>
     29#include <linux/of_platform.h>
     30#include <linux/usb/ehci_pdriver.h>
     31#include <linux/usb/ohci_pdriver.h>
     32
     33MODULE_AUTHOR("Hauke Mehrtens");
     34MODULE_DESCRIPTION("Common USB driver for BCMA Bus");
     35MODULE_LICENSE("GPL");
     36
     37/* See BCMA_CLKCTLST_EXTRESREQ and BCMA_CLKCTLST_EXTRESST */
     38#define USB_BCMA_CLKCTLST_USB_CLK_REQ			0x00000100
     39
     40struct bcma_hcd_device {
     41	struct bcma_device *core;
     42	struct platform_device *ehci_dev;
     43	struct platform_device *ohci_dev;
     44	struct gpio_desc *gpio_desc;
     45};
     46
     47/* Wait for bitmask in a register to get set or cleared.
     48 * timeout is in units of ten-microseconds.
     49 */
     50static int bcma_wait_bits(struct bcma_device *dev, u16 reg, u32 bitmask,
     51			  int timeout)
     52{
     53	int i;
     54	u32 val;
     55
     56	for (i = 0; i < timeout; i++) {
     57		val = bcma_read32(dev, reg);
     58		if ((val & bitmask) == bitmask)
     59			return 0;
     60		udelay(10);
     61	}
     62
     63	return -ETIMEDOUT;
     64}
     65
     66static void bcma_hcd_4716wa(struct bcma_device *dev)
     67{
     68#ifdef CONFIG_BCMA_DRIVER_MIPS
     69	/* Work around for 4716 failures. */
     70	if (dev->bus->chipinfo.id == 0x4716) {
     71		u32 tmp;
     72
     73		tmp = bcma_cpu_clock(&dev->bus->drv_mips);
     74		if (tmp >= 480000000)
     75			tmp = 0x1846b; /* set CDR to 0x11(fast) */
     76		else if (tmp == 453000000)
     77			tmp = 0x1046b; /* set CDR to 0x10(slow) */
     78		else
     79			tmp = 0;
     80
     81		/* Change Shim mdio control reg to fix host not acking at
     82		 * high frequencies
     83		 */
     84		if (tmp) {
     85			bcma_write32(dev, 0x524, 0x1); /* write sel to enable */
     86			udelay(500);
     87
     88			bcma_write32(dev, 0x524, tmp);
     89			udelay(500);
     90			bcma_write32(dev, 0x524, 0x4ab);
     91			udelay(500);
     92			bcma_read32(dev, 0x528);
     93			bcma_write32(dev, 0x528, 0x80000000);
     94		}
     95	}
     96#endif /* CONFIG_BCMA_DRIVER_MIPS */
     97}
     98
     99/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */
    100static void bcma_hcd_init_chip_mips(struct bcma_device *dev)
    101{
    102	u32 tmp;
    103
    104	/*
    105	 * USB 2.0 special considerations:
    106	 *
    107	 * 1. Since the core supports both OHCI and EHCI functions, it must
    108	 *    only be reset once.
    109	 *
    110	 * 2. In addition to the standard SI reset sequence, the Host Control
    111	 *    Register must be programmed to bring the USB core and various
    112	 *    phy components out of reset.
    113	 */
    114	if (!bcma_core_is_enabled(dev)) {
    115		bcma_core_enable(dev, 0);
    116		mdelay(10);
    117		if (dev->id.rev >= 5) {
    118			/* Enable Misc PLL */
    119			tmp = bcma_read32(dev, 0x1e0);
    120			tmp |= 0x100;
    121			bcma_write32(dev, 0x1e0, tmp);
    122			if (bcma_wait_bits(dev, 0x1e0, 1 << 24, 100))
    123				printk(KERN_EMERG "Failed to enable misc PPL!\n");
    124
    125			/* Take out of resets */
    126			bcma_write32(dev, 0x200, 0x4ff);
    127			udelay(25);
    128			bcma_write32(dev, 0x200, 0x6ff);
    129			udelay(25);
    130
    131			/* Make sure digital and AFE are locked in USB PHY */
    132			bcma_write32(dev, 0x524, 0x6b);
    133			udelay(50);
    134			tmp = bcma_read32(dev, 0x524);
    135			udelay(50);
    136			bcma_write32(dev, 0x524, 0xab);
    137			udelay(50);
    138			tmp = bcma_read32(dev, 0x524);
    139			udelay(50);
    140			bcma_write32(dev, 0x524, 0x2b);
    141			udelay(50);
    142			tmp = bcma_read32(dev, 0x524);
    143			udelay(50);
    144			bcma_write32(dev, 0x524, 0x10ab);
    145			udelay(50);
    146			tmp = bcma_read32(dev, 0x524);
    147
    148			if (bcma_wait_bits(dev, 0x528, 0xc000, 10000)) {
    149				tmp = bcma_read32(dev, 0x528);
    150				printk(KERN_EMERG
    151				       "USB20H mdio_rddata 0x%08x\n", tmp);
    152			}
    153			bcma_write32(dev, 0x528, 0x80000000);
    154			tmp = bcma_read32(dev, 0x314);
    155			udelay(265);
    156			bcma_write32(dev, 0x200, 0x7ff);
    157			udelay(10);
    158
    159			/* Take USB and HSIC out of non-driving modes */
    160			bcma_write32(dev, 0x510, 0);
    161		} else {
    162			bcma_write32(dev, 0x200, 0x7ff);
    163
    164			udelay(1);
    165		}
    166
    167		bcma_hcd_4716wa(dev);
    168	}
    169}
    170
    171/*
    172 * bcma_hcd_usb20_old_arm_init - Initialize old USB 2.0 controller on ARM
    173 *
    174 * Old USB 2.0 core is identified as BCMA_CORE_USB20_HOST and was introduced
    175 * long before Northstar devices. It seems some cheaper chipsets like BCM53573
    176 * still use it.
    177 * Initialization of this old core differs between MIPS and ARM.
    178 */
    179static int bcma_hcd_usb20_old_arm_init(struct bcma_hcd_device *usb_dev)
    180{
    181	struct bcma_device *core = usb_dev->core;
    182	struct device *dev = &core->dev;
    183	struct bcma_device *pmu_core;
    184
    185	usleep_range(10000, 20000);
    186	if (core->id.rev < 5)
    187		return 0;
    188
    189	pmu_core = bcma_find_core(core->bus, BCMA_CORE_PMU);
    190	if (!pmu_core) {
    191		dev_err(dev, "Could not find PMU core\n");
    192		return -ENOENT;
    193	}
    194
    195	/* Take USB core out of reset */
    196	bcma_awrite32(core, BCMA_IOCTL, BCMA_IOCTL_CLK | BCMA_IOCTL_FGC);
    197	usleep_range(100, 200);
    198	bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
    199	usleep_range(100, 200);
    200	bcma_awrite32(core, BCMA_RESET_CTL, 0);
    201	usleep_range(100, 200);
    202	bcma_awrite32(core, BCMA_IOCTL, BCMA_IOCTL_CLK);
    203	usleep_range(100, 200);
    204
    205	/* Enable Misc PLL */
    206	bcma_write32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT |
    207					  BCMA_CLKCTLST_HQCLKREQ |
    208					  USB_BCMA_CLKCTLST_USB_CLK_REQ);
    209	usleep_range(100, 200);
    210
    211	bcma_write32(core, 0x510, 0xc7f85000);
    212	bcma_write32(core, 0x510, 0xc7f85003);
    213	usleep_range(300, 600);
    214
    215	/* Program USB PHY PLL parameters */
    216	bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_ADDR, 0x6);
    217	bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_DATA, 0x005360c1);
    218	usleep_range(100, 200);
    219	bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_ADDR, 0x7);
    220	bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_DATA, 0x0);
    221	usleep_range(100, 200);
    222	bcma_set32(pmu_core, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
    223	usleep_range(100, 200);
    224
    225	bcma_write32(core, 0x510, 0x7f8d007);
    226	udelay(1000);
    227
    228	/* Take controller out of reset */
    229	bcma_write32(core, 0x200, 0x4ff);
    230	usleep_range(25, 50);
    231	bcma_write32(core, 0x200, 0x6ff);
    232	usleep_range(25, 50);
    233	bcma_write32(core, 0x200, 0x7ff);
    234	usleep_range(25, 50);
    235
    236	of_platform_default_populate(dev->of_node, NULL, dev);
    237
    238	return 0;
    239}
    240
    241static void bcma_hcd_usb20_ns_init_hc(struct bcma_device *dev)
    242{
    243	u32 val;
    244
    245	/* Set packet buffer OUT threshold */
    246	val = bcma_read32(dev, 0x94);
    247	val &= 0xffff;
    248	val |= 0x80 << 16;
    249	bcma_write32(dev, 0x94, val);
    250
    251	/* Enable break memory transfer */
    252	val = bcma_read32(dev, 0x9c);
    253	val |= 1;
    254	bcma_write32(dev, 0x9c, val);
    255
    256	/*
    257	 * Broadcom initializes PHY and then waits to ensure HC is ready to be
    258	 * configured. In our case the order is reversed. We just initialized
    259	 * controller and we let HCD initialize PHY, so let's wait (sleep) now.
    260	 */
    261	usleep_range(1000, 2000);
    262}
    263
    264/*
    265 * bcma_hcd_usb20_ns_init - Initialize Northstar USB 2.0 controller
    266 */
    267static int bcma_hcd_usb20_ns_init(struct bcma_hcd_device *bcma_hcd)
    268{
    269	struct bcma_device *core = bcma_hcd->core;
    270	struct bcma_chipinfo *ci = &core->bus->chipinfo;
    271	struct device *dev = &core->dev;
    272
    273	bcma_core_enable(core, 0);
    274
    275	if (ci->id == BCMA_CHIP_ID_BCM4707 ||
    276	    ci->id == BCMA_CHIP_ID_BCM53018)
    277		bcma_hcd_usb20_ns_init_hc(core);
    278
    279	of_platform_default_populate(dev->of_node, NULL, dev);
    280
    281	return 0;
    282}
    283
    284static void bcma_hci_platform_power_gpio(struct bcma_device *dev, bool val)
    285{
    286	struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
    287
    288	if (IS_ERR_OR_NULL(usb_dev->gpio_desc))
    289		return;
    290
    291	gpiod_set_value(usb_dev->gpio_desc, val);
    292}
    293
    294static const struct usb_ehci_pdata ehci_pdata = {
    295};
    296
    297static const struct usb_ohci_pdata ohci_pdata = {
    298};
    299
    300static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev,
    301						    const char *name, u32 addr,
    302						    const void *data,
    303						    size_t size)
    304{
    305	struct platform_device *hci_dev;
    306	struct resource hci_res[2];
    307	int ret;
    308
    309	memset(hci_res, 0, sizeof(hci_res));
    310
    311	hci_res[0].start = addr;
    312	hci_res[0].end = hci_res[0].start + 0x1000 - 1;
    313	hci_res[0].flags = IORESOURCE_MEM;
    314
    315	hci_res[1].start = dev->irq;
    316	hci_res[1].flags = IORESOURCE_IRQ;
    317
    318	hci_dev = platform_device_alloc(name, 0);
    319	if (!hci_dev)
    320		return ERR_PTR(-ENOMEM);
    321
    322	hci_dev->dev.parent = &dev->dev;
    323	hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
    324
    325	ret = platform_device_add_resources(hci_dev, hci_res,
    326					    ARRAY_SIZE(hci_res));
    327	if (ret)
    328		goto err_alloc;
    329	if (data)
    330		ret = platform_device_add_data(hci_dev, data, size);
    331	if (ret)
    332		goto err_alloc;
    333	ret = platform_device_add(hci_dev);
    334	if (ret)
    335		goto err_alloc;
    336
    337	return hci_dev;
    338
    339err_alloc:
    340	platform_device_put(hci_dev);
    341	return ERR_PTR(ret);
    342}
    343
    344static int bcma_hcd_usb20_init(struct bcma_hcd_device *usb_dev)
    345{
    346	struct bcma_device *dev = usb_dev->core;
    347	struct bcma_chipinfo *chipinfo = &dev->bus->chipinfo;
    348	u32 ohci_addr;
    349	int err;
    350
    351	if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32)))
    352		return -EOPNOTSUPP;
    353
    354	bcma_hcd_init_chip_mips(dev);
    355
    356	/* In AI chips EHCI is addrspace 0, OHCI is 1 */
    357	ohci_addr = dev->addr_s[0];
    358	if ((chipinfo->id == BCMA_CHIP_ID_BCM5357 ||
    359	     chipinfo->id == BCMA_CHIP_ID_BCM4749)
    360	    && chipinfo->rev == 0)
    361		ohci_addr = 0x18009000;
    362
    363	usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, "ohci-platform",
    364						 ohci_addr, &ohci_pdata,
    365						 sizeof(ohci_pdata));
    366	if (IS_ERR(usb_dev->ohci_dev))
    367		return PTR_ERR(usb_dev->ohci_dev);
    368
    369	usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, "ehci-platform",
    370						 dev->addr, &ehci_pdata,
    371						 sizeof(ehci_pdata));
    372	if (IS_ERR(usb_dev->ehci_dev)) {
    373		err = PTR_ERR(usb_dev->ehci_dev);
    374		goto err_unregister_ohci_dev;
    375	}
    376
    377	return 0;
    378
    379err_unregister_ohci_dev:
    380	platform_device_unregister(usb_dev->ohci_dev);
    381	return err;
    382}
    383
    384static int bcma_hcd_usb30_init(struct bcma_hcd_device *bcma_hcd)
    385{
    386	struct bcma_device *core = bcma_hcd->core;
    387	struct device *dev = &core->dev;
    388
    389	bcma_core_enable(core, 0);
    390
    391	of_platform_default_populate(dev->of_node, NULL, dev);
    392
    393	return 0;
    394}
    395
    396static int bcma_hcd_probe(struct bcma_device *core)
    397{
    398	int err;
    399	struct bcma_hcd_device *usb_dev;
    400
    401	/* TODO: Probably need checks here; is the core connected? */
    402
    403	usb_dev = devm_kzalloc(&core->dev, sizeof(struct bcma_hcd_device),
    404			       GFP_KERNEL);
    405	if (!usb_dev)
    406		return -ENOMEM;
    407	usb_dev->core = core;
    408
    409	if (core->dev.of_node)
    410		usb_dev->gpio_desc = devm_gpiod_get(&core->dev, "vcc",
    411						    GPIOD_OUT_HIGH);
    412
    413	switch (core->id.id) {
    414	case BCMA_CORE_USB20_HOST:
    415		if (IS_ENABLED(CONFIG_ARM))
    416			err = bcma_hcd_usb20_old_arm_init(usb_dev);
    417		else if (IS_ENABLED(CONFIG_MIPS))
    418			err = bcma_hcd_usb20_init(usb_dev);
    419		else
    420			err = -ENOTSUPP;
    421		break;
    422	case BCMA_CORE_NS_USB20:
    423		err = bcma_hcd_usb20_ns_init(usb_dev);
    424		break;
    425	case BCMA_CORE_NS_USB30:
    426		err = bcma_hcd_usb30_init(usb_dev);
    427		break;
    428	default:
    429		return -ENODEV;
    430	}
    431	if (err)
    432		return err;
    433
    434	bcma_set_drvdata(core, usb_dev);
    435	return 0;
    436}
    437
    438static void bcma_hcd_remove(struct bcma_device *dev)
    439{
    440	struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
    441	struct platform_device *ohci_dev = usb_dev->ohci_dev;
    442	struct platform_device *ehci_dev = usb_dev->ehci_dev;
    443
    444	if (ohci_dev)
    445		platform_device_unregister(ohci_dev);
    446	if (ehci_dev)
    447		platform_device_unregister(ehci_dev);
    448
    449	bcma_core_disable(dev, 0);
    450}
    451
    452static void bcma_hcd_shutdown(struct bcma_device *dev)
    453{
    454	bcma_hci_platform_power_gpio(dev, false);
    455	bcma_core_disable(dev, 0);
    456}
    457
    458#ifdef CONFIG_PM
    459
    460static int bcma_hcd_suspend(struct bcma_device *dev)
    461{
    462	bcma_hci_platform_power_gpio(dev, false);
    463	bcma_core_disable(dev, 0);
    464
    465	return 0;
    466}
    467
    468static int bcma_hcd_resume(struct bcma_device *dev)
    469{
    470	bcma_hci_platform_power_gpio(dev, true);
    471	bcma_core_enable(dev, 0);
    472
    473	return 0;
    474}
    475
    476#else /* !CONFIG_PM */
    477#define bcma_hcd_suspend	NULL
    478#define bcma_hcd_resume	NULL
    479#endif /* CONFIG_PM */
    480
    481static const struct bcma_device_id bcma_hcd_table[] = {
    482	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS),
    483	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB20, BCMA_ANY_REV, BCMA_ANY_CLASS),
    484	BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB30, BCMA_ANY_REV, BCMA_ANY_CLASS),
    485	{},
    486};
    487MODULE_DEVICE_TABLE(bcma, bcma_hcd_table);
    488
    489static struct bcma_driver bcma_hcd_driver = {
    490	.name		= KBUILD_MODNAME,
    491	.id_table	= bcma_hcd_table,
    492	.probe		= bcma_hcd_probe,
    493	.remove		= bcma_hcd_remove,
    494	.shutdown	= bcma_hcd_shutdown,
    495	.suspend	= bcma_hcd_suspend,
    496	.resume		= bcma_hcd_resume,
    497};
    498module_bcma_driver(bcma_hcd_driver);