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

sdio.c (11455B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * This file is part of wl1271
      4 *
      5 * Copyright (C) 2009-2010 Nokia Corporation
      6 *
      7 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
      8 */
      9
     10#include <linux/irq.h>
     11#include <linux/module.h>
     12#include <linux/vmalloc.h>
     13#include <linux/platform_device.h>
     14#include <linux/mmc/sdio.h>
     15#include <linux/mmc/sdio_func.h>
     16#include <linux/mmc/sdio_ids.h>
     17#include <linux/mmc/card.h>
     18#include <linux/mmc/host.h>
     19#include <linux/gpio.h>
     20#include <linux/pm_runtime.h>
     21#include <linux/printk.h>
     22#include <linux/of.h>
     23#include <linux/of_irq.h>
     24
     25#include "wlcore.h"
     26#include "wl12xx_80211.h"
     27#include "io.h"
     28
     29static bool dump;
     30
     31struct wl12xx_sdio_glue {
     32	struct device *dev;
     33	struct platform_device *core;
     34};
     35
     36static const struct sdio_device_id wl1271_devices[] = {
     37	{ SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) },
     38	{}
     39};
     40MODULE_DEVICE_TABLE(sdio, wl1271_devices);
     41
     42static void wl1271_sdio_set_block_size(struct device *child,
     43				       unsigned int blksz)
     44{
     45	struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
     46	struct sdio_func *func = dev_to_sdio_func(glue->dev);
     47
     48	sdio_claim_host(func);
     49	sdio_set_block_size(func, blksz);
     50	sdio_release_host(func);
     51}
     52
     53static int __must_check wl12xx_sdio_raw_read(struct device *child, int addr,
     54					     void *buf, size_t len, bool fixed)
     55{
     56	int ret;
     57	struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
     58	struct sdio_func *func = dev_to_sdio_func(glue->dev);
     59
     60	sdio_claim_host(func);
     61
     62	if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG)) {
     63		((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
     64		dev_dbg(child->parent, "sdio read 52 addr 0x%x, byte 0x%02x\n",
     65			addr, ((u8 *)buf)[0]);
     66	} else {
     67		if (fixed)
     68			ret = sdio_readsb(func, buf, addr, len);
     69		else
     70			ret = sdio_memcpy_fromio(func, buf, addr, len);
     71
     72		dev_dbg(child->parent, "sdio read 53 addr 0x%x, %zu bytes\n",
     73			addr, len);
     74	}
     75
     76	sdio_release_host(func);
     77
     78	if (WARN_ON(ret))
     79		dev_err(child->parent, "sdio read failed (%d)\n", ret);
     80
     81	if (unlikely(dump)) {
     82		printk(KERN_DEBUG "wlcore_sdio: READ from 0x%04x\n", addr);
     83		print_hex_dump(KERN_DEBUG, "wlcore_sdio: READ ",
     84			       DUMP_PREFIX_OFFSET, 16, 1,
     85			       buf, len, false);
     86	}
     87
     88	return ret;
     89}
     90
     91static int __must_check wl12xx_sdio_raw_write(struct device *child, int addr,
     92					      void *buf, size_t len, bool fixed)
     93{
     94	int ret;
     95	struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
     96	struct sdio_func *func = dev_to_sdio_func(glue->dev);
     97
     98	sdio_claim_host(func);
     99
    100	if (unlikely(dump)) {
    101		printk(KERN_DEBUG "wlcore_sdio: WRITE to 0x%04x\n", addr);
    102		print_hex_dump(KERN_DEBUG, "wlcore_sdio: WRITE ",
    103				DUMP_PREFIX_OFFSET, 16, 1,
    104				buf, len, false);
    105	}
    106
    107	if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG)) {
    108		sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
    109		dev_dbg(child->parent, "sdio write 52 addr 0x%x, byte 0x%02x\n",
    110			addr, ((u8 *)buf)[0]);
    111	} else {
    112		dev_dbg(child->parent, "sdio write 53 addr 0x%x, %zu bytes\n",
    113			addr, len);
    114
    115		if (fixed)
    116			ret = sdio_writesb(func, addr, buf, len);
    117		else
    118			ret = sdio_memcpy_toio(func, addr, buf, len);
    119	}
    120
    121	sdio_release_host(func);
    122
    123	if (WARN_ON(ret))
    124		dev_err(child->parent, "sdio write failed (%d)\n", ret);
    125
    126	return ret;
    127}
    128
    129static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue)
    130{
    131	int ret;
    132	struct sdio_func *func = dev_to_sdio_func(glue->dev);
    133	struct mmc_card *card = func->card;
    134
    135	ret = pm_runtime_resume_and_get(&card->dev);
    136	if (ret < 0) {
    137		dev_err(glue->dev, "%s: failed to get_sync(%d)\n",
    138			__func__, ret);
    139
    140		return ret;
    141	}
    142
    143	sdio_claim_host(func);
    144	/*
    145	 * To guarantee that the SDIO card is power cycled, as required to make
    146	 * the FW programming to succeed, let's do a brute force HW reset.
    147	 */
    148	mmc_hw_reset(card);
    149
    150	sdio_enable_func(func);
    151	sdio_release_host(func);
    152
    153	return 0;
    154}
    155
    156static int wl12xx_sdio_power_off(struct wl12xx_sdio_glue *glue)
    157{
    158	struct sdio_func *func = dev_to_sdio_func(glue->dev);
    159	struct mmc_card *card = func->card;
    160
    161	sdio_claim_host(func);
    162	sdio_disable_func(func);
    163	sdio_release_host(func);
    164
    165	/* Let runtime PM know the card is powered off */
    166	pm_runtime_put(&card->dev);
    167	return 0;
    168}
    169
    170static int wl12xx_sdio_set_power(struct device *child, bool enable)
    171{
    172	struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent);
    173
    174	if (enable)
    175		return wl12xx_sdio_power_on(glue);
    176	else
    177		return wl12xx_sdio_power_off(glue);
    178}
    179
    180static struct wl1271_if_operations sdio_ops = {
    181	.read		= wl12xx_sdio_raw_read,
    182	.write		= wl12xx_sdio_raw_write,
    183	.power		= wl12xx_sdio_set_power,
    184	.set_block_size = wl1271_sdio_set_block_size,
    185};
    186
    187#ifdef CONFIG_OF
    188
    189static const struct wilink_family_data wl127x_data = {
    190	.name = "wl127x",
    191	.nvs_name = "ti-connectivity/wl127x-nvs.bin",
    192};
    193
    194static const struct wilink_family_data wl128x_data = {
    195	.name = "wl128x",
    196	.nvs_name = "ti-connectivity/wl128x-nvs.bin",
    197};
    198
    199static const struct wilink_family_data wl18xx_data = {
    200	.name = "wl18xx",
    201	.cfg_name = "ti-connectivity/wl18xx-conf.bin",
    202	.nvs_name = "ti-connectivity/wl1271-nvs.bin",
    203};
    204
    205static const struct of_device_id wlcore_sdio_of_match_table[] = {
    206	{ .compatible = "ti,wl1271", .data = &wl127x_data },
    207	{ .compatible = "ti,wl1273", .data = &wl127x_data },
    208	{ .compatible = "ti,wl1281", .data = &wl128x_data },
    209	{ .compatible = "ti,wl1283", .data = &wl128x_data },
    210	{ .compatible = "ti,wl1285", .data = &wl128x_data },
    211	{ .compatible = "ti,wl1801", .data = &wl18xx_data },
    212	{ .compatible = "ti,wl1805", .data = &wl18xx_data },
    213	{ .compatible = "ti,wl1807", .data = &wl18xx_data },
    214	{ .compatible = "ti,wl1831", .data = &wl18xx_data },
    215	{ .compatible = "ti,wl1835", .data = &wl18xx_data },
    216	{ .compatible = "ti,wl1837", .data = &wl18xx_data },
    217	{ }
    218};
    219
    220static int wlcore_probe_of(struct device *dev, int *irq, int *wakeirq,
    221			   struct wlcore_platdev_data *pdev_data)
    222{
    223	struct device_node *np = dev->of_node;
    224	const struct of_device_id *of_id;
    225
    226	of_id = of_match_node(wlcore_sdio_of_match_table, np);
    227	if (!of_id)
    228		return -ENODEV;
    229
    230	pdev_data->family = of_id->data;
    231
    232	*irq = irq_of_parse_and_map(np, 0);
    233	if (!*irq) {
    234		dev_err(dev, "No irq in platform data\n");
    235		return -EINVAL;
    236	}
    237
    238	*wakeirq = irq_of_parse_and_map(np, 1);
    239
    240	/* optional clock frequency params */
    241	of_property_read_u32(np, "ref-clock-frequency",
    242			     &pdev_data->ref_clock_freq);
    243	of_property_read_u32(np, "tcxo-clock-frequency",
    244			     &pdev_data->tcxo_clock_freq);
    245
    246	return 0;
    247}
    248#else
    249static int wlcore_probe_of(struct device *dev, int *irq, int *wakeirq,
    250			   struct wlcore_platdev_data *pdev_data)
    251{
    252	return -ENODATA;
    253}
    254#endif
    255
    256static int wl1271_probe(struct sdio_func *func,
    257				  const struct sdio_device_id *id)
    258{
    259	struct wlcore_platdev_data *pdev_data;
    260	struct wl12xx_sdio_glue *glue;
    261	struct resource res[2];
    262	mmc_pm_flag_t mmcflags;
    263	int ret = -ENOMEM;
    264	int irq, wakeirq, num_irqs;
    265	const char *chip_family;
    266
    267	/* We are only able to handle the wlan function */
    268	if (func->num != 0x02)
    269		return -ENODEV;
    270
    271	pdev_data = devm_kzalloc(&func->dev, sizeof(*pdev_data), GFP_KERNEL);
    272	if (!pdev_data)
    273		return -ENOMEM;
    274
    275	pdev_data->if_ops = &sdio_ops;
    276
    277	glue = devm_kzalloc(&func->dev, sizeof(*glue), GFP_KERNEL);
    278	if (!glue)
    279		return -ENOMEM;
    280
    281	glue->dev = &func->dev;
    282
    283	/* Grab access to FN0 for ELP reg. */
    284	func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
    285
    286	/* Use block mode for transferring over one block size of data */
    287	func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
    288
    289	ret = wlcore_probe_of(&func->dev, &irq, &wakeirq, pdev_data);
    290	if (ret)
    291		goto out;
    292
    293	/* if sdio can keep power while host is suspended, enable wow */
    294	mmcflags = sdio_get_host_pm_caps(func);
    295	dev_dbg(glue->dev, "sdio PM caps = 0x%x\n", mmcflags);
    296
    297	if (mmcflags & MMC_PM_KEEP_POWER)
    298		pdev_data->pwr_in_suspend = true;
    299
    300	sdio_set_drvdata(func, glue);
    301
    302	/* Tell PM core that we don't need the card to be powered now */
    303	pm_runtime_put_noidle(&func->dev);
    304
    305	/*
    306	 * Due to a hardware bug, we can't differentiate wl18xx from
    307	 * wl12xx, because both report the same device ID.  The only
    308	 * way to differentiate is by checking the SDIO revision,
    309	 * which is 3.00 on the wl18xx chips.
    310	 */
    311	if (func->card->cccr.sdio_vsn == SDIO_SDIO_REV_3_00)
    312		chip_family = "wl18xx";
    313	else
    314		chip_family = "wl12xx";
    315
    316	glue->core = platform_device_alloc(chip_family, PLATFORM_DEVID_AUTO);
    317	if (!glue->core) {
    318		dev_err(glue->dev, "can't allocate platform_device");
    319		ret = -ENOMEM;
    320		goto out;
    321	}
    322
    323	glue->core->dev.parent = &func->dev;
    324
    325	memset(res, 0x00, sizeof(res));
    326
    327	res[0].start = irq;
    328	res[0].flags = IORESOURCE_IRQ |
    329		       irqd_get_trigger_type(irq_get_irq_data(irq));
    330	res[0].name = "irq";
    331
    332
    333	if (wakeirq > 0) {
    334		res[1].start = wakeirq;
    335		res[1].flags = IORESOURCE_IRQ |
    336			       irqd_get_trigger_type(irq_get_irq_data(wakeirq));
    337		res[1].name = "wakeirq";
    338		num_irqs = 2;
    339	} else {
    340		num_irqs = 1;
    341	}
    342	ret = platform_device_add_resources(glue->core, res, num_irqs);
    343	if (ret) {
    344		dev_err(glue->dev, "can't add resources\n");
    345		goto out_dev_put;
    346	}
    347
    348	ret = platform_device_add_data(glue->core, pdev_data,
    349				       sizeof(*pdev_data));
    350	if (ret) {
    351		dev_err(glue->dev, "can't add platform data\n");
    352		goto out_dev_put;
    353	}
    354
    355	ret = platform_device_add(glue->core);
    356	if (ret) {
    357		dev_err(glue->dev, "can't add platform device\n");
    358		goto out_dev_put;
    359	}
    360	return 0;
    361
    362out_dev_put:
    363	platform_device_put(glue->core);
    364
    365out:
    366	return ret;
    367}
    368
    369static void wl1271_remove(struct sdio_func *func)
    370{
    371	struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func);
    372
    373	/* Undo decrement done above in wl1271_probe */
    374	pm_runtime_get_noresume(&func->dev);
    375
    376	platform_device_unregister(glue->core);
    377}
    378
    379#ifdef CONFIG_PM
    380static int wl1271_suspend(struct device *dev)
    381{
    382	/* Tell MMC/SDIO core it's OK to power down the card
    383	 * (if it isn't already), but not to remove it completely */
    384	struct sdio_func *func = dev_to_sdio_func(dev);
    385	struct wl12xx_sdio_glue *glue = sdio_get_drvdata(func);
    386	struct wl1271 *wl = platform_get_drvdata(glue->core);
    387	mmc_pm_flag_t sdio_flags;
    388	int ret = 0;
    389
    390	if (!wl) {
    391		dev_err(dev, "no wilink module was probed\n");
    392		goto out;
    393	}
    394
    395	dev_dbg(dev, "wl1271 suspend. wow_enabled: %d\n",
    396		wl->wow_enabled);
    397
    398	/* check whether sdio should keep power */
    399	if (wl->wow_enabled) {
    400		sdio_flags = sdio_get_host_pm_caps(func);
    401
    402		if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
    403			dev_err(dev, "can't keep power while host "
    404				     "is suspended\n");
    405			ret = -EINVAL;
    406			goto out;
    407		}
    408
    409		/* keep power while host suspended */
    410		ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
    411		if (ret) {
    412			dev_err(dev, "error while trying to keep power\n");
    413			goto out;
    414		}
    415	}
    416out:
    417	return ret;
    418}
    419
    420static int wl1271_resume(struct device *dev)
    421{
    422	dev_dbg(dev, "wl1271 resume\n");
    423
    424	return 0;
    425}
    426
    427static const struct dev_pm_ops wl1271_sdio_pm_ops = {
    428	.suspend	= wl1271_suspend,
    429	.resume		= wl1271_resume,
    430};
    431#endif
    432
    433static struct sdio_driver wl1271_sdio_driver = {
    434	.name		= "wl1271_sdio",
    435	.id_table	= wl1271_devices,
    436	.probe		= wl1271_probe,
    437	.remove		= wl1271_remove,
    438#ifdef CONFIG_PM
    439	.drv = {
    440		.pm = &wl1271_sdio_pm_ops,
    441	},
    442#endif
    443};
    444
    445static int __init wl1271_init(void)
    446{
    447	return sdio_register_driver(&wl1271_sdio_driver);
    448}
    449
    450static void __exit wl1271_exit(void)
    451{
    452	sdio_unregister_driver(&wl1271_sdio_driver);
    453}
    454
    455module_init(wl1271_init);
    456module_exit(wl1271_exit);
    457
    458module_param(dump, bool, 0600);
    459MODULE_PARM_DESC(dump, "Enable sdio read/write dumps.");
    460
    461MODULE_LICENSE("GPL");
    462MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
    463MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");