1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2/*
3 * Copyright (C) 2020 BayLibre, SAS.
4 * Author: Neil Armstrong <narmstrong@baylibre.com>
5 * Copyright (C) 2014 Amlogic, Inc.
6 *
7 * This PWM is only a set of Gates, Dividers and Counters:
8 * PWM output is achieved by calculating a clock that permits calculating
9 * two periods (low and high). The counter then has to be set to switch after
10 * N cycles for the first half period.
11 * The hardware has no "polarity" setting. This driver reverses the period
12 * cycles (the low length is inverted with the high length) for
13 * PWM_POLARITY_INVERSED.
14 * Setting the polarity will disable and re-enable the PWM output.
15 * Disabling the PWM stops the output immediately (without waiting for the
16 * current period to complete first).
17 */
18
19#include <clk.h>
20#include <div64.h>
21#include <dm.h>
22#include <pwm.h>
23#include <regmap.h>
24#include <linux/io.h>
25#include <linux/math64.h>
26#include <linux/bitfield.h>
27#include <linux/clk-provider.h>
28#include <linux/time.h>
29
30#define REG_PWM_A		0x0
31#define REG_PWM_B		0x4
32#define PWM_LOW_MASK		GENMASK(15, 0)
33#define PWM_HIGH_MASK		GENMASK(31, 16)
34
35#define REG_MISC_AB		0x8
36#define MISC_B_CLK_EN		BIT(23)
37#define MISC_A_CLK_EN		BIT(15)
38#define MISC_CLK_DIV_MASK	0x7f
39#define MISC_B_CLK_DIV_SHIFT	16
40#define MISC_A_CLK_DIV_SHIFT	8
41#define MISC_B_CLK_SEL_SHIFT	6
42#define MISC_A_CLK_SEL_SHIFT	4
43#define MISC_CLK_SEL_MASK	0x3
44#define MISC_B_EN		BIT(1)
45#define MISC_A_EN		BIT(0)
46
47#define MESON_NUM_PWMS		2
48
49static struct meson_pwm_channel_data {
50	u8		reg_offset;
51	u8		clk_sel_shift;
52	u8		clk_div_shift;
53	u32		clk_en_mask;
54	u32		pwm_en_mask;
55} meson_pwm_per_channel_data[MESON_NUM_PWMS] = {
56	{
57		.reg_offset	= REG_PWM_A,
58		.clk_sel_shift	= MISC_A_CLK_SEL_SHIFT,
59		.clk_div_shift	= MISC_A_CLK_DIV_SHIFT,
60		.clk_en_mask	= MISC_A_CLK_EN,
61		.pwm_en_mask	= MISC_A_EN,
62	},
63	{
64		.reg_offset	= REG_PWM_B,
65		.clk_sel_shift	= MISC_B_CLK_SEL_SHIFT,
66		.clk_div_shift	= MISC_B_CLK_DIV_SHIFT,
67		.clk_en_mask	= MISC_B_CLK_EN,
68		.pwm_en_mask	= MISC_B_EN,
69	}
70};
71
72struct meson_pwm_channel {
73	unsigned int hi;
74	unsigned int lo;
75	u8 pre_div;
76	uint period_ns;
77	uint duty_ns;
78	bool configured;
79	bool enabled;
80	bool polarity;
81	struct clk clk;
82};
83
84struct meson_pwm_data {
85	const long *parent_ids;
86	unsigned int num_parents;
87};
88
89struct meson_pwm {
90	const struct meson_pwm_data *data;
91	struct meson_pwm_channel channels[MESON_NUM_PWMS];
92	void __iomem *base;
93};
94
95static int meson_pwm_set_enable(struct udevice *dev, uint channel, bool enable);
96
97static int meson_pwm_set_config(struct udevice *dev, uint channeln,
98				 uint period_ns, uint duty_ns)
99{
100	struct meson_pwm *priv = dev_get_priv(dev);
101	struct meson_pwm_channel *channel;
102	struct meson_pwm_channel_data *channel_data;
103	unsigned int duty, period, pre_div, cnt, duty_cnt;
104	unsigned long fin_freq;
105
106	if (channeln >= MESON_NUM_PWMS)
107		return -ENODEV;
108
109	channel = &priv->channels[channeln];
110	channel_data = &meson_pwm_per_channel_data[channeln];
111
112	period = period_ns;
113	if (channel->polarity)
114		duty = period_ns - duty_ns;
115	else
116		duty = duty_ns;
117
118	debug("%s%d: polarity %s duty %d period %d\n", __func__, channeln,
119	      channel->polarity ? "true" : "false", duty, period);
120
121	fin_freq = clk_get_rate(&channel->clk);
122	if (fin_freq == 0) {
123		printf("%s%d: invalid source clock frequency\n", __func__, channeln);
124		return -EINVAL;
125	}
126
127	debug("%s%d: fin_freq: %lu Hz\n", __func__, channeln, fin_freq);
128
129	pre_div = div64_u64(fin_freq * (u64)period, NSEC_PER_SEC * 0xffffLL);
130	if (pre_div > MISC_CLK_DIV_MASK) {
131		printf("%s%d: unable to get period pre_div\n", __func__, channeln);
132		return -EINVAL;
133	}
134
135	cnt = div64_u64(fin_freq * (u64)period, NSEC_PER_SEC * (pre_div + 1));
136	if (cnt > 0xffff) {
137		printf("%s%d: unable to get period cnt\n", __func__, channeln);
138		return -EINVAL;
139	}
140
141	debug("%s%d: period=%u pre_div=%u cnt=%u\n", __func__, channeln, period, pre_div, cnt);
142
143	if (duty == period) {
144		channel->pre_div = pre_div;
145		channel->hi = cnt;
146		channel->lo = 0;
147	} else if (duty == 0) {
148		channel->pre_div = pre_div;
149		channel->hi = 0;
150		channel->lo = cnt;
151	} else {
152		/* Then check is we can have the duty with the same pre_div */
153		duty_cnt = div64_u64(fin_freq * (u64)duty, NSEC_PER_SEC * (pre_div + 1));
154		if (duty_cnt > 0xffff) {
155			printf("%s%d: unable to get duty cycle\n", __func__, channeln);
156			return -EINVAL;
157		}
158
159		debug("%s%d: duty=%u pre_div=%u duty_cnt=%u\n",
160		      __func__, channeln, duty, pre_div, duty_cnt);
161
162		channel->pre_div = pre_div;
163		channel->hi = duty_cnt;
164		channel->lo = cnt - duty_cnt;
165	}
166
167	channel->period_ns = period_ns;
168	channel->duty_ns = duty_ns;
169	channel->configured = true;
170
171	if (channel->enabled) {
172		meson_pwm_set_enable(dev, channeln, false);
173		meson_pwm_set_enable(dev, channeln, true);
174	}
175
176	return 0;
177}
178
179static int meson_pwm_set_enable(struct udevice *dev, uint channeln, bool enable)
180{
181	struct meson_pwm *priv = dev_get_priv(dev);
182	struct meson_pwm_channel *channel;
183	struct meson_pwm_channel_data *channel_data;
184	u32 value;
185
186	if (channeln >= MESON_NUM_PWMS)
187		return -ENODEV;
188
189	channel = &priv->channels[channeln];
190	channel_data = &meson_pwm_per_channel_data[channeln];
191
192	if (!channel->configured)
193		return -EINVAL;
194
195	if (enable) {
196		if (channel->enabled)
197			return 0;
198
199		value = readl(priv->base + REG_MISC_AB);
200		value &= ~(MISC_CLK_DIV_MASK << channel_data->clk_div_shift);
201		value |= channel->pre_div << channel_data->clk_div_shift;
202		value |= channel_data->clk_en_mask;
203		writel(value, priv->base + REG_MISC_AB);
204
205		value = FIELD_PREP(PWM_HIGH_MASK, channel->hi) |
206			FIELD_PREP(PWM_LOW_MASK, channel->lo);
207		writel(value, priv->base + channel_data->reg_offset);
208
209		value = readl(priv->base + REG_MISC_AB);
210		value |= channel_data->pwm_en_mask;
211		writel(value, priv->base + REG_MISC_AB);
212
213		debug("%s%d: enabled\n", __func__, channeln);
214		channel->enabled = true;
215	} else {
216		if (!channel->enabled)
217			return 0;
218
219		value = readl(priv->base + REG_MISC_AB);
220		value &= channel_data->pwm_en_mask;
221		writel(value, priv->base + REG_MISC_AB);
222
223		debug("%s%d: disabled\n", __func__, channeln);
224		channel->enabled = false;
225	}
226
227	return 0;
228}
229
230static int meson_pwm_set_invert(struct udevice *dev, uint channeln, bool polarity)
231{
232	struct meson_pwm *priv = dev_get_priv(dev);
233	struct meson_pwm_channel *channel;
234
235	if (channeln >= MESON_NUM_PWMS)
236		return -ENODEV;
237
238	debug("%s%d: set invert %s\n", __func__, channeln, polarity ? "true" : "false");
239
240	channel = &priv->channels[channeln];
241
242	channel->polarity = polarity;
243
244	if (!channel->configured)
245		return 0;
246
247	return meson_pwm_set_config(dev, channeln, channel->period_ns, channel->duty_ns);
248}
249
250static int meson_pwm_of_to_plat(struct udevice *dev)
251{
252	struct meson_pwm *priv = dev_get_priv(dev);
253
254	priv->base = dev_read_addr_ptr(dev);
255
256	return 0;
257}
258
259static int meson_pwm_probe(struct udevice *dev)
260{
261	struct meson_pwm *priv = dev_get_priv(dev);
262	struct meson_pwm_data *data;
263	unsigned int i, p;
264	char name[255];
265	int err;
266	u32 reg;
267
268	data = (struct meson_pwm_data *)dev_get_driver_data(dev);
269	if (!data)
270		return -EINVAL;
271
272	for (i = 0; i < MESON_NUM_PWMS; i++) {
273		struct meson_pwm_channel *channel = &priv->channels[i];
274		struct meson_pwm_channel_data *channel_data = &meson_pwm_per_channel_data[i];
275
276		snprintf(name, sizeof(name), "clkin%u", i);
277
278		err = clk_get_by_name(dev, name, &channel->clk);
279		/* If clock is not specified, use the already set clock */
280		if (err == -ENODATA) {
281			struct udevice *cdev;
282			struct uclass *uc;
283
284			/* Get parent from mux */
285			p = (readl(priv->base + REG_MISC_AB) >> channel_data->clk_sel_shift) &
286				MISC_CLK_SEL_MASK;
287
288			if (p >= data->num_parents) {
289				printf("%s%d: hw parent is invalid\n", __func__, i);
290				return -EINVAL;
291			}
292
293			if (data->parent_ids[p] == -1) {
294				/* Search for xtal clk */
295				const char *str;
296
297				err = uclass_get(UCLASS_CLK, &uc);
298				if (err)
299					return err;
300
301				uclass_foreach_dev(cdev, uc) {
302					if (strcmp(cdev->driver->name, "fixed_rate_clock"))
303						continue;
304
305					str = ofnode_read_string(dev_ofnode(cdev),
306								 "clock-output-names");
307					if (!str)
308						continue;
309
310					if (!strcmp(str, "xtal")) {
311						err = uclass_get_device_by_ofnode(UCLASS_CLK,
312										  dev_ofnode(cdev),
313										  &cdev);
314						if (err) {
315							printf("%s%d: Failed to get xtal clk\n", __func__, i);
316							return err;
317						}
318
319						break;
320					}
321				}
322
323				if (!cdev) {
324					printf("%s%d: Failed to find xtal clk device\n", __func__, i);
325					return -EINVAL;
326				}
327
328				channel->clk.dev = cdev;
329				channel->clk.id = 0;
330				channel->clk.data = 0;
331			} else {
332				/* Look for parent clock */
333				err = uclass_get(UCLASS_CLK, &uc);
334				if (err)
335					return err;
336
337				uclass_foreach_dev(cdev, uc) {
338					if (strstr(cdev->driver->name, "meson_clk"))
339						break;
340				}
341
342				if (!cdev) {
343					printf("%s%d: Failed to find clk device\n", __func__, i);
344					return -EINVAL;
345				}
346
347				err = uclass_get_device_by_ofnode(UCLASS_CLK,
348								  dev_ofnode(cdev),
349								  &cdev);
350				if (err) {
351					printf("%s%d: Failed to get clk controller\n", __func__, i);
352					return err;
353				}
354
355				channel->clk.dev = cdev;
356				channel->clk.id = data->parent_ids[p];
357				channel->clk.data = 0;
358			}
359
360			/* We have our source clock, do not alter HW clock mux */
361			continue;
362		} else
363			return err;
364
365		/* Get id in list */
366		for (p = 0 ; p < data->num_parents ; ++p) {
367			if (!strcmp(channel->clk.dev->driver->name, "fixed_rate_clock")) {
368				if (data->parent_ids[p] == -1)
369					break;
370			} else {
371				if (data->parent_ids[p] == channel->clk.id)
372					break;
373			}
374		}
375
376		/* Invalid clock ID */
377		if (p == data->num_parents) {
378			printf("%s%d: source clock is invalid\n", __func__, i);
379			return -EINVAL;
380		}
381
382		/* switch parent in mux */
383		reg = readl(priv->base + REG_MISC_AB);
384
385		debug("%s%d: switching parent %d to %d\n", __func__, i,
386		      (reg >> channel_data->clk_sel_shift) & MISC_CLK_SEL_MASK, p);
387
388		reg &= MISC_CLK_SEL_MASK << channel_data->clk_sel_shift;
389		reg |= (p & MISC_CLK_SEL_MASK) << channel_data->clk_sel_shift;
390		writel(reg, priv->base + REG_MISC_AB);
391	}
392
393	return 0;
394}
395
396static const struct pwm_ops meson_pwm_ops = {
397	.set_config	= meson_pwm_set_config,
398	.set_enable	= meson_pwm_set_enable,
399	.set_invert	= meson_pwm_set_invert,
400};
401
402#define XTAL			-1
403
404/* Local clock ids aliases to avoid define conflicts */
405#define GXBB_CLKID_HDMI_PLL		2
406#define GXBB_CLKID_FCLK_DIV3		5
407#define GXBB_CLKID_FCLK_DIV4		6
408#define GXBB_CLKID_CLK81		12
409
410static const long pwm_gxbb_parent_ids[] = {
411	XTAL, GXBB_CLKID_HDMI_PLL, GXBB_CLKID_FCLK_DIV4, GXBB_CLKID_FCLK_DIV3
412};
413
414static const struct meson_pwm_data pwm_gxbb_data = {
415	.parent_ids = pwm_gxbb_parent_ids,
416	.num_parents = ARRAY_SIZE(pwm_gxbb_parent_ids),
417};
418
419/*
420 * Only the 2 first inputs of the GXBB AO PWMs are valid
421 * The last 2 are grounded
422 */
423static const long pwm_gxbb_ao_parent_ids[] = {
424	XTAL, GXBB_CLKID_CLK81
425};
426
427static const struct meson_pwm_data pwm_gxbb_ao_data = {
428	.parent_ids = pwm_gxbb_ao_parent_ids,
429	.num_parents = ARRAY_SIZE(pwm_gxbb_ao_parent_ids),
430};
431
432/* Local clock ids aliases to avoid define conflicts */
433#define AXG_CLKID_FCLK_DIV3		3
434#define AXG_CLKID_FCLK_DIV4		4
435#define AXG_CLKID_FCLK_DIV5		5
436#define AXG_CLKID_CLK81			10
437
438static const long pwm_axg_ee_parent_ids[] = {
439	XTAL, AXG_CLKID_FCLK_DIV5, AXG_CLKID_FCLK_DIV4, AXG_CLKID_FCLK_DIV3
440};
441
442static const struct meson_pwm_data pwm_axg_ee_data = {
443	.parent_ids = pwm_axg_ee_parent_ids,
444	.num_parents = ARRAY_SIZE(pwm_axg_ee_parent_ids),
445};
446
447static const long pwm_axg_ao_parent_ids[] = {
448	AXG_CLKID_CLK81, XTAL, AXG_CLKID_FCLK_DIV4, AXG_CLKID_FCLK_DIV5
449};
450
451static const struct meson_pwm_data pwm_axg_ao_data = {
452	.parent_ids = pwm_axg_ao_parent_ids,
453	.num_parents = ARRAY_SIZE(pwm_axg_ao_parent_ids),
454};
455
456/* Local clock ids aliases to avoid define conflicts */
457#define G12A_CLKID_FCLK_DIV3		3
458#define G12A_CLKID_FCLK_DIV4		4
459#define G12A_CLKID_FCLK_DIV5		5
460#define G12A_CLKID_CLK81		10
461#define G12A_CLKID_HDMI_PLL		128
462
463static const long pwm_g12a_ao_ab_parent_ids[] = {
464	XTAL, G12A_CLKID_CLK81, G12A_CLKID_FCLK_DIV4, G12A_CLKID_FCLK_DIV5
465};
466
467static const struct meson_pwm_data pwm_g12a_ao_ab_data = {
468	.parent_ids = pwm_g12a_ao_ab_parent_ids,
469	.num_parents = ARRAY_SIZE(pwm_g12a_ao_ab_parent_ids),
470};
471
472static const long pwm_g12a_ao_cd_parent_ids[] = {
473	XTAL, G12A_CLKID_CLK81,
474};
475
476static const struct meson_pwm_data pwm_g12a_ao_cd_data = {
477	.parent_ids = pwm_g12a_ao_cd_parent_ids,
478	.num_parents = ARRAY_SIZE(pwm_g12a_ao_cd_parent_ids),
479};
480
481static const long pwm_g12a_ee_parent_ids[] = {
482	XTAL, G12A_CLKID_HDMI_PLL, G12A_CLKID_FCLK_DIV4, G12A_CLKID_FCLK_DIV3
483};
484
485static const struct meson_pwm_data pwm_g12a_ee_data = {
486	.parent_ids = pwm_g12a_ee_parent_ids,
487	.num_parents = ARRAY_SIZE(pwm_g12a_ee_parent_ids),
488};
489
490static const struct udevice_id meson_pwm_ids[] = {
491	{
492		.compatible = "amlogic,meson-gxbb-pwm",
493		.data = (ulong)&pwm_gxbb_data
494	},
495	{
496		.compatible = "amlogic,meson-gxbb-ao-pwm",
497		.data = (ulong)&pwm_gxbb_ao_data
498	},
499	{
500		.compatible = "amlogic,meson-axg-ee-pwm",
501		.data = (ulong)&pwm_axg_ee_data
502	},
503	{
504		.compatible = "amlogic,meson-axg-ao-pwm",
505		.data = (ulong)&pwm_axg_ao_data
506	},
507	{
508		.compatible = "amlogic,meson-g12a-ee-pwm",
509		.data = (ulong)&pwm_g12a_ee_data
510	},
511	{
512		.compatible = "amlogic,meson-g12a-ao-pwm-ab",
513		.data = (ulong)&pwm_g12a_ao_ab_data
514	},
515	{
516		.compatible = "amlogic,meson-g12a-ao-pwm-cd",
517		.data = (ulong)&pwm_g12a_ao_cd_data
518	},
519};
520
521U_BOOT_DRIVER(meson_pwm) = {
522	.name	= "meson_pwm",
523	.id	= UCLASS_PWM,
524	.of_match = meson_pwm_ids,
525	.ops	= &meson_pwm_ops,
526	.of_to_plat = meson_pwm_of_to_plat,
527	.probe	 = meson_pwm_probe,
528	.priv_auto	= sizeof(struct meson_pwm),
529};
530