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

pwm-imx-tpm.c (11759B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright 2018-2019 NXP.
      4 *
      5 * Limitations:
      6 * - The TPM counter and period counter are shared between
      7 *   multiple channels, so all channels should use same period
      8 *   settings.
      9 * - Changes to polarity cannot be latched at the time of the
     10 *   next period start.
     11 * - Changing period and duty cycle together isn't atomic,
     12 *   with the wrong timing it might happen that a period is
     13 *   produced with old duty cycle but new period settings.
     14 */
     15
     16#include <linux/bitfield.h>
     17#include <linux/bitops.h>
     18#include <linux/clk.h>
     19#include <linux/err.h>
     20#include <linux/io.h>
     21#include <linux/module.h>
     22#include <linux/of.h>
     23#include <linux/platform_device.h>
     24#include <linux/pwm.h>
     25#include <linux/slab.h>
     26
     27#define PWM_IMX_TPM_PARAM	0x4
     28#define PWM_IMX_TPM_GLOBAL	0x8
     29#define PWM_IMX_TPM_SC		0x10
     30#define PWM_IMX_TPM_CNT		0x14
     31#define PWM_IMX_TPM_MOD		0x18
     32#define PWM_IMX_TPM_CnSC(n)	(0x20 + (n) * 0x8)
     33#define PWM_IMX_TPM_CnV(n)	(0x24 + (n) * 0x8)
     34
     35#define PWM_IMX_TPM_PARAM_CHAN			GENMASK(7, 0)
     36
     37#define PWM_IMX_TPM_SC_PS			GENMASK(2, 0)
     38#define PWM_IMX_TPM_SC_CMOD			GENMASK(4, 3)
     39#define PWM_IMX_TPM_SC_CMOD_INC_EVERY_CLK	FIELD_PREP(PWM_IMX_TPM_SC_CMOD, 1)
     40#define PWM_IMX_TPM_SC_CPWMS			BIT(5)
     41
     42#define PWM_IMX_TPM_CnSC_CHF	BIT(7)
     43#define PWM_IMX_TPM_CnSC_MSB	BIT(5)
     44#define PWM_IMX_TPM_CnSC_MSA	BIT(4)
     45
     46/*
     47 * The reference manual describes this field as two separate bits. The
     48 * semantic of the two bits isn't orthogonal though, so they are treated
     49 * together as a 2-bit field here.
     50 */
     51#define PWM_IMX_TPM_CnSC_ELS	GENMASK(3, 2)
     52#define PWM_IMX_TPM_CnSC_ELS_INVERSED	FIELD_PREP(PWM_IMX_TPM_CnSC_ELS, 1)
     53#define PWM_IMX_TPM_CnSC_ELS_NORMAL	FIELD_PREP(PWM_IMX_TPM_CnSC_ELS, 2)
     54
     55
     56#define PWM_IMX_TPM_MOD_WIDTH	16
     57#define PWM_IMX_TPM_MOD_MOD	GENMASK(PWM_IMX_TPM_MOD_WIDTH - 1, 0)
     58
     59struct imx_tpm_pwm_chip {
     60	struct pwm_chip chip;
     61	struct clk *clk;
     62	void __iomem *base;
     63	struct mutex lock;
     64	u32 user_count;
     65	u32 enable_count;
     66	u32 real_period;
     67};
     68
     69struct imx_tpm_pwm_param {
     70	u8 prescale;
     71	u32 mod;
     72	u32 val;
     73};
     74
     75static inline struct imx_tpm_pwm_chip *
     76to_imx_tpm_pwm_chip(struct pwm_chip *chip)
     77{
     78	return container_of(chip, struct imx_tpm_pwm_chip, chip);
     79}
     80
     81/*
     82 * This function determines for a given pwm_state *state that a consumer
     83 * might request the pwm_state *real_state that eventually is implemented
     84 * by the hardware and the necessary register values (in *p) to achieve
     85 * this.
     86 */
     87static int pwm_imx_tpm_round_state(struct pwm_chip *chip,
     88				   struct imx_tpm_pwm_param *p,
     89				   struct pwm_state *real_state,
     90				   const struct pwm_state *state)
     91{
     92	struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip);
     93	u32 rate, prescale, period_count, clock_unit;
     94	u64 tmp;
     95
     96	rate = clk_get_rate(tpm->clk);
     97	tmp = (u64)state->period * rate;
     98	clock_unit = DIV_ROUND_CLOSEST_ULL(tmp, NSEC_PER_SEC);
     99	if (clock_unit <= PWM_IMX_TPM_MOD_MOD)
    100		prescale = 0;
    101	else
    102		prescale = ilog2(clock_unit) + 1 - PWM_IMX_TPM_MOD_WIDTH;
    103
    104	if ((!FIELD_FIT(PWM_IMX_TPM_SC_PS, prescale)))
    105		return -ERANGE;
    106	p->prescale = prescale;
    107
    108	period_count = (clock_unit + ((1 << prescale) >> 1)) >> prescale;
    109	p->mod = period_count;
    110
    111	/* calculate real period HW can support */
    112	tmp = (u64)period_count << prescale;
    113	tmp *= NSEC_PER_SEC;
    114	real_state->period = DIV_ROUND_CLOSEST_ULL(tmp, rate);
    115
    116	/*
    117	 * if eventually the PWM output is inactive, either
    118	 * duty cycle is 0 or status is disabled, need to
    119	 * make sure the output pin is inactive.
    120	 */
    121	if (!state->enabled)
    122		real_state->duty_cycle = 0;
    123	else
    124		real_state->duty_cycle = state->duty_cycle;
    125
    126	tmp = (u64)p->mod * real_state->duty_cycle;
    127	p->val = DIV64_U64_ROUND_CLOSEST(tmp, real_state->period);
    128
    129	real_state->polarity = state->polarity;
    130	real_state->enabled = state->enabled;
    131
    132	return 0;
    133}
    134
    135static void pwm_imx_tpm_get_state(struct pwm_chip *chip,
    136				  struct pwm_device *pwm,
    137				  struct pwm_state *state)
    138{
    139	struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip);
    140	u32 rate, val, prescale;
    141	u64 tmp;
    142
    143	/* get period */
    144	state->period = tpm->real_period;
    145
    146	/* get duty cycle */
    147	rate = clk_get_rate(tpm->clk);
    148	val = readl(tpm->base + PWM_IMX_TPM_SC);
    149	prescale = FIELD_GET(PWM_IMX_TPM_SC_PS, val);
    150	tmp = readl(tpm->base + PWM_IMX_TPM_CnV(pwm->hwpwm));
    151	tmp = (tmp << prescale) * NSEC_PER_SEC;
    152	state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, rate);
    153
    154	/* get polarity */
    155	val = readl(tpm->base + PWM_IMX_TPM_CnSC(pwm->hwpwm));
    156	if ((val & PWM_IMX_TPM_CnSC_ELS) == PWM_IMX_TPM_CnSC_ELS_INVERSED)
    157		state->polarity = PWM_POLARITY_INVERSED;
    158	else
    159		/*
    160		 * Assume reserved values (2b00 and 2b11) to yield
    161		 * normal polarity.
    162		 */
    163		state->polarity = PWM_POLARITY_NORMAL;
    164
    165	/* get channel status */
    166	state->enabled = FIELD_GET(PWM_IMX_TPM_CnSC_ELS, val) ? true : false;
    167}
    168
    169/* this function is supposed to be called with mutex hold */
    170static int pwm_imx_tpm_apply_hw(struct pwm_chip *chip,
    171				struct imx_tpm_pwm_param *p,
    172				struct pwm_state *state,
    173				struct pwm_device *pwm)
    174{
    175	struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip);
    176	bool period_update = false;
    177	bool duty_update = false;
    178	u32 val, cmod, cur_prescale;
    179	unsigned long timeout;
    180	struct pwm_state c;
    181
    182	if (state->period != tpm->real_period) {
    183		/*
    184		 * TPM counter is shared by multiple channels, so
    185		 * prescale and period can NOT be modified when
    186		 * there are multiple channels in use with different
    187		 * period settings.
    188		 */
    189		if (tpm->user_count > 1)
    190			return -EBUSY;
    191
    192		val = readl(tpm->base + PWM_IMX_TPM_SC);
    193		cmod = FIELD_GET(PWM_IMX_TPM_SC_CMOD, val);
    194		cur_prescale = FIELD_GET(PWM_IMX_TPM_SC_PS, val);
    195		if (cmod && cur_prescale != p->prescale)
    196			return -EBUSY;
    197
    198		/* set TPM counter prescale */
    199		val &= ~PWM_IMX_TPM_SC_PS;
    200		val |= FIELD_PREP(PWM_IMX_TPM_SC_PS, p->prescale);
    201		writel(val, tpm->base + PWM_IMX_TPM_SC);
    202
    203		/*
    204		 * set period count:
    205		 * if the PWM is disabled (CMOD[1:0] = 2b00), then MOD register
    206		 * is updated when MOD register is written.
    207		 *
    208		 * if the PWM is enabled (CMOD[1:0] ≠ 2b00), the period length
    209		 * is latched into hardware when the next period starts.
    210		 */
    211		writel(p->mod, tpm->base + PWM_IMX_TPM_MOD);
    212		tpm->real_period = state->period;
    213		period_update = true;
    214	}
    215
    216	pwm_imx_tpm_get_state(chip, pwm, &c);
    217
    218	/* polarity is NOT allowed to be changed if PWM is active */
    219	if (c.enabled && c.polarity != state->polarity)
    220		return -EBUSY;
    221
    222	if (state->duty_cycle != c.duty_cycle) {
    223		/*
    224		 * set channel value:
    225		 * if the PWM is disabled (CMOD[1:0] = 2b00), then CnV register
    226		 * is updated when CnV register is written.
    227		 *
    228		 * if the PWM is enabled (CMOD[1:0] ≠ 2b00), the duty length
    229		 * is latched into hardware when the next period starts.
    230		 */
    231		writel(p->val, tpm->base + PWM_IMX_TPM_CnV(pwm->hwpwm));
    232		duty_update = true;
    233	}
    234
    235	/* make sure MOD & CnV registers are updated */
    236	if (period_update || duty_update) {
    237		timeout = jiffies + msecs_to_jiffies(tpm->real_period /
    238						     NSEC_PER_MSEC + 1);
    239		while (readl(tpm->base + PWM_IMX_TPM_MOD) != p->mod
    240		       || readl(tpm->base + PWM_IMX_TPM_CnV(pwm->hwpwm))
    241		       != p->val) {
    242			if (time_after(jiffies, timeout))
    243				return -ETIME;
    244			cpu_relax();
    245		}
    246	}
    247
    248	/*
    249	 * polarity settings will enabled/disable output status
    250	 * immediately, so if the channel is disabled, need to
    251	 * make sure MSA/MSB/ELS are set to 0 which means channel
    252	 * disabled.
    253	 */
    254	val = readl(tpm->base + PWM_IMX_TPM_CnSC(pwm->hwpwm));
    255	val &= ~(PWM_IMX_TPM_CnSC_ELS | PWM_IMX_TPM_CnSC_MSA |
    256		 PWM_IMX_TPM_CnSC_MSB);
    257	if (state->enabled) {
    258		/*
    259		 * set polarity (for edge-aligned PWM modes)
    260		 *
    261		 * ELS[1:0] = 2b10 yields normal polarity behaviour,
    262		 * ELS[1:0] = 2b01 yields inversed polarity.
    263		 * The other values are reserved.
    264		 */
    265		val |= PWM_IMX_TPM_CnSC_MSB;
    266		val |= (state->polarity == PWM_POLARITY_NORMAL) ?
    267			PWM_IMX_TPM_CnSC_ELS_NORMAL :
    268			PWM_IMX_TPM_CnSC_ELS_INVERSED;
    269	}
    270	writel(val, tpm->base + PWM_IMX_TPM_CnSC(pwm->hwpwm));
    271
    272	/* control the counter status */
    273	if (state->enabled != c.enabled) {
    274		val = readl(tpm->base + PWM_IMX_TPM_SC);
    275		if (state->enabled) {
    276			if (++tpm->enable_count == 1)
    277				val |= PWM_IMX_TPM_SC_CMOD_INC_EVERY_CLK;
    278		} else {
    279			if (--tpm->enable_count == 0)
    280				val &= ~PWM_IMX_TPM_SC_CMOD;
    281		}
    282		writel(val, tpm->base + PWM_IMX_TPM_SC);
    283	}
    284
    285	return 0;
    286}
    287
    288static int pwm_imx_tpm_apply(struct pwm_chip *chip,
    289			     struct pwm_device *pwm,
    290			     const struct pwm_state *state)
    291{
    292	struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip);
    293	struct imx_tpm_pwm_param param;
    294	struct pwm_state real_state;
    295	int ret;
    296
    297	ret = pwm_imx_tpm_round_state(chip, &param, &real_state, state);
    298	if (ret)
    299		return ret;
    300
    301	mutex_lock(&tpm->lock);
    302	ret = pwm_imx_tpm_apply_hw(chip, &param, &real_state, pwm);
    303	mutex_unlock(&tpm->lock);
    304
    305	return ret;
    306}
    307
    308static int pwm_imx_tpm_request(struct pwm_chip *chip, struct pwm_device *pwm)
    309{
    310	struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip);
    311
    312	mutex_lock(&tpm->lock);
    313	tpm->user_count++;
    314	mutex_unlock(&tpm->lock);
    315
    316	return 0;
    317}
    318
    319static void pwm_imx_tpm_free(struct pwm_chip *chip, struct pwm_device *pwm)
    320{
    321	struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip);
    322
    323	mutex_lock(&tpm->lock);
    324	tpm->user_count--;
    325	mutex_unlock(&tpm->lock);
    326}
    327
    328static const struct pwm_ops imx_tpm_pwm_ops = {
    329	.request = pwm_imx_tpm_request,
    330	.free = pwm_imx_tpm_free,
    331	.get_state = pwm_imx_tpm_get_state,
    332	.apply = pwm_imx_tpm_apply,
    333	.owner = THIS_MODULE,
    334};
    335
    336static int pwm_imx_tpm_probe(struct platform_device *pdev)
    337{
    338	struct imx_tpm_pwm_chip *tpm;
    339	int ret;
    340	u32 val;
    341
    342	tpm = devm_kzalloc(&pdev->dev, sizeof(*tpm), GFP_KERNEL);
    343	if (!tpm)
    344		return -ENOMEM;
    345
    346	platform_set_drvdata(pdev, tpm);
    347
    348	tpm->base = devm_platform_ioremap_resource(pdev, 0);
    349	if (IS_ERR(tpm->base))
    350		return PTR_ERR(tpm->base);
    351
    352	tpm->clk = devm_clk_get(&pdev->dev, NULL);
    353	if (IS_ERR(tpm->clk))
    354		return dev_err_probe(&pdev->dev, PTR_ERR(tpm->clk),
    355				     "failed to get PWM clock\n");
    356
    357	ret = clk_prepare_enable(tpm->clk);
    358	if (ret) {
    359		dev_err(&pdev->dev,
    360			"failed to prepare or enable clock: %d\n", ret);
    361		return ret;
    362	}
    363
    364	tpm->chip.dev = &pdev->dev;
    365	tpm->chip.ops = &imx_tpm_pwm_ops;
    366
    367	/* get number of channels */
    368	val = readl(tpm->base + PWM_IMX_TPM_PARAM);
    369	tpm->chip.npwm = FIELD_GET(PWM_IMX_TPM_PARAM_CHAN, val);
    370
    371	mutex_init(&tpm->lock);
    372
    373	ret = pwmchip_add(&tpm->chip);
    374	if (ret) {
    375		dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
    376		clk_disable_unprepare(tpm->clk);
    377	}
    378
    379	return ret;
    380}
    381
    382static int pwm_imx_tpm_remove(struct platform_device *pdev)
    383{
    384	struct imx_tpm_pwm_chip *tpm = platform_get_drvdata(pdev);
    385
    386	pwmchip_remove(&tpm->chip);
    387
    388	clk_disable_unprepare(tpm->clk);
    389
    390	return 0;
    391}
    392
    393static int __maybe_unused pwm_imx_tpm_suspend(struct device *dev)
    394{
    395	struct imx_tpm_pwm_chip *tpm = dev_get_drvdata(dev);
    396
    397	if (tpm->enable_count > 0)
    398		return -EBUSY;
    399
    400	clk_disable_unprepare(tpm->clk);
    401
    402	return 0;
    403}
    404
    405static int __maybe_unused pwm_imx_tpm_resume(struct device *dev)
    406{
    407	struct imx_tpm_pwm_chip *tpm = dev_get_drvdata(dev);
    408	int ret = 0;
    409
    410	ret = clk_prepare_enable(tpm->clk);
    411	if (ret)
    412		dev_err(dev, "failed to prepare or enable clock: %d\n", ret);
    413
    414	return ret;
    415}
    416
    417static SIMPLE_DEV_PM_OPS(imx_tpm_pwm_pm,
    418			 pwm_imx_tpm_suspend, pwm_imx_tpm_resume);
    419
    420static const struct of_device_id imx_tpm_pwm_dt_ids[] = {
    421	{ .compatible = "fsl,imx7ulp-pwm", },
    422	{ /* sentinel */ }
    423};
    424MODULE_DEVICE_TABLE(of, imx_tpm_pwm_dt_ids);
    425
    426static struct platform_driver imx_tpm_pwm_driver = {
    427	.driver = {
    428		.name = "imx7ulp-tpm-pwm",
    429		.of_match_table = imx_tpm_pwm_dt_ids,
    430		.pm = &imx_tpm_pwm_pm,
    431	},
    432	.probe	= pwm_imx_tpm_probe,
    433	.remove = pwm_imx_tpm_remove,
    434};
    435module_platform_driver(imx_tpm_pwm_driver);
    436
    437MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
    438MODULE_DESCRIPTION("i.MX TPM PWM Driver");
    439MODULE_LICENSE("GPL v2");