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-sifive.c (8751B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2017-2018 SiFive
      4 * For SiFive's PWM IP block documentation please refer Chapter 14 of
      5 * Reference Manual : https://static.dev.sifive.com/FU540-C000-v1.0.pdf
      6 *
      7 * Limitations:
      8 * - When changing both duty cycle and period, we cannot prevent in
      9 *   software that the output might produce a period with mixed
     10 *   settings (new period length and old duty cycle).
     11 * - The hardware cannot generate a 100% duty cycle.
     12 * - The hardware generates only inverted output.
     13 */
     14#include <linux/clk.h>
     15#include <linux/io.h>
     16#include <linux/module.h>
     17#include <linux/platform_device.h>
     18#include <linux/pwm.h>
     19#include <linux/slab.h>
     20#include <linux/bitfield.h>
     21
     22/* Register offsets */
     23#define PWM_SIFIVE_PWMCFG		0x0
     24#define PWM_SIFIVE_PWMCOUNT		0x8
     25#define PWM_SIFIVE_PWMS			0x10
     26#define PWM_SIFIVE_PWMCMP0		0x20
     27
     28/* PWMCFG fields */
     29#define PWM_SIFIVE_PWMCFG_SCALE		GENMASK(3, 0)
     30#define PWM_SIFIVE_PWMCFG_STICKY	BIT(8)
     31#define PWM_SIFIVE_PWMCFG_ZERO_CMP	BIT(9)
     32#define PWM_SIFIVE_PWMCFG_DEGLITCH	BIT(10)
     33#define PWM_SIFIVE_PWMCFG_EN_ALWAYS	BIT(12)
     34#define PWM_SIFIVE_PWMCFG_EN_ONCE	BIT(13)
     35#define PWM_SIFIVE_PWMCFG_CENTER	BIT(16)
     36#define PWM_SIFIVE_PWMCFG_GANG		BIT(24)
     37#define PWM_SIFIVE_PWMCFG_IP		BIT(28)
     38
     39/* PWM_SIFIVE_SIZE_PWMCMP is used to calculate offset for pwmcmpX registers */
     40#define PWM_SIFIVE_SIZE_PWMCMP		4
     41#define PWM_SIFIVE_CMPWIDTH		16
     42#define PWM_SIFIVE_DEFAULT_PERIOD	10000000
     43
     44struct pwm_sifive_ddata {
     45	struct pwm_chip	chip;
     46	struct mutex lock; /* lock to protect user_count */
     47	struct notifier_block notifier;
     48	struct clk *clk;
     49	void __iomem *regs;
     50	unsigned int real_period;
     51	unsigned int approx_period;
     52	int user_count;
     53};
     54
     55static inline
     56struct pwm_sifive_ddata *pwm_sifive_chip_to_ddata(struct pwm_chip *c)
     57{
     58	return container_of(c, struct pwm_sifive_ddata, chip);
     59}
     60
     61static int pwm_sifive_request(struct pwm_chip *chip, struct pwm_device *pwm)
     62{
     63	struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
     64
     65	mutex_lock(&ddata->lock);
     66	ddata->user_count++;
     67	mutex_unlock(&ddata->lock);
     68
     69	return 0;
     70}
     71
     72static void pwm_sifive_free(struct pwm_chip *chip, struct pwm_device *pwm)
     73{
     74	struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
     75
     76	mutex_lock(&ddata->lock);
     77	ddata->user_count--;
     78	mutex_unlock(&ddata->lock);
     79}
     80
     81static void pwm_sifive_update_clock(struct pwm_sifive_ddata *ddata,
     82				    unsigned long rate)
     83{
     84	unsigned long long num;
     85	unsigned long scale_pow;
     86	int scale;
     87	u32 val;
     88	/*
     89	 * The PWM unit is used with pwmzerocmp=0, so the only way to modify the
     90	 * period length is using pwmscale which provides the number of bits the
     91	 * counter is shifted before being feed to the comparators. A period
     92	 * lasts (1 << (PWM_SIFIVE_CMPWIDTH + pwmscale)) clock ticks.
     93	 * (1 << (PWM_SIFIVE_CMPWIDTH + scale)) * 10^9/rate = period
     94	 */
     95	scale_pow = div64_ul(ddata->approx_period * (u64)rate, NSEC_PER_SEC);
     96	scale = clamp(ilog2(scale_pow) - PWM_SIFIVE_CMPWIDTH, 0, 0xf);
     97
     98	val = PWM_SIFIVE_PWMCFG_EN_ALWAYS |
     99	      FIELD_PREP(PWM_SIFIVE_PWMCFG_SCALE, scale);
    100	writel(val, ddata->regs + PWM_SIFIVE_PWMCFG);
    101
    102	/* As scale <= 15 the shift operation cannot overflow. */
    103	num = (unsigned long long)NSEC_PER_SEC << (PWM_SIFIVE_CMPWIDTH + scale);
    104	ddata->real_period = div64_ul(num, rate);
    105	dev_dbg(ddata->chip.dev,
    106		"New real_period = %u ns\n", ddata->real_period);
    107}
    108
    109static void pwm_sifive_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
    110				 struct pwm_state *state)
    111{
    112	struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
    113	u32 duty, val;
    114
    115	duty = readl(ddata->regs + PWM_SIFIVE_PWMCMP0 +
    116		     pwm->hwpwm * PWM_SIFIVE_SIZE_PWMCMP);
    117
    118	state->enabled = duty > 0;
    119
    120	val = readl(ddata->regs + PWM_SIFIVE_PWMCFG);
    121	if (!(val & PWM_SIFIVE_PWMCFG_EN_ALWAYS))
    122		state->enabled = false;
    123
    124	state->period = ddata->real_period;
    125	state->duty_cycle =
    126		(u64)duty * ddata->real_period >> PWM_SIFIVE_CMPWIDTH;
    127	state->polarity = PWM_POLARITY_INVERSED;
    128}
    129
    130static int pwm_sifive_enable(struct pwm_chip *chip, bool enable)
    131{
    132	struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
    133	int ret;
    134
    135	if (enable) {
    136		ret = clk_enable(ddata->clk);
    137		if (ret) {
    138			dev_err(ddata->chip.dev, "Enable clk failed\n");
    139			return ret;
    140		}
    141	} else {
    142		clk_disable(ddata->clk);
    143	}
    144
    145	return 0;
    146}
    147
    148static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm,
    149			    const struct pwm_state *state)
    150{
    151	struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
    152	struct pwm_state cur_state;
    153	unsigned int duty_cycle;
    154	unsigned long long num;
    155	bool enabled;
    156	int ret = 0;
    157	u32 frac;
    158
    159	if (state->polarity != PWM_POLARITY_INVERSED)
    160		return -EINVAL;
    161
    162	ret = clk_enable(ddata->clk);
    163	if (ret) {
    164		dev_err(ddata->chip.dev, "Enable clk failed\n");
    165		return ret;
    166	}
    167
    168	mutex_lock(&ddata->lock);
    169	cur_state = pwm->state;
    170	enabled = cur_state.enabled;
    171
    172	duty_cycle = state->duty_cycle;
    173	if (!state->enabled)
    174		duty_cycle = 0;
    175
    176	/*
    177	 * The problem of output producing mixed setting as mentioned at top,
    178	 * occurs here. To minimize the window for this problem, we are
    179	 * calculating the register values first and then writing them
    180	 * consecutively
    181	 */
    182	num = (u64)duty_cycle * (1U << PWM_SIFIVE_CMPWIDTH);
    183	frac = DIV64_U64_ROUND_CLOSEST(num, state->period);
    184	/* The hardware cannot generate a 100% duty cycle */
    185	frac = min(frac, (1U << PWM_SIFIVE_CMPWIDTH) - 1);
    186
    187	if (state->period != ddata->approx_period) {
    188		if (ddata->user_count != 1) {
    189			ret = -EBUSY;
    190			goto exit;
    191		}
    192		ddata->approx_period = state->period;
    193		pwm_sifive_update_clock(ddata, clk_get_rate(ddata->clk));
    194	}
    195
    196	writel(frac, ddata->regs + PWM_SIFIVE_PWMCMP0 +
    197	       pwm->hwpwm * PWM_SIFIVE_SIZE_PWMCMP);
    198
    199	if (state->enabled != enabled)
    200		pwm_sifive_enable(chip, state->enabled);
    201
    202exit:
    203	clk_disable(ddata->clk);
    204	mutex_unlock(&ddata->lock);
    205	return ret;
    206}
    207
    208static const struct pwm_ops pwm_sifive_ops = {
    209	.request = pwm_sifive_request,
    210	.free = pwm_sifive_free,
    211	.get_state = pwm_sifive_get_state,
    212	.apply = pwm_sifive_apply,
    213	.owner = THIS_MODULE,
    214};
    215
    216static int pwm_sifive_clock_notifier(struct notifier_block *nb,
    217				     unsigned long event, void *data)
    218{
    219	struct clk_notifier_data *ndata = data;
    220	struct pwm_sifive_ddata *ddata =
    221		container_of(nb, struct pwm_sifive_ddata, notifier);
    222
    223	if (event == POST_RATE_CHANGE)
    224		pwm_sifive_update_clock(ddata, ndata->new_rate);
    225
    226	return NOTIFY_OK;
    227}
    228
    229static int pwm_sifive_probe(struct platform_device *pdev)
    230{
    231	struct device *dev = &pdev->dev;
    232	struct pwm_sifive_ddata *ddata;
    233	struct pwm_chip *chip;
    234	int ret;
    235
    236	ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
    237	if (!ddata)
    238		return -ENOMEM;
    239
    240	mutex_init(&ddata->lock);
    241	chip = &ddata->chip;
    242	chip->dev = dev;
    243	chip->ops = &pwm_sifive_ops;
    244	chip->npwm = 4;
    245
    246	ddata->regs = devm_platform_ioremap_resource(pdev, 0);
    247	if (IS_ERR(ddata->regs))
    248		return PTR_ERR(ddata->regs);
    249
    250	ddata->clk = devm_clk_get(dev, NULL);
    251	if (IS_ERR(ddata->clk))
    252		return dev_err_probe(dev, PTR_ERR(ddata->clk),
    253				     "Unable to find controller clock\n");
    254
    255	ret = clk_prepare_enable(ddata->clk);
    256	if (ret) {
    257		dev_err(dev, "failed to enable clock for pwm: %d\n", ret);
    258		return ret;
    259	}
    260
    261	/* Watch for changes to underlying clock frequency */
    262	ddata->notifier.notifier_call = pwm_sifive_clock_notifier;
    263	ret = clk_notifier_register(ddata->clk, &ddata->notifier);
    264	if (ret) {
    265		dev_err(dev, "failed to register clock notifier: %d\n", ret);
    266		goto disable_clk;
    267	}
    268
    269	ret = pwmchip_add(chip);
    270	if (ret < 0) {
    271		dev_err(dev, "cannot register PWM: %d\n", ret);
    272		goto unregister_clk;
    273	}
    274
    275	platform_set_drvdata(pdev, ddata);
    276	dev_dbg(dev, "SiFive PWM chip registered %d PWMs\n", chip->npwm);
    277
    278	return 0;
    279
    280unregister_clk:
    281	clk_notifier_unregister(ddata->clk, &ddata->notifier);
    282disable_clk:
    283	clk_disable_unprepare(ddata->clk);
    284
    285	return ret;
    286}
    287
    288static int pwm_sifive_remove(struct platform_device *dev)
    289{
    290	struct pwm_sifive_ddata *ddata = platform_get_drvdata(dev);
    291	bool is_enabled = false;
    292	struct pwm_device *pwm;
    293	int ch;
    294
    295	for (ch = 0; ch < ddata->chip.npwm; ch++) {
    296		pwm = &ddata->chip.pwms[ch];
    297		if (pwm->state.enabled) {
    298			is_enabled = true;
    299			break;
    300		}
    301	}
    302	if (is_enabled)
    303		clk_disable(ddata->clk);
    304
    305	clk_disable_unprepare(ddata->clk);
    306	pwmchip_remove(&ddata->chip);
    307	clk_notifier_unregister(ddata->clk, &ddata->notifier);
    308
    309	return 0;
    310}
    311
    312static const struct of_device_id pwm_sifive_of_match[] = {
    313	{ .compatible = "sifive,pwm0" },
    314	{},
    315};
    316MODULE_DEVICE_TABLE(of, pwm_sifive_of_match);
    317
    318static struct platform_driver pwm_sifive_driver = {
    319	.probe = pwm_sifive_probe,
    320	.remove = pwm_sifive_remove,
    321	.driver = {
    322		.name = "pwm-sifive",
    323		.of_match_table = pwm_sifive_of_match,
    324	},
    325};
    326module_platform_driver(pwm_sifive_driver);
    327
    328MODULE_DESCRIPTION("SiFive PWM driver");
    329MODULE_LICENSE("GPL v2");