All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/31] Add DM support for omap PWM backlight
@ 2020-08-25  9:20 Dario Binacchi
  2020-08-25  9:20 ` [PATCH 01/31] clk: remove a redundant header Dario Binacchi
                   ` (25 more replies)
  0 siblings, 26 replies; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:20 UTC (permalink / raw)
  To: u-boot


The series was born from the need to manage the PWM backlight of the
display connected to my beaglebone board. To hit the target, I had to
develop drivers for PWM management which in turn relied on drivers for
managing timers and clocks, all developed according to the driver model.
My intention was to use the SoC-specific API only at strictly necessary
points in the code. My previous patches for migrating the AM335x display
driver to the driver model had required the implementation of additional
functions outside the concerns of the driver, (settings for dividing the
pixel clock rate, configuring the display DPLL rate, ....) not being
able to use the API of the related clock drivers. This series shouldn't
have repeated the same kind of mistake. Furthermore, I also wanted to fix
that kind of forced choice. Almost everything should have been accessible
via the driver model API. In the series there are also some patches that
could be submitted separately, but which I have however inserted to avoid
applying future patches to incorporate them.
With this last consideration, I hope I have convincingly justified the
large number of patches in the series.

The patch enabling address translation into a CPU physical address from
device-tree even in case of crossing levels with #size-cells = <0>, is
crucial for the series. The previous implementation was unable to
perform the address translation required by the am33xx device tree.
I tried to apply in a conservative way as few changes as possible and
to verify the execution of all the tests already developed, as well as
the new ones I added for the new feature.


Dario Binacchi (31):
  clk: remove a redundant header
  clk: export generic routines
  arch: sandbox: fix typo in clk.h
  clk: add clk_round_rate()
  clk: ti: add mux clock driver
  arm: ti: am33xx: add DPLL_EN_FAST_RELOCK_BYPASS macro
  clk: ti: am33xx: add DPLL clock drivers
  clk: ti: add divider clock driver
  clk: ti: refactor mux and divider clock drivers
  clk: ti: add gate clock driver
  ti: am33xx: fix do_enable_clocks() to accept NULL parameters
  clk: ti: add support for clkctrl clocks
  clk: ti: move drivers to 'ti' directory
  clk: ti: omap4: add clock manager driver
  clk: ti: am335x: add clock manager driver
  fdt: translate address if #size-cells = <0>
  omap: timer: fix the rate setting
  misc: am33xx: add control module driver
  pwm: ti: am33xx: add enhanced pwm driver
  pwm: ti: am33xx: add subsystem driver
  video: backlight: fix pwm's duty cycle calculation
  video: backlight: fix pwm data structure description
  dm: core: improve uclass_get_device_by_phandle_id() description
  gpio: fix gpio_request_by_name() description
  dm: core: add a function to decode display timings
  video: omap: add panel driver
  video: omap: enable LCD clock domain through DM API
  video: omap: set LCD clock rate through DM API
  video: omap: split the legacy code from the DM code
  video: omap: move drivers to 'ti' directory
  board: ti: am335x-ice: get CDCE913 clock device

 arch/arm/dts/am335x-brppt1-mmc.dts            |   3 +-
 arch/arm/dts/am335x-brppt1-nand.dts           |   3 +-
 arch/arm/dts/am335x-brppt1-spi.dts            |   3 +-
 arch/arm/dts/am335x-brsmarc1.dts              |   2 +-
 arch/arm/dts/am335x-brxre1.dts                |   3 +-
 arch/arm/dts/am335x-evm-u-boot.dtsi           |   7 +-
 arch/arm/dts/am335x-evmsk-u-boot.dtsi         |   6 +-
 arch/arm/dts/am335x-guardian-u-boot.dtsi      |   8 +-
 arch/arm/dts/am335x-pdu001-u-boot.dtsi        |   8 +-
 arch/arm/dts/am335x-pxm50-u-boot.dtsi         |   6 +-
 arch/arm/dts/am335x-rut-u-boot.dtsi           |   6 +-
 arch/arm/dts/am33xx.dtsi                      |  12 +
 arch/arm/dts/da850-evm-u-boot.dtsi            |   8 +-
 arch/arm/include/asm/arch-am33xx/clock.h      |   1 +
 arch/arm/mach-omap2/am33xx/clock.c            |  10 +-
 arch/arm/mach-omap2/am33xx/clock_am33xx.c     |   2 +-
 arch/sandbox/dts/test.dts                     |  67 +++
 arch/sandbox/include/asm/clk.h                |  35 +-
 board/ti/am335x/board.c                       |   2 +-
 board/ti/am43xx/board.c                       |   2 +-
 common/fdt_support.c                          |  10 +-
 doc/device-tree-bindings/arm/omap,ctrl.txt    |  82 +++
 doc/device-tree-bindings/arm/omap,prcm.txt    |  63 +++
 .../clock/clock-bindings.txt                  | 186 +++++++
 .../clock/gpio-gate-clock.txt                 |  21 +
 .../clock/ti,autoidle.txt                     |  39 ++
 doc/device-tree-bindings/clock/ti,clkctrl.txt |  61 +++
 .../clock/ti,clockdomain.txt                  |  24 +
 doc/device-tree-bindings/clock/ti,divider.txt | 117 +++++
 doc/device-tree-bindings/clock/ti,dpll.txt    |  85 ++++
 doc/device-tree-bindings/clock/ti,gate.txt    | 106 ++++
 doc/device-tree-bindings/clock/ti,mux.txt     |  79 +++
 .../pinctrl/pinctrl-single.txt                | 255 ++++++++++
 doc/device-tree-bindings/pwm/ti,ehrpwm.txt    |  49 ++
 doc/device-tree-bindings/pwm/ti,pwmss.txt     |  58 +++
 drivers/clk/Kconfig                           |   9 +-
 drivers/clk/Makefile                          |   2 +-
 drivers/clk/clk-divider.c                     |  18 +-
 drivers/clk/clk-uclass.c                      |  15 +
 drivers/clk/clk_sandbox.c                     |  17 +
 drivers/clk/clk_sandbox_test.c                |  10 +
 drivers/clk/ti/Kconfig                        |  42 ++
 drivers/clk/ti/Makefile                       |  18 +
 drivers/clk/ti/am3-prcm.c                     |  73 +++
 drivers/clk/ti/clk-am3-dpll-x2.c              |  78 +++
 drivers/clk/ti/clk-am3-dpll.c                 | 267 ++++++++++
 drivers/clk/ti/clk-ctrl.c                     | 102 ++++
 drivers/clk/ti/clk-divider.c                  | 380 ++++++++++++++
 drivers/clk/ti/clk-gate.c                     |  92 ++++
 drivers/clk/ti/clk-mux.c                      | 252 ++++++++++
 drivers/clk/{clk-ti-sci.c => ti/clk-sci.c}    |   0
 drivers/clk/ti/clk.c                          |  34 ++
 drivers/clk/ti/clk.h                          |  13 +
 drivers/clk/ti/omap4-cm.c                     |  22 +
 drivers/core/Kconfig                          |  12 +
 drivers/core/fdtaddr.c                        |   2 +-
 drivers/core/of_addr.c                        |  14 +-
 drivers/core/ofnode.c                         |  11 +-
 drivers/core/read.c                           |   6 +
 drivers/misc/Kconfig                          |   7 +
 drivers/misc/Makefile                         |   1 +
 drivers/misc/ti-am3-scm.c                     |  90 ++++
 drivers/pwm/Kconfig                           |  13 +
 drivers/pwm/Makefile                          |   2 +
 drivers/pwm/pwm-ti-ehrpwm.c                   | 465 ++++++++++++++++++
 drivers/pwm/pwm-ti-pwmss.c                    |  95 ++++
 drivers/timer/omap-timer.c                    |   6 +-
 drivers/video/Kconfig                         |   5 +-
 drivers/video/Makefile                        |   2 +-
 drivers/video/pwm_backlight.c                 |   4 +-
 drivers/video/ti/Kconfig                      |   8 +
 drivers/video/ti/Makefile                     |  10 +
 drivers/video/{ => ti}/am335x-fb.c            | 342 +------------
 drivers/video/{ => ti}/am335x-fb.h            |   4 -
 drivers/video/ti/tilcdc-panel.c               | 171 +++++++
 drivers/video/ti/tilcdc-panel.h               |  14 +
 drivers/video/ti/tilcdc.c                     | 438 +++++++++++++++++
 drivers/video/ti/tilcdc.h                     |  38 ++
 include/asm-generic/gpio.h                    |   2 +-
 include/clk-uclass.h                          |   8 +
 include/clk.h                                 |  29 ++
 include/dm/read.h                             |  24 +
 include/dm/uclass.h                           |   3 +-
 include/linux/clk-provider.h                  |  11 +-
 test/dm/clk.c                                 |  22 +
 test/dm/panel.c                               |  12 +-
 test/dm/test-fdt.c                            | 153 +++++-
 87 files changed, 4459 insertions(+), 438 deletions(-)
 create mode 100644 doc/device-tree-bindings/arm/omap,ctrl.txt
 create mode 100644 doc/device-tree-bindings/arm/omap,prcm.txt
 create mode 100644 doc/device-tree-bindings/clock/clock-bindings.txt
 create mode 100644 doc/device-tree-bindings/clock/gpio-gate-clock.txt
 create mode 100644 doc/device-tree-bindings/clock/ti,autoidle.txt
 create mode 100644 doc/device-tree-bindings/clock/ti,clkctrl.txt
 create mode 100644 doc/device-tree-bindings/clock/ti,clockdomain.txt
 create mode 100644 doc/device-tree-bindings/clock/ti,divider.txt
 create mode 100644 doc/device-tree-bindings/clock/ti,dpll.txt
 create mode 100644 doc/device-tree-bindings/clock/ti,gate.txt
 create mode 100644 doc/device-tree-bindings/clock/ti,mux.txt
 create mode 100644 doc/device-tree-bindings/pinctrl/pinctrl-single.txt
 create mode 100644 doc/device-tree-bindings/pwm/ti,ehrpwm.txt
 create mode 100644 doc/device-tree-bindings/pwm/ti,pwmss.txt
 create mode 100644 drivers/clk/ti/Kconfig
 create mode 100644 drivers/clk/ti/Makefile
 create mode 100644 drivers/clk/ti/am3-prcm.c
 create mode 100644 drivers/clk/ti/clk-am3-dpll-x2.c
 create mode 100644 drivers/clk/ti/clk-am3-dpll.c
 create mode 100644 drivers/clk/ti/clk-ctrl.c
 create mode 100644 drivers/clk/ti/clk-divider.c
 create mode 100644 drivers/clk/ti/clk-gate.c
 create mode 100644 drivers/clk/ti/clk-mux.c
 rename drivers/clk/{clk-ti-sci.c => ti/clk-sci.c} (100%)
 create mode 100644 drivers/clk/ti/clk.c
 create mode 100644 drivers/clk/ti/clk.h
 create mode 100644 drivers/clk/ti/omap4-cm.c
 create mode 100644 drivers/misc/ti-am3-scm.c
 create mode 100644 drivers/pwm/pwm-ti-ehrpwm.c
 create mode 100644 drivers/pwm/pwm-ti-pwmss.c
 create mode 100644 drivers/video/ti/Kconfig
 create mode 100644 drivers/video/ti/Makefile
 rename drivers/video/{ => ti}/am335x-fb.c (54%)
 rename drivers/video/{ => ti}/am335x-fb.h (97%)
 create mode 100644 drivers/video/ti/tilcdc-panel.c
 create mode 100644 drivers/video/ti/tilcdc-panel.h
 create mode 100644 drivers/video/ti/tilcdc.c
 create mode 100644 drivers/video/ti/tilcdc.h

-- 
2.17.1

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 01/31] clk: remove a redundant header
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
@ 2020-08-25  9:20 ` Dario Binacchi
  2020-08-28 23:36   ` Simon Glass
  2020-08-25  9:20 ` [PATCH 02/31] clk: export generic routines Dario Binacchi
                   ` (24 subsequent siblings)
  25 siblings, 1 reply; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:20 UTC (permalink / raw)
  To: u-boot

The linux/err.h header file was included twice.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 include/linux/clk-provider.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 79dce8f0ad..a2630056de 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -12,7 +12,6 @@
 #include <linux/bitops.h>
 #include <linux/err.h>
 #include <clk-uclass.h>
-#include <linux/err.h>
 
 struct udevice;
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 02/31] clk: export generic routines
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
  2020-08-25  9:20 ` [PATCH 01/31] clk: remove a redundant header Dario Binacchi
@ 2020-08-25  9:20 ` Dario Binacchi
  2020-08-28 23:36   ` Simon Glass
  2020-08-25  9:20 ` [PATCH 03/31] arch: sandbox: fix typo in clk.h Dario Binacchi
                   ` (23 subsequent siblings)
  25 siblings, 1 reply; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:20 UTC (permalink / raw)
  To: u-boot

Export routines that can be used by other drivers avoiding duplicating
code.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 drivers/clk/clk-divider.c    | 18 +++++++++---------
 include/linux/clk-provider.h | 10 ++++++++++
 2 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 8f59d7fb72..9fd5fa8423 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -28,7 +28,7 @@
 
 #define UBOOT_DM_CLK_CCF_DIVIDER "ccf_clk_divider"
 
-static unsigned int _get_table_div(const struct clk_div_table *table,
+unsigned int divider_get_table_div(const struct clk_div_table *table,
 				   unsigned int val)
 {
 	const struct clk_div_table *clkt;
@@ -49,7 +49,7 @@ static unsigned int _get_div(const struct clk_div_table *table,
 	if (flags & CLK_DIVIDER_MAX_AT_ZERO)
 		return val ? val : clk_div_mask(width) + 1;
 	if (table)
-		return _get_table_div(table, val);
+		return divider_get_table_div(table, val);
 	return val + 1;
 }
 
@@ -89,7 +89,7 @@ static ulong clk_divider_recalc_rate(struct clk *clk)
 				   divider->flags, divider->width);
 }
 
-static bool _is_valid_table_div(const struct clk_div_table *table,
+bool divider_is_valid_table_div(const struct clk_div_table *table,
 				unsigned int div)
 {
 	const struct clk_div_table *clkt;
@@ -100,17 +100,17 @@ static bool _is_valid_table_div(const struct clk_div_table *table,
 	return false;
 }
 
-static bool _is_valid_div(const struct clk_div_table *table, unsigned int div,
-			  unsigned long flags)
+bool divider_is_valid_div(const struct clk_div_table *table,
+			  unsigned int div, unsigned long flags)
 {
 	if (flags & CLK_DIVIDER_POWER_OF_TWO)
 		return is_power_of_2(div);
 	if (table)
-		return _is_valid_table_div(table, div);
+		return divider_is_valid_table_div(table, div);
 	return true;
 }
 
-static unsigned int _get_table_val(const struct clk_div_table *table,
+unsigned int divider_get_table_val(const struct clk_div_table *table,
 				   unsigned int div)
 {
 	const struct clk_div_table *clkt;
@@ -131,7 +131,7 @@ static unsigned int _get_val(const struct clk_div_table *table,
 	if (flags & CLK_DIVIDER_MAX_AT_ZERO)
 		return (div == clk_div_mask(width) + 1) ? 0 : div;
 	if (table)
-		return  _get_table_val(table, div);
+		return  divider_get_table_val(table, div);
 	return div - 1;
 }
 int divider_get_val(unsigned long rate, unsigned long parent_rate,
@@ -142,7 +142,7 @@ int divider_get_val(unsigned long rate, unsigned long parent_rate,
 
 	div = DIV_ROUND_UP_ULL((u64)parent_rate, rate);
 
-	if (!_is_valid_div(table, div, flags))
+	if (!divider_is_valid_div(table, div, flags))
 		return -EINVAL;
 
 	value = _get_val(table, div, flags, width);
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index a2630056de..b7cc8d89f1 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -74,6 +74,7 @@ struct clk_mux {
 #define to_clk_mux(_clk) container_of(_clk, struct clk_mux, clk)
 extern const struct clk_ops clk_mux_ops;
 u8 clk_mux_get_parent(struct clk *clk);
+unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index);
 
 struct clk_gate {
 	struct clk	clk;
@@ -124,6 +125,15 @@ struct clk_divider {
 #define CLK_DIVIDER_READ_ONLY		BIT(5)
 #define CLK_DIVIDER_MAX_AT_ZERO		BIT(6)
 extern const struct clk_ops clk_divider_ops;
+
+unsigned int divider_get_table_div(const struct clk_div_table *table,
+				   unsigned int val);
+unsigned int divider_get_table_val(const struct clk_div_table *table,
+				   unsigned int div);
+bool divider_is_valid_div(const struct clk_div_table *table,
+			  unsigned int div, unsigned long flags);
+bool divider_is_valid_table_div(const struct clk_div_table *table,
+				unsigned int div);
 unsigned long divider_recalc_rate(struct clk *hw, unsigned long parent_rate,
 				  unsigned int val,
 				  const struct clk_div_table *table,
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 03/31] arch: sandbox: fix typo in clk.h
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
  2020-08-25  9:20 ` [PATCH 01/31] clk: remove a redundant header Dario Binacchi
  2020-08-25  9:20 ` [PATCH 02/31] clk: export generic routines Dario Binacchi
@ 2020-08-25  9:20 ` Dario Binacchi
  2020-08-29 21:20   ` Simon Glass
  2020-08-25  9:20 ` [PATCH 04/31] clk: add clk_round_rate() Dario Binacchi
                   ` (22 subsequent siblings)
  25 siblings, 1 reply; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:20 UTC (permalink / raw)
  To: u-boot

Fix the 'devivce' typo in arch/sandbox/include/asm/clk.h.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 arch/sandbox/include/asm/clk.h | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/arch/sandbox/include/asm/clk.h b/arch/sandbox/include/asm/clk.h
index c184c4bffc..1163e61026 100644
--- a/arch/sandbox/include/asm/clk.h
+++ b/arch/sandbox/include/asm/clk.h
@@ -74,7 +74,7 @@ int sandbox_clk_query_requested(struct udevice *dev, int id);
  * sandbox_clk_test_get - Ask the sandbox clock test device to request its
  * clocks.
  *
- * @dev:	The sandbox clock test (client) devivce.
+ * @dev:	The sandbox clock test (client) device.
  * @return:	0 if OK, or a negative error code.
  */
 int sandbox_clk_test_get(struct udevice *dev);
@@ -83,7 +83,7 @@ int sandbox_clk_test_get(struct udevice *dev);
  * sandbox_clk_test_devm_get - Ask the sandbox clock test device to request its
  * clocks using the managed API.
  *
- * @dev:	The sandbox clock test (client) devivce.
+ * @dev:	The sandbox clock test (client) device.
  * @return:	0 if OK, or a negative error code.
  */
 int sandbox_clk_test_devm_get(struct udevice *dev);
@@ -92,7 +92,7 @@ int sandbox_clk_test_devm_get(struct udevice *dev);
  * sandbox_clk_test_get_bulk - Ask the sandbox clock test device to request its
  * clocks with the bulk clk API.
  *
- * @dev:	The sandbox clock test (client) devivce.
+ * @dev:	The sandbox clock test (client) device.
  * @return:	0 if OK, or a negative error code.
  */
 int sandbox_clk_test_get_bulk(struct udevice *dev);
@@ -100,7 +100,7 @@ int sandbox_clk_test_get_bulk(struct udevice *dev);
  * sandbox_clk_test_get_rate - Ask the sandbox clock test device to query a
  * clock's rate.
  *
- * @dev:	The sandbox clock test (client) devivce.
+ * @dev:	The sandbox clock test (client) device.
  * @id:		The test device's clock ID to query.
  * @return:	The rate of the clock.
  */
@@ -109,7 +109,7 @@ ulong sandbox_clk_test_get_rate(struct udevice *dev, int id);
  * sandbox_clk_test_set_rate - Ask the sandbox clock test device to set a
  * clock's rate.
  *
- * @dev:	The sandbox clock test (client) devivce.
+ * @dev:	The sandbox clock test (client) device.
  * @id:		The test device's clock ID to configure.
  * @return:	The new rate of the clock.
  */
@@ -118,7 +118,7 @@ ulong sandbox_clk_test_set_rate(struct udevice *dev, int id, ulong rate);
  * sandbox_clk_test_enable - Ask the sandbox clock test device to enable a
  * clock.
  *
- * @dev:	The sandbox clock test (client) devivce.
+ * @dev:	The sandbox clock test (client) device.
  * @id:		The test device's clock ID to configure.
  * @return:	0 if OK, or a negative error code.
  */
@@ -127,7 +127,7 @@ int sandbox_clk_test_enable(struct udevice *dev, int id);
  * sandbox_clk_test_enable_bulk - Ask the sandbox clock test device to enable
  * all clocks in it's clock bulk struct.
  *
- * @dev:	The sandbox clock test (client) devivce.
+ * @dev:	The sandbox clock test (client) device.
  * @return:	0 if OK, or a negative error code.
  */
 int sandbox_clk_test_enable_bulk(struct udevice *dev);
@@ -135,7 +135,7 @@ int sandbox_clk_test_enable_bulk(struct udevice *dev);
  * sandbox_clk_test_disable - Ask the sandbox clock test device to disable a
  * clock.
  *
- * @dev:	The sandbox clock test (client) devivce.
+ * @dev:	The sandbox clock test (client) device.
  * @id:		The test device's clock ID to configure.
  * @return:	0 if OK, or a negative error code.
  */
@@ -144,7 +144,7 @@ int sandbox_clk_test_disable(struct udevice *dev, int id);
  * sandbox_clk_test_disable_bulk - Ask the sandbox clock test device to disable
  * all clocks in it's clock bulk struct.
  *
- * @dev:	The sandbox clock test (client) devivce.
+ * @dev:	The sandbox clock test (client) device.
  * @return:	0 if OK, or a negative error code.
  */
 int sandbox_clk_test_disable_bulk(struct udevice *dev);
@@ -152,7 +152,7 @@ int sandbox_clk_test_disable_bulk(struct udevice *dev);
  * sandbox_clk_test_free - Ask the sandbox clock test device to free its
  * clocks.
  *
- * @dev:	The sandbox clock test (client) devivce.
+ * @dev:	The sandbox clock test (client) device.
  * @return:	0 if OK, or a negative error code.
  */
 int sandbox_clk_test_free(struct udevice *dev);
@@ -160,7 +160,7 @@ int sandbox_clk_test_free(struct udevice *dev);
  * sandbox_clk_test_release_bulk - Ask the sandbox clock test device to release
  * all clocks in it's clock bulk struct.
  *
- * @dev:	The sandbox clock test (client) devivce.
+ * @dev:	The sandbox clock test (client) device.
  * @return:	0 if OK, or a negative error code.
  */
 int sandbox_clk_test_release_bulk(struct udevice *dev);
@@ -168,7 +168,7 @@ int sandbox_clk_test_release_bulk(struct udevice *dev);
  * sandbox_clk_test_valid - Ask the sandbox clock test device to check its
  * clocks are valid.
  *
- * @dev:	The sandbox clock test (client) devivce.
+ * @dev:	The sandbox clock test (client) device.
  * @return:	0 if OK, or a negative error code.
  */
 int sandbox_clk_test_valid(struct udevice *dev);
@@ -176,7 +176,7 @@ int sandbox_clk_test_valid(struct udevice *dev);
  * sandbox_clk_test_valid - Ask the sandbox clock test device to check its
  * clocks are valid.
  *
- * @dev:	The sandbox clock test (client) devivce.
+ * @dev:	The sandbox clock test (client) device.
  * @return:	0 if OK, or a negative error code.
  */
 struct clk *sandbox_clk_test_get_devm_clk(struct udevice *dev, int id);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 04/31] clk: add clk_round_rate()
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (2 preceding siblings ...)
  2020-08-25  9:20 ` [PATCH 03/31] arch: sandbox: fix typo in clk.h Dario Binacchi
@ 2020-08-25  9:20 ` Dario Binacchi
  2020-08-29 21:20   ` Simon Glass
  2020-08-25  9:20 ` [PATCH 05/31] clk: ti: add mux clock driver Dario Binacchi
                   ` (21 subsequent siblings)
  25 siblings, 1 reply; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:20 UTC (permalink / raw)
  To: u-boot

It returns the rate which will be set if you ask clk_set_rate() to set
that rate. It provides a way to query exactly what rate you'll get if
you call clk_set_rate() with that same argument.
So essentially, clk_round_rate() and clk_set_rate() are equivalent
except the former does not modify the clock hardware in any way.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 arch/sandbox/include/asm/clk.h |  9 +++++++++
 drivers/clk/clk-uclass.c       | 15 +++++++++++++++
 drivers/clk/clk_sandbox.c      | 17 +++++++++++++++++
 drivers/clk/clk_sandbox_test.c | 10 ++++++++++
 include/clk-uclass.h           |  8 ++++++++
 include/clk.h                  | 29 +++++++++++++++++++++++++++++
 test/dm/clk.c                  | 22 ++++++++++++++++++++++
 7 files changed, 110 insertions(+)

diff --git a/arch/sandbox/include/asm/clk.h b/arch/sandbox/include/asm/clk.h
index 1163e61026..68a8687f57 100644
--- a/arch/sandbox/include/asm/clk.h
+++ b/arch/sandbox/include/asm/clk.h
@@ -105,6 +105,15 @@ int sandbox_clk_test_get_bulk(struct udevice *dev);
  * @return:	The rate of the clock.
  */
 ulong sandbox_clk_test_get_rate(struct udevice *dev, int id);
+/**
+ * sandbox_clk_test_round_rate - Ask the sandbox clock test device to round a
+ * clock's rate.
+ *
+ * @dev:	The sandbox clock test (client) device.
+ * @id:		The test device's clock ID to configure.
+ * @return:	The rounded rate of the clock.
+ */
+ulong sandbox_clk_test_round_rate(struct udevice *dev, int id, ulong rate);
 /**
  * sandbox_clk_test_set_rate - Ask the sandbox clock test device to set a
  * clock's rate.
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 934cd5787a..1b5541c3af 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -494,6 +494,21 @@ long long clk_get_parent_rate(struct clk *clk)
 	return pclk->rate;
 }
 
+ulong clk_round_rate(struct clk *clk, ulong rate)
+{
+	const struct clk_ops *ops;
+
+	debug("%s(clk=%p, rate=%lu)\n", __func__, clk, rate);
+	if (!clk_valid(clk))
+		return 0;
+
+	ops = clk_dev_ops(clk->dev);
+	if (!ops->round_rate)
+		return -ENOSYS;
+
+	return ops->round_rate(clk, rate);
+}
+
 ulong clk_set_rate(struct clk *clk, ulong rate)
 {
 	const struct clk_ops *ops;
diff --git a/drivers/clk/clk_sandbox.c b/drivers/clk/clk_sandbox.c
index 768fbb7c52..8361b930df 100644
--- a/drivers/clk/clk_sandbox.c
+++ b/drivers/clk/clk_sandbox.c
@@ -30,6 +30,22 @@ static ulong sandbox_clk_get_rate(struct clk *clk)
 	return priv->rate[clk->id];
 }
 
+static ulong sandbox_clk_round_rate(struct clk *clk, ulong rate)
+{
+	struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
+
+	if (!priv->probed)
+		return -ENODEV;
+
+	if (clk->id >= SANDBOX_CLK_ID_COUNT)
+		return -EINVAL;
+
+	if (!rate)
+		return -EINVAL;
+
+	return rate;
+}
+
 static ulong sandbox_clk_set_rate(struct clk *clk, ulong rate)
 {
 	struct sandbox_clk_priv *priv = dev_get_priv(clk->dev);
@@ -103,6 +119,7 @@ static int sandbox_clk_free(struct clk *clk)
 }
 
 static struct clk_ops sandbox_clk_ops = {
+	.round_rate	= sandbox_clk_round_rate,
 	.get_rate	= sandbox_clk_get_rate,
 	.set_rate	= sandbox_clk_set_rate,
 	.enable		= sandbox_clk_enable,
diff --git a/drivers/clk/clk_sandbox_test.c b/drivers/clk/clk_sandbox_test.c
index 873383856f..f7b77aa674 100644
--- a/drivers/clk/clk_sandbox_test.c
+++ b/drivers/clk/clk_sandbox_test.c
@@ -86,6 +86,16 @@ ulong sandbox_clk_test_get_rate(struct udevice *dev, int id)
 	return clk_get_rate(sbct->clkps[id]);
 }
 
+ulong sandbox_clk_test_round_rate(struct udevice *dev, int id, ulong rate)
+{
+	struct sandbox_clk_test *sbct = dev_get_priv(dev);
+
+	if (id < 0 || id >= SANDBOX_CLK_TEST_ID_COUNT)
+		return -EINVAL;
+
+	return clk_round_rate(sbct->clkps[id], rate);
+}
+
 ulong sandbox_clk_test_set_rate(struct udevice *dev, int id, ulong rate)
 {
 	struct sandbox_clk_test *sbct = dev_get_priv(dev);
diff --git a/include/clk-uclass.h b/include/clk-uclass.h
index dac42dab36..50e8681b55 100644
--- a/include/clk-uclass.h
+++ b/include/clk-uclass.h
@@ -61,6 +61,14 @@ struct clk_ops {
 	 * @return 0 if OK, or a negative error code.
 	 */
 	int (*rfree)(struct clk *clock);
+	/**
+	 * round_rate() - Adjust a rate to the exact rate a clock can provide.
+	 *
+	 * @clk:	The clock to manipulate.
+	 * @rate:	Desidered clock rate in Hz.
+	 * @return rounded rate in Hz, or -ve error code.
+	 */
+	ulong (*round_rate)(struct clk *clk, ulong rate);
 	/**
 	 * get_rate() - Get current clock rate.
 	 *
diff --git a/include/clk.h b/include/clk.h
index a62e2efa2c..cce763b05b 100644
--- a/include/clk.h
+++ b/include/clk.h
@@ -366,6 +366,30 @@ struct clk *clk_get_parent(struct clk *clk);
  */
 long long clk_get_parent_rate(struct clk *clk);
 
+/**
+ * clk_round_rate() - Adjust a rate to the exact rate a clock can provide
+ *
+ * This answers the question "if I were to pass @rate to clk_set_rate(),
+ * what clock rate would I end up with?" without changing the hardware
+ * in any way.  In other words:
+ *
+ *   rate = clk_round_rate(clk, r);
+ *
+ * and:
+ *
+ *   clk_set_rate(clk, r);
+ *   rate = clk_get_rate(clk);
+ *
+ * are equivalent except the former does not modify the clock hardware
+ * in any way.
+ *
+ * @clk: A clock struct that was previously successfully requested by
+ *       clk_request/get_by_*().
+ * @rate: desired clock rate in Hz.
+ * @return rounded rate in Hz, or -ve error code.
+ */
+ulong clk_round_rate(struct clk *clk, ulong rate);
+
 /**
  * clk_set_rate() - Set current clock rate.
  *
@@ -482,6 +506,11 @@ static inline long long clk_get_parent_rate(struct clk *clk)
 	return -ENOSYS;
 }
 
+static inline ulong clk_round_rate(struct clk *clk, ulong rate)
+{
+	return -ENOSYS;
+}
+
 static inline ulong clk_set_rate(struct clk *clk, ulong rate)
 {
 	return -ENOSYS;
diff --git a/test/dm/clk.c b/test/dm/clk.c
index edca3b49f6..21997ed892 100644
--- a/test/dm/clk.c
+++ b/test/dm/clk.c
@@ -112,6 +112,28 @@ static int dm_test_clk(struct unit_test_state *uts)
 	rate = sandbox_clk_test_set_rate(dev_test, SANDBOX_CLK_TEST_ID_I2C, 0);
 	ut_assert(IS_ERR_VALUE(rate));
 
+	ut_asserteq(10000, sandbox_clk_test_get_rate(dev_test,
+						     SANDBOX_CLK_TEST_ID_SPI));
+	ut_asserteq(20000, sandbox_clk_test_get_rate(dev_test,
+						     SANDBOX_CLK_TEST_ID_I2C));
+
+	ut_asserteq(5000, sandbox_clk_test_round_rate(dev_test,
+						      SANDBOX_CLK_TEST_ID_SPI,
+						      5000));
+	ut_asserteq(7000, sandbox_clk_test_round_rate(dev_test,
+						      SANDBOX_CLK_TEST_ID_I2C,
+						      7000));
+
+	ut_asserteq(10000, sandbox_clk_test_get_rate(dev_test,
+						     SANDBOX_CLK_TEST_ID_SPI));
+	ut_asserteq(20000, sandbox_clk_test_get_rate(dev_test,
+						     SANDBOX_CLK_TEST_ID_I2C));
+
+	rate = sandbox_clk_test_round_rate(dev_test, SANDBOX_CLK_TEST_ID_SPI, 0);
+	ut_assert(IS_ERR_VALUE(rate));
+	rate = sandbox_clk_test_round_rate(dev_test, SANDBOX_CLK_TEST_ID_I2C, 0);
+	ut_assert(IS_ERR_VALUE(rate));
+
 	ut_asserteq(10000, sandbox_clk_test_get_rate(dev_test,
 						     SANDBOX_CLK_TEST_ID_SPI));
 	ut_asserteq(20000, sandbox_clk_test_get_rate(dev_test,
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 05/31] clk: ti: add mux clock driver
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (3 preceding siblings ...)
  2020-08-25  9:20 ` [PATCH 04/31] clk: add clk_round_rate() Dario Binacchi
@ 2020-08-25  9:20 ` Dario Binacchi
  2020-08-25  9:20 ` [PATCH 06/31] arm: ti: am33xx: add DPLL_EN_FAST_RELOCK_BYPASS macro Dario Binacchi
                   ` (20 subsequent siblings)
  25 siblings, 0 replies; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:20 UTC (permalink / raw)
  To: u-boot

The driver manages a register-mapped multiplexer with multiple input
clock signals or parents, one of which can be selected as output. It
uses routines provided by the common clock framework (ccf).

The code is based on the drivers/clk/ti/mux.c driver of the Linux
kernel.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 .../clock/clock-bindings.txt                  | 186 ++++++++++++
 doc/device-tree-bindings/clock/ti,mux.txt     |  79 +++++
 drivers/clk/Kconfig                           |   6 +
 drivers/clk/Makefile                          |   1 +
 drivers/clk/clk-ti-mux.c                      | 275 ++++++++++++++++++
 5 files changed, 547 insertions(+)
 create mode 100644 doc/device-tree-bindings/clock/clock-bindings.txt
 create mode 100644 doc/device-tree-bindings/clock/ti,mux.txt
 create mode 100644 drivers/clk/clk-ti-mux.c

diff --git a/doc/device-tree-bindings/clock/clock-bindings.txt b/doc/device-tree-bindings/clock/clock-bindings.txt
new file mode 100644
index 0000000000..8a55fdcf96
--- /dev/null
+++ b/doc/device-tree-bindings/clock/clock-bindings.txt
@@ -0,0 +1,186 @@
+This binding is a work-in-progress, and are based on some experimental
+work by benh[1].
+
+Sources of clock signal can be represented by any node in the device
+tree.  Those nodes are designated as clock providers.  Clock consumer
+nodes use a phandle and clock specifier pair to connect clock provider
+outputs to clock inputs.  Similar to the gpio specifiers, a clock
+specifier is an array of zero, one or more cells identifying the clock
+output on a device.  The length of a clock specifier is defined by the
+value of a #clock-cells property in the clock provider node.
+
+[1] http://patchwork.ozlabs.org/patch/31551/
+
+==Clock providers==
+
+Required properties:
+#clock-cells:	   Number of cells in a clock specifier; Typically 0 for nodes
+		   with a single clock output and 1 for nodes with multiple
+		   clock outputs.
+
+Optional properties:
+clock-output-names: Recommended to be a list of strings of clock output signal
+		    names indexed by the first cell in the clock specifier.
+		    However, the meaning of clock-output-names is domain
+		    specific to the clock provider, and is only provided to
+		    encourage using the same meaning for the majority of clock
+		    providers.  This format may not work for clock providers
+		    using a complex clock specifier format.  In those cases it
+		    is recommended to omit this property and create a binding
+		    specific names property.
+
+		    Clock consumer nodes must never directly reference
+		    the provider's clock-output-names property.
+
+For example:
+
+    oscillator {
+        #clock-cells = <1>;
+        clock-output-names = "ckil", "ckih";
+    };
+
+- this node defines a device with two clock outputs, the first named
+  "ckil" and the second named "ckih".  Consumer nodes always reference
+  clocks by index. The names should reflect the clock output signal
+  names for the device.
+
+clock-indices:	   If the identifying number for the clocks in the node
+		   is not linear from zero, then this allows the mapping of
+		   identifiers into the clock-output-names array.
+
+For example, if we have two clocks <&oscillator 1> and <&oscillator 3>:
+
+	oscillator {
+		compatible = "myclocktype";
+		#clock-cells = <1>;
+		clock-indices = <1>, <3>;
+		clock-output-names = "clka", "clkb";
+	}
+
+	This ensures we do not have any empty strings in clock-output-names
+
+
+==Clock consumers==
+
+Required properties:
+clocks:		List of phandle and clock specifier pairs, one pair
+		for each clock input to the device.  Note: if the
+		clock provider specifies '0' for #clock-cells, then
+		only the phandle portion of the pair will appear.
+
+Optional properties:
+clock-names:	List of clock input name strings sorted in the same
+		order as the clocks property.  Consumers drivers
+		will use clock-names to match clock input names
+		with clocks specifiers.
+clock-ranges:	Empty property indicating that child nodes can inherit named
+		clocks from this node. Useful for bus nodes to provide a
+		clock to their children.
+
+For example:
+
+    device {
+        clocks = <&osc 1>, <&ref 0>;
+        clock-names = "baud", "register";
+    };
+
+
+This represents a device with two clock inputs, named "baud" and "register".
+The baud clock is connected to output 1 of the &osc device, and the register
+clock is connected to output 0 of the &ref.
+
+==Example==
+
+    /* external oscillator */
+    osc: oscillator {
+        compatible = "fixed-clock";
+        #clock-cells = <0>;
+        clock-frequency  = <32678>;
+        clock-output-names = "osc";
+    };
+
+    /* phase-locked-loop device, generates a higher frequency clock
+     * from the external oscillator reference */
+    pll: pll at 4c000 {
+        compatible = "vendor,some-pll-interface"
+        #clock-cells = <1>;
+        clocks = <&osc 0>;
+        clock-names = "ref";
+        reg = <0x4c000 0x1000>;
+        clock-output-names = "pll", "pll-switched";
+    };
+
+    /* UART, using the low frequency oscillator for the baud clock,
+     * and the high frequency switched PLL output for register
+     * clocking */
+    uart at a000 {
+        compatible = "fsl,imx-uart";
+        reg = <0xa000 0x1000>;
+        interrupts = <33>;
+        clocks = <&osc 0>, <&pll 1>;
+        clock-names = "baud", "register";
+    };
+
+This DT fragment defines three devices: an external oscillator to provide a
+low-frequency reference clock, a PLL device to generate a higher frequency
+clock signal, and a UART.
+
+* The oscillator is fixed-frequency, and provides one clock output, named "osc".
+* The PLL is both a clock provider and a clock consumer. It uses the clock
+  signal generated by the external oscillator, and provides two output signals
+  ("pll" and "pll-switched").
+* The UART has its baud clock connected the external oscillator and its
+  register clock connected to the PLL clock (the "pll-switched" signal)
+
+==Assigned clock parents and rates==
+
+Some platforms may require initial configuration of default parent clocks
+and clock frequencies. Such a configuration can be specified in a device tree
+node through assigned-clocks, assigned-clock-parents and assigned-clock-rates
+properties. The assigned-clock-parents property should contain a list of parent
+clocks in the form of a phandle and clock specifier pair and the
+assigned-clock-rates property should contain a list of frequencies in Hz. Both
+these properties should correspond to the clocks listed in the assigned-clocks
+property.
+
+To skip setting parent or rate of a clock its corresponding entry should be
+set to 0, or can be omitted if it is not followed by any non-zero entry.
+
+    uart at a000 {
+        compatible = "fsl,imx-uart";
+        reg = <0xa000 0x1000>;
+        ...
+        clocks = <&osc 0>, <&pll 1>;
+        clock-names = "baud", "register";
+
+        assigned-clocks = <&clkcon 0>, <&pll 2>;
+        assigned-clock-parents = <&pll 2>;
+        assigned-clock-rates = <0>, <460800>;
+    };
+
+In this example the <&pll 2> clock is set as parent of clock <&clkcon 0> and
+the <&pll 2> clock is assigned a frequency value of 460800 Hz.
+
+Configuring a clock's parent and rate through the device node that consumes
+the clock can be done only for clocks that have a single user. Specifying
+conflicting parent or rate configuration in multiple consumer nodes for
+a shared clock is forbidden.
+
+Configuration of common clocks, which affect multiple consumer devices can
+be similarly specified in the clock provider node.
+
+==Protected clocks==
+
+Some platforms or firmwares may not fully expose all the clocks to the OS, such
+as in situations where those clks are used by drivers running in ARM secure
+execution levels. Such a configuration can be specified in device tree with the
+protected-clocks property in the form of a clock specifier list. This property should
+only be specified in the node that is providing the clocks being protected:
+
+   clock-controller at a000f000 {
+        compatible = "vendor,clk95;
+        reg = <0xa000f000 0x1000>
+        #clocks-cells = <1>;
+        ...
+        protected-clocks = <UART3_CLK>, <SPI5_CLK>;
+   };
diff --git a/doc/device-tree-bindings/clock/ti,mux.txt b/doc/device-tree-bindings/clock/ti,mux.txt
new file mode 100644
index 0000000000..4c279288cb
--- /dev/null
+++ b/doc/device-tree-bindings/clock/ti,mux.txt
@@ -0,0 +1,79 @@
+Binding for TI mux clock.
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1].  It assumes a
+register-mapped multiplexer with multiple input clock signals or
+parents, one of which can be selected as output.  This clock does not
+gate or adjust the parent rate via a divider or multiplier.
+
+By default the "clocks" property lists the parents in the same order
+as they are programmed into the register.  E.g:
+
+	clocks = <&foo_clock>, <&bar_clock>, <&baz_clock>;
+
+results in programming the register as follows:
+
+register value		selected parent clock
+0			foo_clock
+1			bar_clock
+2			baz_clock
+
+Some clock controller IPs do not allow a value of zero to be programmed
+into the register, instead indexing begins at 1.  The optional property
+"index-starts-at-one" modified the scheme as follows:
+
+register value		selected clock parent
+1			foo_clock
+2			bar_clock
+3			baz_clock
+
+The binding must provide the register to control the mux. Optionally
+the number of bits to shift the control field in the register can be
+supplied. If the shift value is missing it is the same as supplying
+a zero shift.
+
+[1] doc/device-tree-bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be "ti,mux-clock" or "ti,composite-mux-clock".
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks : link phandles of parent clocks
+- reg : register offset for register controlling adjustable mux
+
+Optional properties:
+- ti,bit-shift : number of bits to shift the bit-mask, defaults to
+  0 if not present
+- ti,index-starts-at-one : valid input select programming starts at 1, not
+  zero
+- ti,set-rate-parent : clk_set_rate is propagated to parent clock,
+  not supported by the composite-mux-clock subtype
+- ti,latch-bit : latch the mux value to HW, only needed if the register
+  access requires this. As an example, dra7x DPLL_GMAC H14 muxing
+  implements such behavior.
+
+Examples:
+
+sys_clkin_ck: sys_clkin_ck at 4a306110 {
+	#clock-cells = <0>;
+	compatible = "ti,mux-clock";
+	clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_27000000_ck>, <&virt_38400000_ck>;
+	reg = <0x0110>;
+	ti,index-starts-at-one;
+};
+
+abe_dpll_bypass_clk_mux_ck: abe_dpll_bypass_clk_mux_ck at 4a306108 {
+	#clock-cells = <0>;
+	compatible = "ti,mux-clock";
+	clocks = <&sys_clkin_ck>, <&sys_32k_ck>;
+	ti,bit-shift = <24>;
+	reg = <0x0108>;
+};
+
+mcbsp5_mux_fck: mcbsp5_mux_fck {
+	#clock-cells = <0>;
+	compatible = "ti,composite-mux-clock";
+	clocks = <&core_96m_fck>, <&mcbsp_clks>;
+	ti,bit-shift = <4>;
+	reg = <0x02d8>;
+};
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 6003e140b5..f070d2637f 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -98,6 +98,12 @@ config CLK_STM32F
 	  This clock driver adds support for RCC clock management
 	  for STM32F4 and STM32F7 SoCs.
 
+config CLK_TI_MUX
+	bool "TI mux clock driver"
+	depends on CLK && OF_CONTROL && CLK_CCF
+	help
+	  This enables the mux clock driver support on TI's SoCs.
+
 config CLK_TI_SCI
 	bool "TI System Control Interface (TI SCI) clock driver"
 	depends on CLK && TI_SCI_PROTOCOL && OF_CONTROL
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index cda4b4b605..c0dfe4b599 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_SANDBOX) += clk_sandbox.o
 obj-$(CONFIG_SANDBOX) += clk_sandbox_test.o
 obj-$(CONFIG_SANDBOX_CLK_CCF) += clk_sandbox_ccf.o
 obj-$(CONFIG_STM32H7) += clk_stm32h7.o
+obj-$(CONFIG_CLK_TI_MUX) += clk-ti-mux.o
 obj-$(CONFIG_CLK_TI_SCI) += clk-ti-sci.o
 obj-$(CONFIG_CLK_VERSAL) += clk_versal.o
 obj-$(CONFIG_CLK_CDCE9XX) += clk-cdce9xx.o
diff --git a/drivers/clk/clk-ti-mux.c b/drivers/clk/clk-ti-mux.c
new file mode 100644
index 0000000000..7e39dd3477
--- /dev/null
+++ b/drivers/clk/clk-ti-mux.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TI multiplexer clock support
+ *
+ * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+ *
+ * Based on Linux kernel drivers/clk/ti/mux.c
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <clk-uclass.h>
+#include <asm/io.h>
+#include <linux/clk-provider.h>
+
+struct clk_ti_mux_priv {
+	struct clk_bulk parents;
+	fdt_addr_t reg;
+	u32 flags;
+	u32 mux_flags;
+	u32 mask;
+	u32 shift;
+	s32 latch;
+};
+
+static void clk_ti_mux_rmw(u32 val, u32 mask, fdt_addr_t reg)
+{
+	u32 v;
+
+	v = readl(reg);
+	v &= ~mask;
+	v |= val;
+	writel(v, reg);
+}
+
+static void clk_ti_mux_latch(fdt_addr_t reg, s8 shift)
+{
+	u32 latch;
+
+	if (shift < 0)
+		return;
+
+	latch = 1 << shift;
+
+	clk_ti_mux_rmw(latch, latch, reg);
+	clk_ti_mux_rmw(0, latch, reg);
+	readl(reg);		/* OCP barrier */
+}
+
+static struct clk *clk_ti_mux_get_parent_by_index(struct clk_bulk *parents,
+						  int index)
+{
+	if (index < 0 || !parents)
+		return ERR_PTR(-EINVAL);
+
+	if (index >= parents->count)
+		return ERR_PTR(-ENODEV);
+
+	return &parents->clks[index];
+}
+
+static int clk_ti_mux_get_parent_index(struct clk_bulk *parents,
+				       struct clk *parent)
+{
+	int i;
+
+	if (!parents || !parent)
+		return -EINVAL;
+
+	for (i = 0; i < parents->count; i++) {
+		if (parents->clks[i].dev == parent->dev)
+			return i;
+	}
+
+	return -ENODEV;
+}
+
+static int clk_ti_mux_get_index(struct clk *clk)
+{
+	struct clk_ti_mux_priv *priv = dev_get_priv(clk->dev);
+	u32 val;
+
+	val = readl(priv->reg);
+	val >>= priv->shift;
+	val &= priv->mask;
+
+	if (val && (priv->flags & CLK_MUX_INDEX_BIT))
+		val = ffs(val) - 1;
+
+	if (val && (priv->flags & CLK_MUX_INDEX_ONE))
+		val--;
+
+	if (val >= priv->parents.count)
+		return -EINVAL;
+
+	return val;
+}
+
+static int clk_ti_mux_set_parent(struct clk *clk, struct clk *parent)
+{
+	struct clk_ti_mux_priv *priv = dev_get_priv(clk->dev);
+	int index;
+	u32 val;
+
+	index = clk_ti_mux_get_parent_index(&priv->parents, parent);
+	if (index < 0) {
+		dev_err(clk->dev, "failed to get parent clock\n");
+		return index;
+	}
+
+	index = clk_mux_index_to_val(NULL, priv->flags, index);
+
+	if (priv->flags & CLK_MUX_HIWORD_MASK) {
+		val = priv->mask << (priv->shift + 16);
+	} else {
+		val = readl(priv->reg);
+		val &= ~(priv->mask << priv->shift);
+	}
+
+	val |= index << priv->shift;
+	writel(val, priv->reg);
+	clk_ti_mux_latch(priv->reg, priv->latch);
+	return 0;
+}
+
+static ulong clk_ti_mux_set_rate(struct clk *clk, ulong rate)
+{
+	struct clk_ti_mux_priv *priv = dev_get_priv(clk->dev);
+	struct clk *parent;
+	int index;
+
+	if ((clk->flags & CLK_SET_RATE_PARENT) == 0)
+		return -ENOSYS;
+
+	index = clk_ti_mux_get_index(clk);
+	parent = clk_ti_mux_get_parent_by_index(&priv->parents, index);
+	if (IS_ERR(parent))
+		return PTR_ERR(parent);
+
+	rate = clk_set_rate(parent, rate);
+	dev_dbg(clk->dev, "rate=%ld\n", rate);
+	return rate;
+}
+
+static ulong clk_ti_mux_get_rate(struct clk *clk)
+{
+	struct clk_ti_mux_priv *priv = dev_get_priv(clk->dev);
+	int index;
+	struct clk *parent;
+	ulong rate;
+
+	index = clk_ti_mux_get_index(clk);
+	parent = clk_ti_mux_get_parent_by_index(&priv->parents, index);
+	if (IS_ERR(parent))
+		return PTR_ERR(parent);
+
+	rate = clk_get_rate(parent);
+	dev_dbg(clk->dev, "rate=%ld\n", rate);
+	return rate;
+}
+
+static ulong clk_ti_mux_round_rate(struct clk *clk, ulong rate)
+{
+	struct clk_ti_mux_priv *priv = dev_get_priv(clk->dev);
+	struct clk *parent;
+	int index;
+
+	if ((clk->flags & CLK_SET_RATE_PARENT) == 0)
+		return -ENOSYS;
+
+	index = clk_ti_mux_get_index(clk);
+	parent = clk_ti_mux_get_parent_by_index(&priv->parents, index);
+	if (IS_ERR(parent))
+		return PTR_ERR(parent);
+
+	rate = clk_round_rate(parent, rate);
+	dev_dbg(clk->dev, "rate=%ld\n", rate);
+	return rate;
+}
+
+static int clk_ti_mux_request(struct clk *clk)
+{
+	struct clk_ti_mux_priv *priv = dev_get_priv(clk->dev);
+	struct clk *parent;
+	int index;
+
+	clk->flags = priv->flags;
+
+	index = clk_ti_mux_get_index(clk);
+	parent = clk_ti_mux_get_parent_by_index(&priv->parents, index);
+	if (IS_ERR(parent))
+		return PTR_ERR(parent);
+
+	return clk_ti_mux_set_parent(clk, parent);
+}
+
+static struct clk_ops clk_ti_mux_ops = {
+	.request = clk_ti_mux_request,
+	.round_rate = clk_ti_mux_round_rate,
+	.get_rate = clk_ti_mux_get_rate,
+	.set_rate = clk_ti_mux_set_rate,
+	.set_parent = clk_ti_mux_set_parent,
+};
+
+static int clk_ti_mux_remove(struct udevice *dev)
+{
+	struct clk_ti_mux_priv *priv = dev_get_priv(dev);
+	int err;
+
+	err = clk_release_all(priv->parents.clks, priv->parents.count);
+	if (err)
+		dev_dbg(dev, "could not release all parents' clocks\n");
+
+	return err;
+}
+
+static int clk_ti_mux_probe(struct udevice *dev)
+{
+	struct clk_ti_mux_priv *priv = dev_get_priv(dev);
+	int err;
+
+	err = clk_get_bulk(dev, &priv->parents);
+	if (err || priv->parents.count < 2) {
+		dev_err(dev, "mux-clock must have parents\n");
+		return err ? err : -EFAULT;
+	}
+
+	/* Generate bit-mask based on parents info */
+	priv->mask = priv->parents.count;
+	if (!(priv->mux_flags & CLK_MUX_INDEX_ONE))
+		priv->mask--;
+
+	priv->mask = (1 << fls(priv->mask)) - 1;
+	return 0;
+}
+
+static int clk_ti_mux_ofdata_to_platdata(struct udevice *dev)
+{
+	struct clk_ti_mux_priv *priv = dev_get_priv(dev);
+
+	priv->reg = dev_read_addr(dev);
+	if (priv->reg == FDT_ADDR_T_NONE) {
+		dev_err(dev, "failed to get register\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "reg=0x%08lx\n", priv->reg);
+	priv->shift = dev_read_u32_default(dev, "ti,bit-shift", 0);
+	priv->latch = dev_read_s32_default(dev, "ti,latch-bit", -EINVAL);
+
+	priv->flags = CLK_SET_RATE_NO_REPARENT;
+	if (dev_read_bool(dev, "ti,set-rate-parent"))
+		priv->flags |= CLK_SET_RATE_PARENT;
+
+	if (dev_read_bool(dev, "ti,index-starts-at-one"))
+		priv->mux_flags |= CLK_MUX_INDEX_ONE;
+
+	return 0;
+}
+
+static const struct udevice_id clk_ti_mux_of_match[] = {
+	{.compatible = "ti,mux-clock"},
+	{},
+};
+
+U_BOOT_DRIVER(clk_ti_mux) = {
+	.name = "ti_mux_clock",
+	.id = UCLASS_CLK,
+	.of_match = clk_ti_mux_of_match,
+	.ofdata_to_platdata = clk_ti_mux_ofdata_to_platdata,
+	.probe = clk_ti_mux_probe,
+	.remove = clk_ti_mux_remove,
+	.priv_auto_alloc_size = sizeof(struct clk_ti_mux_priv),
+	.ops = &clk_ti_mux_ops,
+};
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 06/31] arm: ti: am33xx: add DPLL_EN_FAST_RELOCK_BYPASS macro
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (4 preceding siblings ...)
  2020-08-25  9:20 ` [PATCH 05/31] clk: ti: add mux clock driver Dario Binacchi
@ 2020-08-25  9:20 ` Dario Binacchi
  2020-08-25  9:21 ` [PATCH 07/31] clk: ti: am33xx: add DPLL clock drivers Dario Binacchi
                   ` (19 subsequent siblings)
  25 siblings, 0 replies; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:20 UTC (permalink / raw)
  To: u-boot

Add missing DPLL_EN_FAST_RELOCK_BYPASS macro. Used to put the DPLL in
idle bypass fast relock mode.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 arch/arm/include/asm/arch-am33xx/clock.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/include/asm/arch-am33xx/clock.h b/arch/arm/include/asm/arch-am33xx/clock.h
index dc7a9b188d..5d775902bb 100644
--- a/arch/arm/include/asm/arch-am33xx/clock.h
+++ b/arch/arm/include/asm/arch-am33xx/clock.h
@@ -66,6 +66,7 @@
 #define DPLL_EN_STOP			1
 #define DPLL_EN_MN_BYPASS		4
 #define DPLL_EN_LOW_POWER_BYPASS	5
+#define DPLL_EN_FAST_RELOCK_BYPASS	6
 #define DPLL_EN_LOCK			7
 
 /* CM_IDLEST_DPLL fields */
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 07/31] clk: ti: am33xx: add DPLL clock drivers
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (5 preceding siblings ...)
  2020-08-25  9:20 ` [PATCH 06/31] arm: ti: am33xx: add DPLL_EN_FAST_RELOCK_BYPASS macro Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  2020-08-25  9:21 ` [PATCH 08/31] clk: ti: add divider clock driver Dario Binacchi
                   ` (18 subsequent siblings)
  25 siblings, 0 replies; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

The digital phase-locked loop (DPLL) provides all interface clocks and
functional clocks to the processor of the AM33xx device. The AM33xx
device integrates five different DPLLs:
 * Core DPLL
 * Per DPLL
 * LCD DPLL
 * DDR DPLL
 * MPU DPLL

The patch adds support for the compatible strings:
 * "ti,am3-dpll-core-clock"
 * "ti,am3-dpll-no-gate-clock"
 * "ti,am3-dpll-no-gate-j-type-clock"
 * "ti,am3-dpll-x2-clock"

The code is loosely based on the drivers/clk/ti/dpll.c drivers of the
Linux kernel.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 doc/device-tree-bindings/clock/ti,dpll.txt |  85 +++++++
 drivers/clk/Kconfig                        |   7 +
 drivers/clk/Makefile                       |   1 +
 drivers/clk/clk-ti-am3-dpll-x2.c           |  78 ++++++
 drivers/clk/clk-ti-am3-dpll.c              | 267 +++++++++++++++++++++
 5 files changed, 438 insertions(+)
 create mode 100644 doc/device-tree-bindings/clock/ti,dpll.txt
 create mode 100644 drivers/clk/clk-ti-am3-dpll-x2.c
 create mode 100644 drivers/clk/clk-ti-am3-dpll.c

diff --git a/doc/device-tree-bindings/clock/ti,dpll.txt b/doc/device-tree-bindings/clock/ti,dpll.txt
new file mode 100644
index 0000000000..a807b09241
--- /dev/null
+++ b/doc/device-tree-bindings/clock/ti,dpll.txt
@@ -0,0 +1,85 @@
+Binding for Texas Instruments DPLL clock.
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1].  It assumes a
+register-mapped DPLL with usually two selectable input clocks
+(reference clock and bypass clock), with digital phase locked
+loop logic for multiplying the input clock to a desired output
+clock. This clock also typically supports different operation
+modes (locked, low power stop etc.) This binding has several
+sub-types, which effectively result in slightly different setup
+for the actual DPLL clock.
+
+[1] doc/device-tree-bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be one of:
+		"ti,omap3-dpll-clock",
+		"ti,omap3-dpll-core-clock",
+		"ti,omap3-dpll-per-clock",
+		"ti,omap3-dpll-per-j-type-clock",
+		"ti,omap4-dpll-clock",
+		"ti,omap4-dpll-x2-clock",
+		"ti,omap4-dpll-core-clock",
+		"ti,omap4-dpll-m4xen-clock",
+		"ti,omap4-dpll-j-type-clock",
+		"ti,omap5-mpu-dpll-clock",
+		"ti,am3-dpll-no-gate-clock",
+		"ti,am3-dpll-j-type-clock",
+		"ti,am3-dpll-no-gate-j-type-clock",
+		"ti,am3-dpll-clock",
+		"ti,am3-dpll-core-clock",
+		"ti,am3-dpll-x2-clock",
+		"ti,omap2-dpll-core-clock",
+
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks : link phandles of parent clocks, first entry lists reference clock
+  and second entry bypass clock
+- reg : offsets for the register set for controlling the DPLL.
+  Registers are listed in following order:
+	"control" - contains the control register base address
+	"idlest" - contains the idle status register base address
+	"mult-div1" - contains the multiplier / divider register base address
+	"autoidle" - contains the autoidle register base address (optional)
+  ti,am3-* dpll types do not have autoidle register
+  ti,omap2-* dpll type does not support idlest / autoidle registers
+
+Optional properties:
+- DPLL mode setting - defining any one or more of the following overrides
+  default setting.
+	- ti,low-power-stop : DPLL supports low power stop mode, gating output
+	- ti,low-power-bypass : DPLL output matches rate of parent bypass clock
+	- ti,lock : DPLL locks in programmed rate
+
+Examples:
+	dpll_core_ck: dpll_core_ck at 44e00490 {
+		#clock-cells = <0>;
+		compatible = "ti,omap4-dpll-core-clock";
+		clocks = <&sys_clkin_ck>, <&sys_clkin_ck>;
+		reg = <0x490>, <0x45c>, <0x488>, <0x468>;
+	};
+
+	dpll2_ck: dpll2_ck at 48004004 {
+		#clock-cells = <0>;
+		compatible = "ti,omap3-dpll-clock";
+		clocks = <&sys_ck>, <&dpll2_fck>;
+		ti,low-power-stop;
+		ti,low-power-bypass;
+		ti,lock;
+		reg = <0x4>, <0x24>, <0x34>, <0x40>;
+	};
+
+	dpll_core_ck: dpll_core_ck at 44e00490 {
+		#clock-cells = <0>;
+		compatible = "ti,am3-dpll-core-clock";
+		clocks = <&sys_clkin_ck>, <&sys_clkin_ck>;
+		reg = <0x90>, <0x5c>, <0x68>;
+	};
+
+	dpll_ck: dpll_ck {
+		#clock-cells = <0>;
+		compatible = "ti,omap2-dpll-core-clock";
+		clocks = <&sys_ck>, <&sys_ck>;
+		reg = <0x0500>, <0x0540>;
+	};
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index f070d2637f..bddb454b7c 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -98,6 +98,13 @@ config CLK_STM32F
 	  This clock driver adds support for RCC clock management
 	  for STM32F4 and STM32F7 SoCs.
 
+config CLK_TI_AM3_DPLL
+	bool "TI AM33XX Digital Phase-Locked Loop (DPLL) clock drivers"
+	depends on CLK && OF_CONTROL
+	help
+	  This enables the DPLL clock drivers support on AM33XX SoCs. The DPLL
+	  provides all interface clocks and functional clocks to the processor.
+
 config CLK_TI_MUX
 	bool "TI mux clock driver"
 	depends on CLK && OF_CONTROL && CLK_CCF
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index c0dfe4b599..cc20279a20 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_SANDBOX) += clk_sandbox.o
 obj-$(CONFIG_SANDBOX) += clk_sandbox_test.o
 obj-$(CONFIG_SANDBOX_CLK_CCF) += clk_sandbox_ccf.o
 obj-$(CONFIG_STM32H7) += clk_stm32h7.o
+obj-$(CONFIG_CLK_TI_AM3_DPLL) += clk-ti-am3-dpll.o clk-ti-am3-dpll-x2.o
 obj-$(CONFIG_CLK_TI_MUX) += clk-ti-mux.o
 obj-$(CONFIG_CLK_TI_SCI) += clk-ti-sci.o
 obj-$(CONFIG_CLK_VERSAL) += clk_versal.o
diff --git a/drivers/clk/clk-ti-am3-dpll-x2.c b/drivers/clk/clk-ti-am3-dpll-x2.c
new file mode 100644
index 0000000000..c8dedbe1f8
--- /dev/null
+++ b/drivers/clk/clk-ti-am3-dpll-x2.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TI DPLL x2 clock support
+ *
+ * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+ *
+ * Loosely based on Linux kernel drivers/clk/ti/dpll.c
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <linux/clk-provider.h>
+
+struct clk_ti_am3_dpll_x2_priv {
+	struct clk parent;
+};
+
+static ulong clk_ti_am3_dpll_x2_get_rate(struct clk *clk)
+{
+	struct clk_ti_am3_dpll_x2_priv *priv = dev_get_priv(clk->dev);
+	unsigned long rate;
+
+	rate = clk_get_rate(&priv->parent);
+	if (IS_ERR_VALUE(rate))
+		return rate;
+
+	rate *= 2;
+	dev_dbg(clk->dev, "rate=%ld\n", rate);
+	return rate;
+}
+
+const struct clk_ops clk_ti_am3_dpll_x2_ops = {
+	.get_rate = clk_ti_am3_dpll_x2_get_rate,
+};
+
+static int clk_ti_am3_dpll_x2_remove(struct udevice *dev)
+{
+	struct clk_ti_am3_dpll_x2_priv *priv = dev_get_priv(dev);
+	int err;
+
+	err = clk_release_all(&priv->parent, 1);
+	if (err) {
+		dev_err(dev, "failed to release parent clock\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static int clk_ti_am3_dpll_x2_probe(struct udevice *dev)
+{
+	struct clk_ti_am3_dpll_x2_priv *priv = dev_get_priv(dev);
+	int err;
+
+	err = clk_get_by_index(dev, 0, &priv->parent);
+	if (err) {
+		dev_err(dev, "%s: failed to get parent clock\n", __func__);
+		return err;
+	}
+
+	return 0;
+}
+
+static const struct udevice_id clk_ti_am3_dpll_x2_of_match[] = {
+	{.compatible = "ti,am3-dpll-x2-clock"},
+	{}
+};
+
+U_BOOT_DRIVER(clk_ti_am3_dpll_x2) = {
+	.name = "ti_am3_dpll_x2_clock",
+	.id = UCLASS_CLK,
+	.of_match = clk_ti_am3_dpll_x2_of_match,
+	.probe = clk_ti_am3_dpll_x2_probe,
+	.remove = clk_ti_am3_dpll_x2_remove,
+	.priv_auto_alloc_size = sizeof(struct clk_ti_am3_dpll_x2_priv),
+	.ops = &clk_ti_am3_dpll_x2_ops,
+};
diff --git a/drivers/clk/clk-ti-am3-dpll.c b/drivers/clk/clk-ti-am3-dpll.c
new file mode 100644
index 0000000000..75739f991f
--- /dev/null
+++ b/drivers/clk/clk-ti-am3-dpll.c
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TI DPLL clock support
+ *
+ * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+ *
+ * Loosely based on Linux kernel drivers/clk/ti/dpll.c
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <clk-uclass.h>
+#include <div64.h>
+#include <dm.h>
+#include <hang.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/io.h>
+
+struct clk_ti_am3_dpll_drv_data {
+	ulong max_rate;
+};
+
+struct clk_ti_am3_dpll_priv {
+	fdt_addr_t clkmode_reg;
+	fdt_addr_t idlest_reg;
+	fdt_addr_t clksel_reg;
+	struct clk clk_bypass;
+	struct clk clk_ref;
+	u16 last_rounded_mult;
+	u8 last_rounded_div;
+	ulong max_rate;
+};
+
+static ulong clk_ti_am3_dpll_round_rate(struct clk *clk, ulong rate)
+{
+	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(clk->dev);
+	ulong ret, ref_rate, r;
+	int m, d, err_min, err;
+	int mult = INT_MAX, div = INT_MAX;
+
+	if (priv->max_rate && rate > priv->max_rate) {
+		dev_warn(dev, "%ld is to high a rate, lowered to %ld\n", rate,
+			 priv->max_rate);
+		rate = priv->max_rate;
+	}
+
+	ret = -EFAULT;
+	err = rate;
+	err_min = rate;
+	ref_rate = clk_get_rate(&priv->clk_ref);
+	for (d = 1; err_min && d <= 128; d++) {
+		for (m = 2; m <= 2047; m++) {
+			r = (ref_rate * m) / d;
+			err = abs(r - rate);
+			if (err < err_min) {
+				err_min = err;
+				ret = r;
+				mult = m;
+				div = d;
+
+				if (err == 0)
+					break;
+			} else if (r > rate) {
+				break;
+			}
+		}
+	}
+
+	priv->last_rounded_mult = mult;
+	priv->last_rounded_div = div;
+	dev_dbg(dev, "rate=%ld, best_rate=%ld, mult=%d, div=%d\n", rate, ret,
+		mult, div);
+	return ret;
+}
+
+static ulong clk_ti_am3_dpll_set_rate(struct clk *clk, ulong rate)
+{
+	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(clk->dev);
+	u32 v;
+	ulong round_rate;
+
+	round_rate = clk_ti_am3_dpll_round_rate(clk, rate);
+	if (IS_ERR_VALUE(round_rate))
+		return round_rate;
+
+	v = readl(priv->clksel_reg);
+
+	/* enter bypass mode */
+	clrsetbits_le32(priv->clkmode_reg, CM_CLKMODE_DPLL_DPLL_EN_MASK,
+			DPLL_EN_MN_BYPASS << CM_CLKMODE_DPLL_EN_SHIFT);
+
+	/* wait for bypass mode */
+	if (!wait_on_value(ST_DPLL_CLK_MASK, 0,
+			   (void *)priv->idlest_reg, LDELAY))
+		dev_err(clk->dev, "failed bypassing dpll\n");
+
+	/* set M & N */
+	v &= ~CM_CLKSEL_DPLL_M_MASK;
+	v |= (priv->last_rounded_mult << CM_CLKSEL_DPLL_M_SHIFT) &
+		CM_CLKSEL_DPLL_M_MASK;
+
+	v &= ~CM_CLKSEL_DPLL_N_MASK;
+	v |= ((priv->last_rounded_div - 1) << CM_CLKSEL_DPLL_N_SHIFT) &
+		CM_CLKSEL_DPLL_N_MASK;
+
+	writel(v, priv->clksel_reg);
+
+	/* lock dpll */
+	clrsetbits_le32(priv->clkmode_reg, CM_CLKMODE_DPLL_DPLL_EN_MASK,
+			DPLL_EN_LOCK << CM_CLKMODE_DPLL_EN_SHIFT);
+
+	/* wait till the dpll locks */
+	if (!wait_on_value(ST_DPLL_CLK_MASK, ST_DPLL_CLK_MASK,
+			   (void *)priv->idlest_reg, LDELAY)) {
+		dev_err(clk->dev, "failed locking dpll\n");
+		hang();
+	}
+
+	return round_rate;
+}
+
+static ulong clk_ti_am3_dpll_get_rate(struct clk *clk)
+{
+	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(clk->dev);
+	u64 rate;
+	u32 m, n, v;
+
+	/* Return bypass rate if DPLL is bypassed */
+	v = readl(priv->clkmode_reg);
+	v &= CM_CLKMODE_DPLL_EN_MASK;
+	v >>= CM_CLKMODE_DPLL_EN_SHIFT;
+
+	switch (v) {
+	case DPLL_EN_MN_BYPASS:
+	case DPLL_EN_LOW_POWER_BYPASS:
+	case DPLL_EN_FAST_RELOCK_BYPASS:
+		rate = clk_get_rate(&priv->clk_bypass);
+		dev_dbg(clk->dev, "rate=%lld\n", rate);
+		return rate;
+	}
+
+	v = readl(priv->clksel_reg);
+	m = v & CM_CLKSEL_DPLL_M_MASK;
+	m >>= CM_CLKSEL_DPLL_M_SHIFT;
+	n = v & CM_CLKSEL_DPLL_N_MASK;
+	n >>= CM_CLKSEL_DPLL_N_SHIFT;
+
+	rate = clk_get_rate(&priv->clk_ref) * m;
+	do_div(rate, n + 1);
+	dev_dbg(clk->dev, "rate=%lld\n", rate);
+	return rate;
+}
+
+const struct clk_ops clk_ti_am3_dpll_ops = {
+	.round_rate = clk_ti_am3_dpll_round_rate,
+	.get_rate = clk_ti_am3_dpll_get_rate,
+	.set_rate = clk_ti_am3_dpll_set_rate,
+};
+
+static int clk_ti_am3_dpll_remove(struct udevice *dev)
+{
+	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(dev);
+	int err;
+
+	err = clk_release_all(&priv->clk_bypass, 1);
+	if (err) {
+		dev_err(dev, "failed to release bypass clock\n");
+		return err;
+	}
+
+	err = clk_release_all(&priv->clk_ref, 1);
+	if (err) {
+		dev_err(dev, "failed to release reference clock\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static int clk_ti_am3_dpll_probe(struct udevice *dev)
+{
+	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(dev);
+	int err;
+
+	err = clk_get_by_index(dev, 0, &priv->clk_ref);
+	if (err) {
+		dev_err(dev, "failed to get reference clock\n");
+		return err;
+	}
+
+	err = clk_get_by_index(dev, 1, &priv->clk_bypass);
+	if (err) {
+		dev_err(dev, "failed to get bypass clock\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static int clk_ti_am3_dpll_ofdata_to_platdata(struct udevice *dev)
+{
+	struct clk_ti_am3_dpll_priv *priv = dev_get_priv(dev);
+	struct clk_ti_am3_dpll_drv_data *data =
+		(struct clk_ti_am3_dpll_drv_data *)dev_get_driver_data(dev);
+
+	priv->max_rate = data->max_rate;
+
+	priv->clkmode_reg = dev_read_addr_index(dev, 0);
+	if (priv->clkmode_reg == FDT_ADDR_T_NONE) {
+		dev_err(dev, "failed to get clkmode register\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "clkmode_reg=0x%08lx\n", priv->clkmode_reg);
+
+	priv->idlest_reg = dev_read_addr_index(dev, 1);
+	if (priv->idlest_reg == FDT_ADDR_T_NONE) {
+		dev_err(dev, "failed to get idlest register\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "idlest_reg=0x%08lx\n", priv->idlest_reg);
+
+	priv->clksel_reg = dev_read_addr_index(dev, 2);
+	if (priv->clksel_reg == FDT_ADDR_T_NONE) {
+		dev_err(dev, "failed to get clksel register\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "clksel_reg=0x%08lx\n", priv->clksel_reg);
+
+	return 0;
+}
+
+static const struct clk_ti_am3_dpll_drv_data dpll_no_gate_data = {
+	.max_rate = 1000000000
+};
+
+static const struct clk_ti_am3_dpll_drv_data dpll_no_gate_j_type_data = {
+	.max_rate = 2000000000
+};
+
+static const struct clk_ti_am3_dpll_drv_data dpll_core_data = {
+	.max_rate = 1000000000
+};
+
+static const struct udevice_id clk_ti_am3_dpll_of_match[] = {
+	{.compatible = "ti,am3-dpll-core-clock",
+	 .data = (ulong)&dpll_core_data},
+	{.compatible = "ti,am3-dpll-no-gate-clock",
+	 .data = (ulong)&dpll_no_gate_data},
+	{.compatible = "ti,am3-dpll-no-gate-j-type-clock",
+	 .data = (ulong)&dpll_no_gate_j_type_data},
+	{}
+};
+
+U_BOOT_DRIVER(clk_ti_am3_dpll) = {
+	.name = "ti_am3_dpll_clock",
+	.id = UCLASS_CLK,
+	.of_match = clk_ti_am3_dpll_of_match,
+	.ofdata_to_platdata = clk_ti_am3_dpll_ofdata_to_platdata,
+	.probe = clk_ti_am3_dpll_probe,
+	.remove = clk_ti_am3_dpll_remove,
+	.priv_auto_alloc_size = sizeof(struct clk_ti_am3_dpll_priv),
+	.ops = &clk_ti_am3_dpll_ops,
+};
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 08/31] clk: ti: add divider clock driver
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (6 preceding siblings ...)
  2020-08-25  9:21 ` [PATCH 07/31] clk: ti: am33xx: add DPLL clock drivers Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  2020-08-25  9:21 ` [PATCH 09/31] clk: ti: refactor mux and divider clock drivers Dario Binacchi
                   ` (17 subsequent siblings)
  25 siblings, 0 replies; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

The patch adds support for TI divider clock binding. The driver uses
routines provided by the common clock framework (ccf).

The code is based on the drivers/clk/ti/divider.c driver of the Linux
kernel.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 .../clock/ti,autoidle.txt                     |  39 ++
 doc/device-tree-bindings/clock/ti,divider.txt | 117 +++++
 drivers/clk/Kconfig                           |   6 +
 drivers/clk/Makefile                          |   1 +
 drivers/clk/clk-ti-divider.c                  | 403 ++++++++++++++++++
 5 files changed, 566 insertions(+)
 create mode 100644 doc/device-tree-bindings/clock/ti,autoidle.txt
 create mode 100644 doc/device-tree-bindings/clock/ti,divider.txt
 create mode 100644 drivers/clk/clk-ti-divider.c

diff --git a/doc/device-tree-bindings/clock/ti,autoidle.txt b/doc/device-tree-bindings/clock/ti,autoidle.txt
new file mode 100644
index 0000000000..6c5b77e18c
--- /dev/null
+++ b/doc/device-tree-bindings/clock/ti,autoidle.txt
@@ -0,0 +1,39 @@
+Binding for Texas Instruments autoidle clock.
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1]. It assumes a register mapped
+clock which can be put to idle automatically by hardware based on the usage
+and a configuration bit setting. Autoidle clock is never an individual
+clock, it is always a derivative of some basic clock like a gate, divider,
+or fixed-factor.
+
+[1] doc/device-tree-bindings/clock/clock-bindings.txt
+
+Required properties:
+- reg : offset for the register controlling the autoidle
+- ti,autoidle-shift : bit shift of the autoidle enable bit
+- ti,invert-autoidle-bit : autoidle is enabled by setting the bit to 0
+
+Examples:
+	dpll_core_m4_ck: dpll_core_m4_ck {
+		#clock-cells = <0>;
+		compatible = "ti,divider-clock";
+		clocks = <&dpll_core_x2_ck>;
+		ti,max-div = <31>;
+		ti,autoidle-shift = <8>;
+		reg = <0x2d38>;
+		ti,index-starts-at-one;
+		ti,invert-autoidle-bit;
+	};
+
+	dpll_usb_clkdcoldo_ck: dpll_usb_clkdcoldo_ck {
+		#clock-cells = <0>;
+		compatible = "ti,fixed-factor-clock";
+		clocks = <&dpll_usb_ck>;
+		ti,clock-div = <1>;
+		ti,autoidle-shift = <8>;
+		reg = <0x01b4>;
+		ti,clock-mult = <1>;
+		ti,invert-autoidle-bit;
+	};
diff --git a/doc/device-tree-bindings/clock/ti,divider.txt b/doc/device-tree-bindings/clock/ti,divider.txt
new file mode 100644
index 0000000000..3d0570e915
--- /dev/null
+++ b/doc/device-tree-bindings/clock/ti,divider.txt
@@ -0,0 +1,117 @@
+Binding for TI divider clock
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1].  It assumes a
+register-mapped adjustable clock rate divider that does not gate and has
+only one input clock or parent.  By default the value programmed into
+the register is one less than the actual divisor value.  E.g:
+
+register value		actual divisor value
+0			1
+1			2
+2			3
+
+This assumption may be modified by the following optional properties:
+
+ti,index-starts-at-one - valid divisor values start at 1, not the default
+of 0.  E.g:
+register value		actual divisor value
+1			1
+2			2
+3			3
+
+ti,index-power-of-two - valid divisor values are powers of two.  E.g:
+register value		actual divisor value
+0			1
+1			2
+2			4
+
+Additionally an array of valid dividers may be supplied like so:
+
+	ti,dividers = <4>, <8>, <0>, <16>;
+
+Which will map the resulting values to a divisor table by their index:
+register value		actual divisor value
+0			4
+1			8
+2			<invalid divisor, skipped>
+3			16
+
+Any zero value in this array means the corresponding bit-value is invalid
+and must not be used.
+
+The binding must also provide the register to control the divider and
+unless the divider array is provided, min and max dividers. Optionally
+the number of bits to shift that mask, if necessary. If the shift value
+is missing it is the same as supplying a zero shift.
+
+This binding can also optionally provide support to the hardware autoidle
+feature, see [2].
+
+[1] doc/device-tree-bindings/clock/clock/clock-bindings.txt
+[2] doc/device-tree-bindings/clock/ti,autoidle.txt
+
+Required properties:
+- compatible : shall be "ti,divider-clock" or "ti,composite-divider-clock".
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks : link to phandle of parent clock
+- reg : offset for register controlling adjustable divider
+
+Optional properties:
+- clock-output-names : from common clock binding.
+- ti,dividers : array of integers defining divisors
+- ti,bit-shift : number of bits to shift the divider value, defaults to 0
+- ti,min-div : min divisor for dividing the input clock rate, only
+  needed if the first divisor is offset from the default value (1)
+- ti,max-div : max divisor for dividing the input clock rate, only needed
+  if ti,dividers is not defined.
+- ti,index-starts-at-one : valid divisor programming starts at 1, not zero,
+  only valid if ti,dividers is not defined.
+- ti,index-power-of-two : valid divisor programming must be a power of two,
+  only valid if ti,dividers is not defined.
+- ti,autoidle-shift : bit shift of the autoidle enable bit for the clock,
+  see [2]
+- ti,invert-autoidle-bit : autoidle is enabled by setting the bit to 0,
+  see [2]
+- ti,set-rate-parent : clk_set_rate is propagated to parent
+- ti,latch-bit : latch the divider value to HW, only needed if the register
+  access requires this. As an example dra76x DPLL_GMAC H14 divider implements
+  such behavior.
+
+Examples:
+dpll_usb_m2_ck: dpll_usb_m2_ck at 4a008190 {
+	#clock-cells = <0>;
+	compatible = "ti,divider-clock";
+	clocks = <&dpll_usb_ck>;
+	ti,max-div = <127>;
+	reg = <0x190>;
+	ti,index-starts-at-one;
+};
+
+aess_fclk: aess_fclk at 4a004528 {
+	#clock-cells = <0>;
+	compatible = "ti,divider-clock";
+	clocks = <&abe_clk>;
+	ti,bit-shift = <24>;
+	reg = <0x528>;
+	ti,max-div = <2>;
+};
+
+dpll_core_m3x2_div_ck: dpll_core_m3x2_div_ck {
+	#clock-cells = <0>;
+	compatible = "ti,composite-divider-clock";
+	clocks = <&dpll_core_x2_ck>;
+	ti,max-div = <31>;
+	reg = <0x0134>;
+	ti,index-starts-at-one;
+};
+
+ssi_ssr_div_fck_3430es2: ssi_ssr_div_fck_3430es2 {
+	#clock-cells = <0>;
+	compatible = "ti,composite-divider-clock";
+	clocks = <&corex2_fck>;
+	ti,bit-shift = <8>;
+	reg = <0x0a40>;
+	ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>;
+};
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index bddb454b7c..d7b546d9db 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -105,6 +105,12 @@ config CLK_TI_AM3_DPLL
 	  This enables the DPLL clock drivers support on AM33XX SoCs. The DPLL
 	  provides all interface clocks and functional clocks to the processor.
 
+config CLK_TI_DIVIDER
+	bool "TI divider clock driver"
+	depends on CLK && OF_CONTROL && CLK_CCF
+	help
+	  This enables the divider clock driver support on TI's SoCs.
+
 config CLK_TI_MUX
 	bool "TI mux clock driver"
 	depends on CLK && OF_CONTROL && CLK_CCF
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index cc20279a20..0fcfcc1837 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_SANDBOX) += clk_sandbox_test.o
 obj-$(CONFIG_SANDBOX_CLK_CCF) += clk_sandbox_ccf.o
 obj-$(CONFIG_STM32H7) += clk_stm32h7.o
 obj-$(CONFIG_CLK_TI_AM3_DPLL) += clk-ti-am3-dpll.o clk-ti-am3-dpll-x2.o
+obj-$(CONFIG_CLK_TI_DIVIDER) += clk-ti-divider.o
 obj-$(CONFIG_CLK_TI_MUX) += clk-ti-mux.o
 obj-$(CONFIG_CLK_TI_SCI) += clk-ti-sci.o
 obj-$(CONFIG_CLK_VERSAL) += clk_versal.o
diff --git a/drivers/clk/clk-ti-divider.c b/drivers/clk/clk-ti-divider.c
new file mode 100644
index 0000000000..fa9d60a2d5
--- /dev/null
+++ b/drivers/clk/clk-ti-divider.c
@@ -0,0 +1,403 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TI divider clock support
+ *
+ * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+ *
+ * Loosely based on Linux kernel drivers/clk/ti/divider.c
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <clk-uclass.h>
+#include <div64.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <linux/clk-provider.h>
+#include <linux/kernel.h>
+#include <linux/log2.h>
+
+/*
+ * The reverse of DIV_ROUND_UP: The maximum number which
+ * divided by m is r
+ */
+#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
+
+struct clk_ti_divider_priv {
+	struct clk parent;
+	fdt_addr_t reg;
+	const struct clk_div_table *table;
+	u8 shift;
+	u8 flags;
+	u8 div_flags;
+	s8 latch;
+	u16 min;
+	u16 max;
+	u16 mask;
+};
+
+static void clk_ti_divider_rmw(u32 val, u32 mask, fdt_addr_t reg)
+{
+	u32 v;
+
+	v = readl(reg);
+	v &= ~mask;
+	v |= val;
+	writel(v, reg);
+}
+
+static void clk_ti_divider_latch(fdt_addr_t reg, s8 shift)
+{
+	u32 latch;
+
+	if (shift < 0)
+		return;
+
+	latch = 1 << shift;
+
+	clk_ti_divider_rmw(latch, latch, reg);
+	clk_ti_divider_rmw(0, latch, reg);
+	readl(reg);		/* OCP barrier */
+}
+
+static unsigned int _get_div(const struct clk_div_table *table, ulong flags,
+			     unsigned int val)
+{
+	if (flags & CLK_DIVIDER_ONE_BASED)
+		return val;
+
+	if (flags & CLK_DIVIDER_POWER_OF_TWO)
+		return 1 << val;
+
+	if (table)
+		return divider_get_table_div(table, val);
+
+	return val + 1;
+}
+
+static unsigned int _get_val(const struct clk_div_table *table, ulong flags,
+			     unsigned int div)
+{
+	if (flags & CLK_DIVIDER_ONE_BASED)
+		return div;
+
+	if (flags & CLK_DIVIDER_POWER_OF_TWO)
+		return __ffs(div);
+
+	if (table)
+		return divider_get_table_val(table, div);
+
+	return div - 1;
+}
+
+static int _div_round_up(const struct clk_div_table *table, ulong parent_rate,
+			 ulong rate)
+{
+	const struct clk_div_table *clkt;
+	int up = INT_MAX;
+	int div = DIV_ROUND_UP_ULL((u64)parent_rate, rate);
+
+	for (clkt = table; clkt->div; clkt++) {
+		if (clkt->div == div)
+			return clkt->div;
+		else if (clkt->div < div)
+			continue;
+
+		if ((clkt->div - div) < (up - div))
+			up = clkt->div;
+	}
+
+	return up;
+}
+
+static int _div_round(const struct clk_div_table *table, ulong parent_rate,
+		      ulong rate)
+{
+	if (table)
+		return _div_round_up(table, parent_rate, rate);
+
+	return DIV_ROUND_UP(parent_rate, rate);
+}
+
+static int clk_ti_divider_best_div(struct clk *clk, ulong rate,
+				   ulong *best_parent_rate)
+{
+	struct clk_ti_divider_priv *priv = dev_get_priv(clk->dev);
+	ulong parent_rate, parent_round_rate, max_div;
+	ulong best_rate, r;
+	int i, best_div = 0;
+
+	parent_rate = clk_get_rate(&priv->parent);
+	if (IS_ERR_VALUE(parent_rate))
+		return parent_rate;
+
+	if (!rate)
+		rate = 1;
+
+	if (!(clk->flags & CLK_SET_RATE_PARENT)) {
+		best_div = _div_round(priv->table, parent_rate, rate);
+		if (best_div == 0)
+			best_div = 1;
+
+		if (best_div > priv->max)
+			best_div = priv->max;
+
+		*best_parent_rate = parent_rate;
+		return best_div;
+	}
+
+	max_div = min(ULONG_MAX / rate, (ulong)priv->max);
+	for (best_rate = 0, i = 1; i <= max_div; i++) {
+		if (!divider_is_valid_div(priv->table, priv->div_flags, i))
+			continue;
+
+		/*
+		 * It's the most ideal case if the requested rate can be
+		 * divided from parent clock without needing to change
+		 * parent rate, so return the divider immediately.
+		 */
+		if ((rate * i) == parent_rate) {
+			*best_parent_rate = parent_rate;
+			dev_dbg(dev, "rate=%ld, best_rate=%ld, div=%d\n", rate,
+				rate, i);
+			return i;
+		}
+
+		parent_round_rate = clk_round_rate(&priv->parent,
+						   MULT_ROUND_UP(rate, i));
+		if (IS_ERR_VALUE(parent_round_rate))
+			continue;
+
+		r = DIV_ROUND_UP(parent_round_rate, i);
+		if (r <= rate && r > best_rate) {
+			best_div = i;
+			best_rate = r;
+			*best_parent_rate = parent_round_rate;
+			if (best_rate == rate)
+				break;
+		}
+	}
+
+	if (best_div == 0) {
+		best_div = priv->max;
+		parent_round_rate = clk_round_rate(&priv->parent, 1);
+		if (IS_ERR_VALUE(parent_round_rate))
+			return parent_round_rate;
+	}
+
+	dev_dbg(dev, "rate=%ld, best_rate=%ld, div=%d\n", rate, best_rate,
+		best_div);
+
+	return best_div;
+}
+
+static ulong clk_ti_divider_round_rate(struct clk *clk, ulong rate)
+{
+	ulong parent_rate;
+	int div;
+
+	div = clk_ti_divider_best_div(clk, rate, &parent_rate);
+	if (div < 0)
+		return div;
+
+	return DIV_ROUND_UP(parent_rate, div);
+}
+
+static ulong clk_ti_divider_set_rate(struct clk *clk, ulong rate)
+{
+	struct clk_ti_divider_priv *priv = dev_get_priv(clk->dev);
+	ulong parent_rate;
+	int div;
+	u32 val, v;
+
+	div = clk_ti_divider_best_div(clk, rate, &parent_rate);
+	if (div < 0)
+		return div;
+
+	if (clk->flags & CLK_SET_RATE_PARENT) {
+		parent_rate = clk_set_rate(&priv->parent, parent_rate);
+		if (IS_ERR_VALUE(parent_rate))
+			return parent_rate;
+	}
+
+	val = _get_val(priv->table, priv->div_flags, div);
+
+	v = readl(priv->reg);
+	v &= ~(priv->mask << priv->shift);
+	v |= val << priv->shift;
+	writel(v, priv->reg);
+	clk_ti_divider_latch(priv->reg, priv->latch);
+
+	return clk_get_rate(clk);
+}
+
+static ulong clk_ti_divider_get_rate(struct clk *clk)
+{
+	struct clk_ti_divider_priv *priv = dev_get_priv(clk->dev);
+	ulong rate, parent_rate;
+	unsigned int div;
+	u32 v;
+
+	parent_rate = clk_get_rate(&priv->parent);
+	if (IS_ERR_VALUE(parent_rate))
+		return parent_rate;
+
+	v = readl(priv->reg) >> priv->shift;
+	v &= priv->mask;
+
+	div = _get_div(priv->table, priv->div_flags, v);
+	if (!div) {
+		if (!(priv->div_flags & CLK_DIVIDER_ALLOW_ZERO))
+			dev_warn(clk->dev,
+				 "zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n");
+		return parent_rate;
+	}
+
+	rate = DIV_ROUND_UP(parent_rate, div);
+	dev_dbg(clk->dev, "rate=%ld\n", rate);
+	return rate;
+}
+
+static int clk_ti_divider_request(struct clk *clk)
+{
+	struct clk_ti_divider_priv *priv = dev_get_priv(clk->dev);
+
+	clk->flags = priv->flags;
+	return 0;
+}
+
+const struct clk_ops clk_ti_divider_ops = {
+	.request = clk_ti_divider_request,
+	.round_rate = clk_ti_divider_round_rate,
+	.get_rate = clk_ti_divider_get_rate,
+	.set_rate = clk_ti_divider_set_rate
+};
+
+static int clk_ti_divider_remove(struct udevice *dev)
+{
+	struct clk_ti_divider_priv *priv = dev_get_priv(dev);
+	int err;
+
+	err = clk_release_all(&priv->parent, 1);
+	if (err) {
+		dev_err(dev, "failed to release parent clock\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static int clk_ti_divider_probe(struct udevice *dev)
+{
+	struct clk_ti_divider_priv *priv = dev_get_priv(dev);
+	int err;
+
+	err = clk_get_by_index(dev, 0, &priv->parent);
+	if (err) {
+		dev_err(dev, "failed to get parent clock\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static int clk_ti_divider_ofdata_to_platdata(struct udevice *dev)
+{
+	struct clk_ti_divider_priv *priv = dev_get_priv(dev);
+	struct clk_div_table *table = NULL;
+	u32 val, valid_div;
+	u32 min_div = 0;
+	u32 max_val, max_div = 0;
+	u16 mask;
+	int i, div_num;
+
+	priv->reg = dev_read_addr(dev);
+	dev_dbg(dev, "reg=0x%08lx\n", priv->reg);
+	priv->shift = dev_read_u32_default(dev, "ti,bit-shift", 0);
+	priv->latch = dev_read_s32_default(dev, "ti,latch-bit", -EINVAL);
+	if (dev_read_bool(dev, "ti,index-starts-at-one"))
+		priv->div_flags |= CLK_DIVIDER_ONE_BASED;
+
+	if (dev_read_bool(dev, "ti,index-power-of-two"))
+		priv->div_flags |= CLK_DIVIDER_POWER_OF_TWO;
+
+	if (dev_read_bool(dev, "ti,set-rate-parent"))
+		priv->flags |= CLK_SET_RATE_PARENT;
+
+	if (dev_read_prop(dev, "ti,dividers", &div_num)) {
+		div_num /= sizeof(u32);
+
+		/* Determine required size for divider table */
+		for (i = 0, valid_div = 0; i < div_num; i++) {
+			dev_read_u32_index(dev, "ti,dividers", i, &val);
+			if (val)
+				valid_div++;
+		}
+
+		if (!valid_div) {
+			dev_err(dev, "no valid dividers\n");
+			return -EINVAL;
+		}
+
+		table = calloc(valid_div + 1, sizeof(*table));
+		if (!table)
+			return -ENOMEM;
+
+		for (i = 0, valid_div = 0; i < div_num; i++) {
+			dev_read_u32_index(dev, "ti,dividers", i, &val);
+			if (!val)
+				continue;
+
+			table[valid_div].div = val;
+			table[valid_div].val = i;
+			valid_div++;
+			if (val > max_div)
+				max_div = val;
+
+			if (!min_div || val < min_div)
+				min_div = val;
+		}
+
+		max_val = max_div;
+	} else {
+		/* Divider table not provided, determine min/max divs */
+		min_div = dev_read_u32_default(dev, "ti,min-div", 1);
+		if (dev_read_u32(dev, "ti,max-div", &max_div)) {
+			dev_err(dev, "missing 'max-div' property\n");
+			return -EFAULT;
+		}
+
+		max_val = max_div;
+		if (!(priv->div_flags & CLK_DIVIDER_ONE_BASED) &&
+		    !(priv->div_flags & CLK_DIVIDER_POWER_OF_TWO))
+			max_val--;
+	}
+
+	priv->table = table;
+	priv->min = min_div;
+	priv->max = max_div;
+
+	if (priv->div_flags & CLK_DIVIDER_POWER_OF_TWO)
+		mask = fls(max_val) - 1;
+	else
+		mask = max_val;
+
+	priv->mask = (1 << fls(mask)) - 1;
+	return 0;
+}
+
+static const struct udevice_id clk_ti_divider_of_match[] = {
+	{.compatible = "ti,divider-clock"},
+	{}
+};
+
+U_BOOT_DRIVER(clk_ti_divider) = {
+	.name = "ti_divider_clock",
+	.id = UCLASS_CLK,
+	.of_match = clk_ti_divider_of_match,
+	.ofdata_to_platdata = clk_ti_divider_ofdata_to_platdata,
+	.probe = clk_ti_divider_probe,
+	.remove = clk_ti_divider_remove,
+	.priv_auto_alloc_size = sizeof(struct clk_ti_divider_priv),
+	.ops = &clk_ti_divider_ops,
+};
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 09/31] clk: ti: refactor mux and divider clock drivers
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (7 preceding siblings ...)
  2020-08-25  9:21 ` [PATCH 08/31] clk: ti: add divider clock driver Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  2020-09-03  6:34   ` Lokesh Vutla
  2020-08-25  9:21 ` [PATCH 10/31] clk: ti: add gate clock driver Dario Binacchi
                   ` (16 subsequent siblings)
  25 siblings, 1 reply; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

The patch removes duplicate routines used by the two drivers.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 drivers/clk/Makefile         |  1 +
 drivers/clk/clk-ti-divider.c | 27 ++-------------------------
 drivers/clk/clk-ti-mux.c     | 27 ++-------------------------
 drivers/clk/clk-ti.c         | 34 ++++++++++++++++++++++++++++++++++
 drivers/clk/clk-ti.h         | 13 +++++++++++++
 5 files changed, 52 insertions(+), 50 deletions(-)
 create mode 100644 drivers/clk/clk-ti.c
 create mode 100644 drivers/clk/clk-ti.h

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 0fcfcc1837..21b1e9c364 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_ARCH_ASPEED) += aspeed/
 obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
 obj-$(CONFIG_ARCH_MTMIPS) += mtmips/
 obj-$(CONFIG_ARCH_MESON) += meson/
+obj-$(CONFIG_ARCH_OMAP2PLUS) += clk-ti.o
 obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
 obj-$(CONFIG_ARCH_SOCFPGA) += altera/
 obj-$(CONFIG_CLK_AT91) += at91/
diff --git a/drivers/clk/clk-ti-divider.c b/drivers/clk/clk-ti-divider.c
index fa9d60a2d5..d16cc30cb7 100644
--- a/drivers/clk/clk-ti-divider.c
+++ b/drivers/clk/clk-ti-divider.c
@@ -16,6 +16,7 @@
 #include <linux/clk-provider.h>
 #include <linux/kernel.h>
 #include <linux/log2.h>
+#include "clk-ti.h"
 
 /*
  * The reverse of DIV_ROUND_UP: The maximum number which
@@ -36,30 +37,6 @@ struct clk_ti_divider_priv {
 	u16 mask;
 };
 
-static void clk_ti_divider_rmw(u32 val, u32 mask, fdt_addr_t reg)
-{
-	u32 v;
-
-	v = readl(reg);
-	v &= ~mask;
-	v |= val;
-	writel(v, reg);
-}
-
-static void clk_ti_divider_latch(fdt_addr_t reg, s8 shift)
-{
-	u32 latch;
-
-	if (shift < 0)
-		return;
-
-	latch = 1 << shift;
-
-	clk_ti_divider_rmw(latch, latch, reg);
-	clk_ti_divider_rmw(0, latch, reg);
-	readl(reg);		/* OCP barrier */
-}
-
 static unsigned int _get_div(const struct clk_div_table *table, ulong flags,
 			     unsigned int val)
 {
@@ -226,7 +203,7 @@ static ulong clk_ti_divider_set_rate(struct clk *clk, ulong rate)
 	v &= ~(priv->mask << priv->shift);
 	v |= val << priv->shift;
 	writel(v, priv->reg);
-	clk_ti_divider_latch(priv->reg, priv->latch);
+	clk_ti_latch(priv->reg, priv->latch);
 
 	return clk_get_rate(clk);
 }
diff --git a/drivers/clk/clk-ti-mux.c b/drivers/clk/clk-ti-mux.c
index 7e39dd3477..e4b190bbcc 100644
--- a/drivers/clk/clk-ti-mux.c
+++ b/drivers/clk/clk-ti-mux.c
@@ -12,6 +12,7 @@
 #include <clk-uclass.h>
 #include <asm/io.h>
 #include <linux/clk-provider.h>
+#include "clk-ti.h"
 
 struct clk_ti_mux_priv {
 	struct clk_bulk parents;
@@ -23,30 +24,6 @@ struct clk_ti_mux_priv {
 	s32 latch;
 };
 
-static void clk_ti_mux_rmw(u32 val, u32 mask, fdt_addr_t reg)
-{
-	u32 v;
-
-	v = readl(reg);
-	v &= ~mask;
-	v |= val;
-	writel(v, reg);
-}
-
-static void clk_ti_mux_latch(fdt_addr_t reg, s8 shift)
-{
-	u32 latch;
-
-	if (shift < 0)
-		return;
-
-	latch = 1 << shift;
-
-	clk_ti_mux_rmw(latch, latch, reg);
-	clk_ti_mux_rmw(0, latch, reg);
-	readl(reg);		/* OCP barrier */
-}
-
 static struct clk *clk_ti_mux_get_parent_by_index(struct clk_bulk *parents,
 						  int index)
 {
@@ -119,7 +96,7 @@ static int clk_ti_mux_set_parent(struct clk *clk, struct clk *parent)
 
 	val |= index << priv->shift;
 	writel(val, priv->reg);
-	clk_ti_mux_latch(priv->reg, priv->latch);
+	clk_ti_latch(priv->reg, priv->latch);
 	return 0;
 }
 
diff --git a/drivers/clk/clk-ti.c b/drivers/clk/clk-ti.c
new file mode 100644
index 0000000000..594ef75270
--- /dev/null
+++ b/drivers/clk/clk-ti.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TI clock utilities
+ *
+ * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include "clk-ti.h"
+
+static void clk_ti_rmw(u32 val, u32 mask, fdt_addr_t reg)
+{
+	u32 v;
+
+	v = readl(reg);
+	v &= ~mask;
+	v |= val;
+	writel(v, reg);
+}
+
+void clk_ti_latch(fdt_addr_t reg, s8 shift)
+{
+	u32 latch;
+
+	if (shift < 0)
+		return;
+
+	latch = 1 << shift;
+
+	clk_ti_rmw(latch, latch, reg);
+	clk_ti_rmw(0, latch, reg);
+	readl(reg);		/* OCP barrier */
+}
diff --git a/drivers/clk/clk-ti.h b/drivers/clk/clk-ti.h
new file mode 100644
index 0000000000..601c3823f7
--- /dev/null
+++ b/drivers/clk/clk-ti.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * TI clock utilities header
+ *
+ * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+ */
+
+#ifndef _CLK_TI_H
+#define _CLK_TI_H
+
+void clk_ti_latch(fdt_addr_t reg, s8 shift);
+
+#endif /* #ifndef _CLK_TI_H */
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 10/31] clk: ti: add gate clock driver
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (8 preceding siblings ...)
  2020-08-25  9:21 ` [PATCH 09/31] clk: ti: refactor mux and divider clock drivers Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  2020-08-25  9:21 ` [PATCH 11/31] ti: am33xx: fix do_enable_clocks() to accept NULL parameters Dario Binacchi
                   ` (15 subsequent siblings)
  25 siblings, 0 replies; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

The patch adds support for TI gate clock binding. The code is based on
the drivers/clk/ti/gate.c driver of the Linux kernel.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 .../clock/gpio-gate-clock.txt                 |  21 ++++
 .../clock/ti,clockdomain.txt                  |  24 ++++
 doc/device-tree-bindings/clock/ti,gate.txt    | 106 ++++++++++++++++++
 drivers/clk/Kconfig                           |   6 +
 drivers/clk/Makefile                          |   1 +
 drivers/clk/clk-ti-gate.c                     |  92 +++++++++++++++
 6 files changed, 250 insertions(+)
 create mode 100644 doc/device-tree-bindings/clock/gpio-gate-clock.txt
 create mode 100644 doc/device-tree-bindings/clock/ti,clockdomain.txt
 create mode 100644 doc/device-tree-bindings/clock/ti,gate.txt
 create mode 100644 drivers/clk/clk-ti-gate.c

diff --git a/doc/device-tree-bindings/clock/gpio-gate-clock.txt b/doc/device-tree-bindings/clock/gpio-gate-clock.txt
new file mode 100644
index 0000000000..7cba766cbe
--- /dev/null
+++ b/doc/device-tree-bindings/clock/gpio-gate-clock.txt
@@ -0,0 +1,21 @@
+Binding for simple gpio gated clock.
+
+This binding uses the common clock binding[1].
+
+[1] doc/device-tree-bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be "gpio-gate-clock".
+- #clock-cells : from common clock binding; shall be set to 0.
+- enable-gpios : GPIO reference for enabling and disabling the clock.
+
+Optional properties:
+- clocks: Maximum of one parent clock is supported.
+
+Example:
+	clock {
+		compatible = "gpio-gate-clock";
+		clocks = <&parentclk>;
+		#clock-cells = <0>;
+		enable-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>;
+	};
diff --git a/doc/device-tree-bindings/clock/ti,clockdomain.txt b/doc/device-tree-bindings/clock/ti,clockdomain.txt
new file mode 100644
index 0000000000..cf05ee8bb9
--- /dev/null
+++ b/doc/device-tree-bindings/clock/ti,clockdomain.txt
@@ -0,0 +1,24 @@
+Binding for Texas Instruments clockdomain.
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1] in consumer role.
+Every clock on TI SoC belongs to one clockdomain, but software
+only needs this information for specific clocks which require
+their parent clockdomain to be controlled when the clock is
+enabled/disabled. This binding doesn't define a new clock
+binding type, it is used to group existing clock nodes under
+hardware hierarchy.
+
+[1] doc/device-tree-bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be "ti,clockdomain"
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks : link phandles of clocks within this domain
+
+Examples:
+	dss_clkdm: dss_clkdm {
+		compatible = "ti,clockdomain";
+		clocks = <&dss1_alwon_fck_3430es2>, <&dss_ick_3430es2>;
+	};
diff --git a/doc/device-tree-bindings/clock/ti,gate.txt b/doc/device-tree-bindings/clock/ti,gate.txt
new file mode 100644
index 0000000000..792e2033c0
--- /dev/null
+++ b/doc/device-tree-bindings/clock/ti,gate.txt
@@ -0,0 +1,106 @@
+Binding for Texas Instruments gate clock.
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1]. This clock is
+quite much similar to the basic gate-clock [2], however,
+it supports a number of additional features. If no register
+is provided for this clock, the code assumes that a clockdomain
+will be controlled instead and the corresponding hw-ops for
+that is used.
+
+[1] doc/device-tree-bindings/clock/clock-bindings.txt
+[2] doc/device-tree-bindings/clock/gpio-gate-clock.txt
+[3] doc/device-tree-bindings/clock/ti,clockdomain.txt
+
+Required properties:
+- compatible : shall be one of:
+  "ti,gate-clock" - basic gate clock
+  "ti,wait-gate-clock" - gate clock which waits until clock is active before
+			 returning from clk_enable()
+  "ti,dss-gate-clock" - gate clock with DSS specific hardware handling
+  "ti,am35xx-gate-clock" - gate clock with AM35xx specific hardware handling
+  "ti,clkdm-gate-clock" - clockdomain gate clock, which derives its functional
+			  clock directly from a clockdomain, see [3] how
+			  to map clockdomains properly
+  "ti,hsdiv-gate-clock" - gate clock with OMAP36xx specific hardware handling,
+			  required for a hardware errata
+  "ti,composite-gate-clock" - composite gate clock, to be part of composite
+			      clock
+  "ti,composite-no-wait-gate-clock" - composite gate clock that does not wait
+				      for clock to be active before returning
+				      from clk_enable()
+- #clock-cells : from common clock binding; shall be set to 0
+- clocks : link to phandle of parent clock
+- reg : offset for register controlling adjustable gate, not needed for
+	ti,clkdm-gate-clock type
+
+Optional properties:
+- ti,bit-shift : bit shift for programming the clock gate, invalid for
+		 ti,clkdm-gate-clock type
+- ti,set-bit-to-disable : inverts default gate programming. Setting the bit
+  gates the clock and clearing the bit ungates the clock.
+
+Examples:
+	mmchs2_fck: mmchs2_fck at 48004a00 {
+		#clock-cells = <0>;
+		compatible = "ti,gate-clock";
+		clocks = <&core_96m_fck>;
+		reg = <0x0a00>;
+		ti,bit-shift = <25>;
+	};
+
+	uart4_fck_am35xx: uart4_fck_am35xx {
+		#clock-cells = <0>;
+		compatible = "ti,wait-gate-clock";
+		clocks = <&core_48m_fck>;
+		reg = <0x0a00>;
+		ti,bit-shift = <23>;
+	};
+
+	dss1_alwon_fck_3430es2: dss1_alwon_fck_3430es2 at 48004e00 {
+		#clock-cells = <0>;
+		compatible = "ti,dss-gate-clock";
+		clocks = <&dpll4_m4x2_ck>;
+		reg = <0x0e00>;
+		ti,bit-shift = <0>;
+	};
+
+	emac_ick: emac_ick at 4800259c {
+		#clock-cells = <0>;
+		compatible = "ti,am35xx-gate-clock";
+		clocks = <&ipss_ick>;
+		reg = <0x059c>;
+		ti,bit-shift = <1>;
+	};
+
+	emu_src_ck: emu_src_ck {
+		#clock-cells = <0>;
+		compatible = "ti,clkdm-gate-clock";
+		clocks = <&emu_src_mux_ck>;
+	};
+
+	dpll4_m2x2_ck: dpll4_m2x2_ck at 48004d00 {
+		#clock-cells = <0>;
+		compatible = "ti,hsdiv-gate-clock";
+		clocks = <&dpll4_m2x2_mul_ck>;
+		ti,bit-shift = <0x1b>;
+		reg = <0x0d00>;
+		ti,set-bit-to-disable;
+	};
+
+	vlynq_gate_fck: vlynq_gate_fck {
+		#clock-cells = <0>;
+		compatible = "ti,composite-gate-clock";
+		clocks = <&core_ck>;
+		ti,bit-shift = <3>;
+		reg = <0x0200>;
+	};
+
+	sys_clkout2_src_gate: sys_clkout2_src_gate {
+		#clock-cells = <0>;
+		compatible = "ti,composite-no-wait-gate-clock";
+		clocks = <&core_ck>;
+		ti,bit-shift = <15>;
+		reg = <0x0070>;
+	};
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index d7b546d9db..c0528c2aeb 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -111,6 +111,12 @@ config CLK_TI_DIVIDER
 	help
 	  This enables the divider clock driver support on TI's SoCs.
 
+config CLK_TI_GATE
+	bool "TI gate clock driver"
+	depends on CLK && OF_CONTROL
+	help
+	  This enables the gate clock driver support on TI's SoCs.
+
 config CLK_TI_MUX
 	bool "TI mux clock driver"
 	depends on CLK && OF_CONTROL && CLK_CCF
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 21b1e9c364..4d16fb7a50 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_SANDBOX_CLK_CCF) += clk_sandbox_ccf.o
 obj-$(CONFIG_STM32H7) += clk_stm32h7.o
 obj-$(CONFIG_CLK_TI_AM3_DPLL) += clk-ti-am3-dpll.o clk-ti-am3-dpll-x2.o
 obj-$(CONFIG_CLK_TI_DIVIDER) += clk-ti-divider.o
+obj-$(CONFIG_CLK_TI_GATE) += clk-ti-gate.o
 obj-$(CONFIG_CLK_TI_MUX) += clk-ti-mux.o
 obj-$(CONFIG_CLK_TI_SCI) += clk-ti-sci.o
 obj-$(CONFIG_CLK_VERSAL) += clk_versal.o
diff --git a/drivers/clk/clk-ti-gate.c b/drivers/clk/clk-ti-gate.c
new file mode 100644
index 0000000000..0f86b8a4b3
--- /dev/null
+++ b/drivers/clk/clk-ti-gate.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TI gate clock support
+ *
+ * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+ *
+ * Loosely based on Linux kernel drivers/clk/ti/gate.c
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <clk-uclass.h>
+#include <asm/io.h>
+#include <linux/clk-provider.h>
+
+struct clk_ti_gate_priv {
+	fdt_addr_t reg;
+	u8 enable_bit;
+	u32 flags;
+	bool invert_enable;
+};
+
+static int clk_ti_gate_disable(struct clk *clk)
+{
+	struct clk_ti_gate_priv *priv = dev_get_priv(clk->dev);
+	u32 v;
+
+	v = readl(priv->reg);
+	if (priv->invert_enable)
+		v |= (1 << priv->enable_bit);
+	else
+		v &= ~(1 << priv->enable_bit);
+
+	writel(v, priv->reg);
+	/* No OCP barrier needed here since it is a disable operation */
+	return 0;
+}
+
+static int clk_ti_gate_enable(struct clk *clk)
+{
+	struct clk_ti_gate_priv *priv = dev_get_priv(clk->dev);
+	u32 v;
+
+	v = readl(priv->reg);
+	if (priv->invert_enable)
+		v &= ~(1 << priv->enable_bit);
+	else
+		v |= (1 << priv->enable_bit);
+
+	writel(v, priv->reg);
+	/* OCP barrier */
+	v = readl(priv->reg);
+	return 0;
+}
+
+static int clk_ti_gate_ofdata_to_platdata(struct udevice *dev)
+{
+	struct clk_ti_gate_priv *priv = dev_get_priv(dev);
+
+	priv->reg = dev_read_addr(dev);
+	if (priv->reg == FDT_ADDR_T_NONE) {
+		dev_err(dev, "failed to get control register\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "reg=0x%08lx\n", priv->reg);
+	priv->enable_bit = dev_read_u32_default(dev, "ti,bit-shift", 0);
+	if (dev_read_bool(dev, "ti,set-rate-parent"))
+		priv->flags |= CLK_SET_RATE_PARENT;
+
+	priv->invert_enable = dev_read_bool(dev, "ti,set-bit-to-disable");
+	return 0;
+}
+
+static struct clk_ops clk_ti_gate_ops = {
+	.enable = clk_ti_gate_enable,
+	.disable = clk_ti_gate_disable,
+};
+
+static const struct udevice_id clk_ti_gate_of_match[] = {
+	{ .compatible = "ti,gate-clock" },
+	{ },
+};
+
+U_BOOT_DRIVER(clk_ti_gate) = {
+	.name = "ti_gate_clock",
+	.id = UCLASS_CLK,
+	.of_match = clk_ti_gate_of_match,
+	.ofdata_to_platdata = clk_ti_gate_ofdata_to_platdata,
+	.priv_auto_alloc_size = sizeof(struct clk_ti_gate_priv),
+	.ops = &clk_ti_gate_ops,
+};
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 11/31] ti: am33xx: fix do_enable_clocks() to accept NULL parameters
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (9 preceding siblings ...)
  2020-08-25  9:21 ` [PATCH 10/31] clk: ti: add gate clock driver Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  2020-08-29 21:20   ` Simon Glass
  2020-08-25  9:21 ` [PATCH 12/31] clk: ti: add support for clkctrl clocks Dario Binacchi
                   ` (14 subsequent siblings)
  25 siblings, 1 reply; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

Up till this commit passing NULL as input parameter was allowed, but not
handled properly. When a NULL parameter was passed to the function a data
abort was raised.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 arch/arm/mach-omap2/am33xx/clock.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/am33xx/clock.c b/arch/arm/mach-omap2/am33xx/clock.c
index 8819062aaa..130ee6c6e3 100644
--- a/arch/arm/mach-omap2/am33xx/clock.c
+++ b/arch/arm/mach-omap2/am33xx/clock.c
@@ -194,13 +194,14 @@ void do_enable_clocks(u32 *const *clk_domains,
 	u32 i, max = 100;
 
 	/* Put the clock domains in SW_WKUP mode */
-	for (i = 0; (i < max) && clk_domains[i]; i++) {
+	for (i = 0; (i < max) && clk_domains && clk_domains[i]; i++) {
 		enable_clock_domain(clk_domains[i],
 				    CD_CLKCTRL_CLKTRCTRL_SW_WKUP);
 	}
 
 	/* Clock modules that need to be put in SW_EXPLICIT_EN mode */
-	for (i = 0; (i < max) && clk_modules_explicit_en[i]; i++) {
+	for (i = 0; (i < max) && clk_modules_explicit_en &&
+	     clk_modules_explicit_en[i]; i++) {
 		enable_clock_module(clk_modules_explicit_en[i],
 				    MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN,
 				    wait_for_enable);
@@ -215,12 +216,13 @@ void do_disable_clocks(u32 *const *clk_domains,
 
 
 	/* Clock modules that need to be put in SW_DISABLE */
-	for (i = 0; (i < max) && clk_modules_disable[i]; i++)
+	for (i = 0; (i < max) && clk_modules_disable && clk_modules_disable[i];
+	     i++)
 		disable_clock_module(clk_modules_disable[i],
 				     wait_for_disable);
 
 	/* Put the clock domains in SW_SLEEP mode */
-	for (i = 0; (i < max) && clk_domains[i]; i++)
+	for (i = 0; (i < max) && clk_domains && clk_domains[i]; i++)
 		disable_clock_domain(clk_domains[i]);
 }
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 12/31] clk: ti: add support for clkctrl clocks
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (10 preceding siblings ...)
  2020-08-25  9:21 ` [PATCH 11/31] ti: am33xx: fix do_enable_clocks() to accept NULL parameters Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  2020-08-25  9:21 ` [PATCH 13/31] clk: ti: move drivers to 'ti' directory Dario Binacchi
                   ` (13 subsequent siblings)
  25 siblings, 0 replies; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

Until now the clkctrl clocks have been enabled/disabled through platform
routines. Thanks to this patch they can be enabled and configured directly
by the probed devices that need to use them.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 doc/device-tree-bindings/clock/ti,clkctrl.txt |  61 +++++++++++
 drivers/clk/Kconfig                           |   6 ++
 drivers/clk/Makefile                          |   1 +
 drivers/clk/clk-ti-ctrl.c                     | 102 ++++++++++++++++++
 4 files changed, 170 insertions(+)
 create mode 100644 doc/device-tree-bindings/clock/ti,clkctrl.txt
 create mode 100644 drivers/clk/clk-ti-ctrl.c

diff --git a/doc/device-tree-bindings/clock/ti,clkctrl.txt b/doc/device-tree-bindings/clock/ti,clkctrl.txt
new file mode 100644
index 0000000000..0f73f6295a
--- /dev/null
+++ b/doc/device-tree-bindings/clock/ti,clkctrl.txt
@@ -0,0 +1,61 @@
+Texas Instruments clkctrl clock binding
+
+Texas Instruments SoCs can have a clkctrl clock controller for each
+interconnect target module. The clkctrl clock controller manages functional
+and interface clocks for each module. Each clkctrl controller can also
+gate one or more optional functional clocks for a module, and can have one
+or more clock muxes. There is a clkctrl clock controller typically for each
+interconnect target module on omap4 and later variants.
+
+The clock consumers can specify the index of the clkctrl clock using
+the hardware offset from the clkctrl instance register space. The optional
+clocks can be specified by clkctrl hardware offset and the index of the
+optional clock.
+
+For more information, please see the Linux clock framework binding at
+doc/device-tree-bindings/clock/clock-bindings.txt.
+
+Required properties :
+- compatible : shall be "ti,clkctrl" or a clock domain specific name:
+	       "ti,clkctrl-l4-cfg"
+	       "ti,clkctrl-l4-per"
+	       "ti,clkctrl-l4-secure"
+	       "ti,clkctrl-l4-wkup"
+- #clock-cells : shall contain 2 with the first entry being the instance
+		 offset from the clock domain base and the second being the
+		 clock index
+- reg : clock registers
+
+Example: Clock controller node on omap 4430:
+
+&cm2 {
+	l4per: cm at 1400 {
+		cm_l4per at 0 {
+			cm_l4per_clkctrl: clock at 20 {
+				compatible = "ti,clkctrl-l4-per", "ti,clkctrl";
+				reg = <0x20 0x1b0>;
+				#clock-cells = <2>;
+			};
+		};
+	};
+};
+
+Example: Preprocessor helper macros in dt-bindings/clock/ti-clkctrl.h
+
+#define OMAP4_CLKCTRL_OFFSET		0x20
+#define OMAP4_CLKCTRL_INDEX(offset)	((offset) - OMAP4_CLKCTRL_OFFSET)
+#define MODULEMODE_HWCTRL		1
+#define MODULEMODE_SWCTRL		2
+
+#define OMAP4_GPTIMER10_CLKTRL		OMAP4_CLKCTRL_INDEX(0x28)
+#define OMAP4_GPTIMER11_CLKTRL		OMAP4_CLKCTRL_INDEX(0x30)
+#define OMAP4_GPTIMER2_CLKTRL		OMAP4_CLKCTRL_INDEX(0x38)
+...
+#define OMAP4_GPIO2_CLKCTRL		OMAP_CLKCTRL_INDEX(0x60)
+
+Example: Clock consumer node for GPIO2:
+
+&gpio2 {
+       clocks = <&cm_l4per_clkctrl OMAP4_GPIO2_CLKCTRL 0
+		 &cm_l4per_clkctrl OMAP4_GPIO2_CLKCTRL 8>;
+};
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c0528c2aeb..90c953667a 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -105,6 +105,12 @@ config CLK_TI_AM3_DPLL
 	  This enables the DPLL clock drivers support on AM33XX SoCs. The DPLL
 	  provides all interface clocks and functional clocks to the processor.
 
+config CLK_TI_CTRL
+	bool "TI OMAP4 clock controller"
+	depends on CLK && OF_CONTROL
+	help
+	  This enables the clock controller driver support on TI's SoCs.
+
 config CLK_TI_DIVIDER
 	bool "TI divider clock driver"
 	depends on CLK && OF_CONTROL && CLK_CCF
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 4d16fb7a50..cdc3102ad7 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_SANDBOX) += clk_sandbox_test.o
 obj-$(CONFIG_SANDBOX_CLK_CCF) += clk_sandbox_ccf.o
 obj-$(CONFIG_STM32H7) += clk_stm32h7.o
 obj-$(CONFIG_CLK_TI_AM3_DPLL) += clk-ti-am3-dpll.o clk-ti-am3-dpll-x2.o
+obj-$(CONFIG_CLK_TI_CTRL) += clk-ti-ctrl.o
 obj-$(CONFIG_CLK_TI_DIVIDER) += clk-ti-divider.o
 obj-$(CONFIG_CLK_TI_GATE) += clk-ti-gate.o
 obj-$(CONFIG_CLK_TI_MUX) += clk-ti-mux.o
diff --git a/drivers/clk/clk-ti-ctrl.c b/drivers/clk/clk-ti-ctrl.c
new file mode 100644
index 0000000000..ed0a2ee7d1
--- /dev/null
+++ b/drivers/clk/clk-ti-ctrl.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * OMAP clock controller support
+ *
+ * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <clk-uclass.h>
+#include <asm/arch-am33xx/clock.h>
+
+struct clk_ti_ctrl_priv {
+	fdt_addr_t regs;
+	fdt_size_t regs_size;
+};
+
+static int clk_ti_ctrl_disable(struct clk *clk)
+{
+	struct clk_ti_ctrl_priv *priv = dev_get_priv(clk->dev);
+	u32 *clk_modules[2] = { };
+
+	if (clk->id >= priv->regs_size)
+		return -EINVAL;
+
+	clk_modules[0] = (u32 *)(priv->regs + clk->id);
+	dev_dbg(dev, "module address=%p\n", clk_modules[0]);
+	do_disable_clocks(NULL, clk_modules, 1);
+	return 0;
+}
+
+static int clk_ti_ctrl_enable(struct clk *clk)
+{
+	struct clk_ti_ctrl_priv *priv = dev_get_priv(clk->dev);
+	u32 *clk_modules[2] = { };
+
+	if (clk->id >= priv->regs_size)
+		return -EINVAL;
+
+	clk_modules[0] = (u32 *)(priv->regs + clk->id);
+	dev_dbg(dev, "module address=%p\n", clk_modules[0]);
+	do_enable_clocks(NULL, clk_modules, 1);
+	return 0;
+}
+
+static ulong clk_ti_ctrl_get_rate(struct clk *clk)
+{
+	return 0;
+}
+
+static int clk_ti_ctrl_of_xlate(struct clk *clk,
+				struct ofnode_phandle_args *args)
+{
+	if (args->args_count != 2) {
+		dev_err(dev, "invaild args_count: %d\n", args->args_count);
+		return -EINVAL;
+	}
+
+	if (args->args_count)
+		clk->id = args->args[0];
+	else
+		clk->id = 0;
+
+	dev_dbg(dev, "name=%s, id=%ld\n", clk->dev->name, clk->id);
+	return 0;
+}
+
+static int clk_ti_ctrl_ofdata_to_platdata(struct udevice *dev)
+{
+	struct clk_ti_ctrl_priv *priv = dev_get_priv(dev);
+
+	priv->regs = dev_read_addr_size_index(dev, 0, &priv->regs_size);
+	if (priv->regs == FDT_ADDR_T_NONE) {
+		dev_err(dev, "failed to get control registers\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "regs=0x%08lx, size=0x%08lx\n", priv->regs,
+		priv->regs_size);
+	return 0;
+}
+
+static struct clk_ops clk_ti_ctrl_ops = {
+	.of_xlate = clk_ti_ctrl_of_xlate,
+	.enable = clk_ti_ctrl_enable,
+	.disable = clk_ti_ctrl_disable,
+	.get_rate = clk_ti_ctrl_get_rate,
+};
+
+static const struct udevice_id clk_ti_ctrl_ids[] = {
+	{.compatible = "ti,clkctrl"},
+	{},
+};
+
+U_BOOT_DRIVER(clk_ti_ctrl) = {
+	.name = "ti_ctrl_clk",
+	.id = UCLASS_CLK,
+	.of_match = clk_ti_ctrl_ids,
+	.ofdata_to_platdata = clk_ti_ctrl_ofdata_to_platdata,
+	.ops = &clk_ti_ctrl_ops,
+	.priv_auto_alloc_size = sizeof(struct clk_ti_ctrl_priv),
+};
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 13/31] clk: ti: move drivers to 'ti' directory
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (11 preceding siblings ...)
  2020-08-25  9:21 ` [PATCH 12/31] clk: ti: add support for clkctrl clocks Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  2020-08-25  9:21 ` [PATCH 14/31] clk: ti: omap4: add clock manager driver Dario Binacchi
                   ` (12 subsequent siblings)
  25 siblings, 0 replies; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

Add drivers/clk/ti/ folder and move all TI's code in this folder for
better maintenance.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 drivers/clk/Kconfig                           | 40 +-----------------
 drivers/clk/Makefile                          |  8 +---
 drivers/clk/ti/Kconfig                        | 42 +++++++++++++++++++
 drivers/clk/ti/Makefile                       | 12 ++++++
 .../clk-am3-dpll-x2.c}                        |  0
 .../{clk-ti-am3-dpll.c => ti/clk-am3-dpll.c}  |  0
 drivers/clk/{clk-ti-ctrl.c => ti/clk-ctrl.c}  |  0
 .../{clk-ti-divider.c => ti/clk-divider.c}    |  2 +-
 drivers/clk/{clk-ti-gate.c => ti/clk-gate.c}  |  0
 drivers/clk/{clk-ti-mux.c => ti/clk-mux.c}    |  2 +-
 drivers/clk/{clk-ti-sci.c => ti/clk-sci.c}    |  0
 drivers/clk/{clk-ti.c => ti/clk.c}            |  2 +-
 drivers/clk/{clk-ti.h => ti/clk.h}            |  0
 13 files changed, 59 insertions(+), 49 deletions(-)
 create mode 100644 drivers/clk/ti/Kconfig
 create mode 100644 drivers/clk/ti/Makefile
 rename drivers/clk/{clk-ti-am3-dpll-x2.c => ti/clk-am3-dpll-x2.c} (100%)
 rename drivers/clk/{clk-ti-am3-dpll.c => ti/clk-am3-dpll.c} (100%)
 rename drivers/clk/{clk-ti-ctrl.c => ti/clk-ctrl.c} (100%)
 rename drivers/clk/{clk-ti-divider.c => ti/clk-divider.c} (99%)
 rename drivers/clk/{clk-ti-gate.c => ti/clk-gate.c} (100%)
 rename drivers/clk/{clk-ti-mux.c => ti/clk-mux.c} (99%)
 rename drivers/clk/{clk-ti-sci.c => ti/clk-sci.c} (100%)
 rename drivers/clk/{clk-ti.c => ti/clk.c} (96%)
 rename drivers/clk/{clk-ti.h => ti/clk.h} (100%)

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 90c953667a..42ed6939e6 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -98,45 +98,6 @@ config CLK_STM32F
 	  This clock driver adds support for RCC clock management
 	  for STM32F4 and STM32F7 SoCs.
 
-config CLK_TI_AM3_DPLL
-	bool "TI AM33XX Digital Phase-Locked Loop (DPLL) clock drivers"
-	depends on CLK && OF_CONTROL
-	help
-	  This enables the DPLL clock drivers support on AM33XX SoCs. The DPLL
-	  provides all interface clocks and functional clocks to the processor.
-
-config CLK_TI_CTRL
-	bool "TI OMAP4 clock controller"
-	depends on CLK && OF_CONTROL
-	help
-	  This enables the clock controller driver support on TI's SoCs.
-
-config CLK_TI_DIVIDER
-	bool "TI divider clock driver"
-	depends on CLK && OF_CONTROL && CLK_CCF
-	help
-	  This enables the divider clock driver support on TI's SoCs.
-
-config CLK_TI_GATE
-	bool "TI gate clock driver"
-	depends on CLK && OF_CONTROL
-	help
-	  This enables the gate clock driver support on TI's SoCs.
-
-config CLK_TI_MUX
-	bool "TI mux clock driver"
-	depends on CLK && OF_CONTROL && CLK_CCF
-	help
-	  This enables the mux clock driver support on TI's SoCs.
-
-config CLK_TI_SCI
-	bool "TI System Control Interface (TI SCI) clock driver"
-	depends on CLK && TI_SCI_PROTOCOL && OF_CONTROL
-	help
-	  This enables the clock driver support over TI System Control Interface
-	  available on some new TI's SoCs. If you wish to use clock resources
-	  managed by the TI System Controller, say Y here. Otherwise, say N.
-
 config CLK_HSDK
 	bool "Enable cgu clock driver for HSDK boards"
 	depends on CLK && TARGET_HSDK
@@ -201,6 +162,7 @@ source "drivers/clk/owl/Kconfig"
 source "drivers/clk/renesas/Kconfig"
 source "drivers/clk/sunxi/Kconfig"
 source "drivers/clk/sifive/Kconfig"
+source "drivers/clk/ti/Kconfig"
 source "drivers/clk/tegra/Kconfig"
 source "drivers/clk/uniphier/Kconfig"
 
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index cdc3102ad7..e48e17479f 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -13,12 +13,12 @@ obj-$(CONFIG_$(SPL_TPL_)CLK_COMPOSITE_CCF) += clk-composite.o
 
 obj-y += analogbits/
 obj-y += imx/
+obj-y += ti/
 obj-y += tegra/
 obj-$(CONFIG_ARCH_ASPEED) += aspeed/
 obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
 obj-$(CONFIG_ARCH_MTMIPS) += mtmips/
 obj-$(CONFIG_ARCH_MESON) += meson/
-obj-$(CONFIG_ARCH_OMAP2PLUS) += clk-ti.o
 obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
 obj-$(CONFIG_ARCH_SOCFPGA) += altera/
 obj-$(CONFIG_CLK_AT91) += at91/
@@ -47,11 +47,5 @@ obj-$(CONFIG_SANDBOX) += clk_sandbox.o
 obj-$(CONFIG_SANDBOX) += clk_sandbox_test.o
 obj-$(CONFIG_SANDBOX_CLK_CCF) += clk_sandbox_ccf.o
 obj-$(CONFIG_STM32H7) += clk_stm32h7.o
-obj-$(CONFIG_CLK_TI_AM3_DPLL) += clk-ti-am3-dpll.o clk-ti-am3-dpll-x2.o
-obj-$(CONFIG_CLK_TI_CTRL) += clk-ti-ctrl.o
-obj-$(CONFIG_CLK_TI_DIVIDER) += clk-ti-divider.o
-obj-$(CONFIG_CLK_TI_GATE) += clk-ti-gate.o
-obj-$(CONFIG_CLK_TI_MUX) += clk-ti-mux.o
-obj-$(CONFIG_CLK_TI_SCI) += clk-ti-sci.o
 obj-$(CONFIG_CLK_VERSAL) += clk_versal.o
 obj-$(CONFIG_CLK_CDCE9XX) += clk-cdce9xx.o
diff --git a/drivers/clk/ti/Kconfig b/drivers/clk/ti/Kconfig
new file mode 100644
index 0000000000..3c61046728
--- /dev/null
+++ b/drivers/clk/ti/Kconfig
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+#
+config CLK_TI_AM3_DPLL
+	bool "TI AM33XX Digital Phase-Locked Loop (DPLL) clock drivers"
+	depends on CLK && OF_CONTROL
+	help
+	  This enables the DPLL clock drivers support on AM33XX SoCs. The DPLL
+	  provides all interface clocks and functional clocks to the processor.
+
+config CLK_TI_CTRL
+	bool "TI OMAP4 clock controller"
+	depends on CLK && OF_CONTROL
+	help
+	  This enables the clock controller driver support on TI's SoCs.
+
+config CLK_TI_DIVIDER
+	bool "TI divider clock driver"
+	depends on CLK && OF_CONTROL && CLK_CCF
+	help
+	  This enables the divider clock driver support on TI's SoCs.
+
+config CLK_TI_GATE
+	bool "TI gate clock driver"
+	depends on CLK && OF_CONTROL
+	help
+	  This enables the gate clock driver support on TI's SoCs.
+
+config CLK_TI_MUX
+	bool "TI mux clock driver"
+	depends on CLK && OF_CONTROL && CLK_CCF
+	help
+	  This enables the mux clock driver support on TI's SoCs.
+
+config CLK_TI_SCI
+	bool "TI System Control Interface (TI SCI) clock driver"
+	depends on CLK && TI_SCI_PROTOCOL && OF_CONTROL
+	help
+	  This enables the clock driver support over TI System Control Interface
+	  available on some new TI's SoCs. If you wish to use clock resources
+	  managed by the TI System Controller, say Y here. Otherwise, say N.
diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile
new file mode 100644
index 0000000000..a279a2838d
--- /dev/null
+++ b/drivers/clk/ti/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+#
+
+obj-$(CONFIG_ARCH_OMAP2PLUS) += clk.o
+obj-$(CONFIG_CLK_TI_AM3_DPLL) += clk-am3-dpll.o clk-am3-dpll-x2.o
+obj-$(CONFIG_CLK_TI_CTRL) += clk-ctrl.o
+obj-$(CONFIG_CLK_TI_DIVIDER) += clk-divider.o
+obj-$(CONFIG_CLK_TI_GATE) += clk-gate.o
+obj-$(CONFIG_CLK_TI_MUX) += clk-mux.o
+obj-$(CONFIG_CLK_TI_SCI) += clk-sci.o
diff --git a/drivers/clk/clk-ti-am3-dpll-x2.c b/drivers/clk/ti/clk-am3-dpll-x2.c
similarity index 100%
rename from drivers/clk/clk-ti-am3-dpll-x2.c
rename to drivers/clk/ti/clk-am3-dpll-x2.c
diff --git a/drivers/clk/clk-ti-am3-dpll.c b/drivers/clk/ti/clk-am3-dpll.c
similarity index 100%
rename from drivers/clk/clk-ti-am3-dpll.c
rename to drivers/clk/ti/clk-am3-dpll.c
diff --git a/drivers/clk/clk-ti-ctrl.c b/drivers/clk/ti/clk-ctrl.c
similarity index 100%
rename from drivers/clk/clk-ti-ctrl.c
rename to drivers/clk/ti/clk-ctrl.c
diff --git a/drivers/clk/clk-ti-divider.c b/drivers/clk/ti/clk-divider.c
similarity index 99%
rename from drivers/clk/clk-ti-divider.c
rename to drivers/clk/ti/clk-divider.c
index d16cc30cb7..65b6abd18b 100644
--- a/drivers/clk/clk-ti-divider.c
+++ b/drivers/clk/ti/clk-divider.c
@@ -16,7 +16,7 @@
 #include <linux/clk-provider.h>
 #include <linux/kernel.h>
 #include <linux/log2.h>
-#include "clk-ti.h"
+#include "clk.h"
 
 /*
  * The reverse of DIV_ROUND_UP: The maximum number which
diff --git a/drivers/clk/clk-ti-gate.c b/drivers/clk/ti/clk-gate.c
similarity index 100%
rename from drivers/clk/clk-ti-gate.c
rename to drivers/clk/ti/clk-gate.c
diff --git a/drivers/clk/clk-ti-mux.c b/drivers/clk/ti/clk-mux.c
similarity index 99%
rename from drivers/clk/clk-ti-mux.c
rename to drivers/clk/ti/clk-mux.c
index e4b190bbcc..a3ebef251c 100644
--- a/drivers/clk/clk-ti-mux.c
+++ b/drivers/clk/ti/clk-mux.c
@@ -12,7 +12,7 @@
 #include <clk-uclass.h>
 #include <asm/io.h>
 #include <linux/clk-provider.h>
-#include "clk-ti.h"
+#include "clk.h"
 
 struct clk_ti_mux_priv {
 	struct clk_bulk parents;
diff --git a/drivers/clk/clk-ti-sci.c b/drivers/clk/ti/clk-sci.c
similarity index 100%
rename from drivers/clk/clk-ti-sci.c
rename to drivers/clk/ti/clk-sci.c
diff --git a/drivers/clk/clk-ti.c b/drivers/clk/ti/clk.c
similarity index 96%
rename from drivers/clk/clk-ti.c
rename to drivers/clk/ti/clk.c
index 594ef75270..e44b90ad6a 100644
--- a/drivers/clk/clk-ti.c
+++ b/drivers/clk/ti/clk.c
@@ -7,7 +7,7 @@
 
 #include <common.h>
 #include <asm/io.h>
-#include "clk-ti.h"
+#include "clk.h"
 
 static void clk_ti_rmw(u32 val, u32 mask, fdt_addr_t reg)
 {
diff --git a/drivers/clk/clk-ti.h b/drivers/clk/ti/clk.h
similarity index 100%
rename from drivers/clk/clk-ti.h
rename to drivers/clk/ti/clk.h
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 14/31] clk: ti: omap4: add clock manager driver
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (12 preceding siblings ...)
  2020-08-25  9:21 ` [PATCH 13/31] clk: ti: move drivers to 'ti' directory Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  2020-08-25  9:21 ` [PATCH 15/31] clk: ti: am335x: " Dario Binacchi
                   ` (11 subsequent siblings)
  25 siblings, 0 replies; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

This minimal driver is only used to bind child devices.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 doc/device-tree-bindings/arm/omap,prcm.txt | 63 ++++++++++++++++++++++
 drivers/clk/ti/Makefile                    |  2 +-
 drivers/clk/ti/omap4-cm.c                  | 22 ++++++++
 3 files changed, 86 insertions(+), 1 deletion(-)
 create mode 100644 doc/device-tree-bindings/arm/omap,prcm.txt
 create mode 100644 drivers/clk/ti/omap4-cm.c

diff --git a/doc/device-tree-bindings/arm/omap,prcm.txt b/doc/device-tree-bindings/arm/omap,prcm.txt
new file mode 100644
index 0000000000..123b17bd84
--- /dev/null
+++ b/doc/device-tree-bindings/arm/omap,prcm.txt
@@ -0,0 +1,63 @@
+OMAP PRCM bindings
+
+Power Reset and Clock Manager lists the device clocks and clockdomains under
+a DT hierarchy. Each TI SoC can have multiple PRCM entities listed for it,
+each describing one module and the clock hierarchy under it. see [1] for
+documentation about the individual clock/clockdomain nodes.
+
+[1] doc/device-tree-bindings/clock/ti,*.txt
+
+Required properties:
+- compatible:	Must be one of:
+		"ti,am3-prcm"
+		"ti,am4-prcm"
+		"ti,omap2-prcm"
+		"ti,omap3-prm"
+		"ti,omap3-cm"
+		"ti,omap4-cm1"
+		"ti,omap4-prm"
+		"ti,omap4-cm2"
+		"ti,omap4-scrm"
+		"ti,omap5-prm"
+		"ti,omap5-cm-core-aon"
+		"ti,omap5-scrm"
+		"ti,omap5-cm-core"
+		"ti,dra7-prm"
+		"ti,dra7-cm-core-aon"
+		"ti,dra7-cm-core"
+		"ti,dm814-prcm"
+		"ti,dm816-prcm"
+- reg:		Contains PRCM module register address range
+		(base address and length)
+- clocks:	clocks for this module
+- clockdomains:	clockdomains for this module
+
+Example:
+
+cm: cm at 48004000 {
+	compatible = "ti,omap3-cm";
+	reg = <0x48004000 0x4000>;
+
+	cm_clocks: clocks {
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
+
+	cm_clockdomains: clockdomains {
+	};
+}
+
+&cm_clocks {
+	omap2_32k_fck: omap_32k_fck {
+		#clock-cells = <0>;
+		compatible = "fixed-clock";
+		clock-frequency = <32768>;
+	};
+};
+
+&cm_clockdomains {
+	core_l3_clkdm: core_l3_clkdm {
+		compatible = "ti,clockdomain";
+		clocks = <&sdrc_ick>;
+	};
+};
diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile
index a279a2838d..0b7e61cdf7 100644
--- a/drivers/clk/ti/Makefile
+++ b/drivers/clk/ti/Makefile
@@ -3,7 +3,7 @@
 # Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
 #
 
-obj-$(CONFIG_ARCH_OMAP2PLUS) += clk.o
+obj-$(CONFIG_ARCH_OMAP2PLUS) += clk.o omap4-cm.o
 obj-$(CONFIG_CLK_TI_AM3_DPLL) += clk-am3-dpll.o clk-am3-dpll-x2.o
 obj-$(CONFIG_CLK_TI_CTRL) += clk-ctrl.o
 obj-$(CONFIG_CLK_TI_DIVIDER) += clk-divider.o
diff --git a/drivers/clk/ti/omap4-cm.c b/drivers/clk/ti/omap4-cm.c
new file mode 100644
index 0000000000..3cdc9b2888
--- /dev/null
+++ b/drivers/clk/ti/omap4-cm.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * OMAP4 clock manager (cm)
+ *
+ * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/lists.h>
+
+static const struct udevice_id ti_omap4_cm_ids[] = {
+	{.compatible = "ti,omap4-cm"},
+	{}
+};
+
+U_BOOT_DRIVER(ti_omap4_cm) = {
+	.name = "ti_omap4_cm",
+	.id = UCLASS_SIMPLE_BUS,
+	.of_match = ti_omap4_cm_ids,
+	.bind = dm_scan_fdt_dev,
+};
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 15/31] clk: ti: am335x: add clock manager driver
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (13 preceding siblings ...)
  2020-08-25  9:21 ` [PATCH 14/31] clk: ti: omap4: add clock manager driver Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  2020-08-25  9:21 ` [PATCH 16/31] fdt: translate address if #size-cells = <0> Dario Binacchi
                   ` (10 subsequent siblings)
  25 siblings, 0 replies; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

The implementation of this driver was needed to bind the sub-nodes of
the 'clocks' node. In fact, the lack of the compatible property in
the 'clocks' node does not allow the generic 'simple-bus' driver to bind
the 'clocks' node and in turn its sub-nodes.
The 'prcm at 200000' node is therefore the node closest to the 'clocks'
node whose driver can bind all the 'clocks' sub-nodes.

prcm: prcm at 200000 {
	compatible = "ti,am3-prcm", "simple-bus";
	reg = <0x200000 0x4000>;
	#address-cells = <1>;
	#size-cells = <1>;
	ranges = <0 0x200000 0x4000>;

	prcm_clocks: clocks {
		#address-cells = <1>;
		#size-cells = <0>;
	};

	prcm_clockdomains: clockdomains {
	};
};

&prcm_clocks {
	...
	dpll_core_ck: dpll_core_ck at 490 {
        	#clock-cells = <0>;
		compatible = "ti,am3-dpll-core-clock";
		clocks = <&sys_clkin_ck>, <&sys_clkin_ck>;
		reg = <0x0490>, <0x045c>, <0x0468>;
	};
	...
};

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 drivers/clk/ti/Makefile   |  8 ++++-
 drivers/clk/ti/am3-prcm.c | 73 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/ti/am3-prcm.c

diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile
index 0b7e61cdf7..3d6e0cd79d 100644
--- a/drivers/clk/ti/Makefile
+++ b/drivers/clk/ti/Makefile
@@ -3,7 +3,13 @@
 # Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
 #
 
-obj-$(CONFIG_ARCH_OMAP2PLUS) += clk.o omap4-cm.o
+ifeq ($(CONFIG_ARCH_OMAP2PLUS), y)
+
+obj-y += clk.o omap4-cm.o
+obj-$(CONFIG_AM33XX) += am3-prcm.o
+
+endif # CONFIG_ARCH_OMAP2PLUS
+
 obj-$(CONFIG_CLK_TI_AM3_DPLL) += clk-am3-dpll.o clk-am3-dpll-x2.o
 obj-$(CONFIG_CLK_TI_CTRL) += clk-ctrl.o
 obj-$(CONFIG_CLK_TI_DIVIDER) += clk-divider.o
diff --git a/drivers/clk/ti/am3-prcm.c b/drivers/clk/ti/am3-prcm.c
new file mode 100644
index 0000000000..8461de6077
--- /dev/null
+++ b/drivers/clk/ti/am3-prcm.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * AM335x power reset and clock manager (prcm)
+ *
+ * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <linux/err.h>
+
+static int ti_am3_prcm_bind(struct udevice *dev)
+{
+	ofnode clocks_node;
+	int err;
+
+	err = dm_scan_fdt_dev(dev);
+	if (err) {
+		dev_err(dev, "%s: dm_scan_fdt, err=%d\n", __func__, err);
+		return err;
+	}
+
+	clocks_node = ofnode_find_subnode(dev_ofnode(dev), "clocks");
+	if (!ofnode_valid(clocks_node)) {
+		dev_err(dev, "%s: failed to get clocks sub-node\n", __func__);
+		return -ENODEV;
+	}
+
+	err = device_bind_driver_to_node(dev, "ti_am3_prcm_clocks",
+					 "prcm_clocks", clocks_node, NULL);
+	if (err) {
+		dev_err(dev, "%s: failed to bind prcm_clocks\n", __func__);
+		return err;
+	}
+
+	return 0;
+}
+
+static const struct udevice_id ti_am3_prcm_ids[] = {
+	{.compatible = "ti,am3-prcm"},
+	{}
+};
+
+U_BOOT_DRIVER(ti_am3_prcm) = {
+	.name = "ti_am3_prcm",
+	.id = UCLASS_SIMPLE_BUS,
+	.of_match = ti_am3_prcm_ids,
+	.bind = ti_am3_prcm_bind,
+};
+
+static int ti_am3_prcm_clocks_bind(struct udevice *dev)
+{
+	ofnode node;
+	int err;
+
+	ofnode_for_each_subnode(node, dev_ofnode(dev)) {
+		err = lists_bind_fdt(dev, node, NULL, false);
+		if (err) {
+			dev_err(dev, "%s: lists_bind_fdt, err=%d\n",
+				__func__, err);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+U_BOOT_DRIVER(ti_am3_prcm_clocks) = {
+	.name = "ti_am3_prcm_clocks",
+	.id = UCLASS_SIMPLE_BUS,
+	.bind = ti_am3_prcm_clocks_bind,
+};
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 16/31] fdt: translate address if #size-cells = <0>
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (14 preceding siblings ...)
  2020-08-25  9:21 ` [PATCH 15/31] clk: ti: am335x: " Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  2020-08-29 21:20   ` Simon Glass
  2020-08-25  9:21 ` [PATCH 17/31] omap: timer: fix the rate setting Dario Binacchi
                   ` (9 subsequent siblings)
  25 siblings, 1 reply; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

The __of_translate_address routine translates an address from the
device tree into a CPU physical address. A note in the description of
the routine explains that the crossing of any level with
since inherited from IBM. This does not happen for Texas Instruments, or
at least for the beaglebone device tree. Without this patch, in fact,
the translation into physical addresses of the registers contained in the
am33xx-clocks.dtsi nodes would not be possible. They all have a parent
with #size-cells = <0>.

The CONFIG_OF_TRANSLATE_ZERO_SIZE_CELLS symbol makes translation
possible even in the case of crossing levels with #size-cells = <0>.

The patch acts conservatively on address translation, except for
removing a check within the of_translate_one function in the
drivers/core/of_addr.c file:

+
        ranges = of_get_property(parent, rprop, &rlen);
-       if (ranges == NULL && !of_empty_ranges_quirk(parent)) {
-               debug("no ranges; cannot translate\n");
-               return 1;
-       }
        if (ranges == NULL || rlen == 0) {
                offset = of_read_number(addr, na);
                memset(addr, 0, pna * 4);
		debug("empty ranges; 1:1 translation\n");

There are two reasons:
1 The function of_empty_ranges_quirk always returns false, invalidating
  the following if statement in case of null ranges. Therefore one of
  the two checks is useless.

2 The implementation of the of_translate_one function found in the
  common/fdt_support.c file has removed this check while keeping the one
  about the 1:1 translation.

The patch adds a test and modifies a check for the correctness of an
address in the case of enabling translation also for zero size cells.
The added test checks translations of addresses generated by nodes of
a device tree similar to those you can find in the files am33xx.dtsi
and am33xx-clocks.dtsi for which the patch was created.

The patch was also tested on a beaglebone black board. The addresses
generated for the registers of the loaded drivers are those specified
by the AM335x reference manual.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
Tested-by: Dario Binacchi <dariobin@libero.it>
---

 arch/sandbox/dts/test.dts | 21 +++++++++++
 common/fdt_support.c      | 10 ++++--
 drivers/core/Kconfig      | 12 +++++++
 drivers/core/fdtaddr.c    |  2 +-
 drivers/core/of_addr.c    | 14 +++-----
 drivers/core/ofnode.c     | 11 ++++--
 test/dm/test-fdt.c        | 73 +++++++++++++++++++++++++++++++++++++--
 7 files changed, 127 insertions(+), 16 deletions(-)

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 1d8956abbe..7f5d8f3aeb 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -39,6 +39,7 @@
 		fdt-dummy1 = "/translation-test at 8000/dev at 1,100";
 		fdt-dummy2 = "/translation-test at 8000/dev at 2,200";
 		fdt-dummy3 = "/translation-test at 8000/noxlatebus at 3,300/dev at 42";
+		fdt-dummy4 = "/translation-test at 8000/xlatebus at 4,400/devs/dev at 19";
 		usb0 = &usb_0;
 		usb1 = &usb_1;
 		usb2 = &usb_2;
@@ -977,6 +978,7 @@
 			  1 0x100 0x9000 0x1000
 			  2 0x200 0xA000 0x1000
 			  3 0x300 0xB000 0x1000
+			  4 0x400 0xC000 0x1000
 			 >;
 
 		dma-ranges = <0 0x000 0x10000000 0x1000
@@ -1013,6 +1015,25 @@
 				reg = <0x42>;
 			};
 		};
+
+		xlatebus at 4,400 {
+			compatible = "sandbox,zero-size-cells-bus";
+			reg = <4 0x400 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 4 0x400 0x1000>;
+
+			devs {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				dev at 19 {
+					compatible = "denx,u-boot-fdt-dummy";
+					reg = <0x19>;
+				};
+			};
+		};
+
 	};
 
 	osd {
diff --git a/common/fdt_support.c b/common/fdt_support.c
index a565b470f8..402401e073 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -1001,8 +1001,14 @@ void fdt_del_node_and_alias(void *blob, const char *alias)
 /* Max address size we deal with */
 #define OF_MAX_ADDR_CELLS	4
 #define OF_BAD_ADDR	FDT_ADDR_T_NONE
-#define OF_CHECK_COUNTS(na, ns)	((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
-			(ns) > 0)
+#define OF_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS)
+#if defined(CONFIG_OF_TRANSLATE_ZERO_SIZE_CELLS)
+#define OF_CHECK_SIZE_COUNT(ns) ((ns) >= 0)
+#else
+#define OF_CHECK_SIZE_COUNT(ns) ((ns) > 0)
+#endif
+#define OF_CHECK_COUNTS(na, ns) (OF_CHECK_ADDR_COUNT(na) && \
+				 OF_CHECK_SIZE_COUNT(ns))
 
 /* Debug utility */
 #ifdef DEBUG
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index 00d1d80dc3..2a683ae404 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -217,6 +217,18 @@ config OF_TRANSLATE
 	  used for the address translation. This function is faster and
 	  smaller in size than fdt_translate_address().
 
+config OF_TRANSLATE_ZERO_SIZE_CELLS
+	bool "Enable translation for zero size cells"
+	depends on OF_TRANSLATE
+	default n
+	help
+	  The routine used to translate an FDT address into a physical CPU
+	  address was developed by IBM. It considers that crossing any level
+	  with #size-cells = <0> makes translation impossible, even if it is
+	  not the way it was specified.
+	  Enabling this option makes translation possible even in the case
+	  of crossing levels with #size-cells = <0>.
+
 config SPL_OF_TRANSLATE
 	bool "Translate addresses using fdt_translate_address in SPL"
 	depends on SPL_DM && SPL_OF_CONTROL
diff --git a/drivers/core/fdtaddr.c b/drivers/core/fdtaddr.c
index 8b48aa5bc5..5a9f08aa44 100644
--- a/drivers/core/fdtaddr.c
+++ b/drivers/core/fdtaddr.c
@@ -49,7 +49,7 @@ fdt_addr_t devfdt_get_addr_index(const struct udevice *dev, int index)
 
 		reg += index * (na + ns);
 
-		if (ns) {
+		if (IS_ENABLED(CONFIG_OF_TRANSLATE_ZERO_SIZE_CELLS) || ns) {
 			/*
 			 * Use the full-fledged translate function for complex
 			 * bus setups.
diff --git a/drivers/core/of_addr.c b/drivers/core/of_addr.c
index ca34d84922..ddac5f9a2b 100644
--- a/drivers/core/of_addr.c
+++ b/drivers/core/of_addr.c
@@ -18,7 +18,11 @@
 /* Max address size we deal with */
 #define OF_MAX_ADDR_CELLS	4
 #define OF_CHECK_ADDR_COUNT(na)	((na) > 0 && (na) <= OF_MAX_ADDR_CELLS)
+#if defined(CONFIG_OF_TRANSLATE_ZERO_SIZE_CELLS)
+#define OF_CHECK_COUNTS(na, ns)	(OF_CHECK_ADDR_COUNT(na) && (ns) >= 0)
+#else
 #define OF_CHECK_COUNTS(na, ns)	(OF_CHECK_ADDR_COUNT(na) && (ns) > 0)
+#endif
 
 static struct of_bus *of_match_bus(struct device_node *np);
 
@@ -162,11 +166,6 @@ const __be32 *of_get_address(const struct device_node *dev, int index,
 }
 EXPORT_SYMBOL(of_get_address);
 
-static int of_empty_ranges_quirk(const struct device_node *np)
-{
-	return false;
-}
-
 static int of_translate_one(const struct device_node *parent,
 			    struct of_bus *bus, struct of_bus *pbus,
 			    __be32 *addr, int na, int ns, int pna,
@@ -193,11 +192,8 @@ static int of_translate_one(const struct device_node *parent,
 	 * As far as we know, this damage only exists on Apple machines, so
 	 * This code is only enabled on powerpc. --gcl
 	 */
+
 	ranges = of_get_property(parent, rprop, &rlen);
-	if (ranges == NULL && !of_empty_ranges_quirk(parent)) {
-		debug("no ranges; cannot translate\n");
-		return 1;
-	}
 	if (ranges == NULL || rlen == 0) {
 		offset = of_read_number(addr, na);
 		memset(addr, 0, pna * 4);
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index d02d8d33fe..b5744e86c3 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -304,7 +304,10 @@ fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
 
 		ns = of_n_size_cells(ofnode_to_np(node));
 
-		if (IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
+		if (IS_ENABLED(CONFIG_OF_TRANSLATE) &&
+		    (ns > 0 ||
+		     (IS_ENABLED(CONFIG_OF_TRANSLATE_ZERO_SIZE_CELLS) &&
+		      ns >= 0))) {
 			return of_translate_address(ofnode_to_np(node), prop_val);
 		} else {
 			na = of_n_addr_cells(ofnode_to_np(node));
@@ -655,8 +658,12 @@ fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
 		ns = of_n_size_cells(np);
 		*sizep = of_read_number(prop + na, ns);
 
-		if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
+		if (CONFIG_IS_ENABLED(OF_TRANSLATE) &&
+		    (ns > 0 ||
+		     (IS_ENABLED(CONFIG_OF_TRANSLATE_ZERO_SIZE_CELLS) &&
+		      ns >= 0))) {
 			return of_translate_address(np, prop);
+		}
 		else
 			return of_read_number(prop, na);
 	} else {
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index 04802deb7f..30a7a933dd 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -581,6 +581,64 @@ U_BOOT_DRIVER(fdt_dummy_drv) = {
 	.id	= UCLASS_TEST_DUMMY,
 };
 
+static int zero_size_cells_bus_bind(struct udevice *dev)
+{
+	ofnode child;
+	int err;
+
+	ofnode_for_each_subnode(child, dev_ofnode(dev)) {
+		if (ofnode_get_property(child, "compatible", NULL))
+			continue;
+
+		err = device_bind_driver_to_node(dev,
+						 "zero_size_cells_bus_child_drv",
+						 "zero_size_cells_bus_child",
+						 child, NULL);
+		if (err) {
+			dev_err(dev, "%s: failed to bind %s\n", __func__,
+				ofnode_get_name(child));
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static const struct udevice_id zero_size_cells_bus_ids[] = {
+	{ .compatible = "sandbox,zero-size-cells-bus" },
+	{ }
+};
+
+U_BOOT_DRIVER(zero_size_cells_bus) = {
+	.name = "zero_size_cells_bus_drv",
+	.id = UCLASS_TEST_DUMMY,
+	.of_match = zero_size_cells_bus_ids,
+	.bind = zero_size_cells_bus_bind,
+};
+
+static int zero_size_cells_bus_child_bind(struct udevice *dev)
+{
+	ofnode child;
+	int err;
+
+	ofnode_for_each_subnode(child, dev_ofnode(dev)) {
+		err = lists_bind_fdt(dev, child, NULL, false);
+		if (err) {
+			dev_err(dev, "%s: lists_bind_fdt, err=%d\n",
+				__func__, err);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+U_BOOT_DRIVER(zero_size_cells_bus_child_drv) = {
+	.name = "zero_size_cells_bus_child_drv",
+	.id = UCLASS_TEST_DUMMY,
+	.bind = zero_size_cells_bus_child_bind,
+};
+
 static int dm_test_fdt_translation(struct unit_test_state *uts)
 {
 	struct udevice *dev;
@@ -599,10 +657,21 @@ static int dm_test_fdt_translation(struct unit_test_state *uts)
 	ut_asserteq_str("dev at 2,200", dev->name);
 	ut_asserteq(0xA000, dev_read_addr(dev));
 
-	/* No translation for busses with #size-cells == 0 */
 	ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 3, true, &dev));
 	ut_asserteq_str("dev at 42", dev->name);
-	ut_asserteq(0x42, dev_read_addr(dev));
+
+	if (!IS_ENABLED(CONFIG_OF_TRANSLATE_ZERO_SIZE_CELLS)) {
+		/* No translation for busses with #size-cells == 0 */
+		ut_asserteq(0x42, dev_read_addr(dev));
+	} else {
+		/* Translation for busses with #size-cells == 0 */
+		ut_asserteq(0x8042, dev_read_addr(dev));
+
+		ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 4, true,
+						      &dev));
+		ut_asserteq_str("dev at 19", dev->name);
+		ut_asserteq(0xC019, dev_read_addr(dev));
+	}
 
 	/* dma address translation */
 	ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 0, true, &dev));
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 17/31] omap: timer: fix the rate setting
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (15 preceding siblings ...)
  2020-08-25  9:21 ` [PATCH 16/31] fdt: translate address if #size-cells = <0> Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  2020-08-25  9:21 ` [PATCH 18/31] misc: am33xx: add control module driver Dario Binacchi
                   ` (8 subsequent siblings)
  25 siblings, 0 replies; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

The prescaler (PTV) setting must be taken into account even when the
timer input clock frequency has been set.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 drivers/timer/omap-timer.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/timer/omap-timer.c b/drivers/timer/omap-timer.c
index cf3d27b96b..60af68e677 100644
--- a/drivers/timer/omap-timer.c
+++ b/drivers/timer/omap-timer.c
@@ -19,8 +19,6 @@
 #define TCLR_PRE_EN			BIT(5)	/* Pre-scaler enable */
 #define TCLR_PTV_SHIFT			(2)	/* Pre-scaler shift value */
 
-#define TIMER_CLOCK             (V_SCLK / (2 << CONFIG_SYS_PTV))
-
 struct omap_gptimer_regs {
 	unsigned int tidr;		/* offset 0x00 */
 	unsigned char res1[12];
@@ -63,7 +61,9 @@ static int omap_timer_probe(struct udevice *dev)
 	struct omap_timer_priv *priv = dev_get_priv(dev);
 
 	if (!uc_priv->clock_rate)
-		uc_priv->clock_rate = TIMER_CLOCK;
+		uc_priv->clock_rate = V_SCLK;
+
+	uc_priv->clock_rate /= (2 << CONFIG_SYS_PTV);
 
 	/* start the counter ticking up, reload value on overflow */
 	writel(0, &priv->regs->tldr);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 18/31] misc: am33xx: add control module driver
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (16 preceding siblings ...)
  2020-08-25  9:21 ` [PATCH 17/31] omap: timer: fix the rate setting Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  2020-09-03  6:31   ` Lokesh Vutla
  2020-08-25  9:21 ` [PATCH 19/31] pwm: ti: am33xx: add enhanced pwm driver Dario Binacchi
                   ` (7 subsequent siblings)
  25 siblings, 1 reply; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

The implementation of this driver was needed to bind the device tree
sub-nodes of the 'clocks' node. In fact, the lack of the compatible
property in the 'clocks' node does not allow the generic 'syscon' or
'simple-bus' drivers linked to the 'scm_conf at 0' node to bind the
'clocks' node and in turn its sub-nodes.
The 'scm at 210000' node is therefore the node closest to the 'clocks' node
whose driver can bind all the 'clocks' sub-nodes.

scm: scm at 210000 {
	compatible = "ti,am3-scm", "simple-bus";
	...

	scm_conf: scm_conf at 0 {
		compatible = "syscon", "simple-bus";
		#address-cells = <1>;
		#size-cells = <1>;
		ranges = <0 0 0x800>;

		scm_clocks: clocks {
			#address-cells = <1>;
			#size-cells = <0>;
		};
	};
};

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 doc/device-tree-bindings/arm/omap,ctrl.txt    |  82 ++++++
 .../pinctrl/pinctrl-single.txt                | 255 ++++++++++++++++++
 drivers/misc/Kconfig                          |   7 +
 drivers/misc/Makefile                         |   1 +
 drivers/misc/ti-am3-scm.c                     |  90 +++++++
 5 files changed, 435 insertions(+)
 create mode 100644 doc/device-tree-bindings/arm/omap,ctrl.txt
 create mode 100644 doc/device-tree-bindings/pinctrl/pinctrl-single.txt
 create mode 100644 drivers/misc/ti-am3-scm.c

diff --git a/doc/device-tree-bindings/arm/omap,ctrl.txt b/doc/device-tree-bindings/arm/omap,ctrl.txt
new file mode 100644
index 0000000000..8efd321cfa
--- /dev/null
+++ b/doc/device-tree-bindings/arm/omap,ctrl.txt
@@ -0,0 +1,82 @@
+OMAP Control Module bindings
+
+Control Module contains miscellaneous features under it based on SoC type.
+Pincontrol is one common feature, and it has a specialized support
+described in [1]. Typically some clock nodes are also under control module.
+Syscon is used to share register level access to drivers external to
+control module driver itself.
+
+See [2] for documentation about clock/clockdomain nodes.
+
+[1] doc/device-tree-bindings/pinctrl/pinctrl-single.txt
+[2] doc/device-tree-bindings/clock/ti,*.txt
+
+Required properties:
+- compatible:	Must be one of:
+		"ti,am3-scm"
+		"ti,am4-scm"
+		"ti,dm814-scrm"
+		"ti,dm816-scrm"
+		"ti,omap2-scm"
+		"ti,omap3-scm"
+		"ti,omap4-scm-core"
+		"ti,omap4-scm-padconf-core"
+		"ti,omap4-scm-wkup"
+		"ti,omap4-scm-padconf-wkup"
+		"ti,omap5-scm-core"
+		"ti,omap5-scm-padconf-core"
+		"ti,omap5-scm-wkup-pad-conf"
+		"ti,dra7-scm-core"
+- reg:		Contains Control Module register address range
+		(base address and length)
+
+Optional properties:
+- clocks:	clocks for this module
+- clockdomains:	clockdomains for this module
+
+Examples:
+
+scm: scm at 2000 {
+	compatible = "ti,omap3-scm", "simple-bus";
+	reg = <0x2000 0x2000>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges = <0 0x2000 0x2000>;
+
+	omap3_pmx_core: pinmux at 30 {
+		compatible = "ti,omap3-padconf",
+			     "pinctrl-single";
+		reg = <0x30 0x230>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		#interrupt-cells = <1>;
+		interrupt-controller;
+		pinctrl-single,register-width = <16>;
+		pinctrl-single,function-mask = <0xff1f>;
+	};
+
+	scm_conf: scm_conf at 270 {
+		compatible = "syscon";
+		reg = <0x270 0x330>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		scm_clocks: clocks {
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+
+	scm_clockdomains: clockdomains {
+	};
+}
+
+&scm_clocks {
+	mcbsp5_mux_fck: mcbsp5_mux_fck {
+		#clock-cells = <0>;
+		compatible = "ti,composite-mux-clock";
+		clocks = <&core_96m_fck>, <&mcbsp_clks>;
+		ti,bit-shift = <4>;
+		reg = <0x02d8>;
+	};
+};
diff --git a/doc/device-tree-bindings/pinctrl/pinctrl-single.txt b/doc/device-tree-bindings/pinctrl/pinctrl-single.txt
new file mode 100644
index 0000000000..e705acd361
--- /dev/null
+++ b/doc/device-tree-bindings/pinctrl/pinctrl-single.txt
@@ -0,0 +1,255 @@
+One-register-per-pin type device tree based pinctrl driver
+
+Required properties:
+- compatible : "pinctrl-single" or "pinconf-single".
+  "pinctrl-single" means that pinconf isn't supported.
+  "pinconf-single" means that generic pinconf is supported.
+
+- reg : offset and length of the register set for the mux registers
+
+- #pinctrl-cells : number of cells in addition to the index, set to 1
+  for pinctrl-single,pins and 2 for pinctrl-single,bits
+
+- pinctrl-single,register-width : pinmux register access width in bits
+
+- pinctrl-single,function-mask : mask of allowed pinmux function bits
+  in the pinmux register
+
+Optional properties:
+- pinctrl-single,function-off : function off mode for disabled state if
+  available and same for all registers; if not specified, disabling of
+  pin functions is ignored
+
+- pinctrl-single,bit-per-mux : boolean to indicate that one register controls
+  more than one pin, for which "pinctrl-single,function-mask" property specifies
+ position mask of pin.
+
+- pinctrl-single,drive-strength : array of value that are used to configure
+  drive strength in the pinmux register. They're value of drive strength
+  current and drive strength mask.
+
+		/* drive strength current, mask */
+		pinctrl-single,power-source = <0x30 0xf0>;
+
+- pinctrl-single,bias-pullup : array of value that are used to configure the
+  input bias pullup in the pinmux register.
+
+		/* input, enabled pullup bits, disabled pullup bits, mask */
+		pinctrl-single,bias-pullup = <0 1 0 1>;
+
+- pinctrl-single,bias-pulldown : array of value that are used to configure the
+  input bias pulldown in the pinmux register.
+
+		/* input, enabled pulldown bits, disabled pulldown bits, mask */
+		pinctrl-single,bias-pulldown = <2 2 0 2>;
+
+  * Two bits to control input bias pullup and pulldown: User should use
+    pinctrl-single,bias-pullup & pinctrl-single,bias-pulldown. One bit means
+    pullup, and the other one bit means pulldown.
+  * Three bits to control input bias enable, pullup and pulldown. User should
+    use pinctrl-single,bias-pullup & pinctrl-single,bias-pulldown. Input bias
+    enable bit should be included in pullup or pulldown bits.
+  * Although driver could set PIN_CONFIG_BIAS_DISABLE, there's no property as
+    pinctrl-single,bias-disable. Because pinctrl single driver could implement
+    it by calling pulldown, pullup disabled.
+
+- pinctrl-single,input-schmitt : array of value that are used to configure
+  input schmitt in the pinmux register. In some silicons, there're two input
+  schmitt value (rising-edge & falling-edge) in the pinmux register.
+
+		/* input schmitt value, mask */
+		pinctrl-single,input-schmitt = <0x30 0x70>;
+
+- pinctrl-single,input-schmitt-enable : array of value that are used to
+  configure input schmitt enable or disable in the pinmux register.
+
+		/* input, enable bits, disable bits, mask */
+		pinctrl-single,input-schmitt-enable = <0x30 0x40 0 0x70>;
+
+- pinctrl-single,low-power-mode : array of value that are used to configure
+  low power mode of this pin. For some silicons, the low power mode will
+  control the output of the pin when the pad including the pin enter low
+  power mode.
+		/* low power mode value, mask */
+		pinctrl-single,low-power-mode = <0x288 0x388>;
+
+- pinctrl-single,gpio-range : list of value that are used to configure a GPIO
+  range. They're value of subnode phandle, pin base in pinctrl device, pin
+  number in this range, GPIO function value of this GPIO range.
+  The number of parameters is depend on #pinctrl-single,gpio-range-cells
+  property.
+
+		/* pin base, nr pins & gpio function */
+		pinctrl-single,gpio-range = <&range 0 3 0 &range 3 9 1>;
+
+- interrupt-controller : standard interrupt controller binding if using
+  interrupts for wake-up events for example. In this case pinctrl-single
+  is set up as a chained interrupt controller and the wake-up interrupts
+  can be requested by the drivers using request_irq().
+
+- #interrupt-cells : standard interrupt binding if using interrupts
+
+This driver assumes that there is only one register for each pin (unless the
+pinctrl-single,bit-per-mux is set), and uses the common pinctrl bindings as
+specified in the pinctrl-bindings.txt document in this directory.
+
+The pin configuration nodes for pinctrl-single are specified as pinctrl
+register offset and value pairs using pinctrl-single,pins. Only the bits
+specified in pinctrl-single,function-mask are updated. For example, setting
+a pin for a device could be done with:
+
+	pinctrl-single,pins = <0xdc 0x118>;
+
+Where 0xdc is the offset from the pinctrl register base address for the
+device pinctrl register, and 0x118 contains the desired value of the
+pinctrl register. See the device example and static board pins example
+below for more information.
+
+In case when one register changes more than one pin's mux the
+pinctrl-single,bits need to be used which takes three parameters:
+
+	pinctrl-single,bits = <0xdc 0x18 0xff>;
+
+Where 0xdc is the offset from the pinctrl register base address for the
+device pinctrl register, 0x18 is the desired value, and 0xff is the sub mask to
+be used when applying this change to the register.
+
+
+Optional sub-node: In case some pins could be configured as GPIO in the pinmux
+register, those pins could be defined as a GPIO range. This sub-node is required
+by pinctrl-single,gpio-range property.
+
+Required properties in sub-node:
+- #pinctrl-single,gpio-range-cells : the number of parameters after phandle in
+  pinctrl-single,gpio-range property.
+
+	range: gpio-range {
+		#pinctrl-single,gpio-range-cells = <3>;
+	};
+
+
+Example:
+
+/* SoC common file */
+
+/* first controller instance for pins in core domain */
+pmx_core: pinmux at 4a100040 {
+	compatible = "pinctrl-single";
+	reg = <0x4a100040 0x0196>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	#interrupt-cells = <1>;
+	interrupt-controller;
+	pinctrl-single,register-width = <16>;
+	pinctrl-single,function-mask = <0xffff>;
+};
+
+/* second controller instance for pins in wkup domain */
+pmx_wkup: pinmux at 4a31e040 {
+	compatible = "pinctrl-single";
+	reg = <0x4a31e040 0x0038>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	#interrupt-cells = <1>;
+	interrupt-controller;
+	pinctrl-single,register-width = <16>;
+	pinctrl-single,function-mask = <0xffff>;
+};
+
+control_devconf0: pinmux at 48002274 {
+	compatible = "pinctrl-single";
+	reg = <0x48002274 4>;	/* Single register */
+	#address-cells = <1>;
+	#size-cells = <0>;
+	pinctrl-single,bit-per-mux;
+	pinctrl-single,register-width = <32>;
+	pinctrl-single,function-mask = <0x5F>;
+};
+
+/* third controller instance for pins in gpio domain */
+pmx_gpio: pinmux at d401e000 {
+	compatible = "pinconf-single";
+	reg = <0xd401e000 0x0330>;
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges;
+
+	pinctrl-single,register-width = <32>;
+	pinctrl-single,function-mask = <7>;
+
+	/* sparse GPIO range could be supported */
+	pinctrl-single,gpio-range = <&range 0 3 0 &range 3 9 1
+				&range 12 1 0 &range 13 29 1
+				&range 43 1 0 &range 44 49 1
+				&range 94 1 1 &range 96 2 1>;
+
+	range: gpio-range {
+		#pinctrl-single,gpio-range-cells = <3>;
+	};
+};
+
+
+/* board specific .dts file */
+
+&pmx_core {
+
+	/*
+	 * map all board specific static pins enabled by the pinctrl driver
+	 * itself during the boot (or just set them up in the bootloader)
+	 */
+	pinctrl-names = "default";
+	pinctrl-0 = <&board_pins>;
+
+	board_pins: pinmux_board_pins {
+		pinctrl-single,pins = <
+			0x6c 0xf
+			0x6e 0xf
+			0x70 0xf
+			0x72 0xf
+		>;
+	};
+
+	uart0_pins: pinmux_uart0_pins {
+		pinctrl-single,pins = <
+			0x208 0		/* UART0_RXD (IOCFG138) */
+			0x20c 0		/* UART0_TXD (IOCFG139) */
+		>;
+		pinctrl-single,bias-pulldown = <0 2 2>;
+		pinctrl-single,bias-pullup = <0 1 1>;
+	};
+
+	/* map uart2 pins */
+	uart2_pins: pinmux_uart2_pins {
+		pinctrl-single,pins = <
+			0xd8 0x118
+			0xda 0
+			0xdc 0x118
+			0xde 0
+		>;
+	};
+};
+
+&control_devconf0 {
+	mcbsp1_pins: pinmux_mcbsp1_pins {
+		pinctrl-single,bits = <
+			0x00 0x18 0x18 /* FSR/CLKR signal from FSX/CLKX pin */
+		>;
+	};
+
+	mcbsp2_clks_pins: pinmux_mcbsp2_clks_pins {
+		pinctrl-single,bits = <
+			0x00 0x40 0x40 /* McBSP2 CLKS from McBSP_CLKS pin */
+		>;
+	};
+
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart0_pins>;
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart2_pins>;
+};
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index b67e906a76..9e8b676637 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -500,4 +500,11 @@ config ESM_PMIC
 	  Support ESM (Error Signal Monitor) on PMIC devices. ESM is used
 	  typically to reboot the board in error condition.
 
+config TI_AM3_SCM
+	bool "AM33XX specific control module support (SCM)"
+	depends on ARCH_OMAP2PLUS
+	help
+	 The control module includes status and control logic not addressed
+	 within the peripherals or the rest of the device infrastructure.
+
 endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 947bd3a647..056fb3b522 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -75,3 +75,4 @@ obj-$(CONFIG_MICROCHIP_FLEXCOM) += microchip_flexcom.o
 obj-$(CONFIG_K3_AVS0) += k3_avs.o
 obj-$(CONFIG_ESM_K3) += k3_esm.o
 obj-$(CONFIG_ESM_PMIC) += esm_pmic.o
+obj-$(CONFIG_TI_AM3_SCM) += ti-am3-scm.o
diff --git a/drivers/misc/ti-am3-scm.c b/drivers/misc/ti-am3-scm.c
new file mode 100644
index 0000000000..e5f4f09261
--- /dev/null
+++ b/drivers/misc/ti-am3-scm.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * AM335x specific control module (scm)
+ *
+ * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/lists.h>
+#include <linux/err.h>
+
+static int ti_am3_scm_bind(struct udevice *dev)
+{
+	int err;
+	struct udevice *conf_dev;
+	ofnode clocks_node, conf_node;
+
+	err = dm_scan_fdt_dev(dev);
+	if (err) {
+		dev_err(dev, "%s: dm_scan_fdt, err=%d\n", __func__, err);
+		return err;
+	}
+
+	conf_node = dev_read_subnode(dev, "scm_conf at 0");
+	if (!ofnode_valid(conf_node)) {
+		dev_err(dev, "%s: failed to get conf sub-node\n", __func__);
+		return -ENODEV;
+	}
+
+	if (uclass_get_device_by_ofnode(UCLASS_SYSCON, conf_node, &conf_dev)) {
+		if (uclass_get_device_by_ofnode(UCLASS_SIMPLE_BUS, conf_node,
+						&conf_dev)) {
+			dev_err(dev, "%s: failed to get conf device\n",
+				__func__);
+			return -ENODEV;
+		}
+	}
+
+	clocks_node = dev_read_subnode(conf_dev, "clocks");
+	if (!ofnode_valid(clocks_node)) {
+		dev_err(dev, "%s: failed to get clocks sub-node\n", __func__);
+		return -ENODEV;
+	}
+
+	err = device_bind_driver_to_node(conf_dev, "ti_am3_scm_clocks",
+					 "scm_clocks", clocks_node, NULL);
+	if (err) {
+		dev_err(dev, "%s: failed to bind scm_clocks\n", __func__);
+		return err;
+	}
+
+	return 0;
+}
+
+static const struct udevice_id ti_am3_scm_ids[] = {
+	{.compatible = "ti,am3-scm"},
+	{}
+};
+
+U_BOOT_DRIVER(ti_am3_scm) = {
+	.name = "ti_am3_scm",
+	.id = UCLASS_SIMPLE_BUS,
+	.of_match = ti_am3_scm_ids,
+	.bind = ti_am3_scm_bind,
+};
+
+static int ti_am3_scm_clocks_bind(struct udevice *dev)
+{
+	ofnode node;
+	int err;
+
+	dev_dbg(dev, "%s: dev=%p\n", __func__, dev);
+	ofnode_for_each_subnode(node, dev_ofnode(dev)) {
+		err = lists_bind_fdt(dev, node, NULL, false);
+		if (err) {
+			dev_err(dev, "%s: lists_bind_fdt, err=%d\n",
+				__func__, err);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+U_BOOT_DRIVER(ti_am3_scm_clocks) = {
+	.name = "ti_am3_scm_clocks",
+	.id = UCLASS_SIMPLE_BUS,
+	.bind = ti_am3_scm_clocks_bind,
+};
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 19/31] pwm: ti: am33xx: add enhanced pwm driver
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (17 preceding siblings ...)
  2020-08-25  9:21 ` [PATCH 18/31] misc: am33xx: add control module driver Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  2020-08-25  9:21 ` [PATCH 20/31] pwm: ti: am33xx: add subsystem driver Dario Binacchi
                   ` (6 subsequent siblings)
  25 siblings, 0 replies; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

Enhanced high resolution PWM module (EHRPWM) hardware can be used to
generate PWM output over 2 channels. This commit adds PWM driver support
for EHRPWM device present on AM33XX SOC.

The code is based on the drivers/pwm/pwm-tiehrpwm.c driver of the Linux
kernel.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 doc/device-tree-bindings/pwm/ti,ehrpwm.txt |  49 +++
 drivers/pwm/Kconfig                        |   6 +
 drivers/pwm/Makefile                       |   1 +
 drivers/pwm/pwm-ti-ehrpwm.c                | 465 +++++++++++++++++++++
 4 files changed, 521 insertions(+)
 create mode 100644 doc/device-tree-bindings/pwm/ti,ehrpwm.txt
 create mode 100644 drivers/pwm/pwm-ti-ehrpwm.c

diff --git a/doc/device-tree-bindings/pwm/ti,ehrpwm.txt b/doc/device-tree-bindings/pwm/ti,ehrpwm.txt
new file mode 100644
index 0000000000..12f1e3bf80
--- /dev/null
+++ b/doc/device-tree-bindings/pwm/ti,ehrpwm.txt
@@ -0,0 +1,49 @@
+TI SOC EHRPWM based PWM controller
+
+Required properties:
+- compatible: Must be "ti,<soc>-ehrpwm".
+  for am33xx  - compatible = "ti,am3352-ehrpwm", "ti,am33xx-ehrpwm";
+  for am4372  - compatible = "ti,am4372-ehrpwm", "ti-am3352-ehrpwm", "ti,am33xx-ehrpwm";
+  for am654   - compatible = "ti,am654-ehrpwm", "ti-am3352-ehrpwm";
+  for da850   - compatible = "ti,da850-ehrpwm", "ti-am3352-ehrpwm", "ti,am33xx-ehrpwm";
+  for dra746 - compatible = "ti,dra746-ehrpwm", "ti-am3352-ehrpwm";
+- #pwm-cells: should be 3. The only third cell flag supported by this binding is
+  PWM_POLARITY_INVERTED.
+- reg: physical base address and size of the registers map.
+
+Optional properties:
+- clocks: Handle to the PWM's time-base and functional clock.
+- clock-names: Must be set to "tbclk" and "fck".
+
+Example:
+
+ehrpwm0: pwm at 48300200 { /* EHRPWM on am33xx */
+	compatible = "ti,am3352-ehrpwm", "ti,am33xx-ehrpwm";
+	#pwm-cells = <3>;
+	reg = <0x48300200 0x100>;
+	clocks = <&ehrpwm0_tbclk>, <&l4ls_gclk>;
+	clock-names = "tbclk", "fck";
+};
+
+ehrpwm0: pwm at 48300200 { /* EHRPWM on am4372 */
+	compatible = "ti,am4372-ehrpwm", "ti,am3352-ehrpwm", "ti,am33xx-ehrpwm";
+	#pwm-cells = <3>;
+	reg = <0x48300200 0x80>;
+	clocks = <&ehrpwm0_tbclk>, <&l4ls_gclk>;
+	clock-names = "tbclk", "fck";
+	ti,hwmods = "ehrpwm0";
+};
+
+ehrpwm0: pwm at 1f00000 { /* EHRPWM on da850 */
+	compatible = "ti,da850-ehrpwm", "ti,am3352-ehrpwm", "ti,am33xx-ehrpwm";
+	#pwm-cells = <3>;
+	reg = <0x1f00000 0x2000>;
+};
+
+ehrpwm0: pwm at 4843e200 { /* EHRPWM on dra746 */
+	compatible = "ti,dra746-ehrpwm", "ti,am3352-ehrpwm";
+	#pwm-cells = <3>;
+	reg = <0x4843e200 0x80>;
+	clocks = <&ehrpwm0_tbclk>, <&l4_root_clk_div>;
+	clock-names = "tbclk", "fck";
+};
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 61eb468cde..e4ba8b3d80 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -68,3 +68,9 @@ config PWM_SUNXI
 	help
 	  This PWM is found on H3, A64 and other Allwinner SoCs. It supports a
 	  programmable period and duty cycle. A 16-bit counter is used.
+
+config PWM_TI_EHRPWM
+	bool "Enable support for the AM335x EHRPWM"
+	depends on DM_PWM
+	help
+	  This enables the AM335x EHRPWM driver support on TI's SoCs.
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 0f4e84b04d..c5f88f7501 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -18,3 +18,4 @@ obj-$(CONFIG_PWM_SANDBOX)	+= sandbox_pwm.o
 obj-$(CONFIG_PWM_SIFIVE)	+= pwm-sifive.o
 obj-$(CONFIG_PWM_TEGRA)		+= tegra_pwm.o
 obj-$(CONFIG_PWM_SUNXI)		+= sunxi_pwm.o
+obj-$(CONFIG_PWM_TI_EHRPWM)	+= pwm-ti-ehrpwm.o
diff --git a/drivers/pwm/pwm-ti-ehrpwm.c b/drivers/pwm/pwm-ti-ehrpwm.c
new file mode 100644
index 0000000000..f46eb9ec37
--- /dev/null
+++ b/drivers/pwm/pwm-ti-ehrpwm.c
@@ -0,0 +1,465 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * EHRPWM PWM driver
+ *
+ * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+ *
+ * Based on Linux kernel drivers/pwm/pwm-tiehrpwm.c
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <div64.h>
+#include <dm.h>
+#include <pwm.h>
+#include <asm/io.h>
+
+#define NSEC_PER_SEC			        1000000000L
+
+/* Time base module registers */
+#define TI_EHRPWM_TBCTL				0x00
+#define TI_EHRPWM_TBPRD				0x0A
+
+#define TI_EHRPWM_TBCTL_PRDLD_MASK		BIT(3)
+#define TI_EHRPWM_TBCTL_PRDLD_SHDW		0
+#define TI_EHRPWM_TBCTL_PRDLD_IMDT		BIT(3)
+#define TI_EHRPWM_TBCTL_CLKDIV_MASK		GENMASK(12, 7)
+#define TI_EHRPWM_TBCTL_CTRMODE_MASK		GENMASK(1, 0)
+#define TI_EHRPWM_TBCTL_CTRMODE_UP		0
+#define TI_EHRPWM_TBCTL_CTRMODE_DOWN		BIT(0)
+#define TI_EHRPWM_TBCTL_CTRMODE_UPDOWN		BIT(1)
+#define TI_EHRPWM_TBCTL_CTRMODE_FREEZE		GENMASK(1, 0)
+
+#define TI_EHRPWM_TBCTL_HSPCLKDIV_SHIFT		7
+#define TI_EHRPWM_TBCTL_CLKDIV_SHIFT		10
+
+#define TI_EHRPWM_CLKDIV_MAX			7
+#define TI_EHRPWM_HSPCLKDIV_MAX			7
+#define TI_EHRPWM_PERIOD_MAX			0xFFFF
+
+/* Counter compare module registers */
+#define TI_EHRPWM_CMPA				0x12
+#define TI_EHRPWM_CMPB				0x14
+
+/* Action qualifier module registers */
+#define TI_EHRPWM_AQCTLA			0x16
+#define TI_EHRPWM_AQCTLB			0x18
+#define TI_EHRPWM_AQSFRC			0x1A
+#define TI_EHRPWM_AQCSFRC			0x1C
+
+#define TI_EHRPWM_AQCTL_CBU_MASK		GENMASK(9, 8)
+#define TI_EHRPWM_AQCTL_CBU_FRCLOW		BIT(8)
+#define TI_EHRPWM_AQCTL_CBU_FRCHIGH		BIT(9)
+#define TI_EHRPWM_AQCTL_CBU_FRCTOGGLE		GENMASK(9, 8)
+#define TI_EHRPWM_AQCTL_CAU_MASK		GENMASK(5, 4)
+#define TI_EHRPWM_AQCTL_CAU_FRCLOW		BIT(4)
+#define TI_EHRPWM_AQCTL_CAU_FRCHIGH		BIT(5)
+#define TI_EHRPWM_AQCTL_CAU_FRCTOGGLE		GENMASK(5, 4)
+#define TI_EHRPWM_AQCTL_PRD_MASK		GENMASK(3, 2)
+#define TI_EHRPWM_AQCTL_PRD_FRCLOW		BIT(2)
+#define TI_EHRPWM_AQCTL_PRD_FRCHIGH		BIT(3)
+#define TI_EHRPWM_AQCTL_PRD_FRCTOGGLE		GENMASK(3, 2)
+#define TI_EHRPWM_AQCTL_ZRO_MASK		GENMASK(1, 0)
+#define TI_EHRPWM_AQCTL_ZRO_FRCLOW		BIT(0)
+#define TI_EHRPWM_AQCTL_ZRO_FRCHIGH		BIT(1)
+#define TI_EHRPWM_AQCTL_ZRO_FRCTOGGLE		GENMASK(1, 0)
+
+#define TI_EHRPWM_AQCTL_CHANA_POLNORMAL		(TI_EHRPWM_AQCTL_CAU_FRCLOW | \
+						 TI_EHRPWM_AQCTL_PRD_FRCHIGH | \
+						 TI_EHRPWM_AQCTL_ZRO_FRCHIGH)
+#define TI_EHRPWM_AQCTL_CHANA_POLINVERSED	(TI_EHRPWM_AQCTL_CAU_FRCHIGH | \
+						 TI_EHRPWM_AQCTL_PRD_FRCLOW | \
+						 TI_EHRPWM_AQCTL_ZRO_FRCLOW)
+#define TI_EHRPWM_AQCTL_CHANB_POLNORMAL		(TI_EHRPWM_AQCTL_CBU_FRCLOW | \
+						 TI_EHRPWM_AQCTL_PRD_FRCHIGH | \
+						 TI_EHRPWM_AQCTL_ZRO_FRCHIGH)
+#define TI_EHRPWM_AQCTL_CHANB_POLINVERSED	(TI_EHRPWM_AQCTL_CBU_FRCHIGH | \
+						 TI_EHRPWM_AQCTL_PRD_FRCLOW | \
+						 TI_EHRPWM_AQCTL_ZRO_FRCLOW)
+
+#define TI_EHRPWM_AQSFRC_RLDCSF_MASK		GENMASK(7, 6)
+#define TI_EHRPWM_AQSFRC_RLDCSF_ZRO		0
+#define TI_EHRPWM_AQSFRC_RLDCSF_PRD		BIT(6)
+#define TI_EHRPWM_AQSFRC_RLDCSF_ZROPRD		BIT(7)
+#define TI_EHRPWM_AQSFRC_RLDCSF_IMDT		GENMASK(7, 6)
+
+#define TI_EHRPWM_AQCSFRC_CSFB_MASK		GENMASK(3, 2)
+#define TI_EHRPWM_AQCSFRC_CSFB_FRCDIS		0
+#define TI_EHRPWM_AQCSFRC_CSFB_FRCLOW		BIT(2)
+#define TI_EHRPWM_AQCSFRC_CSFB_FRCHIGH		BIT(3)
+#define TI_EHRPWM_AQCSFRC_CSFB_DISSWFRC		GENMASK(3, 2)
+#define TI_EHRPWM_AQCSFRC_CSFA_MASK		GENMASK(1, 0)
+#define TI_EHRPWM_AQCSFRC_CSFA_FRCDIS		0
+#define TI_EHRPWM_AQCSFRC_CSFA_FRCLOW		BIT(0)
+#define TI_EHRPWM_AQCSFRC_CSFA_FRCHIGH		BIT(1)
+#define TI_EHRPWM_AQCSFRC_CSFA_DISSWFRC		GENMASK(1, 0)
+
+#define TI_EHRPWM_NUM_CHANNELS                  2
+
+struct ti_ehrpwm_priv {
+	fdt_addr_t regs;
+	u32 clk_rate;
+	struct clk tbclk;
+	unsigned long period_cycles[TI_EHRPWM_NUM_CHANNELS];
+	bool polarity_reversed[TI_EHRPWM_NUM_CHANNELS];
+};
+
+static void ti_ehrpwm_modify(u16 val, u16 mask, fdt_addr_t reg)
+{
+	unsigned short v;
+
+	v = readw(reg);
+	v &= ~mask;
+	v |= val & mask;
+	writew(v, reg);
+}
+
+static int ti_ehrpwm_set_invert(struct udevice *dev, uint channel,
+				bool polarity)
+{
+	struct ti_ehrpwm_priv *priv = dev_get_priv(dev);
+
+	if (channel >= TI_EHRPWM_NUM_CHANNELS)
+		return -ENOSPC;
+
+	/* Configuration of polarity in hardware delayed, do at enable */
+	priv->polarity_reversed[channel] = polarity;
+	return 0;
+}
+
+/**
+ * set_prescale_div -	Set up the prescaler divider function
+ * @rqst_prescaler:	prescaler value min
+ * @prescale_div:	prescaler value set
+ * @tb_clk_div:		Time Base Control prescaler bits
+ */
+static int set_prescale_div(unsigned long rqst_prescaler, u16 *prescale_div,
+			    u16 *tb_clk_div)
+{
+	unsigned int clkdiv, hspclkdiv;
+
+	for (clkdiv = 0; clkdiv <= TI_EHRPWM_CLKDIV_MAX; clkdiv++) {
+		for (hspclkdiv = 0; hspclkdiv <= TI_EHRPWM_HSPCLKDIV_MAX;
+		     hspclkdiv++) {
+			/*
+			 * calculations for prescaler value :
+			 * prescale_div = HSPCLKDIVIDER * CLKDIVIDER.
+			 * HSPCLKDIVIDER =  2 ** hspclkdiv
+			 * CLKDIVIDER = (1),            if clkdiv == 0 *OR*
+			 *              (2 * clkdiv),   if clkdiv != 0
+			 *
+			 * Configure prescale_div value such that period
+			 * register value is less than 65535.
+			 */
+
+			*prescale_div = (1 << clkdiv) *
+				(hspclkdiv ? (hspclkdiv * 2) : 1);
+			if (*prescale_div > rqst_prescaler) {
+				*tb_clk_div =
+				    (clkdiv << TI_EHRPWM_TBCTL_CLKDIV_SHIFT) |
+				    (hspclkdiv <<
+				     TI_EHRPWM_TBCTL_HSPCLKDIV_SHIFT);
+				return 0;
+			}
+		}
+	}
+
+	return 1;
+}
+
+static void ti_ehrpwm_configure_polarity(struct udevice *dev, uint channel)
+{
+	struct ti_ehrpwm_priv *priv = dev_get_priv(dev);
+	u16 aqctl_val, aqctl_mask;
+	unsigned int aqctl_reg;
+
+	/*
+	 * Configure PWM output to HIGH/LOW level on counter
+	 * reaches compare register value and LOW/HIGH level
+	 * on counter value reaches period register value and
+	 * zero value on counter
+	 */
+	if (channel == 1) {
+		aqctl_reg = TI_EHRPWM_AQCTLB;
+		aqctl_mask = TI_EHRPWM_AQCTL_CBU_MASK;
+
+		if (priv->polarity_reversed[channel])
+			aqctl_val = TI_EHRPWM_AQCTL_CHANB_POLINVERSED;
+		else
+			aqctl_val = TI_EHRPWM_AQCTL_CHANB_POLNORMAL;
+	} else {
+		aqctl_reg = TI_EHRPWM_AQCTLA;
+		aqctl_mask = TI_EHRPWM_AQCTL_CAU_MASK;
+
+		if (priv->polarity_reversed[channel])
+			aqctl_val = TI_EHRPWM_AQCTL_CHANA_POLINVERSED;
+		else
+			aqctl_val = TI_EHRPWM_AQCTL_CHANA_POLNORMAL;
+	}
+
+	aqctl_mask |= TI_EHRPWM_AQCTL_PRD_MASK | TI_EHRPWM_AQCTL_ZRO_MASK;
+	ti_ehrpwm_modify(aqctl_val, aqctl_mask, priv->regs + aqctl_reg);
+}
+
+/*
+ * period_ns = 10^9 * (ps_divval * period_cycles) / PWM_CLK_RATE
+ * duty_ns   = 10^9 * (ps_divval * duty_cycles) / PWM_CLK_RATE
+ */
+static int ti_ehrpwm_set_config(struct udevice *dev, uint channel,
+				uint period_ns, uint duty_ns)
+{
+	struct ti_ehrpwm_priv *priv = dev_get_priv(dev);
+	u32 period_cycles, duty_cycles;
+	u16 ps_divval, tb_divval;
+	unsigned int i, cmp_reg;
+	unsigned long long c;
+
+	if (channel >= TI_EHRPWM_NUM_CHANNELS)
+		return -ENOSPC;
+
+	if (period_ns > NSEC_PER_SEC)
+		return -ERANGE;
+
+	c = priv->clk_rate;
+	c = c * period_ns;
+	do_div(c, NSEC_PER_SEC);
+	period_cycles = (unsigned long)c;
+
+	if (period_cycles < 1) {
+		period_cycles = 1;
+		duty_cycles = 1;
+	} else {
+		c = priv->clk_rate;
+		c = c * duty_ns;
+		do_div(c, NSEC_PER_SEC);
+		duty_cycles = (unsigned long)c;
+	}
+
+	dev_dbg(dev, "channel=%d, period_ns=%d, duty_ns=%d\n",
+		channel, period_ns, duty_ns);
+
+	/*
+	 * Period values should be same for multiple PWM channels as IP uses
+	 * same period register for multiple channels.
+	 */
+	for (i = 0; i < TI_EHRPWM_NUM_CHANNELS; i++) {
+		if (priv->period_cycles[i] &&
+		    priv->period_cycles[i] != period_cycles) {
+			/*
+			 * Allow channel to reconfigure period if no other
+			 * channels being configured.
+			 */
+			if (i == channel)
+				continue;
+
+			dev_err(dev, "period value conflicts with channel %u\n",
+				i);
+			return -EINVAL;
+		}
+	}
+
+	priv->period_cycles[channel] = period_cycles;
+
+	/* Configure clock prescaler to support Low frequency PWM wave */
+	if (set_prescale_div(period_cycles / TI_EHRPWM_PERIOD_MAX, &ps_divval,
+			     &tb_divval)) {
+		dev_err(dev, "unsupported values\n");
+		return -EINVAL;
+	}
+
+	/* Update clock prescaler values */
+	ti_ehrpwm_modify(tb_divval, TI_EHRPWM_TBCTL_CLKDIV_MASK,
+			 priv->regs + TI_EHRPWM_TBCTL);
+
+	/* Update period & duty cycle with presacler division */
+	period_cycles = period_cycles / ps_divval;
+	duty_cycles = duty_cycles / ps_divval;
+
+	/* Configure shadow loading on Period register */
+	ti_ehrpwm_modify(TI_EHRPWM_TBCTL_PRDLD_SHDW, TI_EHRPWM_TBCTL_PRDLD_MASK,
+			 priv->regs + TI_EHRPWM_TBCTL);
+
+	writew(period_cycles, priv->regs + TI_EHRPWM_TBPRD);
+
+	/* Configure ehrpwm counter for up-count mode */
+	ti_ehrpwm_modify(TI_EHRPWM_TBCTL_CTRMODE_UP,
+			 TI_EHRPWM_TBCTL_CTRMODE_MASK,
+			 priv->regs + TI_EHRPWM_TBCTL);
+
+	if (channel == 1)
+		/* Channel 1 configured with compare B register */
+		cmp_reg = TI_EHRPWM_CMPB;
+	else
+		/* Channel 0 configured with compare A register */
+		cmp_reg = TI_EHRPWM_CMPA;
+
+	writew(duty_cycles, priv->regs + cmp_reg);
+	return 0;
+}
+
+static int ti_ehrpwm_disable(struct udevice *dev, uint channel)
+{
+	struct ti_ehrpwm_priv *priv = dev_get_priv(dev);
+	u16 aqcsfrc_val, aqcsfrc_mask;
+	int err;
+
+	if (channel >= TI_EHRPWM_NUM_CHANNELS)
+		return -ENOSPC;
+
+	/* Action Qualifier puts PWM output low forcefully */
+	if (channel) {
+		aqcsfrc_val = TI_EHRPWM_AQCSFRC_CSFB_FRCLOW;
+		aqcsfrc_mask = TI_EHRPWM_AQCSFRC_CSFB_MASK;
+	} else {
+		aqcsfrc_val = TI_EHRPWM_AQCSFRC_CSFA_FRCLOW;
+		aqcsfrc_mask = TI_EHRPWM_AQCSFRC_CSFA_MASK;
+	}
+
+	/* Update shadow register first before modifying active register */
+	ti_ehrpwm_modify(TI_EHRPWM_AQSFRC_RLDCSF_ZRO,
+			 TI_EHRPWM_AQSFRC_RLDCSF_MASK,
+			 priv->regs + TI_EHRPWM_AQSFRC);
+
+	ti_ehrpwm_modify(aqcsfrc_val, aqcsfrc_mask,
+			 priv->regs + TI_EHRPWM_AQCSFRC);
+
+	/*
+	 * Changes to immediate action on Action Qualifier. This puts
+	 * Action Qualifier control on PWM output from next TBCLK
+	 */
+	ti_ehrpwm_modify(TI_EHRPWM_AQSFRC_RLDCSF_IMDT,
+			 TI_EHRPWM_AQSFRC_RLDCSF_MASK,
+			 priv->regs + TI_EHRPWM_AQSFRC);
+
+	ti_ehrpwm_modify(aqcsfrc_val, aqcsfrc_mask,
+			 priv->regs + TI_EHRPWM_AQCSFRC);
+
+	/* Disabling TBCLK on PWM disable */
+	err = clk_disable(&priv->tbclk);
+	if (err) {
+		dev_err(dev, "failed to disable tbclk\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static int ti_ehrpwm_enable(struct udevice *dev, uint channel)
+{
+	struct ti_ehrpwm_priv *priv = dev_get_priv(dev);
+	u16 aqcsfrc_val, aqcsfrc_mask;
+	int err;
+
+	if (channel >= TI_EHRPWM_NUM_CHANNELS)
+		return -ENOSPC;
+
+	/* Disabling Action Qualifier on PWM output */
+	if (channel) {
+		aqcsfrc_val = TI_EHRPWM_AQCSFRC_CSFB_FRCDIS;
+		aqcsfrc_mask = TI_EHRPWM_AQCSFRC_CSFB_MASK;
+	} else {
+		aqcsfrc_val = TI_EHRPWM_AQCSFRC_CSFA_FRCDIS;
+		aqcsfrc_mask = TI_EHRPWM_AQCSFRC_CSFA_MASK;
+	}
+
+	/* Changes to shadow mode */
+	ti_ehrpwm_modify(TI_EHRPWM_AQSFRC_RLDCSF_ZRO,
+			 TI_EHRPWM_AQSFRC_RLDCSF_MASK,
+			 priv->regs + TI_EHRPWM_AQSFRC);
+
+	ti_ehrpwm_modify(aqcsfrc_val, aqcsfrc_mask,
+			 priv->regs + TI_EHRPWM_AQCSFRC);
+
+	/* Channels polarity can be configured from action qualifier module */
+	ti_ehrpwm_configure_polarity(dev, channel);
+
+	err = clk_enable(&priv->tbclk);
+	if (err) {
+		dev_err(dev, "failed to enable tbclk\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static int ti_ehrpwm_set_enable(struct udevice *dev, uint channel, bool enable)
+{
+	if (enable)
+		return ti_ehrpwm_enable(dev, channel);
+
+	return ti_ehrpwm_disable(dev, channel);
+}
+
+static int ti_ehrpwm_ofdata_to_platdata(struct udevice *dev)
+{
+	struct ti_ehrpwm_priv *priv = dev_get_priv(dev);
+
+	priv->regs = dev_read_addr(dev);
+	if (priv->regs == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	dev_dbg(dev, "regs=0x%08lx\n", priv->regs);
+	return 0;
+}
+
+static int ti_ehrpwm_remove(struct udevice *dev)
+{
+	struct ti_ehrpwm_priv *priv = dev_get_priv(dev);
+
+	clk_release_all(&priv->tbclk, 1);
+	return 0;
+}
+
+static int ti_ehrpwm_probe(struct udevice *dev)
+{
+	struct ti_ehrpwm_priv *priv = dev_get_priv(dev);
+	struct clk clk;
+	int err;
+
+	err = clk_get_by_name(dev, "fck", &clk);
+	if (err) {
+		dev_err(dev, "failed to get clock\n");
+		return err;
+	}
+
+	priv->clk_rate = clk_get_rate(&clk);
+	if (IS_ERR_VALUE(priv->clk_rate) || !priv->clk_rate) {
+		dev_err(dev, "failed to get clock rate\n");
+		if (IS_ERR_VALUE(priv->clk_rate))
+			return priv->clk_rate;
+
+		return -EINVAL;
+	}
+
+	/* Acquire tbclk for Time Base EHRPWM submodule */
+	err = clk_get_by_name(dev, "tbclk", &priv->tbclk);
+	if (err) {
+		dev_err(dev, "failed to get tbclk clock\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static const struct pwm_ops ti_ehrpwm_ops = {
+	.set_config = ti_ehrpwm_set_config,
+	.set_enable = ti_ehrpwm_set_enable,
+	.set_invert = ti_ehrpwm_set_invert,
+};
+
+static const struct udevice_id ti_ehrpwm_ids[] = {
+	{.compatible = "ti,am3352-ehrpwm"},
+	{.compatible = "ti,am33xx-ehrpwm"},
+	{}
+};
+
+U_BOOT_DRIVER(ti_ehrpwm) = {
+	.name = "ti_ehrpwm",
+	.id = UCLASS_PWM,
+	.of_match = ti_ehrpwm_ids,
+	.ops = &ti_ehrpwm_ops,
+	.ofdata_to_platdata = ti_ehrpwm_ofdata_to_platdata,
+	.probe = ti_ehrpwm_probe,
+	.remove = ti_ehrpwm_remove,
+	.priv_auto_alloc_size = sizeof(struct ti_ehrpwm_priv),
+};
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 20/31] pwm: ti: am33xx: add subsystem driver
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (18 preceding siblings ...)
  2020-08-25  9:21 ` [PATCH 19/31] pwm: ti: am33xx: add enhanced pwm driver Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  2020-08-25  9:21 ` [PATCH 21/31] video: backlight: fix pwm's duty cycle calculation Dario Binacchi
                   ` (5 subsequent siblings)
  25 siblings, 0 replies; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

The TI PWMSS driver is a simple bus driver for providing clock and power
management for the PWM peripherals on TI AM33xx SoCs, namely eCAP,
eHRPWM and eQEP.

Based on more recent versions of the device tree inside the linux kernel,
I added the clock domain for each subsystem in am33x.dtsi so it can be
enabled before probing the peripheral child device and disabled after
its removal.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 arch/arm/dts/am33xx.dtsi                  |  9 +++
 doc/device-tree-bindings/pwm/ti,pwmss.txt | 58 ++++++++++++++
 drivers/pwm/Kconfig                       |  9 ++-
 drivers/pwm/Makefile                      |  1 +
 drivers/pwm/pwm-ti-pwmss.c                | 95 +++++++++++++++++++++++
 5 files changed, 171 insertions(+), 1 deletion(-)
 create mode 100644 doc/device-tree-bindings/pwm/ti,pwmss.txt
 create mode 100644 drivers/pwm/pwm-ti-pwmss.c

diff --git a/arch/arm/dts/am33xx.dtsi b/arch/arm/dts/am33xx.dtsi
index d3dd6a16e7..fa7492a9b6 100644
--- a/arch/arm/dts/am33xx.dtsi
+++ b/arch/arm/dts/am33xx.dtsi
@@ -758,6 +758,9 @@
 				  0x48300180 0x48300180 0x80   /* EQEP */
 				  0x48300200 0x48300200 0x80>; /* EHRPWM */
 
+			clocks = <&l4_per_clkctrl AM3_EPWMSS0_CLKCTRL 0>;
+			clock-names = "fck";
+
 			ecap0: ecap at 48300100 {
 				compatible = "ti,am3352-ecap",
 					     "ti,am33xx-ecap";
@@ -792,6 +795,9 @@
 				  0x48302180 0x48302180 0x80   /* EQEP */
 				  0x48302200 0x48302200 0x80>; /* EHRPWM */
 
+			clocks = <&l4_per_clkctrl AM3_EPWMSS1_CLKCTRL 0>;
+			clock-names = "fck";
+
 			ecap1: ecap at 48302100 {
 				compatible = "ti,am3352-ecap",
 					     "ti,am33xx-ecap";
@@ -826,6 +832,9 @@
 				  0x48304180 0x48304180 0x80   /* EQEP */
 				  0x48304200 0x48304200 0x80>; /* EHRPWM */
 
+			clocks = <&l4_per_clkctrl AM3_EPWMSS2_CLKCTRL 0>;
+			clock-names = "fck";
+
 			ecap2: ecap at 48304100 {
 				compatible = "ti,am3352-ecap",
 					     "ti,am33xx-ecap";
diff --git a/doc/device-tree-bindings/pwm/ti,pwmss.txt b/doc/device-tree-bindings/pwm/ti,pwmss.txt
new file mode 100644
index 0000000000..4633697fbd
--- /dev/null
+++ b/doc/device-tree-bindings/pwm/ti,pwmss.txt
@@ -0,0 +1,58 @@
+TI SOC based PWM Subsystem
+
+Required properties:
+- compatible: Must be "ti,<soc>-pwmss".
+  for am33xx  - compatible = "ti,am33xx-pwmss";
+  for am4372  - compatible = "ti,am4372-pwmss","ti,am33xx-pwmss";
+  for dra746 - compatible = "ti,dra746-pwmss", "ti,am33xx-pwmss"
+
+- reg: physical base address and size of the registers map.
+- address-cells: Specify the number of u32 entries needed in child nodes.
+		  Should set to 1.
+- size-cells: specify number of u32 entries needed to specify child nodes size
+		in reg property. Should set to 1.
+- ranges: describes the address mapping of a memory-mapped bus. Should set to
+	   physical address map of child's base address, physical address within
+	   parent's address  space and length of the address map. For am33xx,
+	   3 set of child register maps present, ECAP register space, EQEP
+	   register space, EHRPWM register space.
+
+Also child nodes should also populated under PWMSS DT node.
+
+Example:
+epwmss0: epwmss at 48300000 { /* PWMSS for am33xx */
+	compatible = "ti,am33xx-pwmss";
+	reg = <0x48300000 0x10>;
+	ti,hwmods = "epwmss0";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges = <0x48300100 0x48300100 0x80   /* ECAP */
+		  0x48300180 0x48300180 0x80   /* EQEP */
+		  0x48300200 0x48300200 0x80>; /* EHRPWM */
+
+	/* child nodes go here */
+};
+
+epwmss0: epwmss at 48300000 { /* PWMSS for am4372 */
+	compatible = "ti,am4372-pwmss","ti,am33xx-pwmss"
+	reg = <0x48300000 0x10>;
+	ti,hwmods = "epwmss0";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges = <0x48300100 0x48300100 0x80   /* ECAP */
+		  0x48300180 0x48300180 0x80   /* EQEP */
+		  0x48300200 0x48300200 0x80>; /* EHRPWM */
+
+	/* child nodes go here */
+};
+
+epwmss0: epwmss at 4843e000 { /* PWMSS for DRA7xx */
+	compatible = "ti,dra746-pwmss", "ti,am33xx-pwmss";
+	reg = <0x4843e000 0x30>;
+	ti,hwmods = "epwmss0";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges;
+
+	/* child nodes go here */
+};
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index e4ba8b3d80..129f5d77ca 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -69,8 +69,15 @@ config PWM_SUNXI
 	  This PWM is found on H3, A64 and other Allwinner SoCs. It supports a
 	  programmable period and duty cycle. A 16-bit counter is used.
 
+config PWM_TI_PWMSS
+	bool "Enable support for the AM335x PWM Subsystem"
+	depends on DM_PWM
+	help
+	  This enables the AM335x PWM subsystem driver support on TI's SOCs.
+
 config PWM_TI_EHRPWM
 	bool "Enable support for the AM335x EHRPWM"
-	depends on DM_PWM
+	depends on PWM_TI_PWMSS
+	default y
 	help
 	  This enables the AM335x EHRPWM driver support on TI's SoCs.
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index c5f88f7501..df9c54e764 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_PWM_SIFIVE)	+= pwm-sifive.o
 obj-$(CONFIG_PWM_TEGRA)		+= tegra_pwm.o
 obj-$(CONFIG_PWM_SUNXI)		+= sunxi_pwm.o
 obj-$(CONFIG_PWM_TI_EHRPWM)	+= pwm-ti-ehrpwm.o
+obj-$(CONFIG_PWM_TI_PWMSS)	+= pwm-ti-pwmss.o
diff --git a/drivers/pwm/pwm-ti-pwmss.c b/drivers/pwm/pwm-ti-pwmss.c
new file mode 100644
index 0000000000..57f86512d6
--- /dev/null
+++ b/drivers/pwm/pwm-ti-pwmss.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Pulse-Width Modulation Subsystem (pwmss)
+ *
+ * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+ */
+#define DEBUG
+#undef CONFIG_LOGLEVEL
+#define CONFIG_LOGLEVEL 8
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+
+struct ti_pwmss_priv {
+	int child_count;
+	struct clk clkdm;
+};
+
+static const struct udevice_id ti_pwmss_ids[] = {
+	{.compatible = "ti,am33xx-pwmss"},
+	{}
+};
+
+static int ti_pwmss_child_post_remove(struct udevice *dev)
+{
+	struct ti_pwmss_priv *priv = dev_get_priv(dev->parent);
+	int err;
+
+	if (--priv->child_count > 0)
+		return 0;
+
+	err = clk_disable(&priv->clkdm);
+	if (err) {
+		dev_err(dev->parent, "%s: failed to disable clock domain\n",
+			__func__);
+		goto clkdm_disable_err;
+	}
+
+	err = clk_release_all(&priv->clkdm, 1);
+	if (err) {
+		dev_err(dev->parent, "%s: failed to release clock domain\n",
+			__func__);
+		goto clkdm_release_err;
+	}
+
+	return 0;
+
+clkdm_release_err:
+	clk_enable(&priv->clkdm);
+clkdm_disable_err:
+	priv->child_count++;
+	return err;
+}
+
+static int ti_pwmss_child_pre_probe(struct udevice *dev)
+{
+	struct ti_pwmss_priv *priv = dev_get_priv(dev->parent);
+	int err;
+
+	if (++priv->child_count > 1)
+		return 0;
+
+	err = clk_get_by_name(dev->parent, "fck", &priv->clkdm);
+	if (err) {
+		dev_err(dev->parent, "%s: failed to get clock domain\n",
+			__func__);
+		goto clkdm_get_err;
+	}
+
+	err = clk_enable(&priv->clkdm);
+	if (err) {
+		dev_err(dev->parent, "%s: failed to enable clock domain\n",
+			__func__);
+		goto clkdm_enable_err;
+	}
+
+	return 0;
+
+clkdm_enable_err:
+	clk_release_all(&priv->clkdm, 1);
+clkdm_get_err:
+	priv->child_count--;
+	return err;
+}
+
+U_BOOT_DRIVER(ti_pwmss) = {
+	.name = "ti_pwmss",
+	.id = UCLASS_SIMPLE_BUS,
+	.of_match = ti_pwmss_ids,
+	.bind = dm_scan_fdt_dev,
+	.child_pre_probe = ti_pwmss_child_pre_probe,
+	.child_post_remove = ti_pwmss_child_post_remove,
+	.priv_auto_alloc_size = sizeof(struct ti_pwmss_priv),
+};
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 21/31] video: backlight: fix pwm's duty cycle calculation
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (19 preceding siblings ...)
  2020-08-25  9:21 ` [PATCH 20/31] pwm: ti: am33xx: add subsystem driver Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  2020-08-29 21:20   ` Simon Glass
  2020-08-25  9:21 ` [PATCH 22/31] video: backlight: fix pwm data structure description Dario Binacchi
                   ` (4 subsequent siblings)
  25 siblings, 1 reply; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

For levels equal to the maximum value, the duty cycle must be equal to
the period.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 drivers/video/pwm_backlight.c |  2 +-
 test/dm/panel.c               | 12 ++++++------
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/video/pwm_backlight.c b/drivers/video/pwm_backlight.c
index 468a5703bd..199ccc030f 100644
--- a/drivers/video/pwm_backlight.c
+++ b/drivers/video/pwm_backlight.c
@@ -63,7 +63,7 @@ static int set_pwm(struct pwm_backlight_priv *priv)
 	int ret;
 
 	duty_cycle = priv->period_ns * (priv->cur_level - priv->min_level) /
-		(priv->max_level - priv->min_level + 1);
+		(priv->max_level - priv->min_level);
 	ret = pwm_set_config(priv->pwm, priv->channel, priv->period_ns,
 			     duty_cycle);
 	if (ret)
diff --git a/test/dm/panel.c b/test/dm/panel.c
index a840fb4951..49f5ac7169 100644
--- a/test/dm/panel.c
+++ b/test/dm/panel.c
@@ -40,7 +40,7 @@ static int dm_test_panel(struct unit_test_state *uts)
 	ut_assertok(sandbox_pwm_get_config(pwm, 0, &period_ns, &duty_ns,
 					   &enable, &polarity));
 	ut_asserteq(1000, period_ns);
-	ut_asserteq(170 * 1000 / 256, duty_ns);
+	ut_asserteq(170 * 1000 / 255, duty_ns);
 	ut_asserteq(true, enable);
 	ut_asserteq(false, polarity);
 	ut_asserteq(1, sandbox_gpio_get_value(gpio, 1));
@@ -49,29 +49,29 @@ static int dm_test_panel(struct unit_test_state *uts)
 	ut_assertok(panel_set_backlight(dev, 40));
 	ut_assertok(sandbox_pwm_get_config(pwm, 0, &period_ns, &duty_ns,
 					   &enable, &polarity));
-	ut_asserteq(64 * 1000 / 256, duty_ns);
+	ut_asserteq(64 * 1000 / 255, duty_ns);
 
 	ut_assertok(panel_set_backlight(dev, BACKLIGHT_MAX));
 	ut_assertok(sandbox_pwm_get_config(pwm, 0, &period_ns, &duty_ns,
 					   &enable, &polarity));
-	ut_asserteq(255 * 1000 / 256, duty_ns);
+	ut_asserteq(255 * 1000 / 255, duty_ns);
 
 	ut_assertok(panel_set_backlight(dev, BACKLIGHT_MIN));
 	ut_assertok(sandbox_pwm_get_config(pwm, 0, &period_ns, &duty_ns,
 					   &enable, &polarity));
-	ut_asserteq(0 * 1000 / 256, duty_ns);
+	ut_asserteq(0 * 1000 / 255, duty_ns);
 	ut_asserteq(1, sandbox_gpio_get_value(gpio, 1));
 
 	ut_assertok(panel_set_backlight(dev, BACKLIGHT_DEFAULT));
 	ut_assertok(sandbox_pwm_get_config(pwm, 0, &period_ns, &duty_ns,
 					   &enable, &polarity));
 	ut_asserteq(true, enable);
-	ut_asserteq(170 * 1000 / 256, duty_ns);
+	ut_asserteq(170 * 1000 / 255, duty_ns);
 
 	ut_assertok(panel_set_backlight(dev, BACKLIGHT_OFF));
 	ut_assertok(sandbox_pwm_get_config(pwm, 0, &period_ns, &duty_ns,
 					   &enable, &polarity));
-	ut_asserteq(0 * 1000 / 256, duty_ns);
+	ut_asserteq(0 * 1000 / 255, duty_ns);
 	ut_asserteq(0, sandbox_gpio_get_value(gpio, 1));
 	ut_asserteq(false, regulator_get_enable(reg));
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 22/31] video: backlight: fix pwm data structure description
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (20 preceding siblings ...)
  2020-08-25  9:21 ` [PATCH 21/31] video: backlight: fix pwm's duty cycle calculation Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  2020-08-25  9:21 ` [PATCH 23/31] dm: core: improve uclass_get_device_by_phandle_id() description Dario Binacchi
                   ` (3 subsequent siblings)
  25 siblings, 0 replies; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

The description of the 'max_level' field was incorrectly assigned to the
'min_level' field.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 drivers/video/pwm_backlight.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/video/pwm_backlight.c b/drivers/video/pwm_backlight.c
index 199ccc030f..9519180ceb 100644
--- a/drivers/video/pwm_backlight.c
+++ b/drivers/video/pwm_backlight.c
@@ -33,7 +33,7 @@
  * @cur_level: Current level for the backlight (index or value)
  * @default_level: Default level for the backlight (index or value)
  * @min_level: Minimum level of the backlight (full off)
- * @min_level: Maximum level of the backlight (full on)
+ * @max_level: Maximum level of the backlight (full on)
  * @enabled: true if backlight is enabled
  */
 struct pwm_backlight_priv {
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 23/31] dm: core: improve uclass_get_device_by_phandle_id() description
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (21 preceding siblings ...)
  2020-08-25  9:21 ` [PATCH 22/31] video: backlight: fix pwm data structure description Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  2020-08-29 21:20   ` Simon Glass
  2020-08-25  9:21 ` [PATCH 24/31] gpio: fix gpio_request_by_name() description Dario Binacchi
                   ` (2 subsequent siblings)
  25 siblings, 1 reply; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

Complete the devp parameter description.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 include/dm/uclass.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index 67ff7466c8..7188304304 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -224,7 +224,8 @@ int uclass_get_device_by_ofnode(enum uclass_id id, ofnode node,
  *
  * @id: uclass ID to look up
  * @phandle_id: the phandle id to look up
- * @devp: Returns pointer to device (there is only one for each node)
+ * @devp: Returns pointer to device (there is only one for each node). NULL if
+ *	there is no such device.
  * @return 0 if OK, -ENODEV if there is no device match the phandle, other
  *	-ve on error
  */
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 24/31] gpio: fix gpio_request_by_name() description
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (22 preceding siblings ...)
  2020-08-25  9:21 ` [PATCH 23/31] dm: core: improve uclass_get_device_by_phandle_id() description Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  2020-08-29 21:20   ` Simon Glass
  2020-08-25  9:21 ` [PATCH 25/31] dm: core: add a function to decode display timings Dario Binacchi
  2020-08-25  9:21 ` [PATCH 26/31] video: omap: add panel driver Dario Binacchi
  25 siblings, 1 reply; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

Replace 'dev->dev' with '@desc->dev' in the gpio_request_by_name function
desc parameter description.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 include/asm-generic/gpio.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index a57dd2665c..f469564f83 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -496,7 +496,7 @@ int gpio_claim_vector(const int *gpio_num_array, const char *fmt);
  * @list_name:	Name of GPIO list (e.g. "board-id-gpios")
  * @index:	Index number of the GPIO in that list use request (0=first)
  * @desc:	Returns GPIO description information. If there is no such
- *		GPIO, dev->dev will be NULL.
+ *		GPIO, @desc->dev will be NULL.
  * @flags:	Indicates the GPIO input/output settings (GPIOD_...)
  * @return 0 if OK, -ENOENT if the GPIO does not exist, -EINVAL if there is
  * something wrong with the list, or other -ve for another error (e.g.
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 25/31] dm: core: add a function to decode display timings
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (23 preceding siblings ...)
  2020-08-25  9:21 ` [PATCH 24/31] gpio: fix gpio_request_by_name() description Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  2020-08-29 21:20   ` Simon Glass
  2020-08-25  9:21 ` [PATCH 26/31] video: omap: add panel driver Dario Binacchi
  25 siblings, 1 reply; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

The patch adds a function to get display timings from the device tree
node attached to the device.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 arch/sandbox/dts/test.dts | 46 ++++++++++++++++++++++
 drivers/core/read.c       |  6 +++
 include/dm/read.h         | 24 ++++++++++++
 test/dm/test-fdt.c        | 80 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 156 insertions(+)

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 7f5d8f3aeb..dcf1a94b82 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -129,6 +129,52 @@
 		str-value = "test string";
 		interrupts-extended = <&irq 3 0>;
 		acpi,name = "GHIJ";
+		display-timings {
+			timing0: 240x320 {
+				clock-frequency = <6500000>;
+				hactive = <240>;
+				vactive = <320>;
+				hfront-porch = <6>;
+				hback-porch = <7>;
+				hsync-len = <1>;
+				vback-porch = <5>;
+				vfront-porch = <8>;
+				vsync-len = <2>;
+				hsync-active = <1>;
+				vsync-active = <0>;
+				de-active = <1>;
+				pixelclk-active = <1>;
+				interlaced;
+				doublescan;
+				doubleclk;
+			};
+			timing1: 480x800 {
+				clock-frequency = <9000000>;
+				hactive = <480>;
+				vactive = <800>;
+				hfront-porch = <10>;
+				hback-porch = <59>;
+				hsync-len = <12>;
+				vback-porch = <15>;
+				vfront-porch = <17>;
+				vsync-len = <16>;
+				hsync-active = <0>;
+				vsync-active = <1>;
+				de-active = <0>;
+				pixelclk-active = <0>;
+			};
+			timing2: 800x480 {
+				clock-frequency = <33500000>;
+				hactive = <800>;
+				vactive = <480>;
+				hback-porch = <89>;
+				hfront-porch = <164>;
+				vback-porch = <23>;
+				vfront-porch = <10>;
+				hsync-len = <11>;
+				vsync-len = <13>;
+			};
+		};
 	};
 
 	junk {
diff --git a/drivers/core/read.c b/drivers/core/read.c
index 8bb456bc3f..27715942d0 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -359,3 +359,9 @@ int dev_get_child_count(const struct udevice *dev)
 {
 	return ofnode_get_child_count(dev_ofnode(dev));
 }
+
+int dev_decode_display_timing(const struct udevice *dev, int index,
+			      struct display_timing *config)
+{
+	return ofnode_decode_display_timing(dev_ofnode(dev), index, config);
+}
diff --git a/include/dm/read.h b/include/dm/read.h
index 0a7aacd2d0..7c15d51cf2 100644
--- a/include/dm/read.h
+++ b/include/dm/read.h
@@ -680,6 +680,23 @@ int dev_read_alias_highest_id(const char *stem);
  */
 int dev_get_child_count(const struct udevice *dev);
 
+/**
+ * dev_decode_display_timing() - decode display timings
+ *
+ * Decode display timings from the supplied 'display-timings' node.
+ * See doc/device-tree-bindings/video/display-timing.txt for binding
+ * information.
+ *
+ * @dev: device to read DT display timings from. The node linked to the device
+ *       contains a child node called 'display-timings' which in turn contains
+ *       one or more display timing nodes.
+ * @index: index number to read (0=first timing subnode)
+ * @config: place to put timings
+ * @return 0 if OK, -FDT_ERR_NOTFOUND if not found
+ */
+int dev_decode_display_timing(const struct udevice *dev, int index,
+			      struct display_timing *config);
+
 #else /* CONFIG_DM_DEV_READ_INLINE is enabled */
 
 static inline int dev_read_u32(const struct udevice *dev,
@@ -1002,6 +1019,13 @@ static inline int dev_get_child_count(const struct udevice *dev)
 	return ofnode_get_child_count(dev_ofnode(dev));
 }
 
+static inline int dev_decode_display_timing(const struct udevice *dev,
+					    int index,
+					    struct display_timing *config)
+{
+	return ofnode_decode_display_timing(dev_ofnode(dev), index, config);
+}
+
 #endif /* CONFIG_DM_DEV_READ_INLINE */
 
 /**
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index 30a7a933dd..c4bb01eeba 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -1120,3 +1120,83 @@ static int dm_test_ofdata_order(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_ofdata_order, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+/* Test dev_decode_display_timing() */
+static int dm_test_decode_display_timing(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	struct display_timing timing;
+
+	ut_assertok(uclass_first_device_err(UCLASS_TEST_FDT, &dev));
+	ut_asserteq_str("a-test", dev->name);
+
+	ut_assertok(dev_decode_display_timing(dev, 0, &timing));
+	ut_assert(timing.hactive.typ == 240);
+	ut_assert(timing.hback_porch.typ == 7);
+	ut_assert(timing.hfront_porch.typ == 6);
+	ut_assert(timing.hsync_len.typ == 1);
+	ut_assert(timing.vactive.typ == 320);
+	ut_assert(timing.vback_porch.typ == 5);
+	ut_assert(timing.vfront_porch.typ == 8);
+	ut_assert(timing.vsync_len.typ == 2);
+	ut_assert(timing.pixelclock.typ == 6500000);
+	ut_assert(timing.flags & DISPLAY_FLAGS_HSYNC_HIGH);
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_HSYNC_LOW));
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_VSYNC_HIGH));
+	ut_assert(timing.flags & DISPLAY_FLAGS_VSYNC_LOW);
+	ut_assert(timing.flags & DISPLAY_FLAGS_DE_HIGH);
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_DE_LOW));
+	ut_assert(timing.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE);
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE));
+	ut_assert(timing.flags & DISPLAY_FLAGS_INTERLACED);
+	ut_assert(timing.flags & DISPLAY_FLAGS_DOUBLESCAN);
+	ut_assert(timing.flags & DISPLAY_FLAGS_DOUBLECLK);
+
+	ut_assertok(dev_decode_display_timing(dev, 1, &timing));
+	ut_assert(timing.hactive.typ == 480);
+	ut_assert(timing.hback_porch.typ == 59);
+	ut_assert(timing.hfront_porch.typ == 10);
+	ut_assert(timing.hsync_len.typ == 12);
+	ut_assert(timing.vactive.typ == 800);
+	ut_assert(timing.vback_porch.typ == 15);
+	ut_assert(timing.vfront_porch.typ == 17);
+	ut_assert(timing.vsync_len.typ == 16);
+	ut_assert(timing.pixelclock.typ == 9000000);
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_HSYNC_HIGH));
+	ut_assert(timing.flags & DISPLAY_FLAGS_HSYNC_LOW);
+	ut_assert(timing.flags & DISPLAY_FLAGS_VSYNC_HIGH);
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_VSYNC_LOW));
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_DE_HIGH));
+	ut_assert(timing.flags & DISPLAY_FLAGS_DE_LOW);
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE));
+	ut_assert(timing.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE);
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_INTERLACED));
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_DOUBLESCAN));
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_DOUBLECLK));
+
+	ut_assertok(dev_decode_display_timing(dev, 2, &timing));
+	ut_assert(timing.hactive.typ == 800);
+	ut_assert(timing.hback_porch.typ == 89);
+	ut_assert(timing.hfront_porch.typ == 164);
+	ut_assert(timing.hsync_len.typ == 11);
+	ut_assert(timing.vactive.typ == 480);
+	ut_assert(timing.vback_porch.typ == 23);
+	ut_assert(timing.vfront_porch.typ == 10);
+	ut_assert(timing.vsync_len.typ == 13);
+	ut_assert(timing.pixelclock.typ == 33500000);
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_HSYNC_HIGH));
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_HSYNC_LOW));
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_VSYNC_HIGH));
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_VSYNC_LOW));
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_DE_HIGH));
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_DE_LOW));
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE));
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE));
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_INTERLACED));
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_DOUBLESCAN));
+	ut_assert(!(timing.flags & DISPLAY_FLAGS_DOUBLECLK));
+
+	ut_assert(dev_decode_display_timing(dev, 3, &timing));
+	return 0;
+}
+DM_TEST(dm_test_decode_display_timing, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 26/31] video: omap: add panel driver
  2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
                   ` (24 preceding siblings ...)
  2020-08-25  9:21 ` [PATCH 25/31] dm: core: add a function to decode display timings Dario Binacchi
@ 2020-08-25  9:21 ` Dario Binacchi
  25 siblings, 0 replies; 43+ messages in thread
From: Dario Binacchi @ 2020-08-25  9:21 UTC (permalink / raw)
  To: u-boot

The previous version of am335x-fb.c contained the functionalities of two
drivers that this patch has split. It was a video type driver that used
the same registration compatible string that now registers a panel type
driver. The proof of this is that two compatible strings were referred
to within the same driver.
There are now two drivers, each with its own compatible string,
functions and API.
Furthermore, the panel driver, in addition to decoding the display
timings, is now also able to manage the backlight.

Signed-off-by: Dario Binacchi <dariobin@libero.it>
---

 arch/arm/dts/am335x-brppt1-mmc.dts       |   3 +-
 arch/arm/dts/am335x-brppt1-nand.dts      |   3 +-
 arch/arm/dts/am335x-brppt1-spi.dts       |   3 +-
 arch/arm/dts/am335x-brsmarc1.dts         |   2 +-
 arch/arm/dts/am335x-brxre1.dts           |   3 +-
 arch/arm/dts/am335x-evm-u-boot.dtsi      |   7 +-
 arch/arm/dts/am335x-evmsk-u-boot.dtsi    |   6 +-
 arch/arm/dts/am335x-guardian-u-boot.dtsi |   8 +-
 arch/arm/dts/am335x-pdu001-u-boot.dtsi   |   8 +-
 arch/arm/dts/am335x-pxm50-u-boot.dtsi    |   6 +-
 arch/arm/dts/am335x-rut-u-boot.dtsi      |   6 +-
 arch/arm/dts/da850-evm-u-boot.dtsi       |   8 +-
 drivers/video/Makefile                   |   1 +
 drivers/video/am335x-fb.c                | 255 ++++++++++-------------
 drivers/video/am335x-fb.h                |  31 +++
 drivers/video/tilcdc-panel.c             | 171 +++++++++++++++
 drivers/video/tilcdc-panel.h             |  14 ++
 17 files changed, 347 insertions(+), 188 deletions(-)
 create mode 100644 drivers/video/tilcdc-panel.c
 create mode 100644 drivers/video/tilcdc-panel.h

diff --git a/arch/arm/dts/am335x-brppt1-mmc.dts b/arch/arm/dts/am335x-brppt1-mmc.dts
index 6f919711f0..9de48bcdde 100644
--- a/arch/arm/dts/am335x-brppt1-mmc.dts
+++ b/arch/arm/dts/am335x-brppt1-mmc.dts
@@ -53,8 +53,6 @@
 		bkl-pwm = <&pwmbacklight>;
 		bkl-tps = <&tps_bl>;
 
-		u-boot,dm-pre-reloc;
-
 		panel-info {
 			ac-bias		= <255>;
 			ac-bias-intrpt	= <0>;
@@ -239,6 +237,7 @@
 };
 
 &lcdc {
+	u-boot,dm-pre-reloc;
 	status = "disabled";
 };
 
diff --git a/arch/arm/dts/am335x-brppt1-nand.dts b/arch/arm/dts/am335x-brppt1-nand.dts
index 9d4340f591..c09651cf13 100644
--- a/arch/arm/dts/am335x-brppt1-nand.dts
+++ b/arch/arm/dts/am335x-brppt1-nand.dts
@@ -53,8 +53,6 @@
 		bkl-pwm = <&pwmbacklight>;
 		bkl-tps = <&tps_bl>;
 
-		u-boot,dm-pre-reloc;
-
 		panel-info {
 			ac-bias		= <255>;
 			ac-bias-intrpt	= <0>;
@@ -229,6 +227,7 @@
 };
 
 &lcdc {
+	u-boot,dm-pre-reloc;
 	status = "disabled";
 };
 
diff --git a/arch/arm/dts/am335x-brppt1-spi.dts b/arch/arm/dts/am335x-brppt1-spi.dts
index c078af8fba..6c86d56906 100644
--- a/arch/arm/dts/am335x-brppt1-spi.dts
+++ b/arch/arm/dts/am335x-brppt1-spi.dts
@@ -54,8 +54,6 @@
 		bkl-pwm = <&pwmbacklight>;
 		bkl-tps = <&tps_bl>;
 
-		u-boot,dm-pre-reloc;
-
 		panel-info {
 			ac-bias		= <255>;
 			ac-bias-intrpt	= <0>;
@@ -260,6 +258,7 @@
 };
 
 &lcdc {
+	u-boot,dm-pre-reloc;
 	status = "disabled";
 };
 
diff --git a/arch/arm/dts/am335x-brsmarc1.dts b/arch/arm/dts/am335x-brsmarc1.dts
index 7e9516e8f8..309adbc1ab 100644
--- a/arch/arm/dts/am335x-brsmarc1.dts
+++ b/arch/arm/dts/am335x-brsmarc1.dts
@@ -59,7 +59,6 @@
 		/*backlight = <&tps_bl>; */
 		compatible = "ti,tilcdc,panel";
 		status = "okay";
-		u-boot,dm-pre-reloc;
 
 		panel-info {
 			ac-bias		= <255>;
@@ -299,6 +298,7 @@
 };
 
 &lcdc {
+	u-boot,dm-pre-reloc;
 	status = "okay";
 	ti,no-reset-on-init;
 	ti,no-idle-on-init;
diff --git a/arch/arm/dts/am335x-brxre1.dts b/arch/arm/dts/am335x-brxre1.dts
index 6091a12fb7..89e84c8e1a 100644
--- a/arch/arm/dts/am335x-brxre1.dts
+++ b/arch/arm/dts/am335x-brxre1.dts
@@ -79,8 +79,6 @@
 
 		backlight = <&tps_bl>;
 
-		u-boot,dm-pre-reloc;
-
 		panel-info {
 			ac-bias		= <255>;
 			ac-bias-intrpt	= <0>;
@@ -255,6 +253,7 @@
 };
 
 &lcdc {
+	u-boot,dm-pre-reloc;
 	status = "okay";
 	ti,no-reset-on-init;
 	ti,no-idle-on-init;
diff --git a/arch/arm/dts/am335x-evm-u-boot.dtsi b/arch/arm/dts/am335x-evm-u-boot.dtsi
index d7b049ef20..4a61cbbd49 100644
--- a/arch/arm/dts/am335x-evm-u-boot.dtsi
+++ b/arch/arm/dts/am335x-evm-u-boot.dtsi
@@ -3,13 +3,10 @@
  * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
  */
 
-/ {
-	panel {
-		u-boot,dm-pre-reloc;
-	};
+&lcdc {
+	u-boot,dm-pre-reloc;
 };
 
-
 &mmc3 {
 	status = "disabled";
 };
diff --git a/arch/arm/dts/am335x-evmsk-u-boot.dtsi b/arch/arm/dts/am335x-evmsk-u-boot.dtsi
index 599fb377e6..b15ba0dcae 100644
--- a/arch/arm/dts/am335x-evmsk-u-boot.dtsi
+++ b/arch/arm/dts/am335x-evmsk-u-boot.dtsi
@@ -5,8 +5,6 @@
  * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
  */
 
-/ {
-	panel {
-		u-boot,dm-pre-reloc;
-	};
+&lcdc {
+	u-boot,dm-pre-reloc;
 };
diff --git a/arch/arm/dts/am335x-guardian-u-boot.dtsi b/arch/arm/dts/am335x-guardian-u-boot.dtsi
index 705ef335bf..15578b945e 100644
--- a/arch/arm/dts/am335x-guardian-u-boot.dtsi
+++ b/arch/arm/dts/am335x-guardian-u-boot.dtsi
@@ -8,16 +8,16 @@
 	ocp {
 		u-boot,dm-pre-reloc;
 	};
-
-	panel {
-		u-boot,dm-pre-reloc;
-	};
 };
 
 &l4_wkup {
 	u-boot,dm-pre-reloc;
 };
 
+&lcdc {
+	u-boot,dm-pre-reloc;
+};
+
 &mmc1 {
 	u-boot,dm-pre-reloc;
 };
diff --git a/arch/arm/dts/am335x-pdu001-u-boot.dtsi b/arch/arm/dts/am335x-pdu001-u-boot.dtsi
index a799fe9bc3..39e1a6129c 100644
--- a/arch/arm/dts/am335x-pdu001-u-boot.dtsi
+++ b/arch/arm/dts/am335x-pdu001-u-boot.dtsi
@@ -7,16 +7,16 @@
 	ocp {
 		u-boot,dm-pre-reloc;
 	};
-
-	panel {
-		u-boot,dm-pre-reloc;
-	};
 };
 
 &l4_wkup {
 	u-boot,dm-pre-reloc;
 };
 
+&lcdc {
+	u-boot,dm-pre-reloc;
+};
+
 &scm {
 	u-boot,dm-pre-reloc;
 };
diff --git a/arch/arm/dts/am335x-pxm50-u-boot.dtsi b/arch/arm/dts/am335x-pxm50-u-boot.dtsi
index 77dfe6e262..b13d271e8b 100644
--- a/arch/arm/dts/am335x-pxm50-u-boot.dtsi
+++ b/arch/arm/dts/am335x-pxm50-u-boot.dtsi
@@ -5,8 +5,6 @@
  * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
  */
 
-/ {
-	panel {
-		u-boot,dm-pre-reloc;
-	};
+&lcdc {
+	u-boot,dm-pre-reloc;
 };
diff --git a/arch/arm/dts/am335x-rut-u-boot.dtsi b/arch/arm/dts/am335x-rut-u-boot.dtsi
index b2b4aa596a..4fc8c9bc2b 100644
--- a/arch/arm/dts/am335x-rut-u-boot.dtsi
+++ b/arch/arm/dts/am335x-rut-u-boot.dtsi
@@ -5,8 +5,6 @@
  * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
  */
 
-/ {
-	panel {
-		u-boot,dm-pre-reloc;
-	};
+&lcdc {
+	u-boot,dm-pre-reloc;
 };
diff --git a/arch/arm/dts/da850-evm-u-boot.dtsi b/arch/arm/dts/da850-evm-u-boot.dtsi
index d588628641..b55dcbbe52 100644
--- a/arch/arm/dts/da850-evm-u-boot.dtsi
+++ b/arch/arm/dts/da850-evm-u-boot.dtsi
@@ -14,10 +14,6 @@
 	nand {
 		compatible = "ti,davinci-nand";
 	};
-
-	panel {
-		u-boot,dm-pre-reloc;
-	};
 };
 
 &eth0 {
@@ -28,6 +24,10 @@
 	compatible = "m25p64", "jedec,spi-nor";
 };
 
+&lcdc {
+	u-boot,dm-pre-reloc;
+};
+
 &mmc0 {
 	u-boot,dm-spl;
 };
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 67a492a2d6..132a63ecea 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_DM_VIDEO) += video-uclass.o vidconsole-uclass.o
 obj-$(CONFIG_DM_VIDEO) += video_bmp.o
 obj-$(CONFIG_PANEL) += panel-uclass.o
 obj-$(CONFIG_SIMPLE_PANEL) += simple_panel.o
+obj-$(CONFIG_AM335X_LCD) += tilcdc-panel.o
 endif
 
 obj-${CONFIG_EXYNOS_FB} += exynos/
diff --git a/drivers/video/am335x-fb.c b/drivers/video/am335x-fb.c
index 2707ff59c7..dc959baa27 100644
--- a/drivers/video/am335x-fb.c
+++ b/drivers/video/am335x-fb.c
@@ -15,6 +15,7 @@
 #include <dm.h>
 #include <lcd.h>
 #include <log.h>
+#include <panel.h>
 #include <video.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/hardware.h>
@@ -25,6 +26,7 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 #include "am335x-fb.h"
+#include "tilcdc-panel.h"
 
 #define LCDC_FMAX				200000000
 
@@ -323,7 +325,7 @@ int am335xfb_init(struct am335x_lcdpanel *panel)
 
 #else /* CONFIG_DM_VIDEO */
 
-#define FBSIZE(t, p)	(((t)->hactive.typ * (t)->vactive.typ * (p)->bpp) >> 3)
+#define FBSIZE(t, p)	(((t).hactive.typ * (t).vactive.typ * (p).bpp) >> 3)
 
 enum {
 	LCD_MAX_WIDTH		= 2048,
@@ -331,39 +333,8 @@ enum {
 	LCD_MAX_LOG2_BPP	= VIDEO_BPP32,
 };
 
-/**
- * tilcdc_panel_info: Panel parameters
- *
- * @ac_bias: AC Bias Pin Frequency
- * @ac_bias_intrpt: AC Bias Pin Transitions per Interrupt
- * @dma_burst_sz: DMA burst size
- * @bpp: Bits per pixel
- * @fdd: FIFO DMA Request Delay
- * @tft_alt_mode: TFT Alternative Signal Mapping (Only for active)
- * @invert_pxl_clk: Invert pixel clock
- * @sync_edge: Horizontal and Vertical Sync Edge: 0=rising 1=falling
- * @sync_ctrl: Horizontal and Vertical Sync: Control: 0=ignore
- * @raster_order: Raster Data Order Select: 1=Most-to-least 0=Least-to-most
- * @fifo_th: DMA FIFO threshold
- */
-struct tilcdc_panel_info {
-	u32 ac_bias;
-	u32 ac_bias_intrpt;
-	u32 dma_burst_sz;
-	u32 bpp;
-	u32 fdd;
-	bool tft_alt_mode;
-	bool invert_pxl_clk;
-	u32 sync_edge;
-	u32 sync_ctrl;
-	u32 raster_order;
-	u32 fifo_th;
-};
-
 struct am335x_fb_priv {
 	struct am335x_lcdhw *regs;
-	struct tilcdc_panel_info panel;
-	struct display_timing timing;
 };
 
 static int am335x_fb_remove(struct udevice *dev)
@@ -381,16 +352,71 @@ static int am335x_fb_probe(struct udevice *dev)
 	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
 	struct am335x_fb_priv *priv = dev_get_priv(dev);
 	struct am335x_lcdhw *regs = priv->regs;
-	struct tilcdc_panel_info *panel = &priv->panel;
-	struct display_timing *timing = &priv->timing;
+	struct udevice *panel;
+	struct tilcdc_panel_info info;
+	struct display_timing timing;
 	struct cm_dpll *const cmdpll = (struct cm_dpll *)CM_DPLL;
 	u32 reg;
+	int err;
 
 	/* Before relocation we don't need to do anything */
 	if (!(gd->flags & GD_FLG_RELOC))
 		return 0;
 
-	am335x_fb_set_pixel_clk_rate(regs, timing->pixelclock.typ);
+	err = uclass_get_device(UCLASS_PANEL, 0, &panel);
+	if (err) {
+		dev_err(dev, "failed to get panel\n");
+		return err;
+	}
+
+	err = panel_get_display_timing(panel, &timing);
+	if (err) {
+		dev_err(dev, "failed to get display timing\n");
+		return err;
+	}
+
+	if (timing.pixelclock.typ > (LCDC_FMAX / 2)) {
+		dev_err(dev, "invalid display clock-frequency: %d Hz\n",
+			timing.pixelclock.typ);
+		return -EINVAL;
+	}
+
+	if (timing.hactive.typ > LCD_MAX_WIDTH)
+		timing.hactive.typ = LCD_MAX_WIDTH;
+
+	if (timing.vactive.typ > LCD_MAX_HEIGHT)
+		timing.vactive.typ = LCD_MAX_HEIGHT;
+
+	err = tilcdc_panel_get_display_info(panel, &info);
+	if (err) {
+		dev_err(dev, "failed to get panel info\n");
+		return err;
+	}
+
+	switch (info.bpp) {
+	case 16:
+	case 24:
+	case 32:
+		break;
+	default:
+		dev_err(dev, "invalid seting, bpp: %d\n", info.bpp);
+		return -EINVAL;
+	}
+
+	switch (info.dma_burst_sz) {
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+	case 16:
+		break;
+	default:
+		dev_err(dev, "invalid setting, dma-burst-sz: %d\n",
+			info.dma_burst_sz);
+		return -EINVAL;
+	}
+
+	am335x_fb_set_pixel_clk_rate(regs, timing.pixelclock.typ);
 
 	/* clock source for LCDC from dispPLL M2 */
 	writel(0, &cmdpll->clklcdcpixelclk);
@@ -411,14 +437,14 @@ static int am335x_fb_probe(struct udevice *dev)
 	writel(reg, &regs->ctrl);
 
 	writel(uc_plat->base, &regs->lcddma_fb0_base);
-	writel(uc_plat->base + FBSIZE(timing, panel),
+	writel(uc_plat->base + FBSIZE(timing, info),
 	       &regs->lcddma_fb0_ceiling);
 	writel(uc_plat->base, &regs->lcddma_fb1_base);
-	writel(uc_plat->base + FBSIZE(timing, panel),
+	writel(uc_plat->base + FBSIZE(timing, info),
 	       &regs->lcddma_fb1_ceiling);
 
-	reg = LCDC_DMA_CTRL_FIFO_TH(panel->fifo_th);
-	switch (panel->dma_burst_sz) {
+	reg = LCDC_DMA_CTRL_FIFO_TH(info.fifo_th);
+	switch (info.dma_burst_sz) {
 	case 1:
 		reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_1);
 		break;
@@ -438,155 +464,84 @@ static int am335x_fb_probe(struct udevice *dev)
 
 	writel(reg, &regs->lcddma_ctrl);
 
-	writel(LCDC_RASTER_TIMING_0_HORLSB(timing->hactive.typ) |
-	       LCDC_RASTER_TIMING_0_HORMSB(timing->hactive.typ) |
-	       LCDC_RASTER_TIMING_0_HFPLSB(timing->hfront_porch.typ) |
-	       LCDC_RASTER_TIMING_0_HBPLSB(timing->hback_porch.typ) |
-	       LCDC_RASTER_TIMING_0_HSWLSB(timing->hsync_len.typ),
+	writel(LCDC_RASTER_TIMING_0_HORLSB(timing.hactive.typ) |
+	       LCDC_RASTER_TIMING_0_HORMSB(timing.hactive.typ) |
+	       LCDC_RASTER_TIMING_0_HFPLSB(timing.hfront_porch.typ) |
+	       LCDC_RASTER_TIMING_0_HBPLSB(timing.hback_porch.typ) |
+	       LCDC_RASTER_TIMING_0_HSWLSB(timing.hsync_len.typ),
 	       &regs->raster_timing0);
 
-	writel(LCDC_RASTER_TIMING_1_VBP(timing->vback_porch.typ) |
-	       LCDC_RASTER_TIMING_1_VFP(timing->vfront_porch.typ) |
-	       LCDC_RASTER_TIMING_1_VSW(timing->vsync_len.typ) |
-	       LCDC_RASTER_TIMING_1_VERLSB(timing->vactive.typ),
+	writel(LCDC_RASTER_TIMING_1_VBP(timing.vback_porch.typ) |
+	       LCDC_RASTER_TIMING_1_VFP(timing.vfront_porch.typ) |
+	       LCDC_RASTER_TIMING_1_VSW(timing.vsync_len.typ) |
+	       LCDC_RASTER_TIMING_1_VERLSB(timing.vactive.typ),
 	       &regs->raster_timing1);
 
-	reg = LCDC_RASTER_TIMING_2_ACB(panel->ac_bias) |
-		LCDC_RASTER_TIMING_2_ACBI(panel->ac_bias_intrpt) |
-		LCDC_RASTER_TIMING_2_HSWMSB(timing->hsync_len.typ) |
-		LCDC_RASTER_TIMING_2_VERMSB(timing->vactive.typ) |
-		LCDC_RASTER_TIMING_2_HBPMSB(timing->hback_porch.typ) |
-		LCDC_RASTER_TIMING_2_HFPMSB(timing->hfront_porch.typ);
+	reg = LCDC_RASTER_TIMING_2_ACB(info.ac_bias) |
+		LCDC_RASTER_TIMING_2_ACBI(info.ac_bias_intrpt) |
+		LCDC_RASTER_TIMING_2_HSWMSB(timing.hsync_len.typ) |
+		LCDC_RASTER_TIMING_2_VERMSB(timing.vactive.typ) |
+		LCDC_RASTER_TIMING_2_HBPMSB(timing.hback_porch.typ) |
+		LCDC_RASTER_TIMING_2_HFPMSB(timing.hfront_porch.typ);
 
-	if (timing->flags & DISPLAY_FLAGS_VSYNC_LOW)
+	if (timing.flags & DISPLAY_FLAGS_VSYNC_LOW)
 		reg |= LCDC_RASTER_TIMING_2_VSYNC_INVERT;
 
-	if (timing->flags & DISPLAY_FLAGS_HSYNC_LOW)
+	if (timing.flags & DISPLAY_FLAGS_HSYNC_LOW)
 		reg |= LCDC_RASTER_TIMING_2_HSYNC_INVERT;
 
-	if (panel->invert_pxl_clk)
+	if (info.invert_pxl_clk)
 		reg |= LCDC_RASTER_TIMING_2_PXCLK_INVERT;
 
-	if (panel->sync_edge)
+	if (info.sync_edge)
 		reg |= LCDC_RASTER_TIMING_2_HSVS_RISEFALL;
 
-	if (panel->sync_ctrl)
+	if (info.sync_ctrl)
 		reg |= LCDC_RASTER_TIMING_2_HSVS_CONTROL;
 
 	writel(reg, &regs->raster_timing2);
 
 	reg = LCDC_RASTER_CTRL_PALMODE_RAWDATA | LCDC_RASTER_CTRL_TFT_MODE |
-		LCDC_RASTER_CTRL_ENABLE | LCDC_RASTER_CTRL_REQDLY(panel->fdd);
+		LCDC_RASTER_CTRL_ENABLE | LCDC_RASTER_CTRL_REQDLY(info.fdd);
 
-	if (panel->tft_alt_mode)
+	if (info.tft_alt_mode)
 		reg |= LCDC_RASTER_CTRL_TFT_ALT_ENABLE;
 
-	if (panel->bpp == 24)
+	if (info.bpp == 24)
 		reg |= LCDC_RASTER_CTRL_TFT_24BPP_MODE;
-	else if (panel->bpp == 32)
+	else if (info.bpp == 32)
 		reg |= LCDC_RASTER_CTRL_TFT_24BPP_MODE |
 			LCDC_RASTER_CTRL_TFT_24BPP_UNPACK;
 
-	if (panel->raster_order)
+	if (info.raster_order)
 		reg |= LCDC_RASTER_CTRL_DATA_ORDER;
 
 	writel(reg, &regs->raster_ctrl);
 
-	uc_priv->xsize = timing->hactive.typ;
-	uc_priv->ysize = timing->vactive.typ;
-	uc_priv->bpix = log_2_n_round_up(panel->bpp);
-	return 0;
-}
-
-static int am335x_fb_ofdata_to_platdata(struct udevice *dev)
-{
-	struct am335x_fb_priv *priv = dev_get_priv(dev);
-	struct tilcdc_panel_info *panel = &priv->panel;
-	struct display_timing *timing = &priv->timing;
-	ofnode node;
-	int err;
+	uc_priv->xsize = timing.hactive.typ;
+	uc_priv->ysize = timing.vactive.typ;
+	uc_priv->bpix = log_2_n_round_up(info.bpp);
 
-	node = ofnode_by_compatible(ofnode_null(), "ti,am33xx-tilcdc");
-	if (!ofnode_valid(node)) {
-		dev_err(dev, "missing 'ti,am33xx-tilcdc' node\n");
-		return -ENXIO;
-	}
-
-	priv->regs = (struct am335x_lcdhw *)ofnode_get_addr(node);
-	dev_dbg(dev, "LCD: base address=0x%x\n", (unsigned int)priv->regs);
-
-	err = ofnode_decode_display_timing(dev_ofnode(dev), 0, timing);
+	err = panel_enable_backlight(panel);
 	if (err) {
-		dev_err(dev, "failed to get display timing\n");
+		dev_err(dev, "failed to enable panel backlight\n");
 		return err;
 	}
 
-	if (timing->pixelclock.typ > (LCDC_FMAX / 2)) {
-		dev_err(dev, "invalid display clock-frequency: %d Hz\n",
-			timing->pixelclock.typ);
-		return -EINVAL;
-	}
-
-	if (timing->hactive.typ > LCD_MAX_WIDTH)
-		timing->hactive.typ = LCD_MAX_WIDTH;
-
-	if (timing->vactive.typ > LCD_MAX_HEIGHT)
-		timing->vactive.typ = LCD_MAX_HEIGHT;
-
-	node = ofnode_find_subnode(dev_ofnode(dev), "panel-info");
-	if (!ofnode_valid(node)) {
-		dev_err(dev, "missing 'panel-info' node\n");
-		return -ENXIO;
-	}
-
-	err |= ofnode_read_u32(node, "ac-bias", &panel->ac_bias);
-	err |= ofnode_read_u32(node, "ac-bias-intrpt", &panel->ac_bias_intrpt);
-	err |= ofnode_read_u32(node, "dma-burst-sz", &panel->dma_burst_sz);
-	err |= ofnode_read_u32(node, "bpp", &panel->bpp);
-	err |= ofnode_read_u32(node, "fdd", &panel->fdd);
-	err |= ofnode_read_u32(node, "sync-edge", &panel->sync_edge);
-	err |= ofnode_read_u32(node, "sync-ctrl", &panel->sync_ctrl);
-	err |= ofnode_read_u32(node, "raster-order", &panel->raster_order);
-	err |= ofnode_read_u32(node, "fifo-th", &panel->fifo_th);
-	if (err) {
-		dev_err(dev, "failed to get panel info\n");
-		return err;
-	}
+	return 0;
+}
 
-	switch (panel->bpp) {
-	case 16:
-	case 24:
-	case 32:
-		break;
-	default:
-		dev_err(dev, "invalid seting, bpp: %d\n", panel->bpp);
-		return -EINVAL;
-	}
+static int am335x_fb_ofdata_to_platdata(struct udevice *dev)
+{
+	struct am335x_fb_priv *priv = dev_get_priv(dev);
 
-	switch (panel->dma_burst_sz) {
-	case 1:
-	case 2:
-	case 4:
-	case 8:
-	case 16:
-		break;
-	default:
-		dev_err(dev, "invalid setting, dma-burst-sz: %d\n",
-			panel->dma_burst_sz);
+	priv->regs = (struct am335x_lcdhw *)dev_read_addr(dev);
+	if ((fdt_addr_t)priv->regs == FDT_ADDR_T_NONE) {
+		dev_err(dev, "failed to get base address\n");
 		return -EINVAL;
 	}
 
-	/* optional */
-	panel->tft_alt_mode = ofnode_read_bool(node, "tft-alt-mode");
-	panel->invert_pxl_clk = ofnode_read_bool(node, "invert-pxl-clk");
-
-	dev_dbg(dev, "LCD: %dx%d, bpp=%d, clk=%d Hz\n", timing->hactive.typ,
-		timing->vactive.typ, panel->bpp, timing->pixelclock.typ);
-	dev_dbg(dev, "     hbp=%d, hfp=%d, hsw=%d\n", timing->hback_porch.typ,
-		timing->hfront_porch.typ, timing->hsync_len.typ);
-	dev_dbg(dev, "     vbp=%d, vfp=%d, vsw=%d\n", timing->vback_porch.typ,
-		timing->vfront_porch.typ, timing->vsync_len.typ);
-
+	dev_dbg(dev, "LCD: base address=0x%x\n", (unsigned int)priv->regs);
 	return 0;
 }
 
@@ -602,7 +557,7 @@ static int am335x_fb_bind(struct udevice *dev)
 }
 
 static const struct udevice_id am335x_fb_ids[] = {
-	{ .compatible = "ti,tilcdc,panel" },
+	{ .compatible = "ti,am33xx-tilcdc" },
 	{ }
 };
 
diff --git a/drivers/video/am335x-fb.h b/drivers/video/am335x-fb.h
index c9f92bc389..4952dd96e9 100644
--- a/drivers/video/am335x-fb.h
+++ b/drivers/video/am335x-fb.h
@@ -70,6 +70,37 @@ struct am335x_lcdpanel {
 
 int am335xfb_init(struct am335x_lcdpanel *panel);
 
+#else /* CONFIG_DM_VIDEO */
+
+/**
+ * tilcdc_panel_info: Panel parameters
+ *
+ * @ac_bias: AC Bias Pin Frequency
+ * @ac_bias_intrpt: AC Bias Pin Transitions per Interrupt
+ * @dma_burst_sz: DMA burst size
+ * @bpp: Bits per pixel
+ * @fdd: FIFO DMA Request Delay
+ * @tft_alt_mode: TFT Alternative Signal Mapping (Only for active)
+ * @invert_pxl_clk: Invert pixel clock
+ * @sync_edge: Horizontal and Vertical Sync Edge: 0=rising 1=falling
+ * @sync_ctrl: Horizontal and Vertical Sync: Control: 0=ignore
+ * @raster_order: Raster Data Order Select: 1=Most-to-least 0=Least-to-most
+ * @fifo_th: DMA FIFO threshold
+ */
+struct tilcdc_panel_info {
+	u32 ac_bias;
+	u32 ac_bias_intrpt;
+	u32 dma_burst_sz;
+	u32 bpp;
+	u32 fdd;
+	bool tft_alt_mode;
+	bool invert_pxl_clk;
+	u32 sync_edge;
+	u32 sync_ctrl;
+	u32 raster_order;
+	u32 fifo_th;
+};
+
 #endif  /* CONFIG_DM_VIDEO */
 
 #endif  /* AM335X_FB_H */
diff --git a/drivers/video/tilcdc-panel.c b/drivers/video/tilcdc-panel.c
new file mode 100644
index 0000000000..911e9b4c73
--- /dev/null
+++ b/drivers/video/tilcdc-panel.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * OMAP panel support
+ *
+ * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+ */
+
+#include <common.h>
+#include <backlight.h>
+#include <clk.h>
+#include <display.h>
+#include <dm.h>
+#include <log.h>
+#include <panel.h>
+#include <asm/gpio.h>
+#include <linux/err.h>
+#include "am335x-fb.h"
+
+struct tilcdc_panel_priv {
+	struct tilcdc_panel_info info;
+	struct display_timing timing;
+	struct udevice *backlight;
+	struct gpio_desc enable;
+};
+
+static int tilcdc_panel_enable_backlight(struct udevice *dev)
+{
+	struct tilcdc_panel_priv *priv = dev_get_priv(dev);
+
+	if (dm_gpio_is_valid(&priv->enable))
+		dm_gpio_set_value(&priv->enable, 1);
+
+	if (priv->backlight)
+		return backlight_enable(priv->backlight);
+
+	return 0;
+}
+
+static int tilcdc_panel_set_backlight(struct udevice *dev, int percent)
+{
+	struct tilcdc_panel_priv *priv = dev_get_priv(dev);
+
+	if (dm_gpio_is_valid(&priv->enable))
+		dm_gpio_set_value(&priv->enable, 1);
+
+	if (priv->backlight)
+		return backlight_set_brightness(priv->backlight, percent);
+
+	return 0;
+}
+
+int tilcdc_panel_get_display_info(struct udevice *dev,
+				  struct tilcdc_panel_info *info)
+{
+	struct tilcdc_panel_priv *priv = dev_get_priv(dev);
+
+	memcpy(info, &priv->info, sizeof(*info));
+	return 0;
+}
+
+static int tilcdc_panel_get_display_timing(struct udevice *dev,
+					   struct display_timing *timing)
+{
+	struct tilcdc_panel_priv *priv = dev_get_priv(dev);
+
+	memcpy(timing, &priv->timing, sizeof(*timing));
+	return 0;
+}
+
+static int tilcdc_panel_remove(struct udevice *dev)
+{
+	struct tilcdc_panel_priv *priv = dev_get_priv(dev);
+
+	if (dm_gpio_is_valid(&priv->enable))
+		dm_gpio_free(dev, &priv->enable);
+
+	return 0;
+}
+
+static int tilcdc_panel_probe(struct udevice *dev)
+{
+	struct tilcdc_panel_priv *priv = dev_get_priv(dev);
+	int err;
+
+	err = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
+					   "backlight", &priv->backlight);
+	if (err)
+		dev_warn(dev, "failed to get backlight\n");
+
+	err = gpio_request_by_name(dev, "enable-gpios", 0, &priv->enable,
+				   GPIOD_IS_OUT);
+	if (err) {
+		dev_warn(dev, "failed to get enable GPIO\n");
+		if (err != -ENOENT)
+			return err;
+	}
+
+	return 0;
+}
+
+static int tilcdc_panel_ofdata_to_platdata(struct udevice *dev)
+{
+	struct tilcdc_panel_priv *priv = dev_get_priv(dev);
+	ofnode node;
+	int err;
+
+	err = ofnode_decode_display_timing(dev_ofnode(dev), 0, &priv->timing);
+	if (err) {
+		dev_err(dev, "failed to get display timing\n");
+		return err;
+	}
+
+	node = dev_read_subnode(dev, "panel-info");
+	if (!ofnode_valid(node)) {
+		dev_err(dev, "missing 'panel-info' node\n");
+		return -ENXIO;
+	}
+
+	err |= ofnode_read_u32(node, "ac-bias", &priv->info.ac_bias);
+	err |= ofnode_read_u32(node, "ac-bias-intrpt",
+			       &priv->info.ac_bias_intrpt);
+	err |= ofnode_read_u32(node, "dma-burst-sz", &priv->info.dma_burst_sz);
+	err |= ofnode_read_u32(node, "bpp", &priv->info.bpp);
+	err |= ofnode_read_u32(node, "fdd", &priv->info.fdd);
+	err |= ofnode_read_u32(node, "sync-edge", &priv->info.sync_edge);
+	err |= ofnode_read_u32(node, "sync-ctrl", &priv->info.sync_ctrl);
+	err |= ofnode_read_u32(node, "raster-order", &priv->info.raster_order);
+	err |= ofnode_read_u32(node, "fifo-th", &priv->info.fifo_th);
+	if (err) {
+		dev_err(dev, "failed to get panel info\n");
+		return err;
+	}
+
+	/* optional */
+	priv->info.tft_alt_mode = ofnode_read_bool(node, "tft-alt-mode");
+	priv->info.invert_pxl_clk = ofnode_read_bool(node, "invert-pxl-clk");
+
+	dev_dbg(dev, "LCD: %dx%d, bpp=%d, clk=%d Hz\n",
+		priv->timing.hactive.typ, priv->timing.vactive.typ,
+		priv->info.bpp, priv->timing.pixelclock.typ);
+	dev_dbg(dev, "     hbp=%d, hfp=%d, hsw=%d\n",
+		priv->timing.hback_porch.typ, priv->timing.hfront_porch.typ,
+		priv->timing.hsync_len.typ);
+	dev_dbg(dev, "     vbp=%d, vfp=%d, vsw=%d\n",
+		priv->timing.vback_porch.typ, priv->timing.vfront_porch.typ,
+		priv->timing.vsync_len.typ);
+
+	return 0;
+}
+
+static const struct panel_ops tilcdc_panel_ops = {
+	.enable_backlight = tilcdc_panel_enable_backlight,
+	.set_backlight = tilcdc_panel_set_backlight,
+	.get_display_timing = tilcdc_panel_get_display_timing,
+};
+
+static const struct udevice_id tilcdc_panel_ids[] = {
+	{.compatible = "ti,tilcdc,panel"},
+	{}
+};
+
+U_BOOT_DRIVER(tilcdc_panel) = {
+	.name = "tilcdc_panel",
+	.id = UCLASS_PANEL,
+	.of_match = tilcdc_panel_ids,
+	.ops = &tilcdc_panel_ops,
+	.ofdata_to_platdata = tilcdc_panel_ofdata_to_platdata,
+	.probe = tilcdc_panel_probe,
+	.remove = tilcdc_panel_remove,
+	.priv_auto_alloc_size = sizeof(struct tilcdc_panel_priv),
+};
diff --git a/drivers/video/tilcdc-panel.h b/drivers/video/tilcdc-panel.h
new file mode 100644
index 0000000000..6b40731304
--- /dev/null
+++ b/drivers/video/tilcdc-panel.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
+ */
+
+#ifndef _TILCDC_PANEL_H
+#define _TILCDC_PANEL_H
+
+#include "am335x-fb.h"
+
+int tilcdc_panel_get_display_info(struct udevice *dev,
+				  struct tilcdc_panel_info *info);
+
+#endif /* _TILCDC_PANEL_H */
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 01/31] clk: remove a redundant header
  2020-08-25  9:20 ` [PATCH 01/31] clk: remove a redundant header Dario Binacchi
@ 2020-08-28 23:36   ` Simon Glass
  0 siblings, 0 replies; 43+ messages in thread
From: Simon Glass @ 2020-08-28 23:36 UTC (permalink / raw)
  To: u-boot

On Tue, 25 Aug 2020 at 03:24, Dario Binacchi <dariobin@libero.it> wrote:
>
> The linux/err.h header file was included twice.
>
> Signed-off-by: Dario Binacchi <dariobin@libero.it>
> ---
>
>  include/linux/clk-provider.h | 1 -
>  1 file changed, 1 deletion(-)
>

Reviewed-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 02/31] clk: export generic routines
  2020-08-25  9:20 ` [PATCH 02/31] clk: export generic routines Dario Binacchi
@ 2020-08-28 23:36   ` Simon Glass
  0 siblings, 0 replies; 43+ messages in thread
From: Simon Glass @ 2020-08-28 23:36 UTC (permalink / raw)
  To: u-boot

Hi Dario,

On Tue, 25 Aug 2020 at 03:24, Dario Binacchi <dariobin@libero.it> wrote:
>
> Export routines that can be used by other drivers avoiding duplicating
> code.
>
> Signed-off-by: Dario Binacchi <dariobin@libero.it>
> ---
>
>  drivers/clk/clk-divider.c    | 18 +++++++++---------
>  include/linux/clk-provider.h | 10 ++++++++++
>  2 files changed, 19 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
> index 8f59d7fb72..9fd5fa8423 100644
> --- a/drivers/clk/clk-divider.c
> +++ b/drivers/clk/clk-divider.c
> @@ -28,7 +28,7 @@
>
>  #define UBOOT_DM_CLK_CCF_DIVIDER "ccf_clk_divider"
>
> -static unsigned int _get_table_div(const struct clk_div_table *table,
> +unsigned int divider_get_table_div(const struct clk_div_table *table,
>                                    unsigned int val)

I think clkdiv_ or clk_divider_ might be a good prefix for the
expected functions in this file, so it is clear it relates to clock.

>  {
>         const struct clk_div_table *clkt;
> @@ -49,7 +49,7 @@ static unsigned int _get_div(const struct clk_div_table *table,
>         if (flags & CLK_DIVIDER_MAX_AT_ZERO)
>                 return val ? val : clk_div_mask(width) + 1;
>         if (table)
> -               return _get_table_div(table, val);
> +               return divider_get_table_div(table, val);
>         return val + 1;
>  }
>
> @@ -89,7 +89,7 @@ static ulong clk_divider_recalc_rate(struct clk *clk)
>                                    divider->flags, divider->width);
>  }
>
> -static bool _is_valid_table_div(const struct clk_div_table *table,
> +bool divider_is_valid_table_div(const struct clk_div_table *table,
>                                 unsigned int div)
>  {
>         const struct clk_div_table *clkt;
> @@ -100,17 +100,17 @@ static bool _is_valid_table_div(const struct clk_div_table *table,
>         return false;
>  }
>
> -static bool _is_valid_div(const struct clk_div_table *table, unsigned int div,
> -                         unsigned long flags)
> +bool divider_is_valid_div(const struct clk_div_table *table,
> +                         unsigned int div, unsigned long flags)
>  {
>         if (flags & CLK_DIVIDER_POWER_OF_TWO)
>                 return is_power_of_2(div);
>         if (table)
> -               return _is_valid_table_div(table, div);
> +               return divider_is_valid_table_div(table, div);
>         return true;
>  }
>
> -static unsigned int _get_table_val(const struct clk_div_table *table,
> +unsigned int divider_get_table_val(const struct clk_div_table *table,
>                                    unsigned int div)
>  {
>         const struct clk_div_table *clkt;
> @@ -131,7 +131,7 @@ static unsigned int _get_val(const struct clk_div_table *table,
>         if (flags & CLK_DIVIDER_MAX_AT_ZERO)
>                 return (div == clk_div_mask(width) + 1) ? 0 : div;
>         if (table)
> -               return  _get_table_val(table, div);
> +               return  divider_get_table_val(table, div);
>         return div - 1;
>  }
>  int divider_get_val(unsigned long rate, unsigned long parent_rate,
> @@ -142,7 +142,7 @@ int divider_get_val(unsigned long rate, unsigned long parent_rate,
>
>         div = DIV_ROUND_UP_ULL((u64)parent_rate, rate);
>
> -       if (!_is_valid_div(table, div, flags))
> +       if (!divider_is_valid_div(table, div, flags))
>                 return -EINVAL;
>
>         value = _get_val(table, div, flags, width);
> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
> index a2630056de..b7cc8d89f1 100644
> --- a/include/linux/clk-provider.h
> +++ b/include/linux/clk-provider.h
> @@ -74,6 +74,7 @@ struct clk_mux {
>  #define to_clk_mux(_clk) container_of(_clk, struct clk_mux, clk)
>  extern const struct clk_ops clk_mux_ops;
>  u8 clk_mux_get_parent(struct clk *clk);
> +unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index);
>
>  struct clk_gate {
>         struct clk      clk;
> @@ -124,6 +125,15 @@ struct clk_divider {
>  #define CLK_DIVIDER_READ_ONLY          BIT(5)
>  #define CLK_DIVIDER_MAX_AT_ZERO                BIT(6)
>  extern const struct clk_ops clk_divider_ops;
> +
> +unsigned int divider_get_table_div(const struct clk_div_table *table,
> +                                  unsigned int val);
> +unsigned int divider_get_table_val(const struct clk_div_table *table,
> +                                  unsigned int div);
> +bool divider_is_valid_div(const struct clk_div_table *table,
> +                         unsigned int div, unsigned long flags);
> +bool divider_is_valid_table_div(const struct clk_div_table *table,
> +                               unsigned int div);

These need full function comments.

>  unsigned long divider_recalc_rate(struct clk *hw, unsigned long parent_rate,
>                                   unsigned int val,
>                                   const struct clk_div_table *table,
> --
> 2.17.1
>

Regards,
SImon

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 03/31] arch: sandbox: fix typo in clk.h
  2020-08-25  9:20 ` [PATCH 03/31] arch: sandbox: fix typo in clk.h Dario Binacchi
@ 2020-08-29 21:20   ` Simon Glass
  0 siblings, 0 replies; 43+ messages in thread
From: Simon Glass @ 2020-08-29 21:20 UTC (permalink / raw)
  To: u-boot

On Tue, 25 Aug 2020 at 03:24, Dario Binacchi <dariobin@libero.it> wrote:
>
> Fix the 'devivce' typo in arch/sandbox/include/asm/clk.h.
>
> Signed-off-by: Dario Binacchi <dariobin@libero.it>
> ---
>
>  arch/sandbox/include/asm/clk.h | 26 +++++++++++++-------------
>  1 file changed, 13 insertions(+), 13 deletions(-)

Reviewed-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 04/31] clk: add clk_round_rate()
  2020-08-25  9:20 ` [PATCH 04/31] clk: add clk_round_rate() Dario Binacchi
@ 2020-08-29 21:20   ` Simon Glass
  2020-08-29 21:48     ` Sean Anderson
  0 siblings, 1 reply; 43+ messages in thread
From: Simon Glass @ 2020-08-29 21:20 UTC (permalink / raw)
  To: u-boot

Hi Dario,

+Stephen Warren
On Tue, 25 Aug 2020 at 03:24, Dario Binacchi <dariobin@libero.it> wrote:
>
> It returns the rate which will be set if you ask clk_set_rate() to set
> that rate. It provides a way to query exactly what rate you'll get if
> you call clk_set_rate() with that same argument.
> So essentially, clk_round_rate() and clk_set_rate() are equivalent
> except the former does not modify the clock hardware in any way.
>
> Signed-off-by: Dario Binacchi <dariobin@libero.it>
> ---
>
>  arch/sandbox/include/asm/clk.h |  9 +++++++++
>  drivers/clk/clk-uclass.c       | 15 +++++++++++++++
>  drivers/clk/clk_sandbox.c      | 17 +++++++++++++++++
>  drivers/clk/clk_sandbox_test.c | 10 ++++++++++
>  include/clk-uclass.h           |  8 ++++++++
>  include/clk.h                  | 29 +++++++++++++++++++++++++++++
>  test/dm/clk.c                  | 22 ++++++++++++++++++++++
>  7 files changed, 110 insertions(+)
>

Reviewed-by: Simon Glass <sjg@chromium.org>

But I wonder if we should change the set_rate() uclass interface to
have a flag value, one of the flags being 'dry run' which doesn't
actually set the value?

You would still have the same call to the uclass functions
clk_set_rate() and clk_round_rate() but the driver API would implement
both with calls to set_rate()?

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 11/31] ti: am33xx: fix do_enable_clocks() to accept NULL parameters
  2020-08-25  9:21 ` [PATCH 11/31] ti: am33xx: fix do_enable_clocks() to accept NULL parameters Dario Binacchi
@ 2020-08-29 21:20   ` Simon Glass
  0 siblings, 0 replies; 43+ messages in thread
From: Simon Glass @ 2020-08-29 21:20 UTC (permalink / raw)
  To: u-boot

On Tue, 25 Aug 2020 at 03:25, Dario Binacchi <dariobin@libero.it> wrote:
>
> Up till this commit passing NULL as input parameter was allowed, but not
> handled properly. When a NULL parameter was passed to the function a data
> abort was raised.
>
> Signed-off-by: Dario Binacchi <dariobin@libero.it>
> ---
>
>  arch/arm/mach-omap2/am33xx/clock.c | 10 ++++++----
>  1 file changed, 6 insertions(+), 4 deletions(-)

Reviewed-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 16/31] fdt: translate address if #size-cells = <0>
  2020-08-25  9:21 ` [PATCH 16/31] fdt: translate address if #size-cells = <0> Dario Binacchi
@ 2020-08-29 21:20   ` Simon Glass
  0 siblings, 0 replies; 43+ messages in thread
From: Simon Glass @ 2020-08-29 21:20 UTC (permalink / raw)
  To: u-boot

Hi Dario,

On Tue, 25 Aug 2020 at 03:25, Dario Binacchi <dariobin@libero.it> wrote:
>
> The __of_translate_address routine translates an address from the
> device tree into a CPU physical address. A note in the description of
> the routine explains that the crossing of any level with

there is something missing here. Do you have a # at the start of the line?

> since inherited from IBM. This does not happen for Texas Instruments, or
> at least for the beaglebone device tree. Without this patch, in fact,
> the translation into physical addresses of the registers contained in the
> am33xx-clocks.dtsi nodes would not be possible. They all have a parent
> with #size-cells = <0>.
>
> The CONFIG_OF_TRANSLATE_ZERO_SIZE_CELLS symbol makes translation
> possible even in the case of crossing levels with #size-cells = <0>.
>
> The patch acts conservatively on address translation, except for
> removing a check within the of_translate_one function in the
> drivers/core/of_addr.c file:
>
> +
>         ranges = of_get_property(parent, rprop, &rlen);
> -       if (ranges == NULL && !of_empty_ranges_quirk(parent)) {
> -               debug("no ranges; cannot translate\n");
> -               return 1;
> -       }
>         if (ranges == NULL || rlen == 0) {
>                 offset = of_read_number(addr, na);
>                 memset(addr, 0, pna * 4);
>                 debug("empty ranges; 1:1 translation\n");
>
> There are two reasons:
> 1 The function of_empty_ranges_quirk always returns false, invalidating
>   the following if statement in case of null ranges. Therefore one of
>   the two checks is useless.
>
> 2 The implementation of the of_translate_one function found in the
>   common/fdt_support.c file has removed this check while keeping the one
>   about the 1:1 translation.
>
> The patch adds a test and modifies a check for the correctness of an
> address in the case of enabling translation also for zero size cells.
> The added test checks translations of addresses generated by nodes of
> a device tree similar to those you can find in the files am33xx.dtsi
> and am33xx-clocks.dtsi for which the patch was created.
>
> The patch was also tested on a beaglebone black board. The addresses
> generated for the registers of the loaded drivers are those specified
> by the AM335x reference manual.
>
> Signed-off-by: Dario Binacchi <dariobin@libero.it>
> Tested-by: Dario Binacchi <dariobin@libero.it>
> ---
>
>  arch/sandbox/dts/test.dts | 21 +++++++++++
>  common/fdt_support.c      | 10 ++++--
>  drivers/core/Kconfig      | 12 +++++++
>  drivers/core/fdtaddr.c    |  2 +-
>  drivers/core/of_addr.c    | 14 +++-----
>  drivers/core/ofnode.c     | 11 ++++--
>  test/dm/test-fdt.c        | 73 +++++++++++++++++++++++++++++++++++++--
>  7 files changed, 127 insertions(+), 16 deletions(-)
>
> diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
> index 1d8956abbe..7f5d8f3aeb 100644
> --- a/arch/sandbox/dts/test.dts
> +++ b/arch/sandbox/dts/test.dts
> @@ -39,6 +39,7 @@
>                 fdt-dummy1 = "/translation-test at 8000/dev at 1,100";
>                 fdt-dummy2 = "/translation-test at 8000/dev at 2,200";
>                 fdt-dummy3 = "/translation-test at 8000/noxlatebus at 3,300/dev at 42";
> +               fdt-dummy4 = "/translation-test at 8000/xlatebus at 4,400/devs/dev at 19";
>                 usb0 = &usb_0;
>                 usb1 = &usb_1;
>                 usb2 = &usb_2;
> @@ -977,6 +978,7 @@
>                           1 0x100 0x9000 0x1000
>                           2 0x200 0xA000 0x1000
>                           3 0x300 0xB000 0x1000
> +                         4 0x400 0xC000 0x1000
>                          >;
>
>                 dma-ranges = <0 0x000 0x10000000 0x1000
> @@ -1013,6 +1015,25 @@
>                                 reg = <0x42>;
>                         };
>                 };
> +
> +               xlatebus at 4,400 {
> +                       compatible = "sandbox,zero-size-cells-bus";
> +                       reg = <4 0x400 0x1000>;
> +                       #address-cells = <1>;
> +                       #size-cells = <1>;
> +                       ranges = <0 4 0x400 0x1000>;
> +
> +                       devs {
> +                               #address-cells = <1>;
> +                               #size-cells = <0>;
> +
> +                               dev at 19 {
> +                                       compatible = "denx,u-boot-fdt-dummy";
> +                                       reg = <0x19>;
> +                               };
> +                       };
> +               };
> +
>         };
>
>         osd {
> diff --git a/common/fdt_support.c b/common/fdt_support.c
> index a565b470f8..402401e073 100644
> --- a/common/fdt_support.c
> +++ b/common/fdt_support.c
> @@ -1001,8 +1001,14 @@ void fdt_del_node_and_alias(void *blob, const char *alias)
>  /* Max address size we deal with */
>  #define OF_MAX_ADDR_CELLS      4
>  #define OF_BAD_ADDR    FDT_ADDR_T_NONE
> -#define OF_CHECK_COUNTS(na, ns)        ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
> -                       (ns) > 0)
> +#define OF_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS)
> +#if defined(CONFIG_OF_TRANSLATE_ZERO_SIZE_CELLS)
> +#define OF_CHECK_SIZE_COUNT(ns) ((ns) >= 0)
> +#else
> +#define OF_CHECK_SIZE_COUNT(ns) ((ns) > 0)
> +#endif
> +#define OF_CHECK_COUNTS(na, ns) (OF_CHECK_ADDR_COUNT(na) && \
> +                                OF_CHECK_SIZE_COUNT(ns))
>
>  /* Debug utility */
>  #ifdef DEBUG
> diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
> index 00d1d80dc3..2a683ae404 100644
> --- a/drivers/core/Kconfig
> +++ b/drivers/core/Kconfig
> @@ -217,6 +217,18 @@ config OF_TRANSLATE
>           used for the address translation. This function is faster and
>           smaller in size than fdt_translate_address().
>
> +config OF_TRANSLATE_ZERO_SIZE_CELLS
> +       bool "Enable translation for zero size cells"
> +       depends on OF_TRANSLATE
> +       default n
> +       help
> +         The routine used to translate an FDT address into a physical CPU
> +         address was developed by IBM. It considers that crossing any level
> +         with #size-cells = <0> makes translation impossible, even if it is
> +         not the way it was specified.
> +         Enabling this option makes translation possible even in the case
> +         of crossing levels with #size-cells = <0>.
> +
>  config SPL_OF_TRANSLATE
>         bool "Translate addresses using fdt_translate_address in SPL"
>         depends on SPL_DM && SPL_OF_CONTROL
> diff --git a/drivers/core/fdtaddr.c b/drivers/core/fdtaddr.c
> index 8b48aa5bc5..5a9f08aa44 100644
> --- a/drivers/core/fdtaddr.c
> +++ b/drivers/core/fdtaddr.c
> @@ -49,7 +49,7 @@ fdt_addr_t devfdt_get_addr_index(const struct udevice *dev, int index)
>
>                 reg += index * (na + ns);
>
> -               if (ns) {
> +               if (IS_ENABLED(CONFIG_OF_TRANSLATE_ZERO_SIZE_CELLS) || ns) {

Here we should check a flag, perhaps in a new gd->dm_flags value, to
determine the behaviour. The problem with using a CONFIG here is that
you cannot test it without recompiling. Also the code-size difference
is negligible.

So you can use the CONFIG to set the flag, perhaps in dm_init(), and
add a helper to change the setting, which can be used in tests.

>                         /*
>                          * Use the full-fledged translate function for complex
>                          * bus setups.
> diff --git a/drivers/core/of_addr.c b/drivers/core/of_addr.c
> index ca34d84922..ddac5f9a2b 100644
> --- a/drivers/core/of_addr.c
> +++ b/drivers/core/of_addr.c
> @@ -18,7 +18,11 @@
>  /* Max address size we deal with */
>  #define OF_MAX_ADDR_CELLS      4
>  #define OF_CHECK_ADDR_COUNT(na)        ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS)
> +#if defined(CONFIG_OF_TRANSLATE_ZERO_SIZE_CELLS)
> +#define OF_CHECK_COUNTS(na, ns)        (OF_CHECK_ADDR_COUNT(na) && (ns) >= 0)
> +#else
>  #define OF_CHECK_COUNTS(na, ns)        (OF_CHECK_ADDR_COUNT(na) && (ns) > 0)

This could be changed to have just one #define by bringing the CONFIG
into the expression.

> +#endif
>
>  static struct of_bus *of_match_bus(struct device_node *np);
>
> @@ -162,11 +166,6 @@ const __be32 *of_get_address(const struct device_node *dev, int index,
>  }
>  EXPORT_SYMBOL(of_get_address);
>
> -static int of_empty_ranges_quirk(const struct device_node *np)
> -{
> -       return false;
> -}
> -
>  static int of_translate_one(const struct device_node *parent,
>                             struct of_bus *bus, struct of_bus *pbus,
>                             __be32 *addr, int na, int ns, int pna,
> @@ -193,11 +192,8 @@ static int of_translate_one(const struct device_node *parent,
>          * As far as we know, this damage only exists on Apple machines, so
>          * This code is only enabled on powerpc. --gcl
>          */
> +
>         ranges = of_get_property(parent, rprop, &rlen);
> -       if (ranges == NULL && !of_empty_ranges_quirk(parent)) {
> -               debug("no ranges; cannot translate\n");
> -               return 1;
> -       }
>         if (ranges == NULL || rlen == 0) {
>                 offset = of_read_number(addr, na);
>                 memset(addr, 0, pna * 4);
> diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
> index d02d8d33fe..b5744e86c3 100644
> --- a/drivers/core/ofnode.c
> +++ b/drivers/core/ofnode.c
> @@ -304,7 +304,10 @@ fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
>
>                 ns = of_n_size_cells(ofnode_to_np(node));
>
> -               if (IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
> +               if (IS_ENABLED(CONFIG_OF_TRANSLATE) &&
> +                   (ns > 0 ||
> +                    (IS_ENABLED(CONFIG_OF_TRANSLATE_ZERO_SIZE_CELLS) &&
> +                     ns >= 0))) {
>                         return of_translate_address(ofnode_to_np(node), prop_val);
>                 } else {
>                         na = of_n_addr_cells(ofnode_to_np(node));
> @@ -655,8 +658,12 @@ fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
>                 ns = of_n_size_cells(np);
>                 *sizep = of_read_number(prop + na, ns);
>
> -               if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0)
> +               if (CONFIG_IS_ENABLED(OF_TRANSLATE) &&
> +                   (ns > 0 ||
> +                    (IS_ENABLED(CONFIG_OF_TRANSLATE_ZERO_SIZE_CELLS) &&
> +                     ns >= 0))) {
>                         return of_translate_address(np, prop);
> +               }
>                 else
>                         return of_read_number(prop, na);
>         } else {
> diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
> index 04802deb7f..30a7a933dd 100644
> --- a/test/dm/test-fdt.c
> +++ b/test/dm/test-fdt.c
> @@ -581,6 +581,64 @@ U_BOOT_DRIVER(fdt_dummy_drv) = {
>         .id     = UCLASS_TEST_DUMMY,
>  };
>
> +static int zero_size_cells_bus_bind(struct udevice *dev)
> +{
> +       ofnode child;
> +       int err;
> +
> +       ofnode_for_each_subnode(child, dev_ofnode(dev)) {
> +               if (ofnode_get_property(child, "compatible", NULL))
> +                       continue;
> +
> +               err = device_bind_driver_to_node(dev,
> +                                                "zero_size_cells_bus_child_drv",
> +                                                "zero_size_cells_bus_child",
> +                                                child, NULL);
> +               if (err) {
> +                       dev_err(dev, "%s: failed to bind %s\n", __func__,
> +                               ofnode_get_name(child));
> +                       return err;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static const struct udevice_id zero_size_cells_bus_ids[] = {
> +       { .compatible = "sandbox,zero-size-cells-bus" },
> +       { }
> +};
> +
> +U_BOOT_DRIVER(zero_size_cells_bus) = {
> +       .name = "zero_size_cells_bus_drv",
> +       .id = UCLASS_TEST_DUMMY,
> +       .of_match = zero_size_cells_bus_ids,
> +       .bind = zero_size_cells_bus_bind,
> +};
> +
> +static int zero_size_cells_bus_child_bind(struct udevice *dev)
> +{
> +       ofnode child;
> +       int err;
> +
> +       ofnode_for_each_subnode(child, dev_ofnode(dev)) {
> +               err = lists_bind_fdt(dev, child, NULL, false);
> +               if (err) {
> +                       dev_err(dev, "%s: lists_bind_fdt, err=%d\n",
> +                               __func__, err);
> +                       return err;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +U_BOOT_DRIVER(zero_size_cells_bus_child_drv) = {
> +       .name = "zero_size_cells_bus_child_drv",
> +       .id = UCLASS_TEST_DUMMY,
> +       .bind = zero_size_cells_bus_child_bind,
> +};
> +
>  static int dm_test_fdt_translation(struct unit_test_state *uts)
>  {
>         struct udevice *dev;
> @@ -599,10 +657,21 @@ static int dm_test_fdt_translation(struct unit_test_state *uts)
>         ut_asserteq_str("dev at 2,200", dev->name);
>         ut_asserteq(0xA000, dev_read_addr(dev));
>
> -       /* No translation for busses with #size-cells == 0 */
>         ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 3, true, &dev));
>         ut_asserteq_str("dev at 42", dev->name);
> -       ut_asserteq(0x42, dev_read_addr(dev));
> +
> +       if (!IS_ENABLED(CONFIG_OF_TRANSLATE_ZERO_SIZE_CELLS)) {

Here, adjust the flag so you can run both tests one after the other.

> +               /* No translation for busses with #size-cells == 0 */
> +               ut_asserteq(0x42, dev_read_addr(dev));
> +       } else {
> +               /* Translation for busses with #size-cells == 0 */
> +               ut_asserteq(0x8042, dev_read_addr(dev));
> +
> +               ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 4, true,
> +                                                     &dev));
> +               ut_asserteq_str("dev at 19", dev->name);
> +               ut_asserteq(0xC019, dev_read_addr(dev));

lower-case hex please

> +       }
>
>         /* dma address translation */
>         ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_DUMMY, 0, true, &dev));
> --
> 2.17.1
>

Regards,
Simon

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 21/31] video: backlight: fix pwm's duty cycle calculation
  2020-08-25  9:21 ` [PATCH 21/31] video: backlight: fix pwm's duty cycle calculation Dario Binacchi
@ 2020-08-29 21:20   ` Simon Glass
  0 siblings, 0 replies; 43+ messages in thread
From: Simon Glass @ 2020-08-29 21:20 UTC (permalink / raw)
  To: u-boot

On Tue, 25 Aug 2020 at 03:25, Dario Binacchi <dariobin@libero.it> wrote:
>
> For levels equal to the maximum value, the duty cycle must be equal to
> the period.
>
> Signed-off-by: Dario Binacchi <dariobin@libero.it>
> ---
>
>  drivers/video/pwm_backlight.c |  2 +-
>  test/dm/panel.c               | 12 ++++++------
>  2 files changed, 7 insertions(+), 7 deletions(-)
>

Reviewed-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 23/31] dm: core: improve uclass_get_device_by_phandle_id() description
  2020-08-25  9:21 ` [PATCH 23/31] dm: core: improve uclass_get_device_by_phandle_id() description Dario Binacchi
@ 2020-08-29 21:20   ` Simon Glass
  0 siblings, 0 replies; 43+ messages in thread
From: Simon Glass @ 2020-08-29 21:20 UTC (permalink / raw)
  To: u-boot

On Tue, 25 Aug 2020 at 03:25, Dario Binacchi <dariobin@libero.it> wrote:
>
> Complete the devp parameter description.
>
> Signed-off-by: Dario Binacchi <dariobin@libero.it>
> ---
>
>  include/dm/uclass.h | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
>

Reviewed-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 24/31] gpio: fix gpio_request_by_name() description
  2020-08-25  9:21 ` [PATCH 24/31] gpio: fix gpio_request_by_name() description Dario Binacchi
@ 2020-08-29 21:20   ` Simon Glass
  0 siblings, 0 replies; 43+ messages in thread
From: Simon Glass @ 2020-08-29 21:20 UTC (permalink / raw)
  To: u-boot

On Tue, 25 Aug 2020 at 03:25, Dario Binacchi <dariobin@libero.it> wrote:
>
> Replace 'dev->dev' with '@desc->dev' in the gpio_request_by_name function
> desc parameter description.
>
> Signed-off-by: Dario Binacchi <dariobin@libero.it>
> ---
>
>  include/asm-generic/gpio.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

Reviewed-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 25/31] dm: core: add a function to decode display timings
  2020-08-25  9:21 ` [PATCH 25/31] dm: core: add a function to decode display timings Dario Binacchi
@ 2020-08-29 21:20   ` Simon Glass
  0 siblings, 0 replies; 43+ messages in thread
From: Simon Glass @ 2020-08-29 21:20 UTC (permalink / raw)
  To: u-boot

On Tue, 25 Aug 2020 at 03:25, Dario Binacchi <dariobin@libero.it> wrote:
>
> The patch adds a function to get display timings from the device tree
> node attached to the device.
>
> Signed-off-by: Dario Binacchi <dariobin@libero.it>
> ---
>
>  arch/sandbox/dts/test.dts | 46 ++++++++++++++++++++++
>  drivers/core/read.c       |  6 +++
>  include/dm/read.h         | 24 ++++++++++++
>  test/dm/test-fdt.c        | 80 +++++++++++++++++++++++++++++++++++++++
>  4 files changed, 156 insertions(+)

Reviewed-by: Simon Glass <sjg@chromium.org>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 04/31] clk: add clk_round_rate()
  2020-08-29 21:20   ` Simon Glass
@ 2020-08-29 21:48     ` Sean Anderson
  2020-08-29 21:50       ` Sean Anderson
  0 siblings, 1 reply; 43+ messages in thread
From: Sean Anderson @ 2020-08-29 21:48 UTC (permalink / raw)
  To: u-boot


On 8/29/20 5:20 PM, Simon Glass wrote:
> Hi Dario,
> 
> +Stephen Warren
> On Tue, 25 Aug 2020 at 03:24, Dario Binacchi <dariobin@libero.it> wrote:
>>
>> It returns the rate which will be set if you ask clk_set_rate() to set
>> that rate. It provides a way to query exactly what rate you'll get if
>> you call clk_set_rate() with that same argument.
>> So essentially, clk_round_rate() and clk_set_rate() are equivalent
>> except the former does not modify the clock hardware in any way.
>>
>> Signed-off-by: Dario Binacchi <dariobin@libero.it>
>> ---
>>
>>  arch/sandbox/include/asm/clk.h |  9 +++++++++
>>  drivers/clk/clk-uclass.c       | 15 +++++++++++++++
>>  drivers/clk/clk_sandbox.c      | 17 +++++++++++++++++
>>  drivers/clk/clk_sandbox_test.c | 10 ++++++++++
>>  include/clk-uclass.h           |  8 ++++++++
>>  include/clk.h                  | 29 +++++++++++++++++++++++++++++
>>  test/dm/clk.c                  | 22 ++++++++++++++++++++++
>>  7 files changed, 110 insertions(+)
>>
> 
> Reviewed-by: Simon Glass <sjg@chromium.org>
> 
> But I wonder if we should change the set_rate() uclass interface to
> have a flag value, one of the flags being 'dry run' which doesn't
> actually set the value?
> 
> You would still have the same call to the uclass functions
> clk_set_rate() and clk_round_rate() but the driver API would implement
> both with calls to set_rate()?

Linux uses separate clk_ops functions for this purpose

>  * @recalc_rate	Recalculate the rate of this clock, by querying hardware. The
>  *		parent rate is an input parameter.  It is up to the caller to
>  *		ensure that the prepare_mutex is held across this call.
>  *		Returns the calculated rate.  Optional, but recommended - if
>  *		this op is not set then clock rate will be initialized to 0.
> (...snip...)
> 	long		(*round_rate)(struct clk_hw *hw, unsigned long rate,
> 					unsigned long *parent_rate);

Besides matching their interface, I think there is good reason for
keeping these functions separate. Existing clock drivers would need to
be rewritten so they don't set the clock rate when you just want to do a
dry run. This way, it's very clear when a driver supports recalc_rate.

--Sean

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 04/31] clk: add clk_round_rate()
  2020-08-29 21:48     ` Sean Anderson
@ 2020-08-29 21:50       ` Sean Anderson
  2020-08-31 16:29         ` Dario Binacchi
  0 siblings, 1 reply; 43+ messages in thread
From: Sean Anderson @ 2020-08-29 21:50 UTC (permalink / raw)
  To: u-boot

On 8/29/20 5:48 PM, Sean Anderson wrote:
> 
> On 8/29/20 5:20 PM, Simon Glass wrote:
>> Hi Dario,
>>
>> +Stephen Warren
>> On Tue, 25 Aug 2020 at 03:24, Dario Binacchi <dariobin@libero.it> wrote:
>>>
>>> It returns the rate which will be set if you ask clk_set_rate() to set
>>> that rate. It provides a way to query exactly what rate you'll get if
>>> you call clk_set_rate() with that same argument.
>>> So essentially, clk_round_rate() and clk_set_rate() are equivalent
>>> except the former does not modify the clock hardware in any way.
>>>
>>> Signed-off-by: Dario Binacchi <dariobin@libero.it>
>>> ---
>>>
>>>  arch/sandbox/include/asm/clk.h |  9 +++++++++
>>>  drivers/clk/clk-uclass.c       | 15 +++++++++++++++
>>>  drivers/clk/clk_sandbox.c      | 17 +++++++++++++++++
>>>  drivers/clk/clk_sandbox_test.c | 10 ++++++++++
>>>  include/clk-uclass.h           |  8 ++++++++
>>>  include/clk.h                  | 29 +++++++++++++++++++++++++++++
>>>  test/dm/clk.c                  | 22 ++++++++++++++++++++++
>>>  7 files changed, 110 insertions(+)
>>>
>>
>> Reviewed-by: Simon Glass <sjg@chromium.org>
>>
>> But I wonder if we should change the set_rate() uclass interface to
>> have a flag value, one of the flags being 'dry run' which doesn't
>> actually set the value?
>>
>> You would still have the same call to the uclass functions
>> clk_set_rate() and clk_round_rate() but the driver API would implement
>> both with calls to set_rate()?
> 
> Linux uses separate clk_ops functions for this purpose
> 
>>  * @recalc_rate	Recalculate the rate of this clock, by querying hardware. The
>>  *		parent rate is an input parameter.  It is up to the caller to
>>  *		ensure that the prepare_mutex is held across this call.
>>  *		Returns the calculated rate.  Optional, but recommended - if
>>  *		this op is not set then clock rate will be initialized to 0.

err, I meant to quote

>  * @round_rate:	Given a target rate as input, returns the closest rate actually
>  *		supported by the clock. The parent rate is an input/output
>  *		parameter.

>> (...snip...)
>> 	long		(*round_rate)(struct clk_hw *hw, unsigned long rate,
>> 					unsigned long *parent_rate);
> 
> Besides matching their interface, I think there is good reason for
> keeping these functions separate. Existing clock drivers would need to
> be rewritten so they don't set the clock rate when you just want to do a
> dry run. This way, it's very clear when a driver supports recalc_rate.
> 
> --Sean
> 

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 04/31] clk: add clk_round_rate()
  2020-08-29 21:50       ` Sean Anderson
@ 2020-08-31 16:29         ` Dario Binacchi
  0 siblings, 0 replies; 43+ messages in thread
From: Dario Binacchi @ 2020-08-31 16:29 UTC (permalink / raw)
  To: u-boot


> Il 29/08/2020 23:50 Sean Anderson <seanga2@gmail.com> ha scritto:
> 
>  
> On 8/29/20 5:48 PM, Sean Anderson wrote:
> > 
> > On 8/29/20 5:20 PM, Simon Glass wrote:
> >> Hi Dario,
> >>
> >> +Stephen Warren
> >> On Tue, 25 Aug 2020 at 03:24, Dario Binacchi <dariobin@libero.it> wrote:
> >>>
> >>> It returns the rate which will be set if you ask clk_set_rate() to set
> >>> that rate. It provides a way to query exactly what rate you'll get if
> >>> you call clk_set_rate() with that same argument.
> >>> So essentially, clk_round_rate() and clk_set_rate() are equivalent
> >>> except the former does not modify the clock hardware in any way.
> >>>
> >>> Signed-off-by: Dario Binacchi <dariobin@libero.it>
> >>> ---
> >>>
> >>>  arch/sandbox/include/asm/clk.h |  9 +++++++++
> >>>  drivers/clk/clk-uclass.c       | 15 +++++++++++++++
> >>>  drivers/clk/clk_sandbox.c      | 17 +++++++++++++++++
> >>>  drivers/clk/clk_sandbox_test.c | 10 ++++++++++
> >>>  include/clk-uclass.h           |  8 ++++++++
> >>>  include/clk.h                  | 29 +++++++++++++++++++++++++++++
> >>>  test/dm/clk.c                  | 22 ++++++++++++++++++++++
> >>>  7 files changed, 110 insertions(+)
> >>>
> >>
> >> Reviewed-by: Simon Glass <sjg@chromium.org>
> >>
> >> But I wonder if we should change the set_rate() uclass interface to
> >> have a flag value, one of the flags being 'dry run' which doesn't
> >> actually set the value?
> >>
> >> You would still have the same call to the uclass functions
> >> clk_set_rate() and clk_round_rate() but the driver API would implement
> >> both with calls to set_rate()?
> > 
> > Linux uses separate clk_ops functions for this purpose
> > 
> >>  * @recalc_rate	Recalculate the rate of this clock, by querying hardware. The
> >>  *		parent rate is an input parameter.  It is up to the caller to
> >>  *		ensure that the prepare_mutex is held across this call.
> >>  *		Returns the calculated rate.  Optional, but recommended - if
> >>  *		this op is not set then clock rate will be initialized to 0.
> 
> err, I meant to quote
> 
> >  * @round_rate:	Given a target rate as input, returns the closest rate actually
> >  *		supported by the clock. The parent rate is an input/output
> >  *		parameter.
> 
> >> (...snip...)
> >> 	long		(*round_rate)(struct clk_hw *hw, unsigned long rate,
> >> 					unsigned long *parent_rate);
> > 
> > Besides matching their interface, I think there is good reason for
> > keeping these functions separate. Existing clock drivers would need to
> > be rewritten so they don't set the clock rate when you just want to do a
> > dry run. This way, it's very clear when a driver supports recalc_rate.

I agree.

> > 
> > --Sean
> >

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 18/31] misc: am33xx: add control module driver
  2020-08-25  9:21 ` [PATCH 18/31] misc: am33xx: add control module driver Dario Binacchi
@ 2020-09-03  6:31   ` Lokesh Vutla
  2020-09-05 10:41     ` Dario Binacchi
  0 siblings, 1 reply; 43+ messages in thread
From: Lokesh Vutla @ 2020-09-03  6:31 UTC (permalink / raw)
  To: u-boot



On 25/08/20 2:51 pm, Dario Binacchi wrote:
> The implementation of this driver was needed to bind the device tree
> sub-nodes of the 'clocks' node. In fact, the lack of the compatible
> property in the 'clocks' node does not allow the generic 'syscon' or
> 'simple-bus' drivers linked to the 'scm_conf at 0' node to bind the
> 'clocks' node and in turn its sub-nodes.
> The 'scm at 210000' node is therefore the node closest to the 'clocks' node
> whose driver can bind all the 'clocks' sub-nodes.
> 
> scm: scm at 210000 {
> 	compatible = "ti,am3-scm", "simple-bus";
> 	...
> 
> 	scm_conf: scm_conf at 0 {
> 		compatible = "syscon", "simple-bus";
> 		#address-cells = <1>;
> 		#size-cells = <1>;
> 		ranges = <0 0 0x800>;
> 
> 		scm_clocks: clocks {
> 			#address-cells = <1>;
> 			#size-cells = <0>;
> 		};
> 	};
> };
> 
> Signed-off-by: Dario Binacchi <dariobin@libero.it>
> ---
> 
>  doc/device-tree-bindings/arm/omap,ctrl.txt    |  82 ++++++
>  .../pinctrl/pinctrl-single.txt                | 255 ++++++++++++++++++

This documentation does not belong to this patch.

>  drivers/misc/Kconfig                          |   7 +
>  drivers/misc/Makefile                         |   1 +
>  drivers/misc/ti-am3-scm.c                     |  90 +++++++
>  5 files changed, 435 insertions(+)
>  create mode 100644 doc/device-tree-bindings/arm/omap,ctrl.txt
>  create mode 100644 doc/device-tree-bindings/pinctrl/pinctrl-single.txt
>  create mode 100644 drivers/misc/ti-am3-scm.c
> 
> diff --git a/doc/device-tree-bindings/arm/omap,ctrl.txt b/doc/device-tree-bindings/arm/omap,ctrl.txt
> new file mode 100644
> index 0000000000..8efd321cfa
> --- /dev/null
> +++ b/doc/device-tree-bindings/arm/omap,ctrl.txt
> @@ -0,0 +1,82 @@
> +OMAP Control Module bindings
> +
> +Control Module contains miscellaneous features under it based on SoC type.
> +Pincontrol is one common feature, and it has a specialized support
> +described in [1]. Typically some clock nodes are also under control module.
> +Syscon is used to share register level access to drivers external to
> +control module driver itself.
> +
> +See [2] for documentation about clock/clockdomain nodes.
> +
> +[1] doc/device-tree-bindings/pinctrl/pinctrl-single.txt
> +[2] doc/device-tree-bindings/clock/ti,*.txt
> +
> +Required properties:
> +- compatible:	Must be one of:
> +		"ti,am3-scm"
> +		"ti,am4-scm"
> +		"ti,dm814-scrm"
> +		"ti,dm816-scrm"
> +		"ti,omap2-scm"
> +		"ti,omap3-scm"
> +		"ti,omap4-scm-core"
> +		"ti,omap4-scm-padconf-core"
> +		"ti,omap4-scm-wkup"
> +		"ti,omap4-scm-padconf-wkup"
> +		"ti,omap5-scm-core"
> +		"ti,omap5-scm-padconf-core"
> +		"ti,omap5-scm-wkup-pad-conf"
> +		"ti,dra7-scm-core"
> +- reg:		Contains Control Module register address range
> +		(base address and length)
> +
> +Optional properties:
> +- clocks:	clocks for this module
> +- clockdomains:	clockdomains for this module
> +
> +Examples:
> +
> +scm: scm at 2000 {
> +	compatible = "ti,omap3-scm", "simple-bus";
> +	reg = <0x2000 0x2000>;
> +	#address-cells = <1>;
> +	#size-cells = <1>;
> +	ranges = <0 0x2000 0x2000>;
> +
> +	omap3_pmx_core: pinmux at 30 {
> +		compatible = "ti,omap3-padconf",
> +			     "pinctrl-single";
> +		reg = <0x30 0x230>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		#interrupt-cells = <1>;
> +		interrupt-controller;
> +		pinctrl-single,register-width = <16>;
> +		pinctrl-single,function-mask = <0xff1f>;
> +	};
> +
> +	scm_conf: scm_conf at 270 {
> +		compatible = "syscon";
> +		reg = <0x270 0x330>;
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +
> +		scm_clocks: clocks {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +	};
> +
> +	scm_clockdomains: clockdomains {
> +	};
> +}
> +
> +&scm_clocks {
> +	mcbsp5_mux_fck: mcbsp5_mux_fck {
> +		#clock-cells = <0>;
> +		compatible = "ti,composite-mux-clock";
> +		clocks = <&core_96m_fck>, <&mcbsp_clks>;
> +		ti,bit-shift = <4>;
> +		reg = <0x02d8>;
> +	};
> +};

[...snip...]


> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> index b67e906a76..9e8b676637 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -500,4 +500,11 @@ config ESM_PMIC
>  	  Support ESM (Error Signal Monitor) on PMIC devices. ESM is used
>  	  typically to reboot the board in error condition.
>  
> +config TI_AM3_SCM
> +	bool "AM33XX specific control module support (SCM)"
> +	depends on ARCH_OMAP2PLUS
> +	help
> +	 The control module includes status and control logic not addressed
> +	 within the peripherals or the rest of the device infrastructure.
> +
>  endmenu
> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> index 947bd3a647..056fb3b522 100644
> --- a/drivers/misc/Makefile
> +++ b/drivers/misc/Makefile
> @@ -75,3 +75,4 @@ obj-$(CONFIG_MICROCHIP_FLEXCOM) += microchip_flexcom.o
>  obj-$(CONFIG_K3_AVS0) += k3_avs.o
>  obj-$(CONFIG_ESM_K3) += k3_esm.o
>  obj-$(CONFIG_ESM_PMIC) += esm_pmic.o
> +obj-$(CONFIG_TI_AM3_SCM) += ti-am3-scm.o
> diff --git a/drivers/misc/ti-am3-scm.c b/drivers/misc/ti-am3-scm.c
> new file mode 100644
> index 0000000000..e5f4f09261
> --- /dev/null
> +++ b/drivers/misc/ti-am3-scm.c
> @@ -0,0 +1,90 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * AM335x specific control module (scm)
> + *
> + * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <dm/lists.h>
> +#include <linux/err.h>
> +
> +static int ti_am3_scm_bind(struct udevice *dev)
> +{
> +	int err;
> +	struct udevice *conf_dev;
> +	ofnode clocks_node, conf_node;
> +
> +	err = dm_scan_fdt_dev(dev);
> +	if (err) {
> +		dev_err(dev, "%s: dm_scan_fdt, err=%d\n", __func__, err);
> +		return err;
> +	}
> +
> +	conf_node = dev_read_subnode(dev, "scm_conf at 0");
> +	if (!ofnode_valid(conf_node)) {
> +		dev_err(dev, "%s: failed to get conf sub-node\n", __func__);
> +		return -ENODEV;
> +	}
> +
> +	if (uclass_get_device_by_ofnode(UCLASS_SYSCON, conf_node, &conf_dev)) {
> +		if (uclass_get_device_by_ofnode(UCLASS_SIMPLE_BUS, conf_node,
> +						&conf_dev)) {
> +			dev_err(dev, "%s: failed to get conf device\n",
> +				__func__);
> +			return -ENODEV;
> +		}
> +	}
> +
> +	clocks_node = dev_read_subnode(conf_dev, "clocks");
> +	if (!ofnode_valid(clocks_node)) {
> +		dev_err(dev, "%s: failed to get clocks sub-node\n", __func__);
> +		return -ENODEV;
> +	}

Isn't clock node an optional property?

Also do we really need a separate UBOOT_DRIVER for scm_clocks? Can it be handled
in the same driver?

Thanks and regards,
Lokesh

> +
> +	err = device_bind_driver_to_node(conf_dev, "ti_am3_scm_clocks",
> +					 "scm_clocks", clocks_node, NULL);
> +	if (err) {
> +		dev_err(dev, "%s: failed to bind scm_clocks\n", __func__);
> +		return err;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct udevice_id ti_am3_scm_ids[] = {
> +	{.compatible = "ti,am3-scm"},
> +	{}
> +};
> +
> +U_BOOT_DRIVER(ti_am3_scm) = {
> +	.name = "ti_am3_scm",
> +	.id = UCLASS_SIMPLE_BUS,
> +	.of_match = ti_am3_scm_ids,
> +	.bind = ti_am3_scm_bind,
> +};
> +
> +static int ti_am3_scm_clocks_bind(struct udevice *dev)
> +{
> +	ofnode node;
> +	int err;
> +
> +	dev_dbg(dev, "%s: dev=%p\n", __func__, dev);
> +	ofnode_for_each_subnode(node, dev_ofnode(dev)) {
> +		err = lists_bind_fdt(dev, node, NULL, false);
> +		if (err) {
> +			dev_err(dev, "%s: lists_bind_fdt, err=%d\n",
> +				__func__, err);
> +			return err;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +U_BOOT_DRIVER(ti_am3_scm_clocks) = {
> +	.name = "ti_am3_scm_clocks",
> +	.id = UCLASS_SIMPLE_BUS,
> +	.bind = ti_am3_scm_clocks_bind,
> +};
> 

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 09/31] clk: ti: refactor mux and divider clock drivers
  2020-08-25  9:21 ` [PATCH 09/31] clk: ti: refactor mux and divider clock drivers Dario Binacchi
@ 2020-09-03  6:34   ` Lokesh Vutla
  0 siblings, 0 replies; 43+ messages in thread
From: Lokesh Vutla @ 2020-09-03  6:34 UTC (permalink / raw)
  To: u-boot



On 25/08/20 2:51 pm, Dario Binacchi wrote:
> The patch removes duplicate routines used by the two drivers.
> 
> Signed-off-by: Dario Binacchi <dariobin@libero.it>

Please squash it into previous patches.

Thanks and regards,
Lokesh

> ---
> 
>  drivers/clk/Makefile         |  1 +
>  drivers/clk/clk-ti-divider.c | 27 ++-------------------------
>  drivers/clk/clk-ti-mux.c     | 27 ++-------------------------
>  drivers/clk/clk-ti.c         | 34 ++++++++++++++++++++++++++++++++++
>  drivers/clk/clk-ti.h         | 13 +++++++++++++
>  5 files changed, 52 insertions(+), 50 deletions(-)
>  create mode 100644 drivers/clk/clk-ti.c
>  create mode 100644 drivers/clk/clk-ti.h
> 
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 0fcfcc1837..21b1e9c364 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -18,6 +18,7 @@ obj-$(CONFIG_ARCH_ASPEED) += aspeed/
>  obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
>  obj-$(CONFIG_ARCH_MTMIPS) += mtmips/
>  obj-$(CONFIG_ARCH_MESON) += meson/
> +obj-$(CONFIG_ARCH_OMAP2PLUS) += clk-ti.o
>  obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
>  obj-$(CONFIG_ARCH_SOCFPGA) += altera/
>  obj-$(CONFIG_CLK_AT91) += at91/
> diff --git a/drivers/clk/clk-ti-divider.c b/drivers/clk/clk-ti-divider.c
> index fa9d60a2d5..d16cc30cb7 100644
> --- a/drivers/clk/clk-ti-divider.c
> +++ b/drivers/clk/clk-ti-divider.c
> @@ -16,6 +16,7 @@
>  #include <linux/clk-provider.h>
>  #include <linux/kernel.h>
>  #include <linux/log2.h>
> +#include "clk-ti.h"
>  
>  /*
>   * The reverse of DIV_ROUND_UP: The maximum number which
> @@ -36,30 +37,6 @@ struct clk_ti_divider_priv {
>  	u16 mask;
>  };
>  
> -static void clk_ti_divider_rmw(u32 val, u32 mask, fdt_addr_t reg)
> -{
> -	u32 v;
> -
> -	v = readl(reg);
> -	v &= ~mask;
> -	v |= val;
> -	writel(v, reg);
> -}
> -
> -static void clk_ti_divider_latch(fdt_addr_t reg, s8 shift)
> -{
> -	u32 latch;
> -
> -	if (shift < 0)
> -		return;
> -
> -	latch = 1 << shift;
> -
> -	clk_ti_divider_rmw(latch, latch, reg);
> -	clk_ti_divider_rmw(0, latch, reg);
> -	readl(reg);		/* OCP barrier */
> -}
> -
>  static unsigned int _get_div(const struct clk_div_table *table, ulong flags,
>  			     unsigned int val)
>  {
> @@ -226,7 +203,7 @@ static ulong clk_ti_divider_set_rate(struct clk *clk, ulong rate)
>  	v &= ~(priv->mask << priv->shift);
>  	v |= val << priv->shift;
>  	writel(v, priv->reg);
> -	clk_ti_divider_latch(priv->reg, priv->latch);
> +	clk_ti_latch(priv->reg, priv->latch);
>  
>  	return clk_get_rate(clk);
>  }
> diff --git a/drivers/clk/clk-ti-mux.c b/drivers/clk/clk-ti-mux.c
> index 7e39dd3477..e4b190bbcc 100644
> --- a/drivers/clk/clk-ti-mux.c
> +++ b/drivers/clk/clk-ti-mux.c
> @@ -12,6 +12,7 @@
>  #include <clk-uclass.h>
>  #include <asm/io.h>
>  #include <linux/clk-provider.h>
> +#include "clk-ti.h"
>  
>  struct clk_ti_mux_priv {
>  	struct clk_bulk parents;
> @@ -23,30 +24,6 @@ struct clk_ti_mux_priv {
>  	s32 latch;
>  };
>  
> -static void clk_ti_mux_rmw(u32 val, u32 mask, fdt_addr_t reg)
> -{
> -	u32 v;
> -
> -	v = readl(reg);
> -	v &= ~mask;
> -	v |= val;
> -	writel(v, reg);
> -}
> -
> -static void clk_ti_mux_latch(fdt_addr_t reg, s8 shift)
> -{
> -	u32 latch;
> -
> -	if (shift < 0)
> -		return;
> -
> -	latch = 1 << shift;
> -
> -	clk_ti_mux_rmw(latch, latch, reg);
> -	clk_ti_mux_rmw(0, latch, reg);
> -	readl(reg);		/* OCP barrier */
> -}
> -
>  static struct clk *clk_ti_mux_get_parent_by_index(struct clk_bulk *parents,
>  						  int index)
>  {
> @@ -119,7 +96,7 @@ static int clk_ti_mux_set_parent(struct clk *clk, struct clk *parent)
>  
>  	val |= index << priv->shift;
>  	writel(val, priv->reg);
> -	clk_ti_mux_latch(priv->reg, priv->latch);
> +	clk_ti_latch(priv->reg, priv->latch);
>  	return 0;
>  }
>  
> diff --git a/drivers/clk/clk-ti.c b/drivers/clk/clk-ti.c
> new file mode 100644
> index 0000000000..594ef75270
> --- /dev/null
> +++ b/drivers/clk/clk-ti.c
> @@ -0,0 +1,34 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * TI clock utilities
> + *
> + * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
> + */
> +
> +#include <common.h>
> +#include <asm/io.h>
> +#include "clk-ti.h"
> +
> +static void clk_ti_rmw(u32 val, u32 mask, fdt_addr_t reg)
> +{
> +	u32 v;
> +
> +	v = readl(reg);
> +	v &= ~mask;
> +	v |= val;
> +	writel(v, reg);
> +}
> +
> +void clk_ti_latch(fdt_addr_t reg, s8 shift)
> +{
> +	u32 latch;
> +
> +	if (shift < 0)
> +		return;
> +
> +	latch = 1 << shift;
> +
> +	clk_ti_rmw(latch, latch, reg);
> +	clk_ti_rmw(0, latch, reg);
> +	readl(reg);		/* OCP barrier */
> +}
> diff --git a/drivers/clk/clk-ti.h b/drivers/clk/clk-ti.h
> new file mode 100644
> index 0000000000..601c3823f7
> --- /dev/null
> +++ b/drivers/clk/clk-ti.h
> @@ -0,0 +1,13 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * TI clock utilities header
> + *
> + * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
> + */
> +
> +#ifndef _CLK_TI_H
> +#define _CLK_TI_H
> +
> +void clk_ti_latch(fdt_addr_t reg, s8 shift);
> +
> +#endif /* #ifndef _CLK_TI_H */
> 

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 18/31] misc: am33xx: add control module driver
  2020-09-03  6:31   ` Lokesh Vutla
@ 2020-09-05 10:41     ` Dario Binacchi
  0 siblings, 0 replies; 43+ messages in thread
From: Dario Binacchi @ 2020-09-05 10:41 UTC (permalink / raw)
  To: u-boot

Hi Lokesh,

> Il 03/09/2020 08:31 Lokesh Vutla <lokeshvutla@ti.com> ha scritto:
> 
>  
> On 25/08/20 2:51 pm, Dario Binacchi wrote:
> > The implementation of this driver was needed to bind the device tree
> > sub-nodes of the 'clocks' node. In fact, the lack of the compatible
> > property in the 'clocks' node does not allow the generic 'syscon' or
> > 'simple-bus' drivers linked to the 'scm_conf at 0' node to bind the
> > 'clocks' node and in turn its sub-nodes.
> > The 'scm at 210000' node is therefore the node closest to the 'clocks' node
> > whose driver can bind all the 'clocks' sub-nodes.
> > 
> > scm: scm at 210000 {
> > 	compatible = "ti,am3-scm", "simple-bus";
> > 	...
> > 
> > 	scm_conf: scm_conf at 0 {
> > 		compatible = "syscon", "simple-bus";
> > 		#address-cells = <1>;
> > 		#size-cells = <1>;
> > 		ranges = <0 0 0x800>;
> > 
> > 		scm_clocks: clocks {
> > 			#address-cells = <1>;
> > 			#size-cells = <0>;
> > 		};
> > 	};
> > };
> > 
> > Signed-off-by: Dario Binacchi <dariobin@libero.it>
> > ---
> > 
> >  doc/device-tree-bindings/arm/omap,ctrl.txt    |  82 ++++++
> >  .../pinctrl/pinctrl-single.txt                | 255 ++++++++++++++++++
> 
> This documentation does not belong to this patch.

The omap,ctrl.txt file references to the pinctrl-single.txt document.
I thought it was better to add it rather than remove that
reference from the omap,ctrl.txt file.

> 
> >  drivers/misc/Kconfig                          |   7 +
> >  drivers/misc/Makefile                         |   1 +
> >  drivers/misc/ti-am3-scm.c                     |  90 +++++++
> >  5 files changed, 435 insertions(+)
> >  create mode 100644 doc/device-tree-bindings/arm/omap,ctrl.txt
> >  create mode 100644 doc/device-tree-bindings/pinctrl/pinctrl-single.txt
> >  create mode 100644 drivers/misc/ti-am3-scm.c
> > 
> > diff --git a/doc/device-tree-bindings/arm/omap,ctrl.txt b/doc/device-tree-bindings/arm/omap,ctrl.txt
> > new file mode 100644
> > index 0000000000..8efd321cfa
> > --- /dev/null
> > +++ b/doc/device-tree-bindings/arm/omap,ctrl.txt
> > @@ -0,0 +1,82 @@
> > +OMAP Control Module bindings
> > +
> > +Control Module contains miscellaneous features under it based on SoC type.
> > +Pincontrol is one common feature, and it has a specialized support
> > +described in [1]. Typically some clock nodes are also under control module.
> > +Syscon is used to share register level access to drivers external to
> > +control module driver itself.
> > +
> > +See [2] for documentation about clock/clockdomain nodes.
> > +
> > +[1] doc/device-tree-bindings/pinctrl/pinctrl-single.txt
> > +[2] doc/device-tree-bindings/clock/ti,*.txt
> > +
> > +Required properties:
> > +- compatible:	Must be one of:
> > +		"ti,am3-scm"
> > +		"ti,am4-scm"
> > +		"ti,dm814-scrm"
> > +		"ti,dm816-scrm"
> > +		"ti,omap2-scm"
> > +		"ti,omap3-scm"
> > +		"ti,omap4-scm-core"
> > +		"ti,omap4-scm-padconf-core"
> > +		"ti,omap4-scm-wkup"
> > +		"ti,omap4-scm-padconf-wkup"
> > +		"ti,omap5-scm-core"
> > +		"ti,omap5-scm-padconf-core"
> > +		"ti,omap5-scm-wkup-pad-conf"
> > +		"ti,dra7-scm-core"
> > +- reg:		Contains Control Module register address range
> > +		(base address and length)
> > +
> > +Optional properties:
> > +- clocks:	clocks for this module
> > +- clockdomains:	clockdomains for this module
> > +
> > +Examples:
> > +
> > +scm: scm at 2000 {
> > +	compatible = "ti,omap3-scm", "simple-bus";
> > +	reg = <0x2000 0x2000>;
> > +	#address-cells = <1>;
> > +	#size-cells = <1>;
> > +	ranges = <0 0x2000 0x2000>;
> > +
> > +	omap3_pmx_core: pinmux at 30 {
> > +		compatible = "ti,omap3-padconf",
> > +			     "pinctrl-single";
> > +		reg = <0x30 0x230>;
> > +		#address-cells = <1>;
> > +		#size-cells = <0>;
> > +		#interrupt-cells = <1>;
> > +		interrupt-controller;
> > +		pinctrl-single,register-width = <16>;
> > +		pinctrl-single,function-mask = <0xff1f>;
> > +	};
> > +
> > +	scm_conf: scm_conf at 270 {
> > +		compatible = "syscon";
> > +		reg = <0x270 0x330>;
> > +		#address-cells = <1>;
> > +		#size-cells = <1>;
> > +
> > +		scm_clocks: clocks {
> > +			#address-cells = <1>;
> > +			#size-cells = <0>;
> > +		};
> > +	};
> > +
> > +	scm_clockdomains: clockdomains {
> > +	};
> > +}
> > +
> > +&scm_clocks {
> > +	mcbsp5_mux_fck: mcbsp5_mux_fck {
> > +		#clock-cells = <0>;
> > +		compatible = "ti,composite-mux-clock";
> > +		clocks = <&core_96m_fck>, <&mcbsp_clks>;
> > +		ti,bit-shift = <4>;
> > +		reg = <0x02d8>;
> > +	};
> > +};
> 
> [...snip...]
> 
> 
> > diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> > index b67e906a76..9e8b676637 100644
> > --- a/drivers/misc/Kconfig
> > +++ b/drivers/misc/Kconfig
> > @@ -500,4 +500,11 @@ config ESM_PMIC
> >  	  Support ESM (Error Signal Monitor) on PMIC devices. ESM is used
> >  	  typically to reboot the board in error condition.
> >  
> > +config TI_AM3_SCM
> > +	bool "AM33XX specific control module support (SCM)"
> > +	depends on ARCH_OMAP2PLUS
> > +	help
> > +	 The control module includes status and control logic not addressed
> > +	 within the peripherals or the rest of the device infrastructure.
> > +
> >  endmenu
> > diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> > index 947bd3a647..056fb3b522 100644
> > --- a/drivers/misc/Makefile
> > +++ b/drivers/misc/Makefile
> > @@ -75,3 +75,4 @@ obj-$(CONFIG_MICROCHIP_FLEXCOM) += microchip_flexcom.o
> >  obj-$(CONFIG_K3_AVS0) += k3_avs.o
> >  obj-$(CONFIG_ESM_K3) += k3_esm.o
> >  obj-$(CONFIG_ESM_PMIC) += esm_pmic.o
> > +obj-$(CONFIG_TI_AM3_SCM) += ti-am3-scm.o
> > diff --git a/drivers/misc/ti-am3-scm.c b/drivers/misc/ti-am3-scm.c
> > new file mode 100644
> > index 0000000000..e5f4f09261
> > --- /dev/null
> > +++ b/drivers/misc/ti-am3-scm.c
> > @@ -0,0 +1,90 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * AM335x specific control module (scm)
> > + *
> > + * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
> > + */
> > +
> > +#include <common.h>
> > +#include <dm.h>
> > +#include <dm/lists.h>
> > +#include <linux/err.h>
> > +
> > +static int ti_am3_scm_bind(struct udevice *dev)
> > +{
> > +	int err;
> > +	struct udevice *conf_dev;
> > +	ofnode clocks_node, conf_node;
> > +
> > +	err = dm_scan_fdt_dev(dev);
> > +	if (err) {
> > +		dev_err(dev, "%s: dm_scan_fdt, err=%d\n", __func__, err);
> > +		return err;
> > +	}
> > +
> > +	conf_node = dev_read_subnode(dev, "scm_conf at 0");
> > +	if (!ofnode_valid(conf_node)) {
> > +		dev_err(dev, "%s: failed to get conf sub-node\n", __func__);
> > +		return -ENODEV;
> > +	}
> > +
> > +	if (uclass_get_device_by_ofnode(UCLASS_SYSCON, conf_node, &conf_dev)) {
> > +		if (uclass_get_device_by_ofnode(UCLASS_SIMPLE_BUS, conf_node,
> > +						&conf_dev)) {
> > +			dev_err(dev, "%s: failed to get conf device\n",
> > +				__func__);
> > +			return -ENODEV;
> > +		}
> > +	}
> > +
> > +	clocks_node = dev_read_subnode(conf_dev, "clocks");
> > +	if (!ofnode_valid(clocks_node)) {
> > +		dev_err(dev, "%s: failed to get clocks sub-node\n", __func__);
> > +		return -ENODEV;
> > +	}
> 
> Isn't clock node an optional property?
> 
> Also do we really need a separate UBOOT_DRIVER for scm_clocks? Can it be handled
> in the same driver?
> 
In the next version of the series, scm_clocks will be handled
by the same driver.

Regards,
Dario

> Thanks and regards,
> Lokesh
> 
> > +
> > +	err = device_bind_driver_to_node(conf_dev, "ti_am3_scm_clocks",
> > +					 "scm_clocks", clocks_node, NULL);
> > +	if (err) {
> > +		dev_err(dev, "%s: failed to bind scm_clocks\n", __func__);
> > +		return err;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct udevice_id ti_am3_scm_ids[] = {
> > +	{.compatible = "ti,am3-scm"},
> > +	{}
> > +};
> > +
> > +U_BOOT_DRIVER(ti_am3_scm) = {
> > +	.name = "ti_am3_scm",
> > +	.id = UCLASS_SIMPLE_BUS,
> > +	.of_match = ti_am3_scm_ids,
> > +	.bind = ti_am3_scm_bind,
> > +};
> > +
> > +static int ti_am3_scm_clocks_bind(struct udevice *dev)
> > +{
> > +	ofnode node;
> > +	int err;
> > +
> > +	dev_dbg(dev, "%s: dev=%p\n", __func__, dev);
> > +	ofnode_for_each_subnode(node, dev_ofnode(dev)) {
> > +		err = lists_bind_fdt(dev, node, NULL, false);
> > +		if (err) {
> > +			dev_err(dev, "%s: lists_bind_fdt, err=%d\n",
> > +				__func__, err);
> > +			return err;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +U_BOOT_DRIVER(ti_am3_scm_clocks) = {
> > +	.name = "ti_am3_scm_clocks",
> > +	.id = UCLASS_SIMPLE_BUS,
> > +	.bind = ti_am3_scm_clocks_bind,
> > +};
> >

^ permalink raw reply	[flat|nested] 43+ messages in thread

end of thread, other threads:[~2020-09-05 10:41 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-25  9:20 [PATCH 00/31] Add DM support for omap PWM backlight Dario Binacchi
2020-08-25  9:20 ` [PATCH 01/31] clk: remove a redundant header Dario Binacchi
2020-08-28 23:36   ` Simon Glass
2020-08-25  9:20 ` [PATCH 02/31] clk: export generic routines Dario Binacchi
2020-08-28 23:36   ` Simon Glass
2020-08-25  9:20 ` [PATCH 03/31] arch: sandbox: fix typo in clk.h Dario Binacchi
2020-08-29 21:20   ` Simon Glass
2020-08-25  9:20 ` [PATCH 04/31] clk: add clk_round_rate() Dario Binacchi
2020-08-29 21:20   ` Simon Glass
2020-08-29 21:48     ` Sean Anderson
2020-08-29 21:50       ` Sean Anderson
2020-08-31 16:29         ` Dario Binacchi
2020-08-25  9:20 ` [PATCH 05/31] clk: ti: add mux clock driver Dario Binacchi
2020-08-25  9:20 ` [PATCH 06/31] arm: ti: am33xx: add DPLL_EN_FAST_RELOCK_BYPASS macro Dario Binacchi
2020-08-25  9:21 ` [PATCH 07/31] clk: ti: am33xx: add DPLL clock drivers Dario Binacchi
2020-08-25  9:21 ` [PATCH 08/31] clk: ti: add divider clock driver Dario Binacchi
2020-08-25  9:21 ` [PATCH 09/31] clk: ti: refactor mux and divider clock drivers Dario Binacchi
2020-09-03  6:34   ` Lokesh Vutla
2020-08-25  9:21 ` [PATCH 10/31] clk: ti: add gate clock driver Dario Binacchi
2020-08-25  9:21 ` [PATCH 11/31] ti: am33xx: fix do_enable_clocks() to accept NULL parameters Dario Binacchi
2020-08-29 21:20   ` Simon Glass
2020-08-25  9:21 ` [PATCH 12/31] clk: ti: add support for clkctrl clocks Dario Binacchi
2020-08-25  9:21 ` [PATCH 13/31] clk: ti: move drivers to 'ti' directory Dario Binacchi
2020-08-25  9:21 ` [PATCH 14/31] clk: ti: omap4: add clock manager driver Dario Binacchi
2020-08-25  9:21 ` [PATCH 15/31] clk: ti: am335x: " Dario Binacchi
2020-08-25  9:21 ` [PATCH 16/31] fdt: translate address if #size-cells = <0> Dario Binacchi
2020-08-29 21:20   ` Simon Glass
2020-08-25  9:21 ` [PATCH 17/31] omap: timer: fix the rate setting Dario Binacchi
2020-08-25  9:21 ` [PATCH 18/31] misc: am33xx: add control module driver Dario Binacchi
2020-09-03  6:31   ` Lokesh Vutla
2020-09-05 10:41     ` Dario Binacchi
2020-08-25  9:21 ` [PATCH 19/31] pwm: ti: am33xx: add enhanced pwm driver Dario Binacchi
2020-08-25  9:21 ` [PATCH 20/31] pwm: ti: am33xx: add subsystem driver Dario Binacchi
2020-08-25  9:21 ` [PATCH 21/31] video: backlight: fix pwm's duty cycle calculation Dario Binacchi
2020-08-29 21:20   ` Simon Glass
2020-08-25  9:21 ` [PATCH 22/31] video: backlight: fix pwm data structure description Dario Binacchi
2020-08-25  9:21 ` [PATCH 23/31] dm: core: improve uclass_get_device_by_phandle_id() description Dario Binacchi
2020-08-29 21:20   ` Simon Glass
2020-08-25  9:21 ` [PATCH 24/31] gpio: fix gpio_request_by_name() description Dario Binacchi
2020-08-29 21:20   ` Simon Glass
2020-08-25  9:21 ` [PATCH 25/31] dm: core: add a function to decode display timings Dario Binacchi
2020-08-29 21:20   ` Simon Glass
2020-08-25  9:21 ` [PATCH 26/31] video: omap: add panel driver Dario Binacchi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.