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

ti-eqep.c (11626B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2019 David Lechner <david@lechnology.com>
      4 *
      5 * Counter driver for Texas Instruments Enhanced Quadrature Encoder Pulse (eQEP)
      6 */
      7
      8#include <linux/bitops.h>
      9#include <linux/counter.h>
     10#include <linux/kernel.h>
     11#include <linux/mod_devicetable.h>
     12#include <linux/module.h>
     13#include <linux/platform_device.h>
     14#include <linux/pm_runtime.h>
     15#include <linux/regmap.h>
     16#include <linux/types.h>
     17
     18/* 32-bit registers */
     19#define QPOSCNT		0x0
     20#define QPOSINIT	0x4
     21#define QPOSMAX		0x8
     22#define QPOSCMP		0xc
     23#define QPOSILAT	0x10
     24#define QPOSSLAT	0x14
     25#define QPOSLAT		0x18
     26#define QUTMR		0x1c
     27#define QUPRD		0x20
     28
     29/* 16-bit registers */
     30#define QWDTMR		0x0	/* 0x24 */
     31#define QWDPRD		0x2	/* 0x26 */
     32#define QDECCTL		0x4	/* 0x28 */
     33#define QEPCTL		0x6	/* 0x2a */
     34#define QCAPCTL		0x8	/* 0x2c */
     35#define QPOSCTL		0xa	/* 0x2e */
     36#define QEINT		0xc	/* 0x30 */
     37#define QFLG		0xe	/* 0x32 */
     38#define QCLR		0x10	/* 0x34 */
     39#define QFRC		0x12	/* 0x36 */
     40#define QEPSTS		0x14	/* 0x38 */
     41#define QCTMR		0x16	/* 0x3a */
     42#define QCPRD		0x18	/* 0x3c */
     43#define QCTMRLAT	0x1a	/* 0x3e */
     44#define QCPRDLAT	0x1c	/* 0x40 */
     45
     46#define QDECCTL_QSRC_SHIFT	14
     47#define QDECCTL_QSRC		GENMASK(15, 14)
     48#define QDECCTL_SOEN		BIT(13)
     49#define QDECCTL_SPSEL		BIT(12)
     50#define QDECCTL_XCR		BIT(11)
     51#define QDECCTL_SWAP		BIT(10)
     52#define QDECCTL_IGATE		BIT(9)
     53#define QDECCTL_QAP		BIT(8)
     54#define QDECCTL_QBP		BIT(7)
     55#define QDECCTL_QIP		BIT(6)
     56#define QDECCTL_QSP		BIT(5)
     57
     58#define QEPCTL_FREE_SOFT	GENMASK(15, 14)
     59#define QEPCTL_PCRM		GENMASK(13, 12)
     60#define QEPCTL_SEI		GENMASK(11, 10)
     61#define QEPCTL_IEI		GENMASK(9, 8)
     62#define QEPCTL_SWI		BIT(7)
     63#define QEPCTL_SEL		BIT(6)
     64#define QEPCTL_IEL		GENMASK(5, 4)
     65#define QEPCTL_PHEN		BIT(3)
     66#define QEPCTL_QCLM		BIT(2)
     67#define QEPCTL_UTE		BIT(1)
     68#define QEPCTL_WDE		BIT(0)
     69
     70/* EQEP Inputs */
     71enum {
     72	TI_EQEP_SIGNAL_QEPA,	/* QEPA/XCLK */
     73	TI_EQEP_SIGNAL_QEPB,	/* QEPB/XDIR */
     74};
     75
     76/* Position Counter Input Modes */
     77enum ti_eqep_count_func {
     78	TI_EQEP_COUNT_FUNC_QUAD_COUNT,
     79	TI_EQEP_COUNT_FUNC_DIR_COUNT,
     80	TI_EQEP_COUNT_FUNC_UP_COUNT,
     81	TI_EQEP_COUNT_FUNC_DOWN_COUNT,
     82};
     83
     84struct ti_eqep_cnt {
     85	struct counter_device counter;
     86	struct regmap *regmap32;
     87	struct regmap *regmap16;
     88};
     89
     90static struct ti_eqep_cnt *ti_eqep_count_from_counter(struct counter_device *counter)
     91{
     92	return counter_priv(counter);
     93}
     94
     95static int ti_eqep_count_read(struct counter_device *counter,
     96			      struct counter_count *count, u64 *val)
     97{
     98	struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter);
     99	u32 cnt;
    100
    101	regmap_read(priv->regmap32, QPOSCNT, &cnt);
    102	*val = cnt;
    103
    104	return 0;
    105}
    106
    107static int ti_eqep_count_write(struct counter_device *counter,
    108			       struct counter_count *count, u64 val)
    109{
    110	struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter);
    111	u32 max;
    112
    113	regmap_read(priv->regmap32, QPOSMAX, &max);
    114	if (val > max)
    115		return -EINVAL;
    116
    117	return regmap_write(priv->regmap32, QPOSCNT, val);
    118}
    119
    120static int ti_eqep_function_read(struct counter_device *counter,
    121				 struct counter_count *count,
    122				 enum counter_function *function)
    123{
    124	struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter);
    125	u32 qdecctl;
    126
    127	regmap_read(priv->regmap16, QDECCTL, &qdecctl);
    128
    129	switch ((qdecctl & QDECCTL_QSRC) >> QDECCTL_QSRC_SHIFT) {
    130	case TI_EQEP_COUNT_FUNC_QUAD_COUNT:
    131		*function = COUNTER_FUNCTION_QUADRATURE_X4;
    132		break;
    133	case TI_EQEP_COUNT_FUNC_DIR_COUNT:
    134		*function = COUNTER_FUNCTION_PULSE_DIRECTION;
    135		break;
    136	case TI_EQEP_COUNT_FUNC_UP_COUNT:
    137		*function = COUNTER_FUNCTION_INCREASE;
    138		break;
    139	case TI_EQEP_COUNT_FUNC_DOWN_COUNT:
    140		*function = COUNTER_FUNCTION_DECREASE;
    141		break;
    142	}
    143
    144	return 0;
    145}
    146
    147static int ti_eqep_function_write(struct counter_device *counter,
    148				  struct counter_count *count,
    149				  enum counter_function function)
    150{
    151	struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter);
    152	enum ti_eqep_count_func qsrc;
    153
    154	switch (function) {
    155	case COUNTER_FUNCTION_QUADRATURE_X4:
    156		qsrc = TI_EQEP_COUNT_FUNC_QUAD_COUNT;
    157		break;
    158	case COUNTER_FUNCTION_PULSE_DIRECTION:
    159		qsrc = TI_EQEP_COUNT_FUNC_DIR_COUNT;
    160		break;
    161	case COUNTER_FUNCTION_INCREASE:
    162		qsrc = TI_EQEP_COUNT_FUNC_UP_COUNT;
    163		break;
    164	case COUNTER_FUNCTION_DECREASE:
    165		qsrc = TI_EQEP_COUNT_FUNC_DOWN_COUNT;
    166		break;
    167	default:
    168		/* should never reach this path */
    169		return -EINVAL;
    170	}
    171
    172	return regmap_write_bits(priv->regmap16, QDECCTL, QDECCTL_QSRC,
    173				 qsrc << QDECCTL_QSRC_SHIFT);
    174}
    175
    176static int ti_eqep_action_read(struct counter_device *counter,
    177			       struct counter_count *count,
    178			       struct counter_synapse *synapse,
    179			       enum counter_synapse_action *action)
    180{
    181	struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter);
    182	enum counter_function function;
    183	u32 qdecctl;
    184	int err;
    185
    186	err = ti_eqep_function_read(counter, count, &function);
    187	if (err)
    188		return err;
    189
    190	switch (function) {
    191	case COUNTER_FUNCTION_QUADRATURE_X4:
    192		/* In quadrature mode, the rising and falling edge of both
    193		 * QEPA and QEPB trigger QCLK.
    194		 */
    195		*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
    196		return 0;
    197	case COUNTER_FUNCTION_PULSE_DIRECTION:
    198		/* In direction-count mode only rising edge of QEPA is counted
    199		 * and QEPB gives direction.
    200		 */
    201		switch (synapse->signal->id) {
    202		case TI_EQEP_SIGNAL_QEPA:
    203			*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
    204			return 0;
    205		case TI_EQEP_SIGNAL_QEPB:
    206			*action = COUNTER_SYNAPSE_ACTION_NONE;
    207			return 0;
    208		default:
    209			/* should never reach this path */
    210			return -EINVAL;
    211		}
    212	case COUNTER_FUNCTION_INCREASE:
    213	case COUNTER_FUNCTION_DECREASE:
    214		/* In up/down-count modes only QEPA is counted and QEPB is not
    215		 * used.
    216		 */
    217		switch (synapse->signal->id) {
    218		case TI_EQEP_SIGNAL_QEPA:
    219			err = regmap_read(priv->regmap16, QDECCTL, &qdecctl);
    220			if (err)
    221				return err;
    222
    223			if (qdecctl & QDECCTL_XCR)
    224				*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
    225			else
    226				*action = COUNTER_SYNAPSE_ACTION_RISING_EDGE;
    227			return 0;
    228		case TI_EQEP_SIGNAL_QEPB:
    229			*action = COUNTER_SYNAPSE_ACTION_NONE;
    230			return 0;
    231		default:
    232			/* should never reach this path */
    233			return -EINVAL;
    234		}
    235	default:
    236		/* should never reach this path */
    237		return -EINVAL;
    238	}
    239}
    240
    241static const struct counter_ops ti_eqep_counter_ops = {
    242	.count_read	= ti_eqep_count_read,
    243	.count_write	= ti_eqep_count_write,
    244	.function_read	= ti_eqep_function_read,
    245	.function_write	= ti_eqep_function_write,
    246	.action_read	= ti_eqep_action_read,
    247};
    248
    249static int ti_eqep_position_ceiling_read(struct counter_device *counter,
    250					 struct counter_count *count,
    251					 u64 *ceiling)
    252{
    253	struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter);
    254	u32 qposmax;
    255
    256	regmap_read(priv->regmap32, QPOSMAX, &qposmax);
    257
    258	*ceiling = qposmax;
    259
    260	return 0;
    261}
    262
    263static int ti_eqep_position_ceiling_write(struct counter_device *counter,
    264					  struct counter_count *count,
    265					  u64 ceiling)
    266{
    267	struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter);
    268
    269	if (ceiling != (u32)ceiling)
    270		return -ERANGE;
    271
    272	regmap_write(priv->regmap32, QPOSMAX, ceiling);
    273
    274	return 0;
    275}
    276
    277static int ti_eqep_position_enable_read(struct counter_device *counter,
    278					struct counter_count *count, u8 *enable)
    279{
    280	struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter);
    281	u32 qepctl;
    282
    283	regmap_read(priv->regmap16, QEPCTL, &qepctl);
    284
    285	*enable = !!(qepctl & QEPCTL_PHEN);
    286
    287	return 0;
    288}
    289
    290static int ti_eqep_position_enable_write(struct counter_device *counter,
    291					 struct counter_count *count, u8 enable)
    292{
    293	struct ti_eqep_cnt *priv = ti_eqep_count_from_counter(counter);
    294
    295	regmap_write_bits(priv->regmap16, QEPCTL, QEPCTL_PHEN, enable ? -1 : 0);
    296
    297	return 0;
    298}
    299
    300static struct counter_comp ti_eqep_position_ext[] = {
    301	COUNTER_COMP_CEILING(ti_eqep_position_ceiling_read,
    302			     ti_eqep_position_ceiling_write),
    303	COUNTER_COMP_ENABLE(ti_eqep_position_enable_read,
    304			    ti_eqep_position_enable_write),
    305};
    306
    307static struct counter_signal ti_eqep_signals[] = {
    308	[TI_EQEP_SIGNAL_QEPA] = {
    309		.id = TI_EQEP_SIGNAL_QEPA,
    310		.name = "QEPA"
    311	},
    312	[TI_EQEP_SIGNAL_QEPB] = {
    313		.id = TI_EQEP_SIGNAL_QEPB,
    314		.name = "QEPB"
    315	},
    316};
    317
    318static const enum counter_function ti_eqep_position_functions[] = {
    319	COUNTER_FUNCTION_QUADRATURE_X4,
    320	COUNTER_FUNCTION_PULSE_DIRECTION,
    321	COUNTER_FUNCTION_INCREASE,
    322	COUNTER_FUNCTION_DECREASE,
    323};
    324
    325static const enum counter_synapse_action ti_eqep_position_synapse_actions[] = {
    326	COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
    327	COUNTER_SYNAPSE_ACTION_RISING_EDGE,
    328	COUNTER_SYNAPSE_ACTION_NONE,
    329};
    330
    331static struct counter_synapse ti_eqep_position_synapses[] = {
    332	{
    333		.actions_list	= ti_eqep_position_synapse_actions,
    334		.num_actions	= ARRAY_SIZE(ti_eqep_position_synapse_actions),
    335		.signal		= &ti_eqep_signals[TI_EQEP_SIGNAL_QEPA],
    336	},
    337	{
    338		.actions_list	= ti_eqep_position_synapse_actions,
    339		.num_actions	= ARRAY_SIZE(ti_eqep_position_synapse_actions),
    340		.signal		= &ti_eqep_signals[TI_EQEP_SIGNAL_QEPB],
    341	},
    342};
    343
    344static struct counter_count ti_eqep_counts[] = {
    345	{
    346		.id		= 0,
    347		.name		= "QPOSCNT",
    348		.functions_list	= ti_eqep_position_functions,
    349		.num_functions	= ARRAY_SIZE(ti_eqep_position_functions),
    350		.synapses	= ti_eqep_position_synapses,
    351		.num_synapses	= ARRAY_SIZE(ti_eqep_position_synapses),
    352		.ext		= ti_eqep_position_ext,
    353		.num_ext	= ARRAY_SIZE(ti_eqep_position_ext),
    354	},
    355};
    356
    357static const struct regmap_config ti_eqep_regmap32_config = {
    358	.name = "32-bit",
    359	.reg_bits = 32,
    360	.val_bits = 32,
    361	.reg_stride = 4,
    362	.max_register = QUPRD,
    363};
    364
    365static const struct regmap_config ti_eqep_regmap16_config = {
    366	.name = "16-bit",
    367	.reg_bits = 16,
    368	.val_bits = 16,
    369	.reg_stride = 2,
    370	.max_register = QCPRDLAT,
    371};
    372
    373static int ti_eqep_probe(struct platform_device *pdev)
    374{
    375	struct device *dev = &pdev->dev;
    376	struct counter_device *counter;
    377	struct ti_eqep_cnt *priv;
    378	void __iomem *base;
    379	int err;
    380
    381	counter = devm_counter_alloc(dev, sizeof(*priv));
    382	if (!counter)
    383		return -ENOMEM;
    384	priv = counter_priv(counter);
    385
    386	base = devm_platform_ioremap_resource(pdev, 0);
    387	if (IS_ERR(base))
    388		return PTR_ERR(base);
    389
    390	priv->regmap32 = devm_regmap_init_mmio(dev, base,
    391					       &ti_eqep_regmap32_config);
    392	if (IS_ERR(priv->regmap32))
    393		return PTR_ERR(priv->regmap32);
    394
    395	priv->regmap16 = devm_regmap_init_mmio(dev, base + 0x24,
    396					       &ti_eqep_regmap16_config);
    397	if (IS_ERR(priv->regmap16))
    398		return PTR_ERR(priv->regmap16);
    399
    400	counter->name = dev_name(dev);
    401	counter->parent = dev;
    402	counter->ops = &ti_eqep_counter_ops;
    403	counter->counts = ti_eqep_counts;
    404	counter->num_counts = ARRAY_SIZE(ti_eqep_counts);
    405	counter->signals = ti_eqep_signals;
    406	counter->num_signals = ARRAY_SIZE(ti_eqep_signals);
    407
    408	platform_set_drvdata(pdev, counter);
    409
    410	/*
    411	 * Need to make sure power is turned on. On AM33xx, this comes from the
    412	 * parent PWMSS bus driver. On AM17xx, this comes from the PSC power
    413	 * domain.
    414	 */
    415	pm_runtime_enable(dev);
    416	pm_runtime_get_sync(dev);
    417
    418	err = counter_add(counter);
    419	if (err < 0) {
    420		pm_runtime_put_sync(dev);
    421		pm_runtime_disable(dev);
    422		return err;
    423	}
    424
    425	return 0;
    426}
    427
    428static int ti_eqep_remove(struct platform_device *pdev)
    429{
    430	struct counter_device *counter = platform_get_drvdata(pdev);
    431	struct device *dev = &pdev->dev;
    432
    433	counter_unregister(counter);
    434	pm_runtime_put_sync(dev);
    435	pm_runtime_disable(dev);
    436
    437	return 0;
    438}
    439
    440static const struct of_device_id ti_eqep_of_match[] = {
    441	{ .compatible = "ti,am3352-eqep", },
    442	{ },
    443};
    444MODULE_DEVICE_TABLE(of, ti_eqep_of_match);
    445
    446static struct platform_driver ti_eqep_driver = {
    447	.probe = ti_eqep_probe,
    448	.remove = ti_eqep_remove,
    449	.driver = {
    450		.name = "ti-eqep-cnt",
    451		.of_match_table = ti_eqep_of_match,
    452	},
    453};
    454module_platform_driver(ti_eqep_driver);
    455
    456MODULE_AUTHOR("David Lechner <david@lechnology.com>");
    457MODULE_DESCRIPTION("TI eQEP counter driver");
    458MODULE_LICENSE("GPL v2");