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

c_can_platform.c (13005B)


      1/*
      2 * Platform CAN bus driver for Bosch C_CAN controller
      3 *
      4 * Copyright (C) 2010 ST Microelectronics
      5 * Bhupesh Sharma <bhupesh.sharma@st.com>
      6 *
      7 * Borrowed heavily from the C_CAN driver originally written by:
      8 * Copyright (C) 2007
      9 * - Sascha Hauer, Marc Kleine-Budde, Pengutronix <s.hauer@pengutronix.de>
     10 * - Simon Kallweit, intefo AG <simon.kallweit@intefo.ch>
     11 *
     12 * Bosch C_CAN controller is compliant to CAN protocol version 2.0 part A and B.
     13 * Bosch C_CAN user manual can be obtained from:
     14 * http://www.semiconductors.bosch.de/media/en/pdf/ipmodules_1/c_can/
     15 * users_manual_c_can.pdf
     16 *
     17 * This file is licensed under the terms of the GNU General Public
     18 * License version 2. This program is licensed "as is" without any
     19 * warranty of any kind, whether express or implied.
     20 */
     21
     22#include <linux/kernel.h>
     23#include <linux/module.h>
     24#include <linux/interrupt.h>
     25#include <linux/delay.h>
     26#include <linux/netdevice.h>
     27#include <linux/if_arp.h>
     28#include <linux/if_ether.h>
     29#include <linux/list.h>
     30#include <linux/io.h>
     31#include <linux/platform_device.h>
     32#include <linux/pm_runtime.h>
     33#include <linux/clk.h>
     34#include <linux/of.h>
     35#include <linux/of_device.h>
     36#include <linux/mfd/syscon.h>
     37#include <linux/regmap.h>
     38
     39#include <linux/can/dev.h>
     40
     41#include "c_can.h"
     42
     43#define DCAN_RAM_INIT_BIT BIT(3)
     44
     45static DEFINE_SPINLOCK(raminit_lock);
     46
     47/* 16-bit c_can registers can be arranged differently in the memory
     48 * architecture of different implementations. For example: 16-bit
     49 * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
     50 * Handle the same by providing a common read/write interface.
     51 */
     52static u16 c_can_plat_read_reg_aligned_to_16bit(const struct c_can_priv *priv,
     53						enum reg index)
     54{
     55	return readw(priv->base + priv->regs[index]);
     56}
     57
     58static void c_can_plat_write_reg_aligned_to_16bit(const struct c_can_priv *priv,
     59						  enum reg index, u16 val)
     60{
     61	writew(val, priv->base + priv->regs[index]);
     62}
     63
     64static u16 c_can_plat_read_reg_aligned_to_32bit(const struct c_can_priv *priv,
     65						enum reg index)
     66{
     67	return readw(priv->base + 2 * priv->regs[index]);
     68}
     69
     70static void c_can_plat_write_reg_aligned_to_32bit(const struct c_can_priv *priv,
     71						  enum reg index, u16 val)
     72{
     73	writew(val, priv->base + 2 * priv->regs[index]);
     74}
     75
     76static void c_can_hw_raminit_wait_syscon(const struct c_can_priv *priv,
     77					 u32 mask, u32 val)
     78{
     79	const struct c_can_raminit *raminit = &priv->raminit_sys;
     80	int timeout = 0;
     81	u32 ctrl = 0;
     82
     83	/* We look only at the bits of our instance. */
     84	val &= mask;
     85	do {
     86		udelay(1);
     87		timeout++;
     88
     89		regmap_read(raminit->syscon, raminit->reg, &ctrl);
     90		if (timeout == 1000) {
     91			dev_err(&priv->dev->dev, "%s: time out\n", __func__);
     92			break;
     93		}
     94	} while ((ctrl & mask) != val);
     95}
     96
     97static void c_can_hw_raminit_syscon(const struct c_can_priv *priv, bool enable)
     98{
     99	const struct c_can_raminit *raminit = &priv->raminit_sys;
    100	u32 ctrl = 0;
    101	u32 mask;
    102
    103	spin_lock(&raminit_lock);
    104
    105	mask = 1 << raminit->bits.start | 1 << raminit->bits.done;
    106	regmap_read(raminit->syscon, raminit->reg, &ctrl);
    107
    108	/* We clear the start bit first. The start bit is
    109	 * looking at the 0 -> transition, but is not self clearing;
    110	 * NOTE: DONE must be written with 1 to clear it.
    111	 * We can't clear the DONE bit here using regmap_update_bits()
    112	 * as it will bypass the write if initial condition is START:0 DONE:1
    113	 * e.g. on DRA7 which needs START pulse.
    114	 */
    115	ctrl &= ~mask;	/* START = 0, DONE = 0 */
    116	regmap_update_bits(raminit->syscon, raminit->reg, mask, ctrl);
    117
    118	/* check if START bit is 0. Ignore DONE bit for now
    119	 * as it can be either 0 or 1.
    120	 */
    121	c_can_hw_raminit_wait_syscon(priv, 1 << raminit->bits.start, ctrl);
    122
    123	if (enable) {
    124		/* Clear DONE bit & set START bit. */
    125		ctrl |= 1 << raminit->bits.start;
    126		/* DONE must be written with 1 to clear it */
    127		ctrl |= 1 << raminit->bits.done;
    128		regmap_update_bits(raminit->syscon, raminit->reg, mask, ctrl);
    129		/* prevent further clearing of DONE bit */
    130		ctrl &= ~(1 << raminit->bits.done);
    131		/* clear START bit if start pulse is needed */
    132		if (raminit->needs_pulse) {
    133			ctrl &= ~(1 << raminit->bits.start);
    134			regmap_update_bits(raminit->syscon, raminit->reg,
    135					   mask, ctrl);
    136		}
    137
    138		ctrl |= 1 << raminit->bits.done;
    139		c_can_hw_raminit_wait_syscon(priv, mask, ctrl);
    140	}
    141	spin_unlock(&raminit_lock);
    142}
    143
    144static u32 c_can_plat_read_reg32(const struct c_can_priv *priv, enum reg index)
    145{
    146	u32 val;
    147
    148	val = priv->read_reg(priv, index);
    149	val |= ((u32)priv->read_reg(priv, index + 1)) << 16;
    150
    151	return val;
    152}
    153
    154static void c_can_plat_write_reg32(const struct c_can_priv *priv,
    155				   enum reg index, u32 val)
    156{
    157	priv->write_reg(priv, index + 1, val >> 16);
    158	priv->write_reg(priv, index, val);
    159}
    160
    161static u32 d_can_plat_read_reg32(const struct c_can_priv *priv, enum reg index)
    162{
    163	return readl(priv->base + priv->regs[index]);
    164}
    165
    166static void d_can_plat_write_reg32(const struct c_can_priv *priv,
    167				   enum reg index, u32 val)
    168{
    169	writel(val, priv->base + priv->regs[index]);
    170}
    171
    172static void c_can_hw_raminit_wait(const struct c_can_priv *priv, u32 mask)
    173{
    174	while (priv->read_reg32(priv, C_CAN_FUNCTION_REG) & mask)
    175		udelay(1);
    176}
    177
    178static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable)
    179{
    180	u32 ctrl;
    181
    182	ctrl = priv->read_reg32(priv, C_CAN_FUNCTION_REG);
    183	ctrl &= ~DCAN_RAM_INIT_BIT;
    184	priv->write_reg32(priv, C_CAN_FUNCTION_REG, ctrl);
    185	c_can_hw_raminit_wait(priv, ctrl);
    186
    187	if (enable) {
    188		ctrl |= DCAN_RAM_INIT_BIT;
    189		priv->write_reg32(priv, C_CAN_FUNCTION_REG, ctrl);
    190		c_can_hw_raminit_wait(priv, ctrl);
    191	}
    192}
    193
    194static const struct c_can_driver_data c_can_drvdata = {
    195	.id = BOSCH_C_CAN,
    196	.msg_obj_num = 32,
    197};
    198
    199static const struct c_can_driver_data d_can_drvdata = {
    200	.id = BOSCH_D_CAN,
    201	.msg_obj_num = 32,
    202};
    203
    204static const struct raminit_bits dra7_raminit_bits[] = {
    205	[0] = { .start = 3, .done = 1, },
    206	[1] = { .start = 5, .done = 2, },
    207};
    208
    209static const struct c_can_driver_data dra7_dcan_drvdata = {
    210	.id = BOSCH_D_CAN,
    211	.msg_obj_num = 64,
    212	.raminit_num = ARRAY_SIZE(dra7_raminit_bits),
    213	.raminit_bits = dra7_raminit_bits,
    214	.raminit_pulse = true,
    215};
    216
    217static const struct raminit_bits am3352_raminit_bits[] = {
    218	[0] = { .start = 0, .done = 8, },
    219	[1] = { .start = 1, .done = 9, },
    220};
    221
    222static const struct c_can_driver_data am3352_dcan_drvdata = {
    223	.id = BOSCH_D_CAN,
    224	.msg_obj_num = 64,
    225	.raminit_num = ARRAY_SIZE(am3352_raminit_bits),
    226	.raminit_bits = am3352_raminit_bits,
    227};
    228
    229static const struct platform_device_id c_can_id_table[] = {
    230	{
    231		.name = KBUILD_MODNAME,
    232		.driver_data = (kernel_ulong_t)&c_can_drvdata,
    233	},
    234	{
    235		.name = "c_can",
    236		.driver_data = (kernel_ulong_t)&c_can_drvdata,
    237	},
    238	{
    239		.name = "d_can",
    240		.driver_data = (kernel_ulong_t)&d_can_drvdata,
    241	},
    242	{ /* sentinel */ },
    243};
    244MODULE_DEVICE_TABLE(platform, c_can_id_table);
    245
    246static const struct of_device_id c_can_of_table[] = {
    247	{ .compatible = "bosch,c_can", .data = &c_can_drvdata },
    248	{ .compatible = "bosch,d_can", .data = &d_can_drvdata },
    249	{ .compatible = "ti,dra7-d_can", .data = &dra7_dcan_drvdata },
    250	{ .compatible = "ti,am3352-d_can", .data = &am3352_dcan_drvdata },
    251	{ .compatible = "ti,am4372-d_can", .data = &am3352_dcan_drvdata },
    252	{ /* sentinel */ },
    253};
    254MODULE_DEVICE_TABLE(of, c_can_of_table);
    255
    256static int c_can_plat_probe(struct platform_device *pdev)
    257{
    258	int ret;
    259	void __iomem *addr;
    260	struct net_device *dev;
    261	struct c_can_priv *priv;
    262	const struct of_device_id *match;
    263	struct resource *mem;
    264	int irq;
    265	struct clk *clk;
    266	const struct c_can_driver_data *drvdata;
    267	struct device_node *np = pdev->dev.of_node;
    268
    269	match = of_match_device(c_can_of_table, &pdev->dev);
    270	if (match) {
    271		drvdata = match->data;
    272	} else if (pdev->id_entry->driver_data) {
    273		drvdata = (struct c_can_driver_data *)
    274			platform_get_device_id(pdev)->driver_data;
    275	} else {
    276		return -ENODEV;
    277	}
    278
    279	/* get the appropriate clk */
    280	clk = devm_clk_get(&pdev->dev, NULL);
    281	if (IS_ERR(clk)) {
    282		ret = PTR_ERR(clk);
    283		goto exit;
    284	}
    285
    286	/* get the platform data */
    287	irq = platform_get_irq(pdev, 0);
    288	if (irq <= 0) {
    289		ret = -ENODEV;
    290		goto exit;
    291	}
    292
    293	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    294	addr = devm_ioremap_resource(&pdev->dev, mem);
    295	if (IS_ERR(addr)) {
    296		ret =  PTR_ERR(addr);
    297		goto exit;
    298	}
    299
    300	/* allocate the c_can device */
    301	dev = alloc_c_can_dev(drvdata->msg_obj_num);
    302	if (!dev) {
    303		ret = -ENOMEM;
    304		goto exit;
    305	}
    306
    307	priv = netdev_priv(dev);
    308	switch (drvdata->id) {
    309	case BOSCH_C_CAN:
    310		priv->regs = reg_map_c_can;
    311		switch (mem->flags & IORESOURCE_MEM_TYPE_MASK) {
    312		case IORESOURCE_MEM_32BIT:
    313			priv->read_reg = c_can_plat_read_reg_aligned_to_32bit;
    314			priv->write_reg = c_can_plat_write_reg_aligned_to_32bit;
    315			priv->read_reg32 = c_can_plat_read_reg32;
    316			priv->write_reg32 = c_can_plat_write_reg32;
    317			break;
    318		case IORESOURCE_MEM_16BIT:
    319		default:
    320			priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
    321			priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
    322			priv->read_reg32 = c_can_plat_read_reg32;
    323			priv->write_reg32 = c_can_plat_write_reg32;
    324			break;
    325		}
    326		break;
    327	case BOSCH_D_CAN:
    328		priv->regs = reg_map_d_can;
    329		priv->read_reg = c_can_plat_read_reg_aligned_to_16bit;
    330		priv->write_reg = c_can_plat_write_reg_aligned_to_16bit;
    331		priv->read_reg32 = d_can_plat_read_reg32;
    332		priv->write_reg32 = d_can_plat_write_reg32;
    333
    334		/* Check if we need custom RAMINIT via syscon. Mostly for TI
    335		 * platforms. Only supported with DT boot.
    336		 */
    337		if (np && of_property_read_bool(np, "syscon-raminit")) {
    338			u32 id;
    339			struct c_can_raminit *raminit = &priv->raminit_sys;
    340
    341			ret = -EINVAL;
    342			raminit->syscon = syscon_regmap_lookup_by_phandle(np,
    343									  "syscon-raminit");
    344			if (IS_ERR(raminit->syscon)) {
    345				/* can fail with -EPROBE_DEFER */
    346				ret = PTR_ERR(raminit->syscon);
    347				free_c_can_dev(dev);
    348				return ret;
    349			}
    350
    351			if (of_property_read_u32_index(np, "syscon-raminit", 1,
    352						       &raminit->reg)) {
    353				dev_err(&pdev->dev,
    354					"couldn't get the RAMINIT reg. offset!\n");
    355				goto exit_free_device;
    356			}
    357
    358			if (of_property_read_u32_index(np, "syscon-raminit", 2,
    359						       &id)) {
    360				dev_err(&pdev->dev,
    361					"couldn't get the CAN instance ID\n");
    362				goto exit_free_device;
    363			}
    364
    365			if (id >= drvdata->raminit_num) {
    366				dev_err(&pdev->dev,
    367					"Invalid CAN instance ID\n");
    368				goto exit_free_device;
    369			}
    370
    371			raminit->bits = drvdata->raminit_bits[id];
    372			raminit->needs_pulse = drvdata->raminit_pulse;
    373
    374			priv->raminit = c_can_hw_raminit_syscon;
    375		} else {
    376			priv->raminit = c_can_hw_raminit;
    377		}
    378		break;
    379	default:
    380		ret = -EINVAL;
    381		goto exit_free_device;
    382	}
    383
    384	dev->irq = irq;
    385	priv->base = addr;
    386	priv->device = &pdev->dev;
    387	priv->can.clock.freq = clk_get_rate(clk);
    388	priv->type = drvdata->id;
    389
    390	platform_set_drvdata(pdev, dev);
    391	SET_NETDEV_DEV(dev, &pdev->dev);
    392
    393	pm_runtime_enable(priv->device);
    394	ret = register_c_can_dev(dev);
    395	if (ret) {
    396		dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
    397			KBUILD_MODNAME, ret);
    398		goto exit_free_device;
    399	}
    400
    401	dev_info(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
    402		 KBUILD_MODNAME, priv->base, dev->irq);
    403	return 0;
    404
    405exit_free_device:
    406	pm_runtime_disable(priv->device);
    407	free_c_can_dev(dev);
    408exit:
    409	dev_err(&pdev->dev, "probe failed\n");
    410
    411	return ret;
    412}
    413
    414static int c_can_plat_remove(struct platform_device *pdev)
    415{
    416	struct net_device *dev = platform_get_drvdata(pdev);
    417	struct c_can_priv *priv = netdev_priv(dev);
    418
    419	unregister_c_can_dev(dev);
    420	pm_runtime_disable(priv->device);
    421	free_c_can_dev(dev);
    422
    423	return 0;
    424}
    425
    426#ifdef CONFIG_PM
    427static int c_can_suspend(struct platform_device *pdev, pm_message_t state)
    428{
    429	int ret;
    430	struct net_device *ndev = platform_get_drvdata(pdev);
    431	struct c_can_priv *priv = netdev_priv(ndev);
    432
    433	if (priv->type != BOSCH_D_CAN) {
    434		dev_warn(&pdev->dev, "Not supported\n");
    435		return 0;
    436	}
    437
    438	if (netif_running(ndev)) {
    439		netif_stop_queue(ndev);
    440		netif_device_detach(ndev);
    441	}
    442
    443	ret = c_can_power_down(ndev);
    444	if (ret) {
    445		netdev_err(ndev, "failed to enter power down mode\n");
    446		return ret;
    447	}
    448
    449	priv->can.state = CAN_STATE_SLEEPING;
    450
    451	return 0;
    452}
    453
    454static int c_can_resume(struct platform_device *pdev)
    455{
    456	int ret;
    457	struct net_device *ndev = platform_get_drvdata(pdev);
    458	struct c_can_priv *priv = netdev_priv(ndev);
    459
    460	if (priv->type != BOSCH_D_CAN) {
    461		dev_warn(&pdev->dev, "Not supported\n");
    462		return 0;
    463	}
    464
    465	ret = c_can_power_up(ndev);
    466	if (ret) {
    467		netdev_err(ndev, "Still in power down mode\n");
    468		return ret;
    469	}
    470
    471	priv->can.state = CAN_STATE_ERROR_ACTIVE;
    472
    473	if (netif_running(ndev)) {
    474		netif_device_attach(ndev);
    475		netif_start_queue(ndev);
    476	}
    477
    478	return 0;
    479}
    480#else
    481#define c_can_suspend NULL
    482#define c_can_resume NULL
    483#endif
    484
    485static struct platform_driver c_can_plat_driver = {
    486	.driver = {
    487		.name = KBUILD_MODNAME,
    488		.of_match_table = c_can_of_table,
    489	},
    490	.probe = c_can_plat_probe,
    491	.remove = c_can_plat_remove,
    492	.suspend = c_can_suspend,
    493	.resume = c_can_resume,
    494	.id_table = c_can_id_table,
    495};
    496
    497module_platform_driver(c_can_plat_driver);
    498
    499MODULE_AUTHOR("Bhupesh Sharma <bhupesh.sharma@st.com>");
    500MODULE_LICENSE("GPL v2");
    501MODULE_DESCRIPTION("Platform CAN bus driver for Bosch C_CAN controller");