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

ftm-quaddec.c (8175B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Flex Timer Module Quadrature decoder
      4 *
      5 * This module implements a driver for decoding the FTM quadrature
      6 * of ex. a LS1021A
      7 */
      8
      9#include <linux/fsl/ftm.h>
     10#include <linux/module.h>
     11#include <linux/platform_device.h>
     12#include <linux/of.h>
     13#include <linux/io.h>
     14#include <linux/mutex.h>
     15#include <linux/counter.h>
     16#include <linux/bitfield.h>
     17#include <linux/types.h>
     18
     19#define FTM_FIELD_UPDATE(ftm, offset, mask, val)			\
     20	({								\
     21		uint32_t flags;						\
     22		ftm_read(ftm, offset, &flags);				\
     23		flags &= ~mask;						\
     24		flags |= FIELD_PREP(mask, val);				\
     25		ftm_write(ftm, offset, flags);				\
     26	})
     27
     28struct ftm_quaddec {
     29	struct platform_device *pdev;
     30	void __iomem *ftm_base;
     31	bool big_endian;
     32	struct mutex ftm_quaddec_mutex;
     33};
     34
     35static void ftm_read(struct ftm_quaddec *ftm, uint32_t offset, uint32_t *data)
     36{
     37	if (ftm->big_endian)
     38		*data = ioread32be(ftm->ftm_base + offset);
     39	else
     40		*data = ioread32(ftm->ftm_base + offset);
     41}
     42
     43static void ftm_write(struct ftm_quaddec *ftm, uint32_t offset, uint32_t data)
     44{
     45	if (ftm->big_endian)
     46		iowrite32be(data, ftm->ftm_base + offset);
     47	else
     48		iowrite32(data, ftm->ftm_base + offset);
     49}
     50
     51/* Hold mutex before modifying write protection state */
     52static void ftm_clear_write_protection(struct ftm_quaddec *ftm)
     53{
     54	uint32_t flag;
     55
     56	/* First see if it is enabled */
     57	ftm_read(ftm, FTM_FMS, &flag);
     58
     59	if (flag & FTM_FMS_WPEN)
     60		FTM_FIELD_UPDATE(ftm, FTM_MODE, FTM_MODE_WPDIS, 1);
     61}
     62
     63static void ftm_set_write_protection(struct ftm_quaddec *ftm)
     64{
     65	FTM_FIELD_UPDATE(ftm, FTM_FMS, FTM_FMS_WPEN, 1);
     66}
     67
     68static void ftm_reset_counter(struct ftm_quaddec *ftm)
     69{
     70	/* Reset hardware counter to CNTIN */
     71	ftm_write(ftm, FTM_CNT, 0x0);
     72}
     73
     74static void ftm_quaddec_init(struct ftm_quaddec *ftm)
     75{
     76	ftm_clear_write_protection(ftm);
     77
     78	/*
     79	 * Do not write in the region from the CNTIN register through the
     80	 * PWMLOAD register when FTMEN = 0.
     81	 * Also reset other fields to zero
     82	 */
     83	ftm_write(ftm, FTM_MODE, FTM_MODE_FTMEN);
     84	ftm_write(ftm, FTM_CNTIN, 0x0000);
     85	ftm_write(ftm, FTM_MOD, 0xffff);
     86	ftm_write(ftm, FTM_CNT, 0x0);
     87	/* Set prescaler, reset other fields to zero */
     88	ftm_write(ftm, FTM_SC, FTM_SC_PS_1);
     89
     90	/* Select quad mode, reset other fields to zero */
     91	ftm_write(ftm, FTM_QDCTRL, FTM_QDCTRL_QUADEN);
     92
     93	/* Unused features and reset to default section */
     94	ftm_write(ftm, FTM_POL, 0x0);
     95	ftm_write(ftm, FTM_FLTCTRL, 0x0);
     96	ftm_write(ftm, FTM_SYNCONF, 0x0);
     97	ftm_write(ftm, FTM_SYNC, 0xffff);
     98
     99	/* Lock the FTM */
    100	ftm_set_write_protection(ftm);
    101}
    102
    103static void ftm_quaddec_disable(void *ftm)
    104{
    105	struct ftm_quaddec *ftm_qua = ftm;
    106
    107	ftm_clear_write_protection(ftm_qua);
    108	ftm_write(ftm_qua, FTM_MODE, 0);
    109	ftm_write(ftm_qua, FTM_QDCTRL, 0);
    110	/*
    111	 * This is enough to disable the counter. No clock has been
    112	 * selected by writing to FTM_SC in init()
    113	 */
    114	ftm_set_write_protection(ftm_qua);
    115}
    116
    117static int ftm_quaddec_get_prescaler(struct counter_device *counter,
    118				     struct counter_count *count, u32 *cnt_mode)
    119{
    120	struct ftm_quaddec *ftm = counter_priv(counter);
    121	uint32_t scflags;
    122
    123	ftm_read(ftm, FTM_SC, &scflags);
    124
    125	*cnt_mode = FIELD_GET(FTM_SC_PS_MASK, scflags);
    126
    127	return 0;
    128}
    129
    130static int ftm_quaddec_set_prescaler(struct counter_device *counter,
    131				     struct counter_count *count, u32 cnt_mode)
    132{
    133	struct ftm_quaddec *ftm = counter_priv(counter);
    134
    135	mutex_lock(&ftm->ftm_quaddec_mutex);
    136
    137	ftm_clear_write_protection(ftm);
    138	FTM_FIELD_UPDATE(ftm, FTM_SC, FTM_SC_PS_MASK, cnt_mode);
    139	ftm_set_write_protection(ftm);
    140
    141	/* Also resets the counter as it is undefined anyway now */
    142	ftm_reset_counter(ftm);
    143
    144	mutex_unlock(&ftm->ftm_quaddec_mutex);
    145	return 0;
    146}
    147
    148static const char * const ftm_quaddec_prescaler[] = {
    149	"1", "2", "4", "8", "16", "32", "64", "128"
    150};
    151
    152static const enum counter_synapse_action ftm_quaddec_synapse_actions[] = {
    153	COUNTER_SYNAPSE_ACTION_BOTH_EDGES
    154};
    155
    156static const enum counter_function ftm_quaddec_count_functions[] = {
    157	COUNTER_FUNCTION_QUADRATURE_X4
    158};
    159
    160static int ftm_quaddec_count_read(struct counter_device *counter,
    161				  struct counter_count *count,
    162				  u64 *val)
    163{
    164	struct ftm_quaddec *const ftm = counter_priv(counter);
    165	uint32_t cntval;
    166
    167	ftm_read(ftm, FTM_CNT, &cntval);
    168
    169	*val = cntval;
    170
    171	return 0;
    172}
    173
    174static int ftm_quaddec_count_write(struct counter_device *counter,
    175				   struct counter_count *count,
    176				   const u64 val)
    177{
    178	struct ftm_quaddec *const ftm = counter_priv(counter);
    179
    180	if (val != 0) {
    181		dev_warn(&ftm->pdev->dev, "Can only accept '0' as new counter value\n");
    182		return -EINVAL;
    183	}
    184
    185	ftm_reset_counter(ftm);
    186
    187	return 0;
    188}
    189
    190static int ftm_quaddec_count_function_read(struct counter_device *counter,
    191					   struct counter_count *count,
    192					   enum counter_function *function)
    193{
    194	*function = COUNTER_FUNCTION_QUADRATURE_X4;
    195
    196	return 0;
    197}
    198
    199static int ftm_quaddec_action_read(struct counter_device *counter,
    200				   struct counter_count *count,
    201				   struct counter_synapse *synapse,
    202				   enum counter_synapse_action *action)
    203{
    204	*action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES;
    205
    206	return 0;
    207}
    208
    209static const struct counter_ops ftm_quaddec_cnt_ops = {
    210	.count_read = ftm_quaddec_count_read,
    211	.count_write = ftm_quaddec_count_write,
    212	.function_read = ftm_quaddec_count_function_read,
    213	.action_read = ftm_quaddec_action_read,
    214};
    215
    216static struct counter_signal ftm_quaddec_signals[] = {
    217	{
    218		.id = 0,
    219		.name = "Channel 1 Phase A"
    220	},
    221	{
    222		.id = 1,
    223		.name = "Channel 1 Phase B"
    224	}
    225};
    226
    227static struct counter_synapse ftm_quaddec_count_synapses[] = {
    228	{
    229		.actions_list = ftm_quaddec_synapse_actions,
    230		.num_actions = ARRAY_SIZE(ftm_quaddec_synapse_actions),
    231		.signal = &ftm_quaddec_signals[0]
    232	},
    233	{
    234		.actions_list = ftm_quaddec_synapse_actions,
    235		.num_actions = ARRAY_SIZE(ftm_quaddec_synapse_actions),
    236		.signal = &ftm_quaddec_signals[1]
    237	}
    238};
    239
    240static DEFINE_COUNTER_ENUM(ftm_quaddec_prescaler_enum, ftm_quaddec_prescaler);
    241
    242static struct counter_comp ftm_quaddec_count_ext[] = {
    243	COUNTER_COMP_COUNT_ENUM("prescaler", ftm_quaddec_get_prescaler,
    244				ftm_quaddec_set_prescaler,
    245				ftm_quaddec_prescaler_enum),
    246};
    247
    248static struct counter_count ftm_quaddec_counts = {
    249	.id = 0,
    250	.name = "Channel 1 Count",
    251	.functions_list = ftm_quaddec_count_functions,
    252	.num_functions = ARRAY_SIZE(ftm_quaddec_count_functions),
    253	.synapses = ftm_quaddec_count_synapses,
    254	.num_synapses = ARRAY_SIZE(ftm_quaddec_count_synapses),
    255	.ext = ftm_quaddec_count_ext,
    256	.num_ext = ARRAY_SIZE(ftm_quaddec_count_ext)
    257};
    258
    259static int ftm_quaddec_probe(struct platform_device *pdev)
    260{
    261	struct counter_device *counter;
    262	struct ftm_quaddec *ftm;
    263
    264	struct device_node *node = pdev->dev.of_node;
    265	struct resource *io;
    266	int ret;
    267
    268	counter = devm_counter_alloc(&pdev->dev, sizeof(*ftm));
    269	if (!counter)
    270		return -ENOMEM;
    271	ftm = counter_priv(counter);
    272
    273	io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    274	if (!io) {
    275		dev_err(&pdev->dev, "Failed to get memory region\n");
    276		return -ENODEV;
    277	}
    278
    279	ftm->pdev = pdev;
    280	ftm->big_endian = of_property_read_bool(node, "big-endian");
    281	ftm->ftm_base = devm_ioremap(&pdev->dev, io->start, resource_size(io));
    282
    283	if (!ftm->ftm_base) {
    284		dev_err(&pdev->dev, "Failed to map memory region\n");
    285		return -EINVAL;
    286	}
    287	counter->name = dev_name(&pdev->dev);
    288	counter->parent = &pdev->dev;
    289	counter->ops = &ftm_quaddec_cnt_ops;
    290	counter->counts = &ftm_quaddec_counts;
    291	counter->num_counts = 1;
    292	counter->signals = ftm_quaddec_signals;
    293	counter->num_signals = ARRAY_SIZE(ftm_quaddec_signals);
    294
    295	mutex_init(&ftm->ftm_quaddec_mutex);
    296
    297	ftm_quaddec_init(ftm);
    298
    299	ret = devm_add_action_or_reset(&pdev->dev, ftm_quaddec_disable, ftm);
    300	if (ret)
    301		return ret;
    302
    303	ret = devm_counter_add(&pdev->dev, counter);
    304	if (ret)
    305		return dev_err_probe(&pdev->dev, ret, "Failed to add counter\n");
    306
    307	return 0;
    308}
    309
    310static const struct of_device_id ftm_quaddec_match[] = {
    311	{ .compatible = "fsl,ftm-quaddec" },
    312	{},
    313};
    314
    315static struct platform_driver ftm_quaddec_driver = {
    316	.driver = {
    317		.name = "ftm-quaddec",
    318		.of_match_table = ftm_quaddec_match,
    319	},
    320	.probe = ftm_quaddec_probe,
    321};
    322
    323module_platform_driver(ftm_quaddec_driver);
    324
    325MODULE_LICENSE("GPL");
    326MODULE_AUTHOR("Kjeld Flarup <kfa@deif.com>");
    327MODULE_AUTHOR("Patrick Havelange <patrick.havelange@essensium.com>");