Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH 1/2 v4] ARM: dts: i.MX25: add AIPS control registers
From: Shawn Guo @ 2017-04-04 13:13 UTC (permalink / raw)
  To: Martin Kaiser
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Sascha Hauer,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1491248825-23041-1-git-send-email-martin-XxZfDwE/svGeZLLa646FqQ@public.gmane.org>

On Mon, Apr 03, 2017 at 09:47:04PM +0200, Martin Kaiser wrote:
> The i.MX25 contains two AHB to IP bridges (AIPS), each of which has a set of
> control registers. Add the memory regions for the control registers to
> the Device Tree.
> 
> Signed-off-by: Martin Kaiser <martin-XxZfDwE/svGeZLLa646FqQ@public.gmane.org>
> Reviewed-by: Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>

Applied, thanks.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 2/3] Documentation: DT: Add entry for FSL LS1088A RDB, QDS boards
From: Shawn Guo @ 2017-04-04 12:59 UTC (permalink / raw)
  To: Harninder Rai
  Cc: Rob Herring, oss-fOR+EgIDQEHk1uMJSBkQmQ@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Stuart Yoder,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
In-Reply-To: <VI1PR0402MB2863D1744E831A8B300580D3E65A0-9IDQY6o3qQh11F+3UnuzFY3W/0Ik+aLCnBOFsp37pqbUKgpGm//BTAC/G2K4zDHf@public.gmane.org>

On Thu, Feb 16, 2017 at 07:44:51AM +0000, Harninder Rai wrote:
> > 
> > Some consistency in the subject please "dt-bindings: arm: ..."
> Thanks Rob.
> 
> Hello Shawn,
> 
> Would you please take care of the subject line while applying the patch or should I send another revision?

Applied 1/3 and this one with subject fixed as suggested.

Shawn
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH linux v6 2/2] drivers: hwmon: Support for ASPEED PWM/Fan tach
From: Guenter Roeck @ 2017-04-04 12:55 UTC (permalink / raw)
  To: Jaghathiswari Rankappagounder Natarajan, joel, jdelvare,
	linux-hwmon, linux-kernel, openbmc, corbet, linux-doc, robh+dt,
	mark.rutland, devicetree
In-Reply-To: <20170403233025.26952-3-jaghu@google.com>

On 04/03/2017 04:30 PM, Jaghathiswari Rankappagounder Natarajan wrote:
> The ASPEED AST2400/2500 PWM controller supports 8 PWM output ports.
> The ASPEED AST2400/2500 Fan tach controller supports 16 tachometer
> inputs.
> The device driver matches on the device tree node. The configuration
> values are read from the device tree and written to the respective registers.
> The driver provides a sysfs entries through which the user can
> configure the duty-cycle value (ranging from 0 to 100 percent) and read
> the fan tach rpm value.
>
> Signed-off-by: Jaghathiswari Rankappagounder Natarajan <jaghu@google.com>

Applied.

Thanks,
Guenter

> ---
>  v6
> - Corrected odd line breaks
> - Changed upto to up to
> - Dropped unrelated changes
> - Removed struct and used regs pointer directly
> - Made groups to be null terminated
> - Made correction in calculation of val/raw_data
> - Removed else after return
> - Removed unnecessary continuation lines
>
>  v5:
> - Changed the driver to suit the changes in the device tree documentation
>
>  v4:
> - Modified this driver to suit the representation in the devicetree
>
>  v3:
> - Only sent out device tree documentation; did not send this driver
>
>  v2:
> - Used BIT()
> - Used regmap
> - Avoided division when raw data is 0
> - Removed empty lines between declaration
> - Removed macros; Used two attribute groups and used is_visible callback
> - Returned error when properties are undefined
> - Removed .owner field
> - Used PTR_ERR_OR_ZERO
> - Removed explicit of_node_put for child nodes
>
>  Documentation/hwmon/aspeed-pwm-tacho |  22 +
>  drivers/hwmon/Kconfig                |   9 +
>  drivers/hwmon/Makefile               |   1 +
>  drivers/hwmon/aspeed-pwm-tacho.c     | 846 +++++++++++++++++++++++++++++++++++
>  4 files changed, 878 insertions(+)
>  create mode 100644 Documentation/hwmon/aspeed-pwm-tacho
>  create mode 100644 drivers/hwmon/aspeed-pwm-tacho.c
>
> diff --git a/Documentation/hwmon/aspeed-pwm-tacho b/Documentation/hwmon/aspeed-pwm-tacho
> new file mode 100644
> index 000000000000..7cfb34977460
> --- /dev/null
> +++ b/Documentation/hwmon/aspeed-pwm-tacho
> @@ -0,0 +1,22 @@
> +Kernel driver aspeed-pwm-tacho
> +==============================
> +
> +Supported chips:
> +	ASPEED AST2400/2500
> +
> +Authors:
> +	<jaghu@google.com>
> +
> +Description:
> +------------
> +This driver implements support for ASPEED AST2400/2500 PWM and Fan Tacho
> +controller. The PWM controller supports upto 8 PWM outputs. The Fan tacho
> +controller supports up to 16 tachometer inputs.
> +
> +The driver provides the following sensor accesses in sysfs:
> +
> +fanX_input	ro	provide current fan rotation value in RPM as reported
> +			by the fan to the device.
> +
> +pwmX		rw	get or set PWM fan control value. This is an integer
> +			value between 0(off) and 255(full speed).
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index 45cef3d2c75c..757b5b0705bf 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -341,6 +341,15 @@ config SENSORS_ASB100
>  	  This driver can also be built as a module.  If so, the module
>  	  will be called asb100.
>
> +config SENSORS_ASPEED
> +	tristate "ASPEED AST2400/AST2500 PWM and Fan tach driver"
> +	help
> +	  This driver provides support for ASPEED AST2400/AST2500 PWM
> +	  and Fan Tacho controllers.
> +
> +	  This driver can also be built as a module. If so, the module
> +	  will be called aspeed_pwm_tacho.
> +
>  config SENSORS_ATXP1
>  	tristate "Attansic ATXP1 VID controller"
>  	depends on I2C
> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> index aecf4ba17460..83025cc9bb45 100644
> --- a/drivers/hwmon/Makefile
> +++ b/drivers/hwmon/Makefile
> @@ -46,6 +46,7 @@ obj-$(CONFIG_SENSORS_ADT7475)	+= adt7475.o
>  obj-$(CONFIG_SENSORS_APPLESMC)	+= applesmc.o
>  obj-$(CONFIG_SENSORS_ARM_SCPI)	+= scpi-hwmon.o
>  obj-$(CONFIG_SENSORS_ASC7621)	+= asc7621.o
> +obj-$(CONFIG_SENSORS_ASPEED)	+= aspeed-pwm-tacho.o
>  obj-$(CONFIG_SENSORS_ATXP1)	+= atxp1.o
>  obj-$(CONFIG_SENSORS_CORETEMP)	+= coretemp.o
>  obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o
> diff --git a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c
> new file mode 100644
> index 000000000000..29010ad94208
> --- /dev/null
> +++ b/drivers/hwmon/aspeed-pwm-tacho.c
> @@ -0,0 +1,846 @@
> +/*
> + * Copyright (c) 2016 Google, Inc
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 or later as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/delay.h>
> +#include <linux/hwmon.h>
> +#include <linux/hwmon-sysfs.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/sysfs.h>
> +#include <linux/regmap.h>
> +
> +/* ASPEED PWM & FAN Tach Register Definition */
> +#define ASPEED_PTCR_CTRL		0x00
> +#define ASPEED_PTCR_CLK_CTRL		0x04
> +#define ASPEED_PTCR_DUTY0_CTRL		0x08
> +#define ASPEED_PTCR_DUTY1_CTRL		0x0c
> +#define ASPEED_PTCR_TYPEM_CTRL		0x10
> +#define ASPEED_PTCR_TYPEM_CTRL1		0x14
> +#define ASPEED_PTCR_TYPEN_CTRL		0x18
> +#define ASPEED_PTCR_TYPEN_CTRL1		0x1c
> +#define ASPEED_PTCR_TACH_SOURCE		0x20
> +#define ASPEED_PTCR_TRIGGER		0x28
> +#define ASPEED_PTCR_RESULT		0x2c
> +#define ASPEED_PTCR_INTR_CTRL		0x30
> +#define ASPEED_PTCR_INTR_STS		0x34
> +#define ASPEED_PTCR_TYPEM_LIMIT		0x38
> +#define ASPEED_PTCR_TYPEN_LIMIT		0x3C
> +#define ASPEED_PTCR_CTRL_EXT		0x40
> +#define ASPEED_PTCR_CLK_CTRL_EXT	0x44
> +#define ASPEED_PTCR_DUTY2_CTRL		0x48
> +#define ASPEED_PTCR_DUTY3_CTRL		0x4c
> +#define ASPEED_PTCR_TYPEO_CTRL		0x50
> +#define ASPEED_PTCR_TYPEO_CTRL1		0x54
> +#define ASPEED_PTCR_TACH_SOURCE_EXT	0x60
> +#define ASPEED_PTCR_TYPEO_LIMIT		0x78
> +
> +/* ASPEED_PTCR_CTRL : 0x00 - General Control Register */
> +#define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART1	15
> +#define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART2	6
> +#define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_MASK	(BIT(7) | BIT(15))
> +
> +#define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART1	14
> +#define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART2	5
> +#define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_MASK	(BIT(6) | BIT(14))
> +
> +#define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART1	13
> +#define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART2	4
> +#define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_MASK	(BIT(5) | BIT(13))
> +
> +#define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART1	12
> +#define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART2	3
> +#define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_MASK	(BIT(4) | BIT(12))
> +
> +#define	ASPEED_PTCR_CTRL_FAN_NUM_EN(x)	BIT(16 + (x))
> +
> +#define	ASPEED_PTCR_CTRL_PWMD_EN	BIT(11)
> +#define	ASPEED_PTCR_CTRL_PWMC_EN	BIT(10)
> +#define	ASPEED_PTCR_CTRL_PWMB_EN	BIT(9)
> +#define	ASPEED_PTCR_CTRL_PWMA_EN	BIT(8)
> +
> +#define	ASPEED_PTCR_CTRL_CLK_SRC	BIT(1)
> +#define	ASPEED_PTCR_CTRL_CLK_EN		BIT(0)
> +
> +/* ASPEED_PTCR_CLK_CTRL : 0x04 - Clock Control Register */
> +/* TYPE N */
> +#define ASPEED_PTCR_CLK_CTRL_TYPEN_MASK		GENMASK(31, 16)
> +#define ASPEED_PTCR_CLK_CTRL_TYPEN_UNIT		24
> +#define ASPEED_PTCR_CLK_CTRL_TYPEN_H		20
> +#define ASPEED_PTCR_CLK_CTRL_TYPEN_L		16
> +/* TYPE M */
> +#define ASPEED_PTCR_CLK_CTRL_TYPEM_MASK         GENMASK(15, 0)
> +#define ASPEED_PTCR_CLK_CTRL_TYPEM_UNIT		8
> +#define ASPEED_PTCR_CLK_CTRL_TYPEM_H		4
> +#define ASPEED_PTCR_CLK_CTRL_TYPEM_L		0
> +
> +/*
> + * ASPEED_PTCR_DUTY_CTRL/1/2/3 : 0x08/0x0C/0x48/0x4C - PWM-FAN duty control
> + * 0/1/2/3 register
> + */
> +#define DUTY_CTRL_PWM2_FALL_POINT	24
> +#define DUTY_CTRL_PWM2_RISE_POINT	16
> +#define DUTY_CTRL_PWM2_RISE_FALL_MASK	GENMASK(31, 16)
> +#define DUTY_CTRL_PWM1_FALL_POINT	8
> +#define DUTY_CTRL_PWM1_RISE_POINT	0
> +#define DUTY_CTRL_PWM1_RISE_FALL_MASK   GENMASK(15, 0)
> +
> +/* ASPEED_PTCR_TYPEM_CTRL : 0x10/0x18/0x50 - Type M/N/O Ctrl 0 Register */
> +#define TYPE_CTRL_FAN_MASK		(GENMASK(5, 1) | GENMASK(31, 16))
> +#define TYPE_CTRL_FAN1_MASK		GENMASK(31, 0)
> +#define TYPE_CTRL_FAN_PERIOD		16
> +#define TYPE_CTRL_FAN_MODE		4
> +#define TYPE_CTRL_FAN_DIVISION		1
> +#define TYPE_CTRL_FAN_TYPE_EN		1
> +
> +/* ASPEED_PTCR_TACH_SOURCE : 0x20/0x60 - Tach Source Register */
> +/* bit [0,1] at 0x20, bit [2] at 0x60 */
> +#define TACH_PWM_SOURCE_BIT01(x)	((x) * 2)
> +#define TACH_PWM_SOURCE_BIT2(x)		((x) * 2)
> +#define TACH_PWM_SOURCE_MASK_BIT01(x)	(0x3 << ((x) * 2))
> +#define TACH_PWM_SOURCE_MASK_BIT2(x)	BIT((x) * 2)
> +
> +/* ASPEED_PTCR_RESULT : 0x2c - Result Register */
> +#define RESULT_STATUS_MASK		BIT(31)
> +#define RESULT_VALUE_MASK		0xfffff
> +
> +/* ASPEED_PTCR_CTRL_EXT : 0x40 - General Control Extension #1 Register */
> +#define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART1	15
> +#define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART2	6
> +#define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_MASK	(BIT(7) | BIT(15))
> +
> +#define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART1	14
> +#define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART2	5
> +#define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_MASK	(BIT(6) | BIT(14))
> +
> +#define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART1	13
> +#define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART2	4
> +#define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_MASK	(BIT(5) | BIT(13))
> +
> +#define ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART1	12
> +#define ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART2	3
> +#define ASPEED_PTCR_CTRL_SET_PWME_TYPE_MASK	(BIT(4) | BIT(12))
> +
> +#define	ASPEED_PTCR_CTRL_PWMH_EN	BIT(11)
> +#define	ASPEED_PTCR_CTRL_PWMG_EN	BIT(10)
> +#define	ASPEED_PTCR_CTRL_PWMF_EN	BIT(9)
> +#define	ASPEED_PTCR_CTRL_PWME_EN	BIT(8)
> +
> +/* ASPEED_PTCR_CLK_EXT_CTRL : 0x44 - Clock Control Extension #1 Register */
> +/* TYPE O */
> +#define ASPEED_PTCR_CLK_CTRL_TYPEO_MASK         GENMASK(15, 0)
> +#define ASPEED_PTCR_CLK_CTRL_TYPEO_UNIT		8
> +#define ASPEED_PTCR_CLK_CTRL_TYPEO_H		4
> +#define ASPEED_PTCR_CLK_CTRL_TYPEO_L		0
> +
> +#define PWM_MAX 255
> +
> +#define M_PWM_DIV_H 0x00
> +#define M_PWM_DIV_L 0x05
> +#define M_PWM_PERIOD 0x5F
> +#define M_TACH_CLK_DIV 0x00
> +#define M_TACH_MODE 0x00
> +#define M_TACH_UNIT 0x1000
> +#define INIT_FAN_CTRL 0xFF
> +
> +void __iomem *regs;
> +
> +struct aspeed_pwm_tacho_data {
> +	struct regmap *regmap;
> +	unsigned long clk_freq;
> +	bool pwm_present[8];
> +	bool fan_tach_present[16];
> +	u8 type_pwm_clock_unit[3];
> +	u8 type_pwm_clock_division_h[3];
> +	u8 type_pwm_clock_division_l[3];
> +	u8 type_fan_tach_clock_division[3];
> +	u16 type_fan_tach_unit[3];
> +	u8 pwm_port_type[8];
> +	u8 pwm_port_fan_ctrl[8];
> +	u8 fan_tach_ch_source[16];
> +	const struct attribute_group *groups[3];
> +};
> +
> +enum type { TYPEM, TYPEN, TYPEO };
> +
> +struct type_params {
> +	u32 l_value;
> +	u32 h_value;
> +	u32 unit_value;
> +	u32 clk_ctrl_mask;
> +	u32 clk_ctrl_reg;
> +	u32 ctrl_reg;
> +	u32 ctrl_reg1;
> +};
> +
> +static const struct type_params type_params[] = {
> +	[TYPEM] = {
> +		.l_value = ASPEED_PTCR_CLK_CTRL_TYPEM_L,
> +		.h_value = ASPEED_PTCR_CLK_CTRL_TYPEM_H,
> +		.unit_value = ASPEED_PTCR_CLK_CTRL_TYPEM_UNIT,
> +		.clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEM_MASK,
> +		.clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL,
> +		.ctrl_reg = ASPEED_PTCR_TYPEM_CTRL,
> +		.ctrl_reg1 = ASPEED_PTCR_TYPEM_CTRL1,
> +	},
> +	[TYPEN] = {
> +		.l_value = ASPEED_PTCR_CLK_CTRL_TYPEN_L,
> +		.h_value = ASPEED_PTCR_CLK_CTRL_TYPEN_H,
> +		.unit_value = ASPEED_PTCR_CLK_CTRL_TYPEN_UNIT,
> +		.clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEN_MASK,
> +		.clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL,
> +		.ctrl_reg = ASPEED_PTCR_TYPEN_CTRL,
> +		.ctrl_reg1 = ASPEED_PTCR_TYPEN_CTRL1,
> +	},
> +	[TYPEO] = {
> +		.l_value = ASPEED_PTCR_CLK_CTRL_TYPEO_L,
> +		.h_value = ASPEED_PTCR_CLK_CTRL_TYPEO_H,
> +		.unit_value = ASPEED_PTCR_CLK_CTRL_TYPEO_UNIT,
> +		.clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEO_MASK,
> +		.clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL_EXT,
> +		.ctrl_reg = ASPEED_PTCR_TYPEO_CTRL,
> +		.ctrl_reg1 = ASPEED_PTCR_TYPEO_CTRL1,
> +	}
> +};
> +
> +enum pwm_port { PWMA, PWMB, PWMC, PWMD, PWME, PWMF, PWMG, PWMH };
> +
> +struct pwm_port_params {
> +	u32 pwm_en;
> +	u32 ctrl_reg;
> +	u32 type_part1;
> +	u32 type_part2;
> +	u32 type_mask;
> +	u32 duty_ctrl_rise_point;
> +	u32 duty_ctrl_fall_point;
> +	u32 duty_ctrl_reg;
> +	u32 duty_ctrl_rise_fall_mask;
> +};
> +
> +static const struct pwm_port_params pwm_port_params[] = {
> +	[PWMA] = {
> +		.pwm_en = ASPEED_PTCR_CTRL_PWMA_EN,
> +		.ctrl_reg = ASPEED_PTCR_CTRL,
> +		.type_part1 = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART1,
> +		.type_part2 = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART2,
> +		.type_mask = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_MASK,
> +		.duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT,
> +		.duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT,
> +		.duty_ctrl_reg = ASPEED_PTCR_DUTY0_CTRL,
> +		.duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK,
> +	},
> +	[PWMB] = {
> +		.pwm_en = ASPEED_PTCR_CTRL_PWMB_EN,
> +		.ctrl_reg = ASPEED_PTCR_CTRL,
> +		.type_part1 = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART1,
> +		.type_part2 = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART2,
> +		.type_mask = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_MASK,
> +		.duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT,
> +		.duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT,
> +		.duty_ctrl_reg = ASPEED_PTCR_DUTY0_CTRL,
> +		.duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK,
> +	},
> +	[PWMC] = {
> +		.pwm_en = ASPEED_PTCR_CTRL_PWMC_EN,
> +		.ctrl_reg = ASPEED_PTCR_CTRL,
> +		.type_part1 = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART1,
> +		.type_part2 = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART2,
> +		.type_mask = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_MASK,
> +		.duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT,
> +		.duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT,
> +		.duty_ctrl_reg = ASPEED_PTCR_DUTY1_CTRL,
> +		.duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK,
> +	},
> +	[PWMD] = {
> +		.pwm_en = ASPEED_PTCR_CTRL_PWMD_EN,
> +		.ctrl_reg = ASPEED_PTCR_CTRL,
> +		.type_part1 = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART1,
> +		.type_part2 = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART2,
> +		.type_mask = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_MASK,
> +		.duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT,
> +		.duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT,
> +		.duty_ctrl_reg = ASPEED_PTCR_DUTY1_CTRL,
> +		.duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK,
> +	},
> +	[PWME] = {
> +		.pwm_en = ASPEED_PTCR_CTRL_PWME_EN,
> +		.ctrl_reg = ASPEED_PTCR_CTRL_EXT,
> +		.type_part1 = ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART1,
> +		.type_part2 = ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART2,
> +		.type_mask = ASPEED_PTCR_CTRL_SET_PWME_TYPE_MASK,
> +		.duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT,
> +		.duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT,
> +		.duty_ctrl_reg = ASPEED_PTCR_DUTY2_CTRL,
> +		.duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK,
> +	},
> +	[PWMF] = {
> +		.pwm_en = ASPEED_PTCR_CTRL_PWMF_EN,
> +		.ctrl_reg = ASPEED_PTCR_CTRL_EXT,
> +		.type_part1 = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART1,
> +		.type_part2 = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART2,
> +		.type_mask = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_MASK,
> +		.duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT,
> +		.duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT,
> +		.duty_ctrl_reg = ASPEED_PTCR_DUTY2_CTRL,
> +		.duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK,
> +	},
> +	[PWMG] = {
> +		.pwm_en = ASPEED_PTCR_CTRL_PWMG_EN,
> +		.ctrl_reg = ASPEED_PTCR_CTRL_EXT,
> +		.type_part1 = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART1,
> +		.type_part2 = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART2,
> +		.type_mask = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_MASK,
> +		.duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT,
> +		.duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT,
> +		.duty_ctrl_reg = ASPEED_PTCR_DUTY3_CTRL,
> +		.duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK,
> +	},
> +	[PWMH] = {
> +		.pwm_en = ASPEED_PTCR_CTRL_PWMH_EN,
> +		.ctrl_reg = ASPEED_PTCR_CTRL_EXT,
> +		.type_part1 = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART1,
> +		.type_part2 = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART2,
> +		.type_mask = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_MASK,
> +		.duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT,
> +		.duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT,
> +		.duty_ctrl_reg = ASPEED_PTCR_DUTY3_CTRL,
> +		.duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK,
> +	}
> +};
> +
> +static int regmap_aspeed_pwm_tacho_reg_write(void *context, unsigned int reg,
> +					     unsigned int val)
> +{
> +	void __iomem *regs = context;
> +
> +	writel(val, regs + reg);
> +	return 0;
> +}
> +
> +static int regmap_aspeed_pwm_tacho_reg_read(void *context, unsigned int reg,
> +					    unsigned int *val)
> +{
> +	void __iomem *regs = context;
> +
> +	*val = readl(regs + reg);
> +	return 0;
> +}
> +
> +static const struct regmap_config aspeed_pwm_tacho_regmap_config = {
> +	.reg_bits = 32,
> +	.val_bits = 32,
> +	.reg_stride = 4,
> +	.max_register = ASPEED_PTCR_TYPEO_LIMIT,
> +	.reg_write = regmap_aspeed_pwm_tacho_reg_write,
> +	.reg_read = regmap_aspeed_pwm_tacho_reg_read,
> +	.fast_io = true,
> +};
> +
> +static void aspeed_set_clock_enable(struct regmap *regmap, bool val)
> +{
> +	regmap_update_bits(regmap, ASPEED_PTCR_CTRL,
> +			   ASPEED_PTCR_CTRL_CLK_EN,
> +			   val ? ASPEED_PTCR_CTRL_CLK_EN : 0);
> +}
> +
> +static void aspeed_set_clock_source(struct regmap *regmap, int val)
> +{
> +	regmap_update_bits(regmap, ASPEED_PTCR_CTRL,
> +			   ASPEED_PTCR_CTRL_CLK_SRC,
> +			   val ? ASPEED_PTCR_CTRL_CLK_SRC : 0);
> +}
> +
> +static void aspeed_set_pwm_clock_values(struct regmap *regmap, u8 type,
> +					u8 div_high, u8 div_low, u8 unit)
> +{
> +	u32 reg_value = ((div_high << type_params[type].h_value) |
> +			 (div_low << type_params[type].l_value) |
> +			 (unit << type_params[type].unit_value));
> +
> +	regmap_update_bits(regmap, type_params[type].clk_ctrl_reg,
> +			   type_params[type].clk_ctrl_mask, reg_value);
> +}
> +
> +static void aspeed_set_pwm_port_enable(struct regmap *regmap, u8 pwm_port,
> +				       bool enable)
> +{
> +	regmap_update_bits(regmap, pwm_port_params[pwm_port].ctrl_reg,
> +			   pwm_port_params[pwm_port].pwm_en,
> +			   enable ? pwm_port_params[pwm_port].pwm_en : 0);
> +}
> +
> +static void aspeed_set_pwm_port_type(struct regmap *regmap,
> +				     u8 pwm_port, u8 type)
> +{
> +	u32 reg_value = (type & 0x1) << pwm_port_params[pwm_port].type_part1;
> +
> +	reg_value |= (type & 0x2) << pwm_port_params[pwm_port].type_part2;
> +
> +	regmap_update_bits(regmap, pwm_port_params[pwm_port].ctrl_reg,
> +			   pwm_port_params[pwm_port].type_mask, reg_value);
> +}
> +
> +static void aspeed_set_pwm_port_duty_rising_falling(struct regmap *regmap,
> +						    u8 pwm_port, u8 rising,
> +						    u8 falling)
> +{
> +	u32 reg_value = (rising <<
> +			 pwm_port_params[pwm_port].duty_ctrl_rise_point);
> +	reg_value |= (falling <<
> +		      pwm_port_params[pwm_port].duty_ctrl_fall_point);
> +
> +	regmap_update_bits(regmap, pwm_port_params[pwm_port].duty_ctrl_reg,
> +			   pwm_port_params[pwm_port].duty_ctrl_rise_fall_mask,
> +			   reg_value);
> +}
> +
> +static void aspeed_set_tacho_type_enable(struct regmap *regmap, u8 type,
> +					 bool enable)
> +{
> +	regmap_update_bits(regmap, type_params[type].ctrl_reg,
> +			   TYPE_CTRL_FAN_TYPE_EN,
> +			   enable ? TYPE_CTRL_FAN_TYPE_EN : 0);
> +}
> +
> +static void aspeed_set_tacho_type_values(struct regmap *regmap, u8 type,
> +					 u8 mode, u16 unit, u8 division)
> +{
> +	u32 reg_value = ((mode << TYPE_CTRL_FAN_MODE) |
> +			 (unit << TYPE_CTRL_FAN_PERIOD) |
> +			 (division << TYPE_CTRL_FAN_DIVISION));
> +
> +	regmap_update_bits(regmap, type_params[type].ctrl_reg,
> +			   TYPE_CTRL_FAN_MASK, reg_value);
> +	regmap_update_bits(regmap, type_params[type].ctrl_reg1,
> +			   TYPE_CTRL_FAN1_MASK, unit << 16);
> +}
> +
> +static void aspeed_set_fan_tach_ch_enable(struct regmap *regmap, u8 fan_tach_ch,
> +					  bool enable)
> +{
> +	regmap_update_bits(regmap, ASPEED_PTCR_CTRL,
> +			   ASPEED_PTCR_CTRL_FAN_NUM_EN(fan_tach_ch),
> +			   enable ?
> +			   ASPEED_PTCR_CTRL_FAN_NUM_EN(fan_tach_ch) : 0);
> +}
> +
> +static void aspeed_set_fan_tach_ch_source(struct regmap *regmap, u8 fan_tach_ch,
> +					  u8 fan_tach_ch_source)
> +{
> +	u32 reg_value1 = ((fan_tach_ch_source & 0x3) <<
> +			  TACH_PWM_SOURCE_BIT01(fan_tach_ch));
> +	u32 reg_value2 = (((fan_tach_ch_source & 0x4) >> 2) <<
> +			  TACH_PWM_SOURCE_BIT2(fan_tach_ch));
> +
> +	regmap_update_bits(regmap, ASPEED_PTCR_TACH_SOURCE,
> +			   TACH_PWM_SOURCE_MASK_BIT01(fan_tach_ch),
> +			   reg_value1);
> +
> +	regmap_update_bits(regmap, ASPEED_PTCR_TACH_SOURCE_EXT,
> +			   TACH_PWM_SOURCE_MASK_BIT2(fan_tach_ch),
> +			   reg_value2);
> +}
> +
> +static void aspeed_set_pwm_port_fan_ctrl(struct aspeed_pwm_tacho_data *priv,
> +					 u8 index, u8 fan_ctrl)
> +{
> +	u16 period, dc_time_on;
> +
> +	period = priv->type_pwm_clock_unit[priv->pwm_port_type[index]];
> +	period += 1;
> +	dc_time_on = (fan_ctrl * period) / PWM_MAX;
> +
> +	if (dc_time_on == 0) {
> +		aspeed_set_pwm_port_enable(priv->regmap, index, false);
> +	} else {
> +		if (dc_time_on == period)
> +			dc_time_on = 0;
> +
> +		aspeed_set_pwm_port_duty_rising_falling(priv->regmap, index, 0,
> +							dc_time_on);
> +		aspeed_set_pwm_port_enable(priv->regmap, index, true);
> +	}
> +}
> +
> +static u32 aspeed_get_fan_tach_ch_measure_period(struct aspeed_pwm_tacho_data
> +						 *priv, u8 type)
> +{
> +	u32 clk;
> +	u16 tacho_unit;
> +	u8 clk_unit, div_h, div_l, tacho_div;
> +
> +	clk = priv->clk_freq;
> +	clk_unit = priv->type_pwm_clock_unit[type];
> +	div_h = priv->type_pwm_clock_division_h[type];
> +	div_h = 0x1 << div_h;
> +	div_l = priv->type_pwm_clock_division_l[type];
> +	if (div_l == 0)
> +		div_l = 1;
> +	else
> +		div_l = div_l * 2;
> +
> +	tacho_unit = priv->type_fan_tach_unit[type];
> +	tacho_div = priv->type_fan_tach_clock_division[type];
> +
> +	tacho_div = 0x4 << (tacho_div * 2);
> +	return clk / (clk_unit * div_h * div_l * tacho_div * tacho_unit);
> +}
> +
> +static u32 aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tacho_data *priv,
> +				      u8 fan_tach_ch)
> +{
> +	u32 raw_data, tach_div, clk_source, timeout = 0, sec, val;
> +	u8 fan_tach_ch_source, type;
> +
> +	regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0);
> +	regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0x1 << fan_tach_ch);
> +
> +	fan_tach_ch_source = priv->fan_tach_ch_source[fan_tach_ch];
> +	type = priv->pwm_port_type[fan_tach_ch_source];
> +
> +	sec = (1000 / aspeed_get_fan_tach_ch_measure_period(priv, type));
> +
> +	msleep(sec);
> +
> +	while (!(regmap_read(priv->regmap, ASPEED_PTCR_RESULT, &val))
> +			& !(val & RESULT_STATUS_MASK)) {
> +		timeout++;
> +		if (timeout > 1)
> +			return 0;
> +		msleep(sec);
> +	}
> +
> +	raw_data = val & RESULT_VALUE_MASK;
> +	tach_div = priv->type_fan_tach_clock_division[type];
> +	tach_div = 0x4 << (tach_div * 2);
> +	clk_source = priv->clk_freq;
> +
> +	if (raw_data == 0)
> +		return 0;
> +
> +	return (clk_source * 60) / (2 * raw_data * tach_div);
> +}
> +
> +static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
> +		       const char *buf, size_t count)
> +{
> +	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
> +	int index = sensor_attr->index;
> +	int ret;
> +	struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
> +	long fan_ctrl;
> +
> +	ret = kstrtol(buf, 10, &fan_ctrl);
> +	if (ret != 0)
> +		return ret;
> +
> +	if (fan_ctrl < 0 || fan_ctrl > PWM_MAX)
> +		return -EINVAL;
> +
> +	if (priv->pwm_port_fan_ctrl[index] == fan_ctrl)
> +		return count;
> +
> +	priv->pwm_port_fan_ctrl[index] = fan_ctrl;
> +	aspeed_set_pwm_port_fan_ctrl(priv, index, fan_ctrl);
> +
> +	return count;
> +}
> +
> +static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
> +			char *buf)
> +{
> +	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
> +	int index = sensor_attr->index;
> +	struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
> +
> +	return sprintf(buf, "%u\n", priv->pwm_port_fan_ctrl[index]);
> +}
> +
> +static ssize_t show_rpm(struct device *dev, struct device_attribute *attr,
> +			char *buf)
> +{
> +	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
> +	int index = sensor_attr->index;
> +	u32 rpm;
> +	struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
> +
> +	rpm = aspeed_get_fan_tach_ch_rpm(priv, index);
> +
> +	return sprintf(buf, "%u\n", rpm);
> +}
> +
> +static umode_t pwm_is_visible(struct kobject *kobj,
> +			      struct attribute *a, int index)
> +{
> +	struct device *dev = container_of(kobj, struct device, kobj);
> +	struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
> +
> +	if (!priv->pwm_present[index])
> +		return 0;
> +	return a->mode;
> +}
> +
> +static umode_t fan_dev_is_visible(struct kobject *kobj,
> +				  struct attribute *a, int index)
> +{
> +	struct device *dev = container_of(kobj, struct device, kobj);
> +	struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
> +
> +	if (!priv->fan_tach_present[index])
> +		return 0;
> +	return a->mode;
> +}
> +
> +static SENSOR_DEVICE_ATTR(pwm0, 0644,
> +			show_pwm, set_pwm, 0);
> +static SENSOR_DEVICE_ATTR(pwm1, 0644,
> +			show_pwm, set_pwm, 1);
> +static SENSOR_DEVICE_ATTR(pwm2, 0644,
> +			show_pwm, set_pwm, 2);
> +static SENSOR_DEVICE_ATTR(pwm3, 0644,
> +			show_pwm, set_pwm, 3);
> +static SENSOR_DEVICE_ATTR(pwm4, 0644,
> +			show_pwm, set_pwm, 4);
> +static SENSOR_DEVICE_ATTR(pwm5, 0644,
> +			show_pwm, set_pwm, 5);
> +static SENSOR_DEVICE_ATTR(pwm6, 0644,
> +			show_pwm, set_pwm, 6);
> +static SENSOR_DEVICE_ATTR(pwm7, 0644,
> +			show_pwm, set_pwm, 7);
> +static struct attribute *pwm_dev_attrs[] = {
> +	&sensor_dev_attr_pwm0.dev_attr.attr,
> +	&sensor_dev_attr_pwm1.dev_attr.attr,
> +	&sensor_dev_attr_pwm2.dev_attr.attr,
> +	&sensor_dev_attr_pwm3.dev_attr.attr,
> +	&sensor_dev_attr_pwm4.dev_attr.attr,
> +	&sensor_dev_attr_pwm5.dev_attr.attr,
> +	&sensor_dev_attr_pwm6.dev_attr.attr,
> +	&sensor_dev_attr_pwm7.dev_attr.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group pwm_dev_group = {
> +	.attrs = pwm_dev_attrs,
> +	.is_visible = pwm_is_visible,
> +};
> +
> +static SENSOR_DEVICE_ATTR(fan0_input, 0444,
> +		show_rpm, NULL, 0);
> +static SENSOR_DEVICE_ATTR(fan1_input, 0444,
> +		show_rpm, NULL, 1);
> +static SENSOR_DEVICE_ATTR(fan2_input, 0444,
> +		show_rpm, NULL, 2);
> +static SENSOR_DEVICE_ATTR(fan3_input, 0444,
> +		show_rpm, NULL, 3);
> +static SENSOR_DEVICE_ATTR(fan4_input, 0444,
> +		show_rpm, NULL, 4);
> +static SENSOR_DEVICE_ATTR(fan5_input, 0444,
> +		show_rpm, NULL, 5);
> +static SENSOR_DEVICE_ATTR(fan6_input, 0444,
> +		show_rpm, NULL, 6);
> +static SENSOR_DEVICE_ATTR(fan7_input, 0444,
> +		show_rpm, NULL, 7);
> +static SENSOR_DEVICE_ATTR(fan8_input, 0444,
> +		show_rpm, NULL, 8);
> +static SENSOR_DEVICE_ATTR(fan9_input, 0444,
> +		show_rpm, NULL, 9);
> +static SENSOR_DEVICE_ATTR(fan10_input, 0444,
> +		show_rpm, NULL, 10);
> +static SENSOR_DEVICE_ATTR(fan11_input, 0444,
> +		show_rpm, NULL, 11);
> +static SENSOR_DEVICE_ATTR(fan12_input, 0444,
> +		show_rpm, NULL, 12);
> +static SENSOR_DEVICE_ATTR(fan13_input, 0444,
> +		show_rpm, NULL, 13);
> +static SENSOR_DEVICE_ATTR(fan14_input, 0444,
> +		show_rpm, NULL, 14);
> +static SENSOR_DEVICE_ATTR(fan15_input, 0444,
> +		show_rpm, NULL, 15);
> +static struct attribute *fan_dev_attrs[] = {
> +	&sensor_dev_attr_fan0_input.dev_attr.attr,
> +	&sensor_dev_attr_fan1_input.dev_attr.attr,
> +	&sensor_dev_attr_fan2_input.dev_attr.attr,
> +	&sensor_dev_attr_fan3_input.dev_attr.attr,
> +	&sensor_dev_attr_fan4_input.dev_attr.attr,
> +	&sensor_dev_attr_fan5_input.dev_attr.attr,
> +	&sensor_dev_attr_fan6_input.dev_attr.attr,
> +	&sensor_dev_attr_fan7_input.dev_attr.attr,
> +	&sensor_dev_attr_fan8_input.dev_attr.attr,
> +	&sensor_dev_attr_fan9_input.dev_attr.attr,
> +	&sensor_dev_attr_fan10_input.dev_attr.attr,
> +	&sensor_dev_attr_fan11_input.dev_attr.attr,
> +	&sensor_dev_attr_fan12_input.dev_attr.attr,
> +	&sensor_dev_attr_fan13_input.dev_attr.attr,
> +	&sensor_dev_attr_fan14_input.dev_attr.attr,
> +	&sensor_dev_attr_fan15_input.dev_attr.attr,
> +	NULL
> +};
> +
> +static const struct attribute_group fan_dev_group = {
> +	.attrs = fan_dev_attrs,
> +	.is_visible = fan_dev_is_visible,
> +};
> +
> +/*
> + * The clock type is type M :
> + * The PWM frequency = 24MHz / (type M clock division L bit *
> + * type M clock division H bit * (type M PWM period bit + 1))
> + */
> +static void aspeed_create_type(struct aspeed_pwm_tacho_data *priv)
> +{
> +	priv->type_pwm_clock_division_h[TYPEM] = M_PWM_DIV_H;
> +	priv->type_pwm_clock_division_l[TYPEM] = M_PWM_DIV_L;
> +	priv->type_pwm_clock_unit[TYPEM] = M_PWM_PERIOD;
> +	aspeed_set_pwm_clock_values(priv->regmap, TYPEM, M_PWM_DIV_H,
> +				    M_PWM_DIV_L, M_PWM_PERIOD);
> +	aspeed_set_tacho_type_enable(priv->regmap, TYPEM, true);
> +	priv->type_fan_tach_clock_division[TYPEM] = M_TACH_CLK_DIV;
> +	priv->type_fan_tach_unit[TYPEM] = M_TACH_UNIT;
> +	aspeed_set_tacho_type_values(priv->regmap, TYPEM, M_TACH_MODE,
> +				     M_TACH_UNIT, M_TACH_CLK_DIV);
> +}
> +
> +static void aspeed_create_pwm_port(struct aspeed_pwm_tacho_data *priv,
> +				   u8 pwm_port)
> +{
> +	aspeed_set_pwm_port_enable(priv->regmap, pwm_port, true);
> +	priv->pwm_present[pwm_port] = true;
> +
> +	priv->pwm_port_type[pwm_port] = TYPEM;
> +	aspeed_set_pwm_port_type(priv->regmap, pwm_port, TYPEM);
> +
> +	priv->pwm_port_fan_ctrl[pwm_port] = INIT_FAN_CTRL;
> +	aspeed_set_pwm_port_fan_ctrl(priv, pwm_port, INIT_FAN_CTRL);
> +}
> +
> +static void aspeed_create_fan_tach_channel(struct aspeed_pwm_tacho_data *priv,
> +					   u8 *fan_tach_ch,
> +					   int count,
> +					   u8 pwm_source)
> +{
> +	u8 val, index;
> +
> +	for (val = 0; val < count; val++) {
> +		index = fan_tach_ch[val];
> +		aspeed_set_fan_tach_ch_enable(priv->regmap, index, true);
> +		priv->fan_tach_present[index] = true;
> +		priv->fan_tach_ch_source[index] = pwm_source;
> +		aspeed_set_fan_tach_ch_source(priv->regmap, index, pwm_source);
> +	}
> +}
> +
> +static int aspeed_create_fan(struct device *dev,
> +			     struct device_node *child,
> +			     struct aspeed_pwm_tacho_data *priv)
> +{
> +	u8 *fan_tach_ch;
> +	u32 pwm_port;
> +	int ret, count;
> +
> +	ret = of_property_read_u32(child, "reg", &pwm_port);
> +	if (ret)
> +		return ret;
> +	aspeed_create_pwm_port(priv, (u8)pwm_port);
> +
> +	count = of_property_count_u8_elems(child, "aspeed,fan-tach-ch");
> +	if (count < 1)
> +		return -EINVAL;
> +	fan_tach_ch = devm_kzalloc(dev, sizeof(*fan_tach_ch) * count,
> +				   GFP_KERNEL);
> +	if (!fan_tach_ch)
> +		return -ENOMEM;
> +	ret = of_property_read_u8_array(child, "aspeed,fan-tach-ch",
> +					fan_tach_ch, count);
> +	if (ret)
> +		return ret;
> +	aspeed_create_fan_tach_channel(priv, fan_tach_ch, count, pwm_port);
> +
> +	return 0;
> +}
> +
> +static int aspeed_pwm_tacho_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np, *child;
> +	struct aspeed_pwm_tacho_data *priv;
> +	void __iomem *regs;
> +	struct resource *res;
> +	struct device *hwmon;
> +	struct clk *clk;
> +	int ret;
> +
> +	np = dev->of_node;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENOENT;
> +	regs = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(regs))
> +		return PTR_ERR(regs);
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +	priv->regmap = devm_regmap_init(dev, NULL, regs,
> +			&aspeed_pwm_tacho_regmap_config);
> +	if (IS_ERR(priv->regmap))
> +		return PTR_ERR(priv->regmap);
> +	regmap_write(priv->regmap, ASPEED_PTCR_TACH_SOURCE, 0);
> +	regmap_write(priv->regmap, ASPEED_PTCR_TACH_SOURCE_EXT, 0);
> +
> +	clk = devm_clk_get(dev, NULL);
> +	if (IS_ERR(clk))
> +		return -ENODEV;
> +	priv->clk_freq = clk_get_rate(clk);
> +	aspeed_set_clock_enable(priv->regmap, true);
> +	aspeed_set_clock_source(priv->regmap, 0);
> +
> +	aspeed_create_type(priv);
> +
> +	for_each_child_of_node(np, child) {
> +		ret = aspeed_create_fan(dev, child, priv);
> +		of_node_put(child);
> +		if (ret)
> +			return ret;
> +	}
> +	of_node_put(np);
> +
> +	priv->groups[0] = &pwm_dev_group;
> +	priv->groups[1] = &fan_dev_group;
> +	priv->groups[2] = NULL;
> +	hwmon = devm_hwmon_device_register_with_groups(dev,
> +						       "aspeed_pwm_tacho",
> +						       priv, priv->groups);
> +
> +	return PTR_ERR_OR_ZERO(hwmon);
> +}
> +
> +static const struct of_device_id of_pwm_tacho_match_table[] = {
> +	{ .compatible = "aspeed,ast2400-pwm-tacho", },
> +	{ .compatible = "aspeed,ast2500-pwm-tacho", },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, of_pwm_tacho_match_table);
> +
> +static struct platform_driver aspeed_pwm_tacho_driver = {
> +	.probe		= aspeed_pwm_tacho_probe,
> +	.driver		= {
> +		.name	= "aspeed_pwm_tacho",
> +		.of_match_table = of_pwm_tacho_match_table,
> +	},
> +};
> +
> +module_platform_driver(aspeed_pwm_tacho_driver);
> +
> +MODULE_AUTHOR("Jaghathiswari Rankappagounder Natarajan <jaghu@google.com>");
> +MODULE_DESCRIPTION("ASPEED PWM and Fan Tacho device driver");
> +MODULE_LICENSE("GPL");
> --
> 2.12.2.715.g7642488e1d-goog
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

^ permalink raw reply

* Re: [PATCH linux v6 1/2] Documentation: dt-bindings: Document bindings for ASPEED AST2400/AST2500 PWM and Fan tach controller device driver
From: Guenter Roeck @ 2017-04-04 12:52 UTC (permalink / raw)
  To: Jaghathiswari Rankappagounder Natarajan,
	joel-U3u1mxZcP9KHXe+LvDLADg, jdelvare-IBi9RG/b67k,
	linux-hwmon-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	openbmc-uLR06cmDAlY/bJ5BZ2RsiQ, corbet-T1hC0tSOHrs,
	linux-doc-u79uwXL29TY76Z2rM5mHXA, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20170403233025.26952-2-jaghu-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>

On 04/03/2017 04:30 PM, Jaghathiswari Rankappagounder Natarajan wrote:
> This binding provides interface for adding values related to ASPEED
> AST2400/2500 PWM and Fan tach controller support.
> The PWM controller can support upto 8 PWM output ports.
> The Fan tach controller can support upto 16 tachometer inputs.
>
> Signed-off-by: Jaghathiswari Rankappagounder Natarajan <jaghu-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>

Applied with Acked-by: From Rob (for v5 with the requested changes made).

Thanks,
Guenter

> ---
>  v6:
> - Changed to aspeed,fan-tach-ch
>
>  v5:
> - Changed the naming scheme to aspeed,ast2400/2500-pwm-tacho
> - Removed gpio pin muxing
> - Added aspeed vendor prefix for fan-tach-ch
> - Changed to fan@0/1
> - Changed reg to 32 bits
>
>  v4:
> - Used 'reg'
>
>  v3:
> - Made the structure more common
>
>  v2:
> - Removed '_' in node and property names
> - Gave some explanation for the properties used
>
>  .../devicetree/bindings/hwmon/aspeed-pwm-tacho.txt | 68 ++++++++++++++++++++++
>  1 file changed, 68 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt
>
> diff --git a/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt b/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt
> new file mode 100644
> index 000000000000..ac0a69ab0755
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hwmon/aspeed-pwm-tacho.txt
> @@ -0,0 +1,68 @@
> +ASPEED AST2400/AST2500 PWM and Fan Tacho controller device driver
> +
> +The ASPEED PWM controller can support upto 8 PWM outputs. The ASPEED Fan Tacho
> +controller can support upto 16 Fan tachometer inputs.
> +
> +There can be upto 8 fans supported. Each fan can have one PWM output and
> +one/two Fan tach inputs.
> +
> +Required properties for pwm-tacho node:
> +- #address-cells : should be 1.
> +
> +- #size-cells : should be 1.
> +
> +- reg : address and length of the register set for the device.
> +
> +- pinctrl-names : a pinctrl state named "default" must be defined.
> +
> +- pinctrl-0 : phandle referencing pin configuration of the PWM ports.
> +
> +- compatible : should be "aspeed,ast2400-pwm-tacho" for AST2400 and
> +	       "aspeed,ast2500-pwm-tacho" for AST2500.
> +
> +- clocks : a fixed clock providing input clock frequency(PWM
> +	   and Fan Tach clock)
> +
> +fan subnode format:
> +===================
> +Under fan subnode there can upto 8 child nodes, with each child node
> +representing a fan. If there are 8 fans each fan can have one PWM port and
> +one/two Fan tach inputs.
> +
> +Required properties for each child node:
> +- reg : should specify PWM source port.
> +	integer value in the range 0 to 7 with 0 indicating PWM port A and
> +	7 indicating PWM port H.
> +
> +- aspeed,fan-tach-ch : should specify the Fan tach input channel.
> +                integer value in the range 0 through 15, with 0 indicating
> +		Fan tach channel 0 and 15 indicating Fan tach channel 15.
> +		Atleast one Fan tach input channel is required.
> +
> +Examples:
> +
> +pwm_tacho_fixed_clk: fixedclk {
> +	compatible = "fixed-clock";
> +	#clock-cells = <0>;
> +	clock-frequency = <24000000>;
> +}
> +
> +pwm_tacho: pwmtachocontroller@1e786000 {
> +	#address-cells = <1>;
> +	#size-cells = <1>;
> +	reg = <0x1E786000 0x1000>;
> +	compatible = "aspeed,ast2500-pwm-tacho";
> +	clocks = <&pwm_tacho_fixed_clk>;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default>;
> +
> +	fan@0 {
> +		reg = <0x00>;
> +		aspeed,fan-tach-ch = /bits/ 8 <0x00>;
> +	};
> +
> +	fan@1 {
> +		reg = <0x01>;
> +		aspeed,fan-tach-ch = /bits/ 8 <0x01 0x02>;
> +	};
> +};
> --
> 2.12.2.715.g7642488e1d-goog
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 2/3] dt-bindings: arm: amlogic: Add SoC information bindings
From: Neil Armstrong @ 2017-04-04 12:49 UTC (permalink / raw)
  To: Rob Herring
  Cc: Arnd Bergmann, Kevin Hilman, Carlo Caione,
	linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Linux ARM,
	Linux Kernel Mailing List,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CAL_JsqKWi=sNgOTTw6+PAxwgFyFQMw6BiUz0uNuG4kWr+ORO_g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On 04/04/2017 02:26 PM, Rob Herring wrote:
> On Tue, Apr 4, 2017 at 3:51 AM, Neil Armstrong <narmstrong-rdvid1DuHRBWk0Htik3J/w@public.gmane.org> wrote:
>> On 04/03/2017 06:34 PM, Rob Herring wrote:
>>> On Fri, Mar 31, 2017 at 04:10:30PM +0200, Neil Armstrong wrote:
>>>> On 03/31/2017 03:44 PM, Arnd Bergmann wrote:
>>>>> On Fri, Mar 31, 2017 at 10:47 AM, Neil Armstrong
>>>>> <narmstrong-rdvid1DuHRBWk0Htik3J/w@public.gmane.org> wrote:
>>>>>> Add bindings for the SoC information register of the Amlogic SoCs.
>>>>>>
>>>>>> Signed-off-by: Neil Armstrong <narmstrong-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
>>>>>> ---
>>>>>>  Documentation/devicetree/bindings/arm/amlogic.txt | 20 ++++++++++++++++++++
>>>>>>  1 file changed, 20 insertions(+)
>>>>>>
>>>>>> diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt
>>>>>> index bfd5b55..b850985 100644
>>>>>> --- a/Documentation/devicetree/bindings/arm/amlogic.txt
>>>>>> +++ b/Documentation/devicetree/bindings/arm/amlogic.txt
>>>>>> @@ -52,3 +52,23 @@ Board compatible values:
>>>>>>    - "amlogic,q201" (Meson gxm s912)
>>>>>>    - "nexbox,a95x" (Meson gxbb or Meson gxl s905x)
>>>>>>    - "nexbox,a1" (Meson gxm s912)
>>>>>> +
>>>>>> +Amlogic Meson GX SoCs Information
>>>>>> +----------------------------------
>>>>>> +
>>>>>> +The Meson SoCs have a Product Register that allows to retrieve SoC type,
>>>>>> +package and revision information. If present, a device node for this register
>>>>>> +should be added.
>>>>>> +
>>>>>> +Required properties:
>>>>>> +  - compatible: For Meson GX SoCs, must be "amlogic,meson-gx-socinfo".
>>>>>> +  - reg: Base address and length of the register block.
>>>>>> +
>>>>>> +Examples
>>>>>> +--------
>>>>>> +
>>>>>> +       chipid@220 {
>>>>>> +               compatible = "amlogic,meson-gx-socinfo";
>>>>>> +               reg = <0x0 0x00220 0x0 0x4>;
>>>>>> +       };
>>>>>> +
>>>>>
>>>>> The register location would hint that this is in the middle of some block of
>>>>> random registers, i.e. a syscon or some unrelated device.
>>>>>
>>>>> Are you sure that "socinfo" is the actual name of the IP block and that
>>>>> it only has a single 32-bit register?
>>>>>
>>>>>      Arnd
>>>>>
>>>>
>>>> Hi Arnd,
>>>>
>>>> I'm sorry I did not find any relevant registers in the docs or source code describing
>>>> it in a specific block of registers, and no close enough register definitions either.
>>>> They may be used by the secure firmware I imagine.
>>>>
>>>> For the register name, Amlogic refers it to "cpu_version" in their code, but it really
>>>> gives some details on the whole SoC and package, and socinfo seems better.
>>>
>>> A register at address 0x220 seems a bit strange (unless there's ranges
>>> you're not showing), but ROM code at this address would be fairly
>>> typical. And putting version information into the ROM is also common.
>>>
>>> Rob
>>>
>>
>> Hi Rob.
>>
>> Indeed it's part of a larger range :
>>                  aobus: aobus@c8100000 {
>>                         compatible = "simple-bus";
>>                         reg = <0x0 0xc8100000 0x0 0x100000>;
>>                         #address-cells = <2>;
>>                         #size-cells = <2>;
>>                         ranges = <0x0 0x0 0x0 0xc8100000 0x0 0x100000>;
>>
>>
>> While scrubbing on the uboot source, I found a sort of block of registers dedicated to communicate with
>> the secure firmware :
>> AO_SEC_REG0                                                     0x140
>> AO_SEC_REG1                                                     0x144
>> AO_SEC_REG2                                                     0x148
>> AO_SEC_TMODE_PWD0                                               0x160
>> AO_SEC_TMODE_PWD1                                               0x164
>> AO_SEC_TMODE_PWD2                                               0x168
>> AO_SEC_TMODE_PWD3                                               0x16C
>> AO_SEC_SCRATCH                                                  0x17C
>> AO_SEC_JTAG_PWD0                                                0x180
>> AO_SEC_JTAG_PWD1                                                0x184
>> AO_SEC_JTAG_PWD2                                                0x188
>> AO_SEC_JTAG_PWD3                                                0x18C
>> AO_SEC_JTAG_SEC_CNTL                                            0x190
>> AO_SEC_JTAG_PWD_ADDR0                                           0x194
>> AO_SEC_JTAG_PWD_ADDR1                                           0x198
>> AO_SEC_JTAG_PWD_ADDR2                                           0x19C
>> AO_SEC_JTAG_PWD_ADDR3                                           0x1A0
>> AO_SEC_SHARED_AHB_SRAM_REG0_0                                   0x1C0
>> AO_SEC_SHARED_AHB_SRAM_REG0_1                                   0x1C4
>> AO_SEC_SHARED_AHB_SRAM_REG0_2                                   0x1C8
>> AO_SEC_SHARED_AHB_SRAM_REG1_0                                   0x1CC
>> AO_SEC_SHARED_AHB_SRAM_REG1_1                                   0x1D0
>> AO_SEC_SHARED_AHB_SRAM_REG1_2                                   0x1D4
>> AO_SEC_SHARED_AHB_SRAM_REG2_0                                   0x1D8
>> AO_SEC_SHARED_AHB_SRAM_REG2_1                                   0x1DC
>> AO_SEC_SHARED_AHB_SRAM_REG2_2                                   0x1E0
>> AO_SEC_SHARED_AHB_SRAM_REG3_0                                   0x1E4
>> AO_SEC_SHARED_AHB_SRAM_REG3_1                                   0x1E8
>> AO_SEC_SHARED_AHB_SRAM_REG3_2                                   0x1EC
>> AO_SEC_AO_AHB_SRAM_REG0_0                                       0x1F0
>> AO_SEC_AO_AHB_SRAM_REG0_1                                       0x1F4
>> AO_SEC_AO_AHB_SRAM_REG1_0                                       0x1F8
>> AO_SEC_AO_AHB_SRAM_REG1_1                                       0x1FC
>> AO_SEC_SD_CFG8                                                  0x220
>> AO_SEC_SD_CFG9                                                  0x224
>> AO_SEC_SD_CFG10                                                 0x228
>> AO_SEC_SD_CFG11                                                 0x22C
>> AO_SEC_SD_CFG12                                                 0x230
>> AO_SEC_SD_CFG13                                                 0x234
>> AO_SEC_SD_CFG14                                                 0x238
>> AO_SEC_SD_CFG15                                                 0x23C
>> AO_SEC_GP_CFG0                                                  0x240
>> AO_SEC_GP_CFG1                                                  0x244
>> AO_SEC_GP_CFG2                                                  0x248
>> AO_SEC_GP_CFG3                                                  0x24C
>> AO_SEC_GP_CFG4                                                  0x250
>> AO_SEC_GP_CFG5                                                  0x254
>> AO_SEC_GP_CFG6                                                  0x258
>> AO_SEC_GP_CFG7                                                  0x25C
>> AO_SEC_GP_CFG8                                                  0x260
>> AO_SEC_GP_CFG9                                                  0x264
>> AO_SEC_GP_CFG10                                                 0x268
>> AO_SEC_GP_CFG11                                                 0x26C
>> AO_SEC_GP_CFG12                                                 0x270
>> AO_SEC_GP_CFG13                                                 0x274
>> AO_SEC_GP_CFG14                                                 0x278
>> AO_SEC_GP_CFG15                                                 0x27C
>>
>>
>> As you see, the register we use here is AO_SEC_SD_CFG8...
>>
>> Should I define all this block as simple-mfd and refer to it as a regmap ?
>>
>> aobus: aobus@c8100000 {
>>         compatible = "simple-bus";
>>         reg = <0x0 0xc8100000 0x0 0x100000>;
>>         #address-cells = <2>;
>>         #size-cells = <2>;
>>         ranges = <0x0 0x0 0x0 0xc8100000 0x0 0x100000>;
>>
>>         ao_secure: ao-secure@140 {
>>                 compatible = "amlogic,meson-gx-ao-secure", "simple-mfd";
>>                 reg = <0x0 0x140 0x0 0x140>;
>>         };
>> };
>>
>> chipid {
>>         compatible = "amlogic,meson-gx-socinfo";
>>         ao-secure = <&ao_secure>;
>>         chip-info-reg = <0xe0>;
> 
> Why even divide it up further in DT? IMO, describing single
> registers/address in DT is too fine grained.
> 
> Rob
> 

Rob, I don't get it.

Maybe something like that ?

aobus: aobus@c8100000 {
        compatible = "simple-bus";
        reg = <0x0 0xc8100000 0x0 0x100000>;
        #address-cells = <2>;
        #size-cells = <2>;
        ranges = <0x0 0x0 0x0 0xc8100000 0x0 0x100000>;

        ao_secure: ao-secure@140 {
                compatible = "amlogic,meson-gx-ao-secure", "simple-mfd", "simple-bus";
                reg = <0x0 0x140 0x0 0x140>;
		#address-cells = <1>;
		#size-cells = <1>;

		chipid@e0 {
        		compatible = "amlogic,meson-gx-socinfo";
			reg = <0xe0 0x4>;
        	};
	};
};

Concerning the fine graining, I'm sorry but the actual information comes from a single register here...

Neil
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH V10 00/12] IOMMU probe deferral support
From: Robin Murphy @ 2017-04-04 12:49 UTC (permalink / raw)
  To: Sricharan R, will.deacon, joro, lorenzo.pieralisi, iommu,
	linux-arm-kernel, linux-arm-msm, m.szyprowski, bhelgaas,
	linux-pci, linux-acpi, tn, hanjun.guo, okaya, robh+dt,
	frowand.list, devicetree, linux-kernel, sudeep.holla, rjw, lenb,
	catalin.marinas, arnd, linux-arch, gregkh
In-Reply-To: <1491301105-5274-1-git-send-email-sricharan@codeaurora.org>

On 04/04/17 11:18, Sricharan R wrote:
> This series calls the dma ops configuration for the devices
> at a generic place so that it works for all busses.
> The dma_configure_ops for a device is now called during
> the device_attach callback just before the probe of the
> bus/driver is called. Similarly dma_deconfigure is called during
> device/driver_detach path.
> 
> pci_bus_add_devices    (platform/amba)(_device_create/driver_register)
>        |                         |
> pci_bus_add_device     (device_add/driver_register)
>        |                         |
> device_attach           device_initial_probe
>        |                         |
> __device_attach_driver    __device_attach_driver
>        |
> driver_probe_device
>        |
> really_probe
>        |
> dma_configure
> 
> Similarly on the device/driver_unregister path __device_release_driver is
> called which inturn calls dma_deconfigure.
> 
> Rebased the series against mainline 4.11-rc5. Applies and builds cleanly
> against mainline and linux-next, iommu-next.
>   
> * Tested with platform and pci devices for probe deferral
>   and reprobe on arm64 based platform.

Sricharan, thanks for keeping this going - I really think we're there now :)

Joerg, I realise that at -rc5 time is getting on a bit already, but even
the non-vintage parts of the series are pretty mature now so it would be
nice to at least give it a spin in -next. If you don't quite share my
confidence for landing it in 4.12, please consider it for early next
cycle to get a full workout.

Thanks,
Robin.

> Previous post of this series [8]. 
> 
> Please note that, i have kept the tested/acked tags intact from V8
> because V9/10 were for more fixes that was added, so the original
> tags that was given for the functional testing remains the same.
> 
>  [V10]
>      * Rebased on top of 4.11-rc5.
>  
>      * Fixed coherent_dma_mask 64bit overflow issue [8]
>        for OF. The fix for OF was added as a separate
>        patch#6, since the issue is true even without probe deferral,
>        but gets reproduced with the probe deferral series.
>        Added Lorenzo's ACPI fix for coherent_dma_mask overflow
>        and the fix for dma_configure getting called more than
>        once for the same device.
> 
>      * Also fixed an build issue caught by kbuild robot for
>        m68k arch. The issue was dma_(de)configure was not
>        getting defined for !CONFIG_HAS_DMA, so fixed that as well.
> 
>  [V9]
>      * Rebased on top of 4.11-rc1.
> 
>      * Merged Robin's fixes for legacy binding issue,
>        pci devices with no iommu-map property and deferencing
>        of_iommu_table after init.
>      
>  [V8]
>      * Picked up all the acks and tested tags from Marek and
>        Hanjun for DT and ACPI patches respectively, since
>        no functional changes was done.
> 
>      * Addressed Minor comments Sinan and Bjorn.
> 
>      * Added Robin's fix for fixing the deferencing NULL for
>        of_iommu_table after init in patch #2.
> 
>      * Rebased it on top of linux-next
> 
>  [V7]
>      * Updated the subject and commit log for patch #6 as per
>        comments from Lorenzo. No functional changes.
> 
>  [V6]
>      * Fixed a bug in dma_configure function pointed out by
>        Robin.
>      * Reordered the patches as per comments from Robin and
>        Lorenzo.
>      * Added Tags.
> 
>  [V5]
>      * Reworked the pci configuration code hanging outside and
>        pushed it to dma_configure as in PATCH#5,6,7.
>        Also added a couple of patches that Lorenzo provided for
>        correcting the Probe deferring mechanism in case of
>        ACPI devices from here [5].
> 
>  [V4]
>      * Took the reworked patches [2] from Robin's branch and
>        rebased on top of Lorenzo's ACPI IORT ARM support series [3].
> 
>      * Added the patches for moving the dma ops configuration of
>        acpi based devices to probe time as well.
>  [V3]
>      * Removed the patch to split dma_masks/dma_ops configuration
>        separately based on review comments that both masks and ops are
>        required only during the device probe time.
> 
>      * Reworked the series based on Generic DT bindings series.
> 
>      * Added call to iommu's remove_device in the cleanup path for arm and
>        arm64.
> 
>      * Removed the notifier trick in arm64 to handle early device
>        registration.
> 
>      * Added reset of dma_ops in cleanup path for arm based on comments.
> 
>      * Fixed the pci_iommu_configure path and tested with PCI device as
>        well.
>  
>      * Fixed a bug to return the correct iommu_ops from patch 7 [4] in
>        last post.
> 
>      * Fixed few other cosmetic comments.
>   
>  [V2]
>      * Updated the Initial post to call dma_configure/deconfigure from
>        generic code
>  
>      * Added iommu add_device callback from of_iommu_configure path
> 
>  [V1]
>      * Initial post from Laurent Pinchart [1]
> 
> [1] http://lists.linuxfoundation.org/pipermail/iommu/2015-May/013016.html
> [2] http://www.linux-arm.org/git?p=linux-rm.git;a=shortlog;h=refs/heads/iommu/defer
> [3] https://lkml.org/lkml/2016/11/21/141
> [4] https://www.mail-archive.com/iommu@xxxxxxxxxxxxxxxxxxxxxxxxxx/msg13940.html
> [5] git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/linux.git iommu/probe-deferral
> [6] http://www.spinics.net/lists/linux-pci/msg57992.html
> [7] https://www.spinics.net/lists/arm-kernel/msg556209.html
> [8] http://patchwork.ozlabs.org/patch/743898/
> 
> Laurent Pinchart (3):
>   of: dma: Move range size workaround to of_dma_get_range()
>   of: dma: Make of_dma_deconfigure() public
>   iommu: of: Handle IOMMU lookup failure with deferred probing or error
> 
> Lorenzo Pieralisi (2):
>   ACPI/IORT: Add function to check SMMUs drivers presence
>   ACPI/IORT: Remove linker section for IORT entries probing
> 
> Robin Murphy (3):
>   iommu/of: Refactor of_iommu_configure() for error handling
>   iommu/of: Prepare for deferred IOMMU configuration
>   iommu/arm-smmu: Clean up early-probing workarounds
> 
> Sricharan R (4):
>   of: device: Fix overflow of coherent_dma_mask
>   of/acpi: Configure dma operations at probe time for platform/amba/pci
>     bus devices
>   drivers: acpi: Handle IOMMU lookup failure with deferred probing or
>     error
>   arm64: dma-mapping: Remove the notifier trick to handle early setting
>     of dma_ops
> 
>  arch/arm64/mm/dma-mapping.c       | 142 +++++---------------------------------
>  drivers/acpi/arm64/iort.c         |  48 ++++++++++++-
>  drivers/acpi/glue.c               |   5 --
>  drivers/acpi/scan.c               |  11 ++-
>  drivers/base/dd.c                 |   9 +++
>  drivers/base/dma-mapping.c        |  41 +++++++++++
>  drivers/iommu/arm-smmu-v3.c       |  46 +-----------
>  drivers/iommu/arm-smmu.c          | 110 +++++++++++++----------------
>  drivers/iommu/of_iommu.c          | 126 ++++++++++++++++++++++++---------
>  drivers/of/address.c              |  20 +++++-
>  drivers/of/device.c               |  36 +++++-----
>  drivers/of/platform.c             |  10 +--
>  drivers/pci/probe.c               |  28 --------
>  include/acpi/acpi_bus.h           |   2 +-
>  include/asm-generic/vmlinux.lds.h |   1 -
>  include/linux/acpi.h              |   7 +-
>  include/linux/acpi_iort.h         |   3 -
>  include/linux/dma-mapping.h       |  12 ++++
>  include/linux/of_device.h         |  10 ++-
>  19 files changed, 329 insertions(+), 338 deletions(-)
> 

^ permalink raw reply

* Re: [PATCH v6 17/39] platform: add video-multiplexer subdevice driver
From: Sakari Ailus @ 2017-04-04 12:47 UTC (permalink / raw)
  To: Steve Longerbeam
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	shawnguo-DgEjT+Ai2ygdnm+yROfE0A, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	fabio.estevam-3arQi8VN3Tc, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
	mchehab-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	nick-gcszYUEDH4VrovVCs/uTlw, markus.heiser-O6JHGLzbNUwb1SvskN2V4Q,
	p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ,
	laurent.pinchart+renesas-ryLnwIuWjnjg/C1BVhZhaw,
	bparrot-l0cyMroinI0, geert-Td1EMuHUCqxL1ZNQvxDV9g,
	arnd-r2nGTMty4D4, sudipm.mukherjee-Re5JQEeQqe8AvxtiuMwx3w,
	minghsiu.tsai-NuS5LvNUpcJWk0Htik3J/w,
	tiffany.lin-NuS5LvNUpcJWk0Htik3J/w,
	jean-christophe.trotin-qxv4g6HH51o,
	horms+renesas-/R6kz+dDXgpPR4JQBCEnsQ,
	niklas.soderlund+renesas-1zkq55x86MTxsAP9Fp7wbw,
	robert.jarzmik-GANU6spQydw, songjun.wu-UWL1GkI3JZL3oGB3hsPCZA,
	andrew-ct.chen-NuS5LvNUpcJWk0Htik3J/w,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	shuah-DgEjT+Ai2ygdnm+yROfE0A, sakari.ailus-VuQAYsv1563Yd54FQh9/CA,
	pavel-+ZI9xUNit7I, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, linux-me
In-Reply-To: <1490661656-10318-18-git-send-email-steve_longerbeam-nmGgyN9QBj3QT0dZR+AlfA@public.gmane.org>

Hi Steve, Philipp and Pavel,

On Mon, Mar 27, 2017 at 05:40:34PM -0700, Steve Longerbeam wrote:
> From: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> 
> This driver can handle SoC internal and external video bus multiplexers,
> controlled either by register bit fields or by a GPIO. The subdevice
> passes through frame interval and mbus configuration of the active input
> to the output side.

The MUX framework is already in linux-next. Could you use that instead of
adding new driver + bindings that are not compliant with the MUX framework?
I don't think it'd be much of a change in terms of code, using the MUX
framework appears quite simple.

In general the driver looks pretty good, especially regarding the user space
API implementation which is important for use with other drivers.

I have some more detailed comments below.

> 
> Signed-off-by: Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> 
> - fixed a cut&paste error in vidsw_remove(): v4l2_async_register_subdev()
>   should be unregister.
> 
> - added media_entity_cleanup() to vidsw_remove().
> 
> - added missing MODULE_DEVICE_TABLE().
>   Suggested-by: Javier Martinez Canillas <javier-0uQlZySMnqxg9hUCZPvPmw@public.gmane.org>
> 
> - there was a line left over from a previous iteration that negated
>   the new way of determining the pad count just before it which
>   has been removed (num_pads = of_get_child_count(np)).
> 
> - removed [gs]_frame_interval ops. timeperframe is not used anywhwere
>   in this subdev, and currently it has no control over frame rate.
> 
> - add link_validate to media_entity_operations.
> 
> - moved devicetree binding doc to a separate commit.
> 
> - Philipp Zabel has developed a set of patches that allow adding
>   to the subdev async notifier waiting list using a chaining method
>   from the async registered callbacks (v4l2_of_subdev_registered()
>   and the prep patches for that). For now, I've removed the use of
>   v4l2_of_subdev_registered() for the vidmux driver's registered
>   callback. This doesn't affect the functionality of this driver,
>   but allows for it to be merged now, before adding the chaining
>   support.
> 
> Signed-off-by: Steve Longerbeam <steve_longerbeam-nmGgyN9QBj3QT0dZR+AlfA@public.gmane.org>
> ---
>  drivers/media/platform/Kconfig             |   8 +
>  drivers/media/platform/Makefile            |   2 +
>  drivers/media/platform/video-multiplexer.c | 451 +++++++++++++++++++++++++++++
>  3 files changed, 461 insertions(+)
>  create mode 100644 drivers/media/platform/video-multiplexer.c
> 
> diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
> index ab0bb48..c9b8d9c 100644
> --- a/drivers/media/platform/Kconfig
> +++ b/drivers/media/platform/Kconfig
> @@ -74,6 +74,14 @@ config VIDEO_M32R_AR_M64278
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called arv.
>  
> +config VIDEO_MULTIPLEXER
> +	tristate "Video Multiplexer"
> +	depends on VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
> +	help
> +	  This driver provides support for SoC internal N:1 video bus
> +	  multiplexers controlled by register bitfields as well as external
> +	  2:1 video multiplexers controlled by a single GPIO.
> +
>  config VIDEO_OMAP3
>  	tristate "OMAP 3 Camera support"
>  	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3
> diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
> index 8959f6e..d418add 100644
> --- a/drivers/media/platform/Makefile
> +++ b/drivers/media/platform/Makefile
> @@ -27,6 +27,8 @@ obj-$(CONFIG_VIDEO_SH_VEU)		+= sh_veu.o
>  
>  obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE)	+= m2m-deinterlace.o
>  
> +obj-$(CONFIG_VIDEO_MULTIPLEXER)		+= video-multiplexer.o
> +
>  obj-$(CONFIG_VIDEO_S3C_CAMIF) 		+= s3c-camif/
>  obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS) 	+= exynos4-is/
>  obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG)	+= s5p-jpeg/
> diff --git a/drivers/media/platform/video-multiplexer.c b/drivers/media/platform/video-multiplexer.c
> new file mode 100644
> index 0000000..b18c317
> --- /dev/null
> +++ b/drivers/media/platform/video-multiplexer.c
> @@ -0,0 +1,451 @@
> +/*
> + * video stream multiplexer controlled via gpio or syscon
> + *
> + * Copyright (C) 2013 Pengutronix, Sascha Hauer <kernel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> + * Copyright (C) 2016 Pengutronix, Philipp Zabel <kernel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_graph.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <media/v4l2-async.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-subdev.h>
> +#include <media/v4l2-of.h>
> +
> +struct vidsw {
> +	struct v4l2_subdev subdev;
> +	unsigned int num_pads;

You could use subdev.entity.num_pads instead of caching the value locally.

> +	struct media_pad *pads;
> +	struct v4l2_mbus_framefmt *format_mbus;
> +	struct v4l2_of_endpoint *endpoint;
> +	struct regmap_field *field;
> +	struct gpio_desc *gpio;
> +	int active;
> +};
> +
> +static inline struct vidsw *v4l2_subdev_to_vidsw(struct v4l2_subdev *sd)
> +{
> +	return container_of(sd, struct vidsw, subdev);
> +}
> +
> +static void vidsw_set_active(struct vidsw *vidsw, int active)
> +{
> +	vidsw->active = active;
> +	if (active < 0)
> +		return;
> +
> +	dev_dbg(vidsw->subdev.dev, "setting %d active\n", active);
> +
> +	if (vidsw->field)
> +		regmap_field_write(vidsw->field, active);
> +	else if (vidsw->gpio)
> +		gpiod_set_value(vidsw->gpio, active);
> +}
> +
> +static int vidsw_link_setup(struct media_entity *entity,
> +			    const struct media_pad *local,
> +			    const struct media_pad *remote, u32 flags)
> +{
> +	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
> +	struct vidsw *vidsw = v4l2_subdev_to_vidsw(sd);
> +
> +	/* We have no limitations on enabling or disabling our output link */
> +	if (local->index == vidsw->num_pads - 1)
> +		return 0;
> +
> +	dev_dbg(sd->dev, "link setup %s -> %s", remote->entity->name,
> +		local->entity->name);
> +
> +	if (!(flags & MEDIA_LNK_FL_ENABLED)) {
> +		if (local->index == vidsw->active) {
> +			dev_dbg(sd->dev, "going inactive\n");
> +			vidsw->active = -1;
> +		}
> +		return 0;
> +	}
> +
> +	if (vidsw->active >= 0) {
> +		struct media_pad *pad;
> +
> +		if (vidsw->active == local->index)
> +			return 0;
> +
> +		pad = media_entity_remote_pad(&vidsw->pads[vidsw->active]);
> +		if (pad) {
> +			struct media_link *link;
> +			int ret;
> +
> +			link = media_entity_find_link(pad,
> +						&vidsw->pads[vidsw->active]);
> +			if (link) {
> +				ret = __media_entity_setup_link(link, 0);

I wouldn't implicitly disable a link, even if only one can be active at a
given time. No other drivers do that either.

Perhaps returning an error might be a better thing to do: if you're
reconfiguring the pipeline anyway, there are likely issues elsewhere in it.

We could also change the behaviour later to allow implicit changes but we
can't later on go the other way without breaking the user space.

> +				if (ret)
> +					return ret;
> +			}
> +		}
> +	}
> +
> +	vidsw_set_active(vidsw, local->index);
> +
> +	return 0;
> +}
> +
> +static struct media_entity_operations vidsw_ops = {
> +	.link_setup = vidsw_link_setup,
> +	.link_validate = v4l2_subdev_link_validate,
> +};
> +
> +static bool vidsw_endpoint_disabled(struct device_node *ep)
> +{
> +	struct device_node *rpp;
> +
> +	if (!of_device_is_available(ep))

ep here is the endpoint, whereas the argument to of_device_is_available()
should correspond to the actual device.

> +		return true;
> +
> +	rpp = of_graph_get_remote_port_parent(ep);
> +	if (!rpp)
> +		return true;
> +
> +	return !of_device_is_available(rpp);
> +}
> +
> +static int vidsw_async_init(struct vidsw *vidsw, struct device_node *node)

I think I'd arrange this closer to probe as it's related to probe directly.
Up to you.

> +{
> +	struct device_node *ep;
> +	u32 portno;
> +	int numports;
> +	int ret;
> +	int i;
> +	bool active_link = false;
> +
> +	numports = vidsw->num_pads;
> +
> +	for (i = 0; i < numports - 1; i++)
> +		vidsw->pads[i].flags = MEDIA_PAD_FL_SINK;
> +	vidsw->pads[numports - 1].flags = MEDIA_PAD_FL_SOURCE;
> +
> +	vidsw->subdev.entity.function = MEDIA_ENT_F_VID_MUX;
> +	ret = media_entity_pads_init(&vidsw->subdev.entity, numports,
> +				     vidsw->pads);
> +	if (ret < 0)
> +		return ret;
> +
> +	vidsw->subdev.entity.ops = &vidsw_ops;
> +
> +	for_each_endpoint_of_node(node, ep) {
> +		struct v4l2_of_endpoint endpoint;
> +
> +		v4l2_of_parse_endpoint(ep, &endpoint);
> +
> +		portno = endpoint.base.port;
> +		if (portno >= numports - 1)
> +			continue;
> +
> +		if (vidsw_endpoint_disabled(ep)) {
> +			dev_dbg(vidsw->subdev.dev,
> +				"port %d disabled\n", portno);
> +			continue;
> +		}
> +
> +		vidsw->endpoint[portno] = endpoint;
> +
> +		if (portno == vidsw->active)
> +			active_link = true;
> +	}
> +
> +	for (portno = 0; portno < numports - 1; portno++) {
> +		if (!vidsw->endpoint[portno].base.local_node)
> +			continue;
> +
> +		/* If the active input is not connected, use another */
> +		if (!active_link) {
> +			vidsw_set_active(vidsw, portno);
> +			active_link = true;
> +		}
> +	}
> +
> +	return v4l2_async_register_subdev(&vidsw->subdev);
> +}
> +
> +int vidsw_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg)

We should get rid of g_mbus_config() in the long run, but as we don't have
the alternative (frame descriptors) isn't up to the job yet I guess it's ok.
I don't think we'll have too many users for the video switch right now.

> +{
> +	struct vidsw *vidsw = v4l2_subdev_to_vidsw(sd);
> +	struct media_pad *pad;
> +	int ret;
> +
> +	if (vidsw->active == -1) {
> +		dev_err(sd->dev, "no configuration for inactive mux\n");
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * Retrieve media bus configuration from the entity connected to the
> +	 * active input
> +	 */
> +	pad = media_entity_remote_pad(&vidsw->pads[vidsw->active]);
> +	if (pad) {
> +		sd = media_entity_to_v4l2_subdev(pad->entity);
> +		ret = v4l2_subdev_call(sd, video, g_mbus_config, cfg);
> +		if (ret == -ENOIOCTLCMD)
> +			pad = NULL;
> +		else if (ret < 0) {
> +			dev_err(sd->dev, "failed to get source configuration\n");
> +			return ret;
> +		}
> +	}
> +	if (!pad) {
> +		/* Mirror the input side on the output side */
> +		cfg->type = vidsw->endpoint[vidsw->active].bus_type;
> +		if (cfg->type == V4L2_MBUS_PARALLEL ||
> +		    cfg->type == V4L2_MBUS_BT656)
> +			cfg->flags = vidsw->endpoint[vidsw->active].bus.parallel.flags;
> +	}
> +
> +	return 0;
> +}
> +
> +static int vidsw_s_stream(struct v4l2_subdev *sd, int enable)
> +{
> +	struct vidsw *vidsw = v4l2_subdev_to_vidsw(sd);
> +	struct v4l2_subdev *upstream_sd;
> +	struct media_pad *pad;
> +
> +	if (vidsw->active == -1) {
> +		dev_err(sd->dev, "Can not start streaming on inactive mux\n");
> +		return -EINVAL;
> +	}
> +
> +	pad = media_entity_remote_pad(&sd->entity.pads[vidsw->active]);
> +	if (!pad) {
> +		dev_err(sd->dev, "Failed to find remote source pad\n");
> +		return -ENOLINK;
> +	}
> +
> +	if (!is_media_entity_v4l2_subdev(pad->entity)) {
> +		dev_err(sd->dev, "Upstream entity is not a v4l2 subdev\n");
> +		return -ENODEV;
> +	}
> +
> +	upstream_sd = media_entity_to_v4l2_subdev(pad->entity);
> +
> +	return v4l2_subdev_call(upstream_sd, video, s_stream, enable);

Now that we'll have more than two drivers involved in the same pipeline it
becomes necessary to define the behaviour of s_stream() throughout the
pipeline --- i.e. whose responsibility is it to call s_stream() on the
sub-devices in the pipeline?

I can submit a patch for that. I think the way you do it here is good, as it
enables the caller to choose the appropriate behaviour, i.e. start the local
device before or after the upstream sub-device.

> +}
> +
> +static const struct v4l2_subdev_video_ops vidsw_subdev_video_ops = {
> +	.g_mbus_config = vidsw_g_mbus_config,
> +	.s_stream = vidsw_s_stream,
> +};
> +
> +static struct v4l2_mbus_framefmt *
> +__vidsw_get_pad_format(struct v4l2_subdev *sd,
> +		       struct v4l2_subdev_pad_config *cfg,
> +		       unsigned int pad, u32 which)
> +{
> +	struct vidsw *vidsw = v4l2_subdev_to_vidsw(sd);
> +
> +	switch (which) {
> +	case V4L2_SUBDEV_FORMAT_TRY:
> +		return v4l2_subdev_get_try_format(sd, cfg, pad);
> +	case V4L2_SUBDEV_FORMAT_ACTIVE:
> +		return &vidsw->format_mbus[pad];
> +	default:
> +		return NULL;
> +	}
> +}
> +
> +static int vidsw_get_format(struct v4l2_subdev *sd,
> +			    struct v4l2_subdev_pad_config *cfg,
> +			    struct v4l2_subdev_format *sdformat)
> +{
> +	sdformat->format = *__vidsw_get_pad_format(sd, cfg, sdformat->pad,
> +						   sdformat->which);
> +	return 0;
> +}
> +
> +static int vidsw_set_format(struct v4l2_subdev *sd,
> +			    struct v4l2_subdev_pad_config *cfg,
> +			    struct v4l2_subdev_format *sdformat)
> +{
> +	struct vidsw *vidsw = v4l2_subdev_to_vidsw(sd);
> +	struct v4l2_mbus_framefmt *mbusformat;
> +
> +	if (sdformat->pad >= vidsw->num_pads)
> +		return -EINVAL;

This check is already performed in v4l2-subdev.c.

> +
> +	mbusformat = __vidsw_get_pad_format(sd, cfg, sdformat->pad,
> +					    sdformat->which);
> +	if (!mbusformat)
> +		return -EINVAL;
> +
> +	/* Output pad mirrors active input pad, no limitations on input pads */

Source and sink pads.

> +	if (sdformat->pad == (vidsw->num_pads - 1) && vidsw->active >= 0)

I think it'd be cleaner to test for the pad flag instead of the number. Or,
add a macro to obtain the source pad number.

> +		sdformat->format = vidsw->format_mbus[vidsw->active];
> +
> +	*mbusformat = sdformat->format;
> +
> +	return 0;
> +}
> +
> +static struct v4l2_subdev_pad_ops vidsw_pad_ops = {
> +	.get_fmt = vidsw_get_format,
> +	.set_fmt = vidsw_set_format,
> +};
> +
> +static struct v4l2_subdev_ops vidsw_subdev_ops = {
> +	.pad = &vidsw_pad_ops,
> +	.video = &vidsw_subdev_video_ops,
> +};
> +
> +static int of_get_reg_field(struct device_node *node, struct reg_field *field)
> +{
> +	u32 bit_mask;
> +	int ret;
> +
> +	ret = of_property_read_u32(node, "reg", &field->reg);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = of_property_read_u32(node, "bit-mask", &bit_mask);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = of_property_read_u32(node, "bit-shift", &field->lsb);
> +	if (ret < 0)
> +		return ret;

I think the above would look nice in a MUX driver. :-)

> +
> +	field->msb = field->lsb + fls(bit_mask) - 1;
> +
> +	return 0;
> +}
> +
> +static int vidsw_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct of_endpoint endpoint;
> +	struct device_node *ep;
> +	struct reg_field field;
> +	struct vidsw *vidsw;
> +	struct regmap *map;
> +	unsigned int num_pads;
> +	int ret;
> +
> +	vidsw = devm_kzalloc(&pdev->dev, sizeof(*vidsw), GFP_KERNEL);
> +	if (!vidsw)
> +		return -ENOMEM;
> +
> +	platform_set_drvdata(pdev, vidsw);
> +
> +	v4l2_subdev_init(&vidsw->subdev, &vidsw_subdev_ops);
> +	snprintf(vidsw->subdev.name, sizeof(vidsw->subdev.name), "%s",
> +			np->name);
> +	vidsw->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> +	vidsw->subdev.dev = &pdev->dev;
> +
> +	/*
> +	 * The largest numbered port is the output port. It determines
> +	 * total number of pads
> +	 */
> +	num_pads = 0;

You can initialise num_pads in variable declaration.

> +	for_each_endpoint_of_node(np, ep) {
> +		of_graph_parse_endpoint(ep, &endpoint);
> +		num_pads = max(num_pads, endpoint.port + 1);

Port numbers come directly from DT.

Shouldn't num_pads be only the number of pads that have links with actual
physical connections? I.e. if a device is disabled, it shouldn't be
counted here.

> +	}
> +
> +	if (num_pads < 2) {
> +		dev_err(&pdev->dev, "Not enough ports %d\n", num_pads);
> +		return -EINVAL;
> +	}
> +
> +	ret = of_get_reg_field(np, &field);
> +	if (ret == 0) {
> +		map = syscon_node_to_regmap(np->parent);
> +		if (!map) {
> +			dev_err(&pdev->dev, "Failed to get syscon register map\n");
> +			return PTR_ERR(map);
> +		}
> +
> +		vidsw->field = devm_regmap_field_alloc(&pdev->dev, map, field);
> +		if (IS_ERR(vidsw->field)) {
> +			dev_err(&pdev->dev, "Failed to allocate regmap field\n");
> +			return PTR_ERR(vidsw->field);
> +		}
> +
> +		regmap_field_read(vidsw->field, &vidsw->active);
> +	} else {
> +		if (num_pads > 3) {
> +			dev_err(&pdev->dev, "Too many ports %d\n", num_pads);
> +			return -EINVAL;
> +		}
> +
> +		vidsw->gpio = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_LOW);
> +		if (IS_ERR(vidsw->gpio)) {
> +			dev_warn(&pdev->dev,
> +				 "could not request control gpio: %d\n", ret);
> +			vidsw->gpio = NULL;
> +		}
> +
> +		vidsw->active = gpiod_get_value(vidsw->gpio) ? 1 : 0;
> +	}
> +
> +	vidsw->num_pads = num_pads;
> +	vidsw->pads = devm_kzalloc(&pdev->dev, sizeof(*vidsw->pads) * num_pads,
> +			GFP_KERNEL);
> +	vidsw->format_mbus = devm_kzalloc(&pdev->dev,
> +			sizeof(*vidsw->format_mbus) * num_pads, GFP_KERNEL);
> +	vidsw->endpoint = devm_kzalloc(&pdev->dev,
> +			sizeof(*vidsw->endpoint) * (num_pads - 1), GFP_KERNEL);
> +
> +	ret = vidsw_async_init(vidsw, np);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int vidsw_remove(struct platform_device *pdev)
> +{
> +	struct vidsw *vidsw = platform_get_drvdata(pdev);
> +	struct v4l2_subdev *sd = &vidsw->subdev;
> +
> +	v4l2_async_unregister_subdev(sd);
> +	media_entity_cleanup(&sd->entity);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id vidsw_dt_ids[] = {
> +	{ .compatible = "video-multiplexer", },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, vidsw_dt_ids);
> +
> +static struct platform_driver vidsw_driver = {
> +	.probe		= vidsw_probe,
> +	.remove		= vidsw_remove,
> +	.driver		= {
> +		.of_match_table = vidsw_dt_ids,
> +		.name = "video-multiplexer",
> +	},
> +};
> +
> +module_platform_driver(vidsw_driver);
> +
> +MODULE_DESCRIPTION("video stream multiplexer");
> +MODULE_AUTHOR("Sascha Hauer, Pengutronix");
> +MODULE_AUTHOR("Philipp Zabel, Pengutronix");
> +MODULE_LICENSE("GPL");

-- 
Kind regards,

Sakari Ailus
e-mail: sakari.ailus-X3B1VOXEql0@public.gmane.org	XMPP: sailus-PCDdDYkjdNMDXYZnReoRVg@public.gmane.org
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH V10 07/12] of/acpi: Configure dma operations at probe time for platform/amba/pci bus devices
From: Sricharan R @ 2017-04-04 12:30 UTC (permalink / raw)
  To: Robin Murphy, will.deacon, joro, lorenzo.pieralisi, iommu,
	linux-arm-kernel, linux-arm-msm, m.szyprowski, bhelgaas,
	linux-pci, linux-acpi, tn, hanjun.guo, okaya, robh+dt,
	frowand.list, devicetree, linux-kernel, sudeep.holla, rjw, lenb,
	catalin.marinas, arnd, linux-arch, gregkh
In-Reply-To: <1d036139-b885-bac6-01c0-78d3ac690d80@arm.com>

Hi Robin,

On 4/4/2017 5:47 PM, Robin Murphy wrote:
> On 04/04/17 11:18, Sricharan R wrote:
>> Configuring DMA ops at probe time will allow deferring device probe when
>> the IOMMU isn't available yet. The dma_configure for the device is
>> now called from the generic device_attach callback just before the
>> bus/driver probe is called. This way, configuring the DMA ops for the
>> device would be called at the same place for all bus_types, hence the
>> deferred probing mechanism should work for all buses as well.
>>
>> pci_bus_add_devices    (platform/amba)(_device_create/driver_register)
>>        |                         |
>> pci_bus_add_device     (device_add/driver_register)
>>        |                         |
>> device_attach           device_initial_probe
>>        |                         |
>> __device_attach_driver    __device_attach_driver
>>        |
>> driver_probe_device
>>        |
>> really_probe
>>        |
>> dma_configure
>>
>> Similarly on the device/driver_unregister path __device_release_driver is
>> called which inturn calls dma_deconfigure.
>>
>> This patch changes the dma ops configuration to probe time for
>> both OF and ACPI based platform/amba/pci bus devices.
>
> Reviewed-by: Robin Murphy <robin.murphy@arm.com>
>
> It's possible we could subsume {of,acpi}_dma_deconfigure() into
> dma_deconfigure() entirely in future if it becomes clear that neither of
> them will ever need to do anything firmware-specific, but I think for
> now it's probably safer to keep the current symmetry - calling
> arch_teardown_dma_ops() twice is benign (and even if it weren't, I'd say
> it really should be!)
>

Ya, calling it twice should cause no harm. If nothing firmware specific
gets added this could simply be put in deconfigure itself in future.
Thanks for all the reviews !!

Regards,
  Sricharan



> Robin.
>
>> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
>> Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
>> Acked-by: Bjorn Helgaas <bhelgaas@google.com> (drivers/pci part)
>> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
>> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
>> ---
>>
>>  [V10] Added dummy dma_(de)configure functions in case
>>        of !CONFIG_HAS_DMA to avoid build breaks.
>>
>>  drivers/acpi/glue.c         |  5 -----
>>  drivers/base/dd.c           |  9 +++++++++
>>  drivers/base/dma-mapping.c  | 40 ++++++++++++++++++++++++++++++++++++++++
>>  drivers/of/platform.c       |  5 +----
>>  drivers/pci/probe.c         | 28 ----------------------------
>>  include/linux/dma-mapping.h | 12 ++++++++++++
>>  6 files changed, 62 insertions(+), 37 deletions(-)
>>
>> diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
>> index fb19e1c..c05f241 100644
>> --- a/drivers/acpi/glue.c
>> +++ b/drivers/acpi/glue.c
>> @@ -176,7 +176,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
>>  	struct list_head *physnode_list;
>>  	unsigned int node_id;
>>  	int retval = -EINVAL;
>> -	enum dev_dma_attr attr;
>>
>>  	if (has_acpi_companion(dev)) {
>>  		if (acpi_dev) {
>> @@ -233,10 +232,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
>>  	if (!has_acpi_companion(dev))
>>  		ACPI_COMPANION_SET(dev, acpi_dev);
>>
>> -	attr = acpi_get_dma_attr(acpi_dev);
>> -	if (attr != DEV_DMA_NOT_SUPPORTED)
>> -		acpi_dma_configure(dev, attr);
>> -
>>  	acpi_physnode_link_name(physical_node_name, node_id);
>>  	retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
>>  				   physical_node_name);
>> diff --git a/drivers/base/dd.c b/drivers/base/dd.c
>> index a1fbf55..4882f06 100644
>> --- a/drivers/base/dd.c
>> +++ b/drivers/base/dd.c
>> @@ -19,6 +19,7 @@
>>
>>  #include <linux/device.h>
>>  #include <linux/delay.h>
>> +#include <linux/dma-mapping.h>
>>  #include <linux/module.h>
>>  #include <linux/kthread.h>
>>  #include <linux/wait.h>
>> @@ -356,6 +357,10 @@ static int really_probe(struct device *dev, struct device_driver *drv)
>>  	if (ret)
>>  		goto pinctrl_bind_failed;
>>
>> +	ret = dma_configure(dev);
>> +	if (ret)
>> +		goto dma_failed;
>> +
>>  	if (driver_sysfs_add(dev)) {
>>  		printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
>>  			__func__, dev_name(dev));
>> @@ -417,6 +422,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
>>  	goto done;
>>
>>  probe_failed:
>> +	dma_deconfigure(dev);
>> +dma_failed:
>>  	if (dev->bus)
>>  		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
>>  					     BUS_NOTIFY_DRIVER_NOT_BOUND, dev);
>> @@ -826,6 +833,8 @@ static void __device_release_driver(struct device *dev, struct device *parent)
>>  			drv->remove(dev);
>>
>>  		device_links_driver_cleanup(dev);
>> +		dma_deconfigure(dev);
>> +
>>  		devres_release_all(dev);
>>  		dev->driver = NULL;
>>  		dev_set_drvdata(dev, NULL);
>> diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
>> index efd71cf..449b948 100644
>> --- a/drivers/base/dma-mapping.c
>> +++ b/drivers/base/dma-mapping.c
>> @@ -7,9 +7,11 @@
>>   * This file is released under the GPLv2.
>>   */
>>
>> +#include <linux/acpi.h>
>>  #include <linux/dma-mapping.h>
>>  #include <linux/export.h>
>>  #include <linux/gfp.h>
>> +#include <linux/of_device.h>
>>  #include <linux/slab.h>
>>  #include <linux/vmalloc.h>
>>
>> @@ -341,3 +343,41 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)
>>  	vunmap(cpu_addr);
>>  }
>>  #endif
>> +
>> +/*
>> + * Common configuration to enable DMA API use for a device
>> + */
>> +#include <linux/pci.h>
>> +
>> +int dma_configure(struct device *dev)
>> +{
>> +	struct device *bridge = NULL, *dma_dev = dev;
>> +	enum dev_dma_attr attr;
>> +
>> +	if (dev_is_pci(dev)) {
>> +		bridge = pci_get_host_bridge_device(to_pci_dev(dev));
>> +		dma_dev = bridge;
>> +		if (IS_ENABLED(CONFIG_OF) && dma_dev->parent &&
>> +		    dma_dev->parent->of_node)
>> +			dma_dev = dma_dev->parent;
>> +	}
>> +
>> +	if (dma_dev->of_node) {
>> +		of_dma_configure(dev, dma_dev->of_node);
>> +	} else if (has_acpi_companion(dma_dev)) {
>> +		attr = acpi_get_dma_attr(to_acpi_device_node(dma_dev->fwnode));
>> +		if (attr != DEV_DMA_NOT_SUPPORTED)
>> +			acpi_dma_configure(dev, attr);
>> +	}
>> +
>> +	if (bridge)
>> +		pci_put_host_bridge_device(bridge);
>> +
>> +	return 0;
>> +}
>> +
>> +void dma_deconfigure(struct device *dev)
>> +{
>> +	of_dma_deconfigure(dev);
>> +	acpi_dma_deconfigure(dev);
>> +}
>> diff --git a/drivers/of/platform.c b/drivers/of/platform.c
>> index 5344db5..2aa4ebb 100644
>> --- a/drivers/of/platform.c
>> +++ b/drivers/of/platform.c
>> @@ -22,6 +22,7 @@
>>  #include <linux/slab.h>
>>  #include <linux/of_address.h>
>>  #include <linux/of_device.h>
>> +#include <linux/of_iommu.h>
>>  #include <linux/of_irq.h>
>>  #include <linux/of_platform.h>
>>  #include <linux/platform_device.h>
>> @@ -186,11 +187,9 @@ static struct platform_device *of_platform_device_create_pdata(
>>
>>  	dev->dev.bus = &platform_bus_type;
>>  	dev->dev.platform_data = platform_data;
>> -	of_dma_configure(&dev->dev, dev->dev.of_node);
>>  	of_msi_configure(&dev->dev, dev->dev.of_node);
>>
>>  	if (of_device_add(dev) != 0) {
>> -		of_dma_deconfigure(&dev->dev);
>>  		platform_device_put(dev);
>>  		goto err_clear_flag;
>>  	}
>> @@ -248,7 +247,6 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
>>  		dev_set_name(&dev->dev, "%s", bus_id);
>>  	else
>>  		of_device_make_bus_id(&dev->dev);
>> -	of_dma_configure(&dev->dev, dev->dev.of_node);
>>
>>  	/* Allow the HW Peripheral ID to be overridden */
>>  	prop = of_get_property(node, "arm,primecell-periphid", NULL);
>> @@ -542,7 +540,6 @@ static int of_platform_device_destroy(struct device *dev, void *data)
>>  		amba_device_unregister(to_amba_device(dev));
>>  #endif
>>
>> -	of_dma_deconfigure(dev);
>>  	of_node_clear_flag(dev->of_node, OF_POPULATED);
>>  	of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
>>  	return 0;
>> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
>> index dfc9a27..5a8dd43 100644
>> --- a/drivers/pci/probe.c
>> +++ b/drivers/pci/probe.c
>> @@ -1893,33 +1893,6 @@ static void pci_set_msi_domain(struct pci_dev *dev)
>>  	dev_set_msi_domain(&dev->dev, d);
>>  }
>>
>> -/**
>> - * pci_dma_configure - Setup DMA configuration
>> - * @dev: ptr to pci_dev struct of the PCI device
>> - *
>> - * Function to update PCI devices's DMA configuration using the same
>> - * info from the OF node or ACPI node of host bridge's parent (if any).
>> - */
>> -static void pci_dma_configure(struct pci_dev *dev)
>> -{
>> -	struct device *bridge = pci_get_host_bridge_device(dev);
>> -
>> -	if (IS_ENABLED(CONFIG_OF) &&
>> -		bridge->parent && bridge->parent->of_node) {
>> -			of_dma_configure(&dev->dev, bridge->parent->of_node);
>> -	} else if (has_acpi_companion(bridge)) {
>> -		struct acpi_device *adev = to_acpi_device_node(bridge->fwnode);
>> -		enum dev_dma_attr attr = acpi_get_dma_attr(adev);
>> -
>> -		if (attr == DEV_DMA_NOT_SUPPORTED)
>> -			dev_warn(&dev->dev, "DMA not supported.\n");
>> -		else
>> -			acpi_dma_configure(&dev->dev, attr);
>> -	}
>> -
>> -	pci_put_host_bridge_device(bridge);
>> -}
>> -
>>  void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
>>  {
>>  	int ret;
>> @@ -1933,7 +1906,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
>>  	dev->dev.dma_mask = &dev->dma_mask;
>>  	dev->dev.dma_parms = &dev->dma_parms;
>>  	dev->dev.coherent_dma_mask = 0xffffffffull;
>> -	pci_dma_configure(dev);
>>
>>  	pci_set_dma_max_seg_size(dev, 65536);
>>  	pci_set_dma_seg_boundary(dev, 0xffffffff);
>> diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
>> index 0977317..4f3eece 100644
>> --- a/include/linux/dma-mapping.h
>> +++ b/include/linux/dma-mapping.h
>> @@ -728,6 +728,18 @@ void *dma_mark_declared_memory_occupied(struct device *dev,
>>  }
>>  #endif /* CONFIG_HAVE_GENERIC_DMA_COHERENT */
>>
>> +#ifdef CONFIG_HAS_DMA
>> +int dma_configure(struct device *dev);
>> +void dma_deconfigure(struct device *dev);
>> +#else
>> +static inline int dma_configure(struct device *dev)
>> +{
>> +	return 0;
>> +}
>> +
>> +static inline void dma_deconfigure(struct device *dev) {}
>> +#endif
>> +
>>  /*
>>   * Managed DMA API
>>   */
>>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

-- 
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

^ permalink raw reply

* [PATCH v3] clk: stm32h7: Add stm32h743 clock driver
From: gabriel.fernandez @ 2017-04-04 12:30 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Russell King, Maxime Coquelin,
	Alexandre Torgue, Michael Turquette, Stephen Boyd, Nicolas Pitre,
	Arnd Bergmann, daniel.thompson, andrea.merello, radoslaw.pietrzyk,
	Lee Jones
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk,
	gabriel.fernandez, ludovic.barre, olivier.bideau, amelie.delaunay

From: Gabriel Fernandez <gabriel.fernandez@st.com>

This patch enables clocks for STM32H743 boards.

Signed-off-by: Gabriel Fernandez <gabriel.fernandez@st.com>

for MFD changes:
Acked-by: Lee Jones <lee.jones@linaro.org>

for DT-Bindings
Acked-by: Rob Herring <robh@kernel.org>
v3:
  - fix compatible string "stm32h7-pll" into "st,stm32h7-pll"
  - fix bad parent name for mco2 clock
  - set CLK_SET_RATE_PARENT for ltdc clock
  - set CLK_IGNORE_UNUSED for pll1
  - disable power domain write protection on disable ops if needed


v2:
  - rename compatible string "stm32,pll" into "stm32h7-pll"
  - suppress "st,pllrge" property
  - suppress "st, frac-status" property
  - change management of "st,frac"  property
	0 : enable 0 pll integer mode 
	other values : enable pll in fractional mode (value is
	the fractional factor)
---
 .../devicetree/bindings/clock/st,stm32h7-rcc.txt   |  151 ++
 drivers/clk/Makefile                               |    1 +
 drivers/clk/clk-stm32h7.c                          | 1675 ++++++++++++++++++++
 include/dt-bindings/clock/stm32h7-clks.h           |  165 ++
 include/dt-bindings/mfd/stm32h7-rcc.h              |  137 ++
 5 files changed, 2129 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/st,stm32h7-rcc.txt
 create mode 100644 drivers/clk/clk-stm32h7.c
 create mode 100644 include/dt-bindings/clock/stm32h7-clks.h
 create mode 100644 include/dt-bindings/mfd/stm32h7-rcc.h

diff --git a/Documentation/devicetree/bindings/clock/st,stm32h7-rcc.txt b/Documentation/devicetree/bindings/clock/st,stm32h7-rcc.txt
new file mode 100644
index 0000000..d34ce5b7
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/st,stm32h7-rcc.txt
@@ -0,0 +1,151 @@
+STMicroelectronics STM32H7 Reset and Clock Controller
+=====================================================
+
+The RCC IP is both a reset and a clock controller.
+
+Please refer to clock-bindings.txt for common clock controller binding usage.
+Please also refer to reset.txt for common reset controller binding usage.
+
+Required properties:
+- compatible: Should be:
+  "st,stm32h743-rcc"
+
+- reg: should be register base and length as documented in the
+  datasheet
+
+- #reset-cells: 1, see below
+
+- #clock-cells : from common clock binding; shall be set to 1
+
+- clocks: External oscillator clock phandle
+  - high speed external clock signal (HSE)
+  - low speed external clock signal (LSE)
+  - external I2S clock (I2S_CKIN)
+
+- st,syscfg: phandle for pwrcfg, mandatory to disable/enable backup domain
+  write protection (RTC clock).
+
+- pll x node: Allow to register a pll with specific parameters.
+  Please see PLL section below.
+
+Example:
+
+	rcc: rcc@58024400 {
+		#reset-cells = <1>;
+		#clock-cells = <2>
+		compatible = "st,stm32h743-rcc", "st,stm32-rcc";
+		reg = <0x58024400 0x400>;
+		clocks = <&clk_hse>, <&clk_lse>, <&clk_i2s_ckin>;
+
+		st,syscfg = <&pwrcfg>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		vco1@0 {
+			#clock-cells = <0>;
+			compatible = "st,stm32h7-pll";
+			reg = <0>;
+		};
+
+		vco2@1 {
+			#clock-cells = <0>;
+			compatible = "st,stm32h7-pll";
+			reg = <1>;
+			st,clock-div = <2>;
+			st,clock-mult = <40>;
+			st,frac = <0>;
+			st,vcosel = <1>;
+		};
+		vco3@2 {
+			#clock-cells = <0>;
+			compatible = "st,stm32h7-pll";
+			reg = <2>;
+			st,clock-div = <2>;
+			st,clock-mult = <40>;
+			st,frac = <1024>;
+			st,vcosel = <1>;
+		};
+	};
+
+
+STM32H7 PLL
+-----------
+
+The VCO of STM32 PLL could be reprensented like this:
+
+  Vref    ---------       --------
+    ---->| / DIVM  |---->| x DIVN | ------> VCO
+          ---------       --------
+		             ^
+			     |
+	                  -------
+		         | FRACN |
+		          -------
+
+When the PLL is configured in integer mode:
+- VCO = ( Vref / DIVM ) * DIVN
+
+When the PLL is configured in fractional mode:
+- VCO = ( Vref / DIVM ) * ( DIVN + FRACN / 2^13)
+
+
+Required properties for pll node:
+- compatible: Should be:
+  "st,stm32h7-pll"
+
+- #clock-cells: from common clock binding; shall be set to 0
+- reg: Should be the pll number.
+
+Optional properties:
+- st,clock-div:  DIVM division factor       : <1..63>
+- st,clock-mult: DIVN multiplication factor : <4..512>
+
+- st,frac:
+   - 0 Pll is configured in integer mode
+   - <1..8191> Pll is configure in fractional mode and the value is
+     the part of the multiplication factor.
+
+- st,vcosel: VCO selection
+  - 0: Wide VCO range:192 to 836 MHz
+  - 1: Medium VCO range:150 to 420 MHz
+
+The peripheral clock consumer should specify the desired clock by
+having the clock ID in its "clocks" phandle cell.
+
+All available clocks are defined as preprocessor macros in
+dt-bindings/clock/stm32h7-clks.h header and can be used in device
+tree sources.
+
+Example:
+
+		timer5: timer@40000c00 {
+			compatible = "st,stm32-timer";
+			reg = <0x40000c00 0x400>;
+			interrupts = <50>;
+			clocks = <&rcc TIM5_CK>;
+
+		};
+
+Specifying softreset control of devices
+=======================================
+
+Device nodes should specify the reset channel required in their "resets"
+property, containing a phandle to the reset device node and an index specifying
+which channel to use.
+The index is the bit number within the RCC registers bank, starting from RCC
+base address.
+It is calculated as: index = register_offset / 4 * 32 + bit_offset.
+Where bit_offset is the bit offset within the register.
+
+For example, for CRC reset:
+  crc = AHB4RSTR_offset / 4 * 32 + CRCRST_bit_offset = 0x88 / 4 * 32 + 19 = 1107
+
+All available preprocessor macros for reset are defined dt-bindings//mfd/stm32h7-rcc.h
+header and can be used in device tree sources.
+
+example:
+
+	timer2 {
+		resets	= <&rcc STM32H7_APB1L_RESET(TIM2)>;
+	};
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 92c12b8..734aa02 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_COMMON_CLK_SI5351)		+= clk-si5351.o
 obj-$(CONFIG_COMMON_CLK_SI514)		+= clk-si514.o
 obj-$(CONFIG_COMMON_CLK_SI570)		+= clk-si570.o
 obj-$(CONFIG_ARCH_STM32)		+= clk-stm32f4.o
+obj-$(CONFIG_ARCH_STM32)		+= clk-stm32h7.o
 obj-$(CONFIG_ARCH_TANGO)		+= clk-tango4.o
 obj-$(CONFIG_CLK_TWL6040)		+= clk-twl6040.o
 obj-$(CONFIG_ARCH_U300)			+= clk-u300.o
diff --git a/drivers/clk/clk-stm32h7.c b/drivers/clk/clk-stm32h7.c
new file mode 100644
index 0000000..cdcb27e
--- /dev/null
+++ b/drivers/clk/clk-stm32h7.c
@@ -0,0 +1,1675 @@
+/*
+ * Copyright (C) Gabriel Fernandez 2017
+ * Author: Gabriel Fernandez <gabriel.fernandez@st.com>
+ *
+ * License terms: GPL V2.0.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/stm32h7-clks.h>
+
+/* Reset Clock Control Registers */
+#define RCC_CR		0x00
+#define RCC_CFGR	0x10
+#define RCC_D1CFGR	0x18
+#define RCC_D2CFGR	0x1C
+#define RCC_D3CFGR	0x20
+#define RCC_PLLCKSELR	0x28
+#define RCC_PLLCFGR	0x2C
+#define RCC_PLL1DIVR	0x30
+#define RCC_PLL1FRACR	0x34
+#define RCC_PLL2DIVR	0x38
+#define RCC_PLL2FRACR	0x3C
+#define RCC_PLL3DIVR	0x40
+#define RCC_PLL3FRACR	0x44
+#define RCC_D1CCIPR	0x4C
+#define RCC_D2CCIP1R	0x50
+#define RCC_D2CCIP2R	0x54
+#define RCC_D3CCIPR	0x58
+#define RCC_BDCR	0x70
+#define RCC_CSR		0x74
+#define RCC_AHB3ENR	0xD4
+#define RCC_AHB1ENR	0xD8
+#define RCC_AHB2ENR	0xDC
+#define RCC_AHB4ENR	0xE0
+#define RCC_APB3ENR	0xE4
+#define RCC_APB1LENR	0xE8
+#define RCC_APB1HENR	0xEC
+#define RCC_APB2ENR	0xF0
+#define RCC_APB4ENR	0xF4
+
+static DEFINE_SPINLOCK(rlock);
+
+static void __iomem *base;
+static struct regmap *pdrm;
+static struct clk_hw **hws;
+
+/* System clock parent */
+static const char * const sys_src[] = {
+	"hsi_ck", "csi_ck", "hse_ck", "pll1_p" };
+
+static const char * const tracein_src[] = {
+	"hsi_ck", "csi_ck", "hse_ck", "pll1_r" };
+
+static const char * const per_src[] = {
+	"hsi_ker", "csi_ker", "hse_ck", "disabled" };
+
+static const char * const pll_src[] = {
+	"hsi_ck", "csi_ck", "hse_ck", "no clock" };
+
+static const char * const sdmmc_src[] = { "pll1_q", "pll2_r" };
+
+static const char * const dsi_src[] = { "ck_dsi_phy", "pll2_q" };
+
+static const char * const qspi_src[] = {
+	"hclk", "pll1_q", "pll2_r", "per_ck" };
+
+static const char * const fmc_src[] = {
+	"hclk", "pll1_q", "pll2_r", "per_ck" };
+
+/* Kernel clock parent */
+static const char * const swp_src[] = {	"pclk1", "hsi_ker" };
+
+static const char * const fdcan_src[] = { "hse_ck", "pll1_q", "pll2_q" };
+
+static const char * const dfsdm1_src[] = { "pclk2", "sys_ck" };
+
+static const char * const spdifrx_src[] = {
+	"pll1_q", "pll2_r", "pll3_r", "hsi_ker" };
+
+static const char *spi_src1[5] = {
+	"pll1_q", "pll2_p", "pll3_p", NULL, "per_ck" };
+
+static const char * const spi_src2[] = {
+	"pclk2", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "hse_ck" };
+
+static const char * const spi_src3[] = {
+	"pclk4", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "hse_ck" };
+
+static const char * const lptim_src1[] = {
+	"pclk1", "pll2_p", "pll3_r", "lse_ck", "lsi_ck", "per_ck" };
+
+static const char * const lptim_src2[] = {
+	"pclk4", "pll2_p", "pll3_r", "lse_ck", "lsi_ck", "per_ck" };
+
+static const char * const cec_src[] = {"lse_ck", "lsi_ck", "csi_ker_div122" };
+
+static const char * const usbotg_src[] = {"pll1_q", "pll3_q", "rc48_ck" };
+
+/* i2c 1,2,3 src */
+static const char * const i2c_src1[] = {
+	"pclk1", "pll3_r", "hsi_ker", "csi_ker" };
+
+static const char * const i2c_src2[] = {
+	"pclk4", "pll3_r", "hsi_ker", "csi_ker" };
+
+static const char * const rng_src[] = {
+	"rc48_ck", "pll1_q", "lse_ck", "lsi_ck" };
+
+/* usart 1,6 src */
+static const char * const usart_src1[] = {
+	"pclk2", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "lse_ck" };
+
+/* usart 2,3,4,5,7,8 src */
+static const char * const usart_src2[] = {
+	"pclk1", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "lse_ck" };
+
+static const char *sai_src[5] = {
+	"pll1_q", "pll2_p", "pll3_p", NULL, "per_ck" };
+
+static const char * const adc_src[] = { "pll2_p", "pll3_r", "per_ck" };
+
+/* lptim 2,3,4,5 src */
+static const char * const lpuart1_src[] = {
+	"pclk3", "pll2_q", "pll3_q", "csi_ker", "lse_ck" };
+
+static const char * const hrtim_src[] = { "tim2_ker", "d1cpre" };
+
+/* RTC clock parent */
+static const char * const rtc_src[] = { "off", "lse_ck", "lsi_ck", "hse_1M" };
+
+/* Micro-controller output clock parent */
+static const char * const mco_src1[] = {
+	"hsi_ck", "lse_ck", "hse_ck", "pll1_q",	"rc48_ck" };
+
+static const char * const mco_src2[] = {
+	"sys_ck", "pll2_p", "hse_ck", "pll1_p", "csi_ck", "lsi_ck" };
+
+/* LCD clock */
+static const char * const ltdc_src[] = {"pll3_r"};
+
+/* Power domain helper */
+static inline void disable_power_domain_write_protection(void)
+{
+	if (pdrm)
+		regmap_update_bits(pdrm, 0x00, (1 << 8), (1 << 8));
+}
+
+static inline void enable_power_domain_write_protection(void)
+{
+	if (pdrm)
+		regmap_update_bits(pdrm, 0x00, (1 << 8), (0 << 8));
+}
+
+static inline int is_enable_power_domain_write_protection(void)
+{
+	if (pdrm) {
+		u32 val;
+
+		regmap_read(pdrm, 0x00, &val);
+
+		return !(val & 0x100);
+	}
+	return -1;
+}
+
+/* Gate clock with ready bit and backup domain management */
+struct stm32_ready_gate {
+	struct	clk_gate gate;
+	u8	bit_rdy;
+	u8	backup_domain;
+};
+
+#define to_ready_gate_clk(_rgate) container_of(_rgate, struct stm32_ready_gate,\
+		gate)
+
+#define RGATE_TIMEOUT 600000
+
+static int ready_gate_clk_is_enabled(struct clk_hw *hw)
+{
+	return clk_gate_ops.is_enabled(hw);
+}
+
+static int ready_gate_clk_enable(struct clk_hw *hw)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+	struct stm32_ready_gate *rgate = to_ready_gate_clk(gate);
+	int dbp_status;
+	int bit_status;
+	unsigned int timeout = RGATE_TIMEOUT;
+
+	if (clk_gate_ops.is_enabled(hw))
+		return 0;
+
+	dbp_status = is_enable_power_domain_write_protection();
+
+	if (rgate->backup_domain && dbp_status)
+		disable_power_domain_write_protection();
+
+	clk_gate_ops.enable(hw);
+
+	do {
+		bit_status = !(readl(gate->reg) & BIT(rgate->bit_rdy));
+
+		if (bit_status)
+			udelay(1000);
+
+	} while (bit_status && --timeout);
+
+	if (rgate->backup_domain && dbp_status)
+		enable_power_domain_write_protection();
+
+	return bit_status;
+}
+
+static void ready_gate_clk_disable(struct clk_hw *hw)
+{
+	struct clk_gate *gate = to_clk_gate(hw);
+	struct stm32_ready_gate *rgate = to_ready_gate_clk(gate);
+	int dbp_status;
+	int bit_status;
+	unsigned int timeout = RGATE_TIMEOUT;
+
+	if (!ready_gate_clk_is_enabled(hw))
+		return;
+
+	dbp_status = is_enable_power_domain_write_protection();
+
+	if (rgate->backup_domain && dbp_status)
+		disable_power_domain_write_protection();
+
+		clk_gate_ops.disable(hw);
+
+	do {
+		bit_status = !!(readl(gate->reg) & BIT(rgate->bit_rdy));
+
+		if (bit_status)
+			udelay(1000);
+
+	} while (bit_status && --timeout);
+	if (rgate->backup_domain && dbp_status)
+		enable_power_domain_write_protection();
+}
+
+static const struct clk_ops ready_gate_clk_ops = {
+	.enable		= ready_gate_clk_enable,
+	.disable	= ready_gate_clk_disable,
+	.is_enabled	= ready_gate_clk_is_enabled,
+};
+
+static struct clk_hw *clk_register_ready_gate(struct device *dev,
+		const char *name, const char *parent_name,
+		void __iomem *reg, u8 bit_idx, u8 bit_rdy,
+		u8 backup_domain, unsigned long flags, spinlock_t *lock)
+{
+	struct stm32_ready_gate *rgate;
+	struct clk_init_data init = { NULL };
+	struct clk_hw *hw;
+	int ret;
+
+	rgate = kzalloc(sizeof(*rgate), GFP_KERNEL);
+	if (!rgate)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &ready_gate_clk_ops;
+	init.flags = flags;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	rgate->bit_rdy = bit_rdy;
+	rgate->backup_domain = backup_domain;
+
+	rgate->gate.lock = lock;
+	rgate->gate.reg = reg;
+	rgate->gate.bit_idx = bit_idx;
+	rgate->gate.hw.init = &init;
+
+	hw = &rgate->gate.hw;
+	ret = clk_hw_register(dev, hw);
+	if (ret) {
+		kfree(rgate);
+		hw = ERR_PTR(ret);
+	}
+
+	return hw;
+}
+
+struct gate_cfg {
+	u32 offset;
+	u8  bit_idx;
+};
+
+struct muxdiv_cfg {
+	u32 offset;
+	u8 shift;
+	u8 width;
+};
+
+struct composite_clk_cfg {
+	struct gate_cfg *gate;
+	struct muxdiv_cfg *mux;
+	struct muxdiv_cfg *div;
+	const char *name;
+	const char * const *parent_name;
+	int num_parents;
+	u32 flags;
+};
+
+struct composite_clk_gcfg_t {
+	u8 flags;
+	const struct clk_ops *ops;
+};
+
+/*
+ * General config definition of a composite clock (only clock diviser for rate)
+ */
+struct composite_clk_gcfg {
+	struct composite_clk_gcfg_t *mux;
+	struct composite_clk_gcfg_t *div;
+	struct composite_clk_gcfg_t *gate;
+};
+
+#define M_CFG_MUX(_mux_ops, _mux_flags)\
+	.mux = &(struct composite_clk_gcfg_t) { _mux_flags, _mux_ops}
+
+#define M_CFG_DIV(_rate_ops, _rate_flags)\
+	.div = &(struct composite_clk_gcfg_t) {_rate_flags, _rate_ops}
+
+#define M_CFG_GATE(_gate_ops, _gate_flags)\
+	.gate = &(struct composite_clk_gcfg_t) { _gate_flags, _gate_ops}
+
+static struct clk_mux *_get_cmux(void __iomem *reg, u8 shift, u8 width,
+		u32 flags, spinlock_t *lock)
+{
+	struct clk_mux *mux;
+
+	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		return ERR_PTR(-ENOMEM);
+
+	mux->reg	= reg;
+	mux->shift	= shift;
+	mux->mask	= (1 << width) - 1;
+	mux->flags	= flags;
+	mux->lock	= lock;
+
+	return mux;
+}
+
+static struct clk_divider *_get_cdiv(void __iomem *reg, u8 shift, u8 width,
+		u32 flags, spinlock_t *lock)
+{
+	struct clk_divider *div;
+
+	div = kzalloc(sizeof(*div), GFP_KERNEL);
+
+	if (!div)
+		return ERR_PTR(-ENOMEM);
+
+	div->reg   = reg;
+	div->shift = shift;
+	div->width = width;
+	div->flags = flags;
+	div->lock  = lock;
+
+	return div;
+}
+
+static struct clk_gate *_get_cgate(void __iomem *reg, u8 bit_idx, u32 flags,
+		spinlock_t *lock)
+{
+	struct clk_gate *gate;
+
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (!gate)
+		return ERR_PTR(-ENOMEM);
+
+	gate->reg	= reg;
+	gate->bit_idx	= bit_idx;
+	gate->flags	= flags;
+	gate->lock	= lock;
+
+	return gate;
+}
+
+struct composite_cfg {
+	struct clk_hw *mux_hw;
+	struct clk_hw *div_hw;
+	struct clk_hw *gate_hw;
+
+	const struct clk_ops *mux_ops;
+	const struct clk_ops *div_ops;
+	const struct clk_ops *gate_ops;
+};
+
+static void get_cfg_composite_div(const struct composite_clk_gcfg *gcfg,
+		const struct composite_clk_cfg *cfg,
+		struct composite_cfg *composite, spinlock_t *lock)
+{
+	struct clk_mux     *mux = NULL;
+	struct clk_divider *div = NULL;
+	struct clk_gate    *gate = NULL;
+	const struct clk_ops *mux_ops, *div_ops, *gate_ops;
+	struct clk_hw *mux_hw;
+	struct clk_hw *div_hw;
+	struct clk_hw *gate_hw;
+
+	mux_ops = div_ops = gate_ops = NULL;
+	mux_hw = div_hw = gate_hw = NULL;
+
+	if (gcfg->mux) {
+		mux = _get_cmux(base + cfg->mux->offset,
+				cfg->mux->shift,
+				cfg->mux->width,
+				gcfg->mux->flags, lock);
+
+		if (!IS_ERR(mux)) {
+			mux_hw = &mux->hw;
+			mux_ops = gcfg->mux->ops ?
+				  gcfg->mux->ops : &clk_mux_ops;
+		}
+	}
+
+	if (gcfg->div) {
+		div = _get_cdiv(base + cfg->div->offset,
+				cfg->div->shift,
+				cfg->div->width,
+				gcfg->div->flags, lock);
+
+		if (!IS_ERR(div)) {
+			div_hw = &div->hw;
+			div_ops = gcfg->div->ops ?
+				  gcfg->div->ops : &clk_divider_ops;
+		}
+
+	}
+
+	if (gcfg->gate) {
+		gate = _get_cgate(base + cfg->gate->offset,
+				cfg->gate->bit_idx,
+				gcfg->gate->flags, lock);
+
+		if (!IS_ERR(gate)) {
+			gate_hw = &gate->hw;
+			gate_ops = gcfg->gate->ops ?
+				   gcfg->gate->ops : &clk_gate_ops;
+		}
+
+	}
+
+	composite->mux_hw = mux_hw;
+	composite->mux_ops = mux_ops;
+
+	composite->div_hw = div_hw;
+	composite->div_ops = div_ops;
+
+	composite->gate_hw = gate_hw;
+	composite->gate_ops = gate_ops;
+}
+
+/* Kernel Timer */
+struct timer_ker {
+	u8 dppre_shift;
+	struct clk_hw hw;
+	spinlock_t *lock;
+};
+
+#define to_timer_ker(_hw) container_of(_hw, struct timer_ker, hw)
+
+static unsigned long timer_ker_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct timer_ker *clk_elem = to_timer_ker(hw);
+	u32 timpre;
+	u32 dppre_shift = clk_elem->dppre_shift;
+	u32 prescaler;
+	u32 mul;
+
+	timpre = (readl(base + RCC_CFGR) >> 15) & 0x01;
+
+	prescaler = (readl(base + RCC_D2CFGR) >> dppre_shift) & 0x03;
+
+	mul = 2;
+
+	if (prescaler < 4)
+		mul = 1;
+
+	else if (timpre && prescaler > 4)
+		mul = 4;
+
+	return parent_rate * mul;
+}
+
+static const struct clk_ops timer_ker_ops = {
+	.recalc_rate = timer_ker_recalc_rate,
+};
+
+static struct clk_hw *clk_register_stm32_timer_ker(struct device *dev,
+		const char *name, const char *parent_name,
+		unsigned long flags,
+		u8 dppre_shift,
+		spinlock_t lock)
+{
+	struct timer_ker *element;
+	struct clk_init_data init;
+	struct clk_hw *hw;
+	int err;
+
+	element = kzalloc(sizeof(*element), GFP_KERNEL);
+	if (!element)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &timer_ker_ops;
+	init.flags = flags;
+	init.parent_names = &parent_name;
+	init.num_parents = 1;
+
+	element->hw.init = &init;
+	element->lock = &lock;
+	element->dppre_shift = dppre_shift;
+
+	hw = &element->hw;
+	err = clk_hw_register(dev, hw);
+
+	if (err) {
+		kfree(element);
+		return ERR_PTR(err);
+	}
+
+	return hw;
+}
+
+static const struct clk_div_table d1cpre_div_table[] = {
+	{ 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1},
+	{ 4, 1 }, { 5, 1 }, { 6, 1 }, { 7, 1},
+	{ 8, 2 }, { 9, 4 }, { 10, 8 }, { 11, 16 },
+	{ 12, 64 }, { 13, 128 }, { 14, 256 },
+	{ 15, 512 },
+	{ 0 },
+};
+
+static const struct clk_div_table ppre_div_table[] = {
+	{ 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1},
+	{ 4, 2 }, { 5, 4 }, { 6, 8 }, { 7, 16 },
+	{ 0 },
+};
+
+static void register_core_and_bus_clocks(void)
+{
+	/* CORE AND BUS */
+	hws[SYS_D1CPRE] = clk_hw_register_divider_table(NULL, "d1cpre",
+			"sys_ck", CLK_IGNORE_UNUSED, base + RCC_D1CFGR, 8, 4, 0,
+			d1cpre_div_table, &rlock);
+
+	hws[HCLK] = clk_hw_register_divider_table(NULL, "hclk", "d1cpre",
+			CLK_IGNORE_UNUSED, base + RCC_D1CFGR, 0, 4, 0,
+			d1cpre_div_table, &rlock);
+
+	/* D1 DOMAIN */
+	/* * CPU Systick */
+	hws[CPU_SYSTICK] = clk_hw_register_fixed_factor(NULL, "systick",
+			"d1cpre", 0, 1, 8);
+
+	/* * APB3 peripheral */
+	hws[PCLK3] = clk_hw_register_divider_table(NULL, "pclk3", "hclk", 0,
+			base + RCC_D1CFGR, 4, 3, 0,
+			ppre_div_table, &rlock);
+
+	/* D2 DOMAIN */
+	/* * APB1 peripheral */
+	hws[PCLK1] = clk_hw_register_divider_table(NULL, "pclk1", "hclk", 0,
+			base + RCC_D2CFGR, 4, 3, 0,
+			ppre_div_table, &rlock);
+
+	/* Timers prescaler clocks */
+	clk_register_stm32_timer_ker(NULL, "tim1_ker", "pclk1", 0,
+			4, rlock);
+
+	/* * APB2 peripheral */
+	hws[PCLK2] = clk_hw_register_divider_table(NULL, "pclk2", "hclk", 0,
+			base + RCC_D2CFGR, 8, 3, 0, ppre_div_table, &rlock);
+
+	clk_register_stm32_timer_ker(NULL, "tim2_ker", "pclk2", 0, 8, rlock);
+
+	/* D3 DOMAIN */
+	/* * APB4 peripheral */
+	hws[PCLK4] = clk_hw_register_divider_table(NULL, "pclk4", "hclk", 0,
+			base + RCC_D3CFGR, 4, 3, 0,
+			ppre_div_table, &rlock);
+}
+
+/* MUX clock configuration */
+struct stm32_mux_clk {
+	const char *name;
+	const char * const *parents;
+	u8 num_parents;
+	u32 offset;
+	u8 shift;
+	u8 width;
+	u32 flags;
+};
+
+#define M_MCLOCF(_name, _parents, _mux_offset, _mux_shift, _mux_width, _flags)\
+{\
+	.name		= _name,\
+	.parents	= _parents,\
+	.num_parents	= ARRAY_SIZE(_parents),\
+	.offset		= _mux_offset,\
+	.shift		= _mux_shift,\
+	.width		= _mux_width,\
+	.flags		= _flags,\
+}
+#define M_MCLOC(_name, _parents, _mux_offset, _mux_shift, _mux_width)\
+	M_MCLOCF(_name, _parents, _mux_offset, _mux_shift, _mux_width, 0)\
+
+static const struct stm32_mux_clk stm32_mclk[] __initconst = {
+	M_MCLOC("per_ck",	per_src,	RCC_D1CCIPR,	28, 3),
+	M_MCLOC("pllsrc",	pll_src,	RCC_PLLCKSELR,	 0, 3),
+	M_MCLOC("sys_ck",	sys_src,	RCC_CFGR,	 0, 3),
+	M_MCLOC("tracein_ck",	tracein_src,	RCC_CFGR,	 0, 3),
+};
+
+/* Oscillary clock configuration */
+struct stm32_osc_clk {
+	const char *name;
+	const char *parent;
+	u32 gate_offset;
+	u8 bit_idx;
+	u8 bit_rdy;
+	u32 flags;
+};
+
+#define OSC_CLKF(_name, _parent, _gate_offset, _bit_idx, _bit_rdy, _flags)\
+{\
+	.name		= _name,\
+	.parent		= _parent,\
+	.gate_offset	= _gate_offset,\
+	.bit_idx	= _bit_idx,\
+	.bit_rdy	= _bit_rdy,\
+	.flags		= _flags,\
+}
+#define OSC_CLK(_name, _parent, _gate_offset, _bit_idx, _bit_rdy)\
+	OSC_CLKF(_name, _parent, _gate_offset, _bit_idx, _bit_rdy, 0)
+
+static const struct stm32_osc_clk stm32_oclk[] __initconst = {
+	OSC_CLKF("hsi_ck",  "hsidiv",   RCC_CR,   0,  2, CLK_IGNORE_UNUSED),
+	OSC_CLKF("hsi_ker", "hsidiv",   RCC_CR,   1,  2, CLK_IGNORE_UNUSED),
+	OSC_CLKF("csi_ck",  "clk-csi",  RCC_CR,   7,  8, CLK_IGNORE_UNUSED),
+	OSC_CLKF("csi_ker", "clk-csi",  RCC_CR,   9,  8, CLK_IGNORE_UNUSED),
+	OSC_CLKF("rc48_ck", "clk-rc48", RCC_CR,  12, 13, CLK_IGNORE_UNUSED),
+	OSC_CLKF("lsi_ck",  "clk-lsi",  RCC_CSR,  0,  1, CLK_IGNORE_UNUSED),
+};
+
+/* PLL configuration */
+struct st32h7_pll_cfg {
+	u8 bit_idx;
+	u32 offset_divr;
+	u8 bit_frac_en;
+	u32 offset_frac;
+	u8 divm;
+};
+
+struct stm32_pll_data {
+	const char *name;
+	const char *parent_name;
+	unsigned long flags;
+	const struct st32h7_pll_cfg *cfg;
+};
+
+static const struct st32h7_pll_cfg stm32h7_pll1 = {
+	.bit_idx = 24,
+	.offset_divr = RCC_PLL1DIVR,
+	.bit_frac_en = 0,
+	.offset_frac = RCC_PLL1FRACR,
+	.divm = 4,
+};
+
+static const struct st32h7_pll_cfg stm32h7_pll2 = {
+	.bit_idx = 26,
+	.offset_divr = RCC_PLL2DIVR,
+	.bit_frac_en = 4,
+	.offset_frac = RCC_PLL2FRACR,
+	.divm = 12,
+};
+
+static const struct st32h7_pll_cfg stm32h7_pll3 = {
+	.bit_idx = 28,
+	.offset_divr = RCC_PLL3DIVR,
+	.bit_frac_en = 8,
+	.offset_frac = RCC_PLL3FRACR,
+	.divm = 20,
+};
+
+static const struct stm32_pll_data stm32_pll[] = {
+	{ "vco1", "pllsrc", CLK_IGNORE_UNUSED, &stm32h7_pll1 },
+	{ "vco2", "pllsrc", 0, &stm32h7_pll2 },
+	{ "vco3", "pllsrc", 0, &stm32h7_pll3 },
+};
+
+struct stm32_fractional_divider {
+	void __iomem	*mreg;
+	u8		mshift;
+	u8		mwidth;
+	u32		mmask;
+
+	void __iomem	*nreg;
+	u8		nshift;
+	u8		nwidth;
+
+	void __iomem	*freg_status;
+	u8		freg_bit;
+	void __iomem	*freg_value;
+	u8		fshift;
+	u8		fwidth;
+
+	u8		flags;
+	struct clk_hw	hw;
+	spinlock_t	*lock;
+};
+
+struct stm32_pll_obj {
+	spinlock_t *lock;
+	struct stm32_fractional_divider div;
+	struct stm32_ready_gate rgate;
+	struct clk_hw hw;
+};
+
+#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw)
+
+static int pll_is_enabled(struct clk_hw *hw)
+{
+	struct stm32_pll_obj *clk_elem = to_pll(hw);
+	struct clk_hw *_hw = &clk_elem->rgate.gate.hw;
+
+	__clk_hw_set_clk(_hw, hw);
+
+	return ready_gate_clk_ops.is_enabled(_hw);
+}
+
+static int pll_enable(struct clk_hw *hw)
+{
+	struct stm32_pll_obj *clk_elem = to_pll(hw);
+	struct clk_hw *_hw = &clk_elem->rgate.gate.hw;
+
+	__clk_hw_set_clk(_hw, hw);
+
+	return ready_gate_clk_ops.enable(_hw);
+}
+
+static void pll_disable(struct clk_hw *hw)
+{
+	struct stm32_pll_obj *clk_elem = to_pll(hw);
+	struct clk_hw *_hw = &clk_elem->rgate.gate.hw;
+
+	__clk_hw_set_clk(_hw, hw);
+
+	ready_gate_clk_ops.disable(_hw);
+}
+
+static int pll_frac_is_enabled(struct clk_hw *hw)
+{
+	struct stm32_pll_obj *clk_elem = to_pll(hw);
+	struct stm32_fractional_divider *fd = &clk_elem->div;
+
+	return (readl(fd->freg_status) >> fd->freg_bit) & 0x01;
+}
+
+static unsigned long pll_read_frac(struct clk_hw *hw)
+{
+	struct stm32_pll_obj *clk_elem = to_pll(hw);
+	struct stm32_fractional_divider *fd = &clk_elem->div;
+
+	return (readl(fd->freg_value) >> fd->fshift) &
+		GENMASK(fd->fwidth - 1, 0);
+}
+
+static unsigned long pll_fd_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct stm32_pll_obj *clk_elem = to_pll(hw);
+	struct stm32_fractional_divider *fd = &clk_elem->div;
+	unsigned long m, n;
+	u32 val, mask;
+	u64 rate, rate1 = 0;
+
+	val = clk_readl(fd->mreg);
+	mask = (GENMASK(fd->mwidth - 1, 0) << fd->mshift);
+	m = (val & mask) >> fd->mshift;
+
+	val = clk_readl(fd->nreg);
+	mask = (GENMASK(fd->nwidth - 1, 0) << fd->nshift);
+	n = ((val & mask) >> fd->nshift) + 1;
+
+	if (!n || !m)
+		return parent_rate;
+
+	rate = (u64)parent_rate * n;
+	do_div(rate, m);
+
+	if (pll_frac_is_enabled(hw)) {
+		val = pll_read_frac(hw);
+		rate1 = (u64) parent_rate * (u64) val;
+		do_div(rate1, (m * 8191));
+	}
+
+	return rate + rate1;
+}
+
+static const struct clk_ops pll_ops = {
+	.enable		= pll_enable,
+	.disable	= pll_disable,
+	.is_enabled	= pll_is_enabled,
+	.recalc_rate	= pll_fd_recalc_rate,
+};
+
+static struct clk_hw *clk_register_stm32_pll(struct device *dev,
+		const char *name,
+		const char *parent,
+		unsigned long flags,
+		const struct st32h7_pll_cfg *cfg,
+		spinlock_t *lock)
+{
+
+	struct stm32_pll_obj *pll;
+	struct clk_init_data init = { NULL };
+	struct clk_hw *hw;
+	int ret;
+	struct stm32_fractional_divider *div = NULL;
+	struct stm32_ready_gate *rgate;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &pll_ops;
+	init.flags = flags;
+	init.parent_names = &parent;
+	init.num_parents = 1;
+	pll->hw.init = &init;
+
+	hw = &pll->hw;
+	rgate = &pll->rgate;
+
+	rgate->bit_rdy = cfg->bit_idx + 1;
+	rgate->gate.lock = lock;
+	rgate->gate.reg = base + RCC_CR;
+	rgate->gate.bit_idx = cfg->bit_idx;
+
+	div = &pll->div;
+	div->flags = 0;
+	div->mreg = base + RCC_PLLCKSELR;
+	div->mshift = cfg->divm;
+	div->mwidth = 6;
+	div->nreg = base +  cfg->offset_divr;
+	div->nshift = 0;
+	div->nwidth = 9;
+
+	div->freg_status = base + RCC_PLLCFGR;
+	div->freg_bit = cfg->bit_frac_en;
+	div->freg_value = base +  cfg->offset_frac;
+	div->fshift = 3;
+	div->fwidth = 13;
+
+	div->lock = lock;
+
+	ret = clk_hw_register(dev, hw);
+	if (ret) {
+		kfree(pll);
+		hw = ERR_PTR(ret);
+	}
+
+	return hw;
+}
+
+/* ODF CLOCKS */
+static unsigned long odf_divider_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	return clk_divider_ops.recalc_rate(hw, parent_rate);
+}
+
+static long odf_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long *prate)
+{
+	return clk_divider_ops.round_rate(hw, rate, prate);
+}
+
+static int odf_divider_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	struct clk_hw *hwp;
+	int pll_status;
+	int ret;
+
+	hwp = clk_hw_get_parent(hw);
+
+	pll_status = pll_is_enabled(hwp);
+
+	if (pll_status)
+		pll_disable(hwp);
+
+	ret = clk_divider_ops.set_rate(hw, rate, parent_rate);
+
+	if (pll_status)
+		pll_enable(hwp);
+
+	return ret;
+}
+
+static const struct clk_ops odf_divider_ops = {
+	.recalc_rate	= odf_divider_recalc_rate,
+	.round_rate	= odf_divider_round_rate,
+	.set_rate	= odf_divider_set_rate,
+};
+
+
+static int odf_gate_is_enabled(struct clk_hw *hw)
+{
+	return clk_gate_ops.is_enabled(hw);
+}
+
+static int odf_gate_enable(struct clk_hw *hw)
+{
+	struct clk_hw *hwp;
+	int pll_status;
+	int ret;
+
+	if (odf_gate_is_enabled(hw))
+		return 0;
+
+	hwp = clk_hw_get_parent(hw);
+
+	pll_status = pll_is_enabled(hwp);
+
+	if (pll_status)
+		pll_disable(hwp);
+
+	ret = clk_gate_ops.enable(hw);
+
+	if (pll_status)
+		pll_enable(hwp);
+
+	return ret;
+}
+
+static void odf_gate_disable(struct clk_hw *hw)
+{
+	struct clk_hw *hwp;
+	int pll_status;
+
+	if (!odf_gate_is_enabled(hw))
+		return;
+
+	clk_gate_ops.disable(hw);
+
+	hwp = clk_hw_get_parent(hw);
+
+	pll_status = pll_is_enabled(hwp);
+
+	if (pll_status)
+		pll_disable(hwp);
+
+	clk_gate_ops.disable(hw);
+
+	if (pll_status)
+		pll_enable(hwp);
+}
+
+static const struct clk_ops odf_gate_ops = {
+	.enable		= odf_gate_enable,
+	.disable	= odf_gate_disable,
+	.is_enabled	= odf_gate_is_enabled,
+};
+
+static struct composite_clk_gcfg odf_clk_gcfg = {
+	M_CFG_DIV(&odf_divider_ops, 0),
+	M_CFG_GATE(&odf_gate_ops, 0),
+};
+
+#define M_ODF_F(_name, _parent, _gate_offset,  _bit_idx, _rate_offset,\
+		_rate_shift, _rate_width, _flags)\
+{\
+	.mux = NULL,\
+	.div = &(struct muxdiv_cfg) {_rate_offset, _rate_shift, _rate_width},\
+	.gate = &(struct gate_cfg) {_gate_offset, _bit_idx },\
+	.name = _name,\
+	.parent_name = &(const char *) {_parent},\
+	.num_parents = 1,\
+	.flags = _flags,\
+}
+
+#define M_ODF(_name, _parent, _gate_offset,  _bit_idx, _rate_offset,\
+		_rate_shift, _rate_width)\
+M_ODF_F(_name, _parent, _gate_offset,  _bit_idx, _rate_offset,\
+		_rate_shift, _rate_width, 0)\
+
+static const struct composite_clk_cfg stm32_odf[3][3] = {
+	{
+		M_ODF_F("pll1_p", "vco1", RCC_PLLCFGR, 16, RCC_PLL1DIVR,  9, 7,
+				CLK_IGNORE_UNUSED),
+		M_ODF_F("pll1_q", "vco1", RCC_PLLCFGR, 17, RCC_PLL1DIVR, 16, 7,
+				CLK_IGNORE_UNUSED),
+		M_ODF_F("pll1_r", "vco1", RCC_PLLCFGR, 18, RCC_PLL1DIVR, 24, 7,
+				CLK_IGNORE_UNUSED),
+	},
+
+	{
+		M_ODF("pll2_p", "vco2", RCC_PLLCFGR, 19, RCC_PLL2DIVR,  9, 7),
+		M_ODF("pll2_q", "vco2", RCC_PLLCFGR, 20, RCC_PLL2DIVR, 16, 7),
+		M_ODF("pll2_r", "vco2", RCC_PLLCFGR, 21, RCC_PLL2DIVR, 24, 7),
+	},
+	{
+		M_ODF("pll3_p", "vco3", RCC_PLLCFGR, 22, RCC_PLL3DIVR,  9, 7),
+		M_ODF("pll3_q", "vco3", RCC_PLLCFGR, 23, RCC_PLL3DIVR, 16, 7),
+		M_ODF("pll3_r", "vco3", RCC_PLLCFGR, 24, RCC_PLL3DIVR, 24, 7),
+	}
+};
+
+/* PLL config structure from DT */
+struct pll_param {
+	u32 index;
+	u32 mult;
+	u32 div;
+	u32 frac;
+	u32 vcosel;
+};
+
+static int of_get_stm32_pll(struct device_node *np, struct pll_param *param)
+{
+	if (of_property_read_u32(np, "reg", &param->index) ||
+			param->index >= ARRAY_SIZE(stm32_pll))
+		return -EINVAL;
+
+	of_property_read_u32(np, "st,clock-div", &param->div);
+
+	of_property_read_u32(np, "st,clock-mult", &param->mult);
+
+	param->frac = ~0;
+	of_property_read_u32(np, "st,frac", &param->frac);
+
+	param->vcosel = ~0;
+	of_property_read_u32(np, "st,vcosel", &param->vcosel);
+
+	return 0;
+}
+
+
+static void stm32_pll_save_param(struct pll_param *pll_dt_cfg,
+		const struct st32h7_pll_cfg *cfg)
+{
+	unsigned long m, n;
+	u32 val, mask;
+	int idx = pll_dt_cfg->index;
+	int pll_status, pllrge;
+	unsigned long ref_ck;
+
+
+	/* Save PLL parameters from DT if needed */
+	m = pll_dt_cfg->div;
+	n = pll_dt_cfg->mult;
+	if (!(n || m || pll_dt_cfg->frac != ~0 ||
+				pll_dt_cfg->vcosel != ~0))
+		return;
+
+	/* We have to disable pll before modify pll register */
+	val = clk_readl(base + RCC_CR);
+	pll_status = val & BIT(cfg->bit_idx);
+	if (pll_status) {
+		val &= ~BIT(cfg->bit_idx);
+		writel(val, base + RCC_CR);
+	}
+
+	/* Save DIVM division factor  */
+	val = clk_readl(base + RCC_PLLCKSELR);
+	mask = 0x3f << cfg->divm;
+	if (m) {
+		val &= ~mask;
+		val |= (m << cfg->divm);
+		writel(val, base + RCC_PLLCKSELR);
+	} else
+		m = (val & mask) >> cfg->divm ?: 1;
+
+	/* Save DIVN multiplication factor */
+	if (n)  {
+		val = clk_readl(base +  cfg->offset_divr);
+		val &= ~0x1ff;
+		val |= (n - 1);
+		writel(val, base +  cfg->offset_divr);
+	}
+
+	/* If there is a "st,frac" property */
+	if (pll_dt_cfg->frac != ~0) {
+		u32 val_status;
+		int status = 0;
+
+		/* 0: pll is configured in integer mode */
+		/* else is configured in fractional mode */
+		if (pll_dt_cfg->frac)
+			status = 1;
+
+		/* clear frac status  before */
+		val_status = readl(base + RCC_PLLCFGR);
+		val_status &= ~BIT(cfg->bit_frac_en);
+		writel(val_status, base + RCC_PLLCFGR);
+
+		/* Save the fractional factor */
+		if (status) {
+			/* write frac value */
+			val = clk_readl(base +  cfg->offset_frac);
+			val &= ~(0x1fff << 3);
+			val |= ((pll_dt_cfg->frac) << 3);
+			writel(val, base +  cfg->offset_frac);
+
+			/* Enable fractional mode */
+			val_status |= status << cfg->bit_frac_en;
+			writel(val_status, base + RCC_PLLCFGR);
+		}
+	}
+
+	/* Save VCO frequency range */
+	if (pll_dt_cfg->vcosel != ~0) {
+		val = readl(base + RCC_PLLCFGR);
+		val &= ~BIT(cfg->bit_frac_en + 1);
+		val |= (pll_dt_cfg->vcosel & 0x01) << (cfg->bit_frac_en + 1);
+		writel(val, base + RCC_PLLCFGR);
+	}
+
+	/* Update PLLRGE */
+	ref_ck = clk_get_rate(__clk_lookup(stm32_pll[idx].parent_name)) / m;
+
+	pllrge = 3;
+	if (ref_ck < 2000000)
+		pllrge = 0;
+	else if (ref_ck < 4000000)
+		pllrge = 1;
+	else if (ref_ck < 8000000)
+		pllrge = 2;
+
+	/* Write reference frequency range */
+	val = readl(base + RCC_PLLCFGR);
+	val &= ~(0x3 << (cfg->bit_frac_en + 2));
+	val |= (pllrge & 0x3) << (cfg->bit_frac_en + 2);
+	writel(val, base + RCC_PLLCFGR);
+
+	/* Restore pll status */
+	if (pll_status) {
+		val = clk_readl(base + RCC_CR);
+		val |= BIT(cfg->bit_idx);
+		writel(val, base + RCC_CR);
+	}
+}
+
+static void stm32_h7_pll_init(struct device_node *np)
+{
+	struct pll_param pll_dt_cfg = { };
+	struct clk_hw *hw;
+	int idx, n;
+
+	if (of_get_stm32_pll(np, &pll_dt_cfg))
+		return;
+
+	idx = pll_dt_cfg.index;
+
+	stm32_pll_save_param(&pll_dt_cfg, stm32_pll[idx].cfg);
+
+	/* Register the VCO */
+	hw = clk_register_stm32_pll(NULL, stm32_pll[idx].name,
+			stm32_pll[idx].parent_name, stm32_pll[idx].flags,
+			stm32_pll[idx].cfg,
+			&rlock);
+
+	/* Register the 3 output dividers */
+	for (n = 0; n < 3; n++) {
+		struct composite_cfg c_cfg;
+
+		get_cfg_composite_div(&odf_clk_gcfg, &stm32_odf[idx][n],
+				&c_cfg,	&rlock);
+
+		hws[ODF_BANK + (idx * 3) + n] = clk_hw_register_composite(NULL,
+				stm32_odf[idx][n].name,
+				stm32_odf[idx][n].parent_name,
+				stm32_odf[idx][n].num_parents,
+				c_cfg.mux_hw, c_cfg.mux_ops,
+				c_cfg.div_hw, c_cfg.div_ops,
+				c_cfg.gate_hw, c_cfg.gate_ops,
+				stm32_odf[idx][n].flags);
+	}
+}
+
+/* PERIF CLOCKS */
+struct pclk_t {
+	u32 gate_offset;
+	u8 bit_idx;
+	const char *name;
+	const char *parent;
+	u32 flags;
+};
+
+#define PER_CLKF(_gate_offset, _bit_idx, _name, _parent, _flags)\
+{\
+	.gate_offset	= _gate_offset,\
+	.bit_idx	= _bit_idx,\
+	.name		= _name,\
+	.parent		= _parent,\
+	.flags		= _flags,\
+}
+#define PER_CLK(_gate_offset, _bit_idx, _name, _parent)\
+	PER_CLKF(_gate_offset, _bit_idx, _name, _parent, 0)
+
+static const struct pclk_t pclk[] = {
+	PER_CLK(RCC_AHB3ENR, 31, "d1sram1", "hclk"),
+	PER_CLK(RCC_AHB3ENR, 30, "itcm", "hclk"),
+	PER_CLK(RCC_AHB3ENR, 29, "dtcm2", "hclk"),
+	PER_CLK(RCC_AHB3ENR, 28, "dtcm1", "hclk"),
+	PER_CLK(RCC_AHB3ENR, 8, "flitf", "hclk"),
+	PER_CLK(RCC_AHB3ENR, 5, "jpgdec", "hclk"),
+	PER_CLK(RCC_AHB3ENR, 4, "dma2d", "hclk"),
+	PER_CLK(RCC_AHB3ENR, 0, "mdma", "hclk"),
+	PER_CLK(RCC_AHB1ENR, 28, "usb2ulpi", "hclk"),
+	PER_CLK(RCC_AHB1ENR, 26, "usb1ulpi", "hclk"),
+	PER_CLK(RCC_AHB1ENR, 17, "eth1rx", "hclk"),
+	PER_CLK(RCC_AHB1ENR, 16, "eth1tx", "hclk"),
+	PER_CLK(RCC_AHB1ENR, 15, "eth1mac", "hclk"),
+	PER_CLK(RCC_AHB1ENR, 14, "art", "hclk"),
+	PER_CLK(RCC_AHB1ENR, 1, "dma2", "hclk"),
+	PER_CLK(RCC_AHB1ENR, 0, "dma1", "hclk"),
+	PER_CLK(RCC_AHB2ENR, 31, "d2sram3", "hclk"),
+	PER_CLK(RCC_AHB2ENR, 30, "d2sram2", "hclk"),
+	PER_CLK(RCC_AHB2ENR, 29, "d2sram1", "hclk"),
+	PER_CLK(RCC_AHB2ENR, 5, "hash", "hclk"),
+	PER_CLK(RCC_AHB2ENR, 4, "crypt", "hclk"),
+	PER_CLK(RCC_AHB2ENR, 0, "camitf", "hclk"),
+	PER_CLK(RCC_AHB4ENR, 28, "bkpram", "hclk"),
+	PER_CLK(RCC_AHB4ENR, 25, "hsem", "hclk"),
+	PER_CLK(RCC_AHB4ENR, 21, "bdma", "hclk"),
+	PER_CLK(RCC_AHB4ENR, 19, "crc", "hclk"),
+	PER_CLK(RCC_AHB4ENR, 10, "gpiok", "hclk"),
+	PER_CLK(RCC_AHB4ENR, 9, "gpioj", "hclk"),
+	PER_CLK(RCC_AHB4ENR, 8, "gpioi", "hclk"),
+	PER_CLK(RCC_AHB4ENR, 7, "gpioh", "hclk"),
+	PER_CLK(RCC_AHB4ENR, 6, "gpiog", "hclk"),
+	PER_CLK(RCC_AHB4ENR, 5, "gpiof", "hclk"),
+	PER_CLK(RCC_AHB4ENR, 4, "gpioe", "hclk"),
+	PER_CLK(RCC_AHB4ENR, 3, "gpiod", "hclk"),
+	PER_CLK(RCC_AHB4ENR, 2, "gpioc", "hclk"),
+	PER_CLK(RCC_AHB4ENR, 1, "gpiob", "hclk"),
+	PER_CLK(RCC_AHB4ENR, 0, "gpioa", "hclk"),
+	PER_CLK(RCC_APB3ENR, 6, "wwdg1", "pclk3"),
+	PER_CLK(RCC_APB1LENR, 29, "dac12", "pclk1"),
+	PER_CLK(RCC_APB1LENR, 11, "wwdg2", "pclk1"),
+	PER_CLK(RCC_APB1LENR, 8, "tim14", "pclk1"),
+	PER_CLK(RCC_APB1LENR, 7, "tim13", "pclk1"),
+	PER_CLK(RCC_APB1LENR, 6, "tim12", "pclk1"),
+	PER_CLK(RCC_APB1LENR, 5, "tim7", "pclk1"),
+	PER_CLK(RCC_APB1LENR, 4, "tim6", "pclk1"),
+	PER_CLK(RCC_APB1LENR, 3, "tim5", "pclk1"),
+	PER_CLK(RCC_APB1LENR, 2, "tim4", "pclk1"),
+	PER_CLK(RCC_APB1LENR, 1, "tim3", "pclk1"),
+	PER_CLK(RCC_APB1LENR, 0, "tim2", "pclk1"),
+	PER_CLK(RCC_APB1HENR, 5, "mdios", "pclk1"),
+	PER_CLK(RCC_APB1HENR, 4, "opamp", "pclk1"),
+	PER_CLK(RCC_APB1HENR, 1, "crs", "pclk1"),
+	PER_CLK(RCC_APB2ENR, 18, "tim17", "pclk2"),
+	PER_CLK(RCC_APB2ENR, 17, "tim16", "pclk2"),
+	PER_CLK(RCC_APB2ENR, 16, "tim15", "pclk2"),
+	PER_CLK(RCC_APB2ENR, 1, "tim8", "pclk2"),
+	PER_CLK(RCC_APB2ENR, 0, "tim1", "pclk2"),
+	PER_CLK(RCC_APB4ENR, 26, "tmpsens", "pclk4"),
+	PER_CLK(RCC_APB4ENR, 16, "rtcapb", "pclk4"),
+	PER_CLK(RCC_APB4ENR, 15, "vref", "pclk4"),
+	PER_CLK(RCC_APB4ENR, 14, "comp12", "pclk4"),
+	PER_CLK(RCC_APB4ENR, 1, "syscfg", "pclk4"),
+};
+
+/* KERNEL CLOCKS */
+#define KER_CLKF(_gate_offset, _bit_idx,\
+		_mux_offset, _mux_shift, _mux_width,\
+		_name, _parent_name,\
+		_flags) \
+{ \
+	.gate = &(struct gate_cfg) {_gate_offset, _bit_idx},\
+	.mux = &(struct muxdiv_cfg) {_mux_offset, _mux_shift, _mux_width },\
+	.name = _name, \
+	.parent_name = _parent_name, \
+	.num_parents = ARRAY_SIZE(_parent_name),\
+	.flags = _flags,\
+}
+#define KER_CLK(_gate_offset, _bit_idx, _mux_offset, _mux_shift, _mux_width,\
+		_name, _parent_name) \
+KER_CLKF(_gate_offset, _bit_idx, _mux_offset, _mux_shift, _mux_width,\
+		_name, _parent_name, 0)\
+
+#define KER_CLKF_NOMUX(_gate_offset, _bit_idx,\
+		_name, _parent_name,\
+		_flags) \
+{ \
+	.gate = &(struct gate_cfg) {_gate_offset, _bit_idx},\
+	.mux = NULL,\
+	.name = _name, \
+	.parent_name = _parent_name, \
+	.num_parents = 1,\
+	.flags = _flags,\
+}
+
+static const struct composite_clk_cfg kclk[] = {
+	KER_CLK(RCC_AHB3ENR,  16, RCC_D1CCIPR,	16, 1, "sdmmc1", sdmmc_src),
+	KER_CLKF(RCC_AHB3ENR, 14, RCC_D1CCIPR,	 4, 2, "quadspi", qspi_src,
+			CLK_IGNORE_UNUSED),
+	KER_CLKF(RCC_AHB3ENR, 12, RCC_D1CCIPR,	 0, 2, "fmc", fmc_src,
+			CLK_IGNORE_UNUSED),
+	KER_CLK(RCC_AHB1ENR,  27, RCC_D2CCIP2R,	20, 2, "usb2otg", usbotg_src),
+	KER_CLK(RCC_AHB1ENR,  25, RCC_D2CCIP2R, 20, 2, "usb1otg", usbotg_src),
+	KER_CLK(RCC_AHB1ENR,   5, RCC_D3CCIPR,	16, 2, "adc12", adc_src),
+	KER_CLK(RCC_AHB2ENR,   9, RCC_D1CCIPR,	16, 1, "sdmmc2", sdmmc_src),
+	KER_CLK(RCC_AHB2ENR,   6, RCC_D2CCIP2R,	 8, 2, "rng", rng_src),
+	KER_CLK(RCC_AHB4ENR,  24, RCC_D3CCIPR,  16, 2, "adc3", adc_src),
+	KER_CLK(RCC_APB3ENR,   4, RCC_D1CCIPR,	 8, 1, "dsi", dsi_src),
+	KER_CLKF_NOMUX(RCC_APB3ENR, 3, "ltdc", ltdc_src, CLK_SET_RATE_PARENT),
+	KER_CLK(RCC_APB1LENR, 31, RCC_D2CCIP2R,  0, 3, "usart8", usart_src2),
+	KER_CLK(RCC_APB1LENR, 30, RCC_D2CCIP2R,  0, 3, "usart7", usart_src2),
+	KER_CLK(RCC_APB1LENR, 27, RCC_D2CCIP2R, 22, 2, "hdmicec", cec_src),
+	KER_CLK(RCC_APB1LENR, 23, RCC_D2CCIP2R, 12, 2, "i2c3", i2c_src1),
+	KER_CLK(RCC_APB1LENR, 22, RCC_D2CCIP2R, 12, 2, "i2c2", i2c_src1),
+	KER_CLK(RCC_APB1LENR, 21, RCC_D2CCIP2R, 12, 2, "i2c1", i2c_src1),
+	KER_CLK(RCC_APB1LENR, 20, RCC_D2CCIP2R,	 0, 3, "uart5", usart_src2),
+	KER_CLK(RCC_APB1LENR, 19, RCC_D2CCIP2R,  0, 3, "uart4", usart_src2),
+	KER_CLK(RCC_APB1LENR, 18, RCC_D2CCIP2R,  0, 3, "usart3", usart_src2),
+	KER_CLK(RCC_APB1LENR, 17, RCC_D2CCIP2R,  0, 3, "usart2", usart_src2),
+	KER_CLK(RCC_APB1LENR, 16, RCC_D2CCIP1R, 20, 2, "spdifrx", spdifrx_src),
+	KER_CLK(RCC_APB1LENR, 15, RCC_D2CCIP1R, 16, 3, "spi3", spi_src1),
+	KER_CLK(RCC_APB1LENR, 14, RCC_D2CCIP1R, 16, 3, "spi2", spi_src1),
+	KER_CLK(RCC_APB1LENR,  9, RCC_D2CCIP2R, 28, 3, "lptim1", lptim_src1),
+	KER_CLK(RCC_APB1HENR,  8, RCC_D2CCIP1R, 28, 2, "fdcan", fdcan_src),
+	KER_CLK(RCC_APB1HENR,  2, RCC_D2CCIP1R, 31, 1, "swp", swp_src),
+	KER_CLK(RCC_APB2ENR,  29, RCC_CFGR,	14, 1, "hrtim", hrtim_src),
+	KER_CLK(RCC_APB2ENR,  28, RCC_D2CCIP1R, 24, 1, "dfsdm1", dfsdm1_src),
+	KER_CLK(RCC_APB2ENR,  24, RCC_D2CCIP1R,  6, 3, "sai3", sai_src),
+	KER_CLK(RCC_APB2ENR,  23, RCC_D2CCIP1R,  6, 3, "sai2", sai_src),
+	KER_CLK(RCC_APB2ENR,  22, RCC_D2CCIP1R,  0, 3, "sai1", sai_src),
+	KER_CLK(RCC_APB2ENR,  20, RCC_D2CCIP1R, 16, 3, "spi5", spi_src2),
+	KER_CLK(RCC_APB2ENR,  13, RCC_D2CCIP1R, 16, 3, "spi4", spi_src2),
+	KER_CLK(RCC_APB2ENR,  12, RCC_D2CCIP1R, 16, 3, "spi1", spi_src1),
+	KER_CLK(RCC_APB2ENR,   5, RCC_D2CCIP2R,  3, 3, "usart6", usart_src1),
+	KER_CLK(RCC_APB2ENR,   4, RCC_D2CCIP2R,  3, 3, "usart1", usart_src1),
+	KER_CLK(RCC_APB4ENR,  21, RCC_D3CCIPR,	24, 3, "sai4b", sai_src),
+	KER_CLK(RCC_APB4ENR,  21, RCC_D3CCIPR,	21, 3, "sai4a", sai_src),
+	KER_CLK(RCC_APB4ENR,  12, RCC_D3CCIPR,	13, 3, "lptim5", lptim_src2),
+	KER_CLK(RCC_APB4ENR,  11, RCC_D3CCIPR,	13, 3, "lptim4", lptim_src2),
+	KER_CLK(RCC_APB4ENR,  10, RCC_D3CCIPR,	13, 3, "lptim3", lptim_src2),
+	KER_CLK(RCC_APB4ENR,   9, RCC_D3CCIPR,	10, 3, "lptim2", lptim_src2),
+	KER_CLK(RCC_APB4ENR,   7, RCC_D3CCIPR,	 8, 2, "i2c4", i2c_src2),
+	KER_CLK(RCC_APB4ENR,   5, RCC_D3CCIPR,	28, 3, "spi6", spi_src3),
+	KER_CLK(RCC_APB4ENR,   3, RCC_D3CCIPR,	 0, 3, "lpuart1", lpuart1_src),
+};
+
+static struct composite_clk_gcfg kernel_clk_cfg = {
+	M_CFG_MUX(NULL, 0),
+	M_CFG_GATE(NULL, 0),
+};
+
+/* RTC clock */
+static u8 rtc_mux_get_parent(struct clk_hw *hw)
+{
+	return clk_mux_ops.get_parent(hw);
+}
+
+static int rtc_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+	int dbp_status;
+	int err;
+
+	dbp_status = is_enable_power_domain_write_protection();
+
+	if (dbp_status)
+		disable_power_domain_write_protection();
+
+	err = clk_mux_ops.set_parent(hw, index);
+
+	if (dbp_status)
+		enable_power_domain_write_protection();
+
+	return err;
+}
+
+static int rtc_mux_determine_rate(struct clk_hw *hw,
+		struct clk_rate_request *req)
+{
+	return clk_mux_ops.determine_rate(hw, req);
+}
+
+static const struct clk_ops rtc_mux_ops = {
+	.get_parent	= rtc_mux_get_parent,
+	.set_parent	= rtc_mux_set_parent,
+	.determine_rate = rtc_mux_determine_rate,
+};
+
+/* Clock gate with backup domain protection management */
+static int bd_gate_is_enabled(struct clk_hw *hw)
+{
+	return clk_gate_ops.is_enabled(hw);
+}
+
+static int bd_gate_enable(struct clk_hw *hw)
+{
+	int dbp_status;
+	int err;
+
+	if (bd_gate_is_enabled(hw))
+		return 0;
+
+	dbp_status = is_enable_power_domain_write_protection();
+
+	if (dbp_status)
+		disable_power_domain_write_protection();
+
+	err = clk_gate_ops.enable(hw);
+
+	if (dbp_status)
+		enable_power_domain_write_protection();
+
+	return err;
+}
+
+static void bd_gate_disable(struct clk_hw *hw)
+{
+	int dbp_status;
+
+	if (!bd_gate_is_enabled(hw))
+		return;
+
+	dbp_status = is_enable_power_domain_write_protection();
+
+	if (dbp_status)
+		disable_power_domain_write_protection();
+
+	clk_gate_ops.disable(hw);
+
+	if (dbp_status)
+		enable_power_domain_write_protection();
+}
+
+static const struct clk_ops bd_gate_ops = {
+	.enable		= bd_gate_enable,
+	.disable	= bd_gate_disable,
+	.is_enabled	= bd_gate_is_enabled,
+};
+
+static struct composite_clk_gcfg rtc_clk_cfg = {
+	M_CFG_MUX(&rtc_mux_ops, 0),
+	M_CFG_GATE(&bd_gate_ops, 0),
+};
+
+static const struct composite_clk_cfg rtc_clk =
+	KER_CLK(RCC_BDCR, 15, RCC_BDCR, 8, 2, "rtc_ck", rtc_src);
+
+/* Micro-controller output clock */
+static struct composite_clk_gcfg mco_clk_cfg = {
+	M_CFG_MUX(NULL, 0),
+	M_CFG_DIV(NULL,	CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO),
+};
+
+#define M_MCO_F(_name, _parents, _mux_offset,  _mux_shift, _mux_width,\
+		_rate_offset, _rate_shift, _rate_width,\
+		_flags)\
+{\
+	.mux = &(struct muxdiv_cfg) {_mux_offset, _mux_shift, _mux_width },\
+	.div = &(struct muxdiv_cfg) {_rate_offset, _rate_shift, _rate_width},\
+	.gate = NULL,\
+	.name = _name,\
+	.parent_name = _parents,\
+	.num_parents = ARRAY_SIZE(_parents),\
+	.flags = _flags,\
+}
+
+static const struct composite_clk_cfg mco_clk[] = {
+	M_MCO_F("mco1", mco_src1, RCC_CFGR, 22, 4, RCC_CFGR, 18, 4, 0),
+	M_MCO_F("mco2", mco_src2, RCC_CFGR, 29, 3, RCC_CFGR, 25, 4, 0),
+};
+
+static void __init stm32h7_rcc_init(struct device_node *np)
+{
+	struct clk_hw_onecell_data *clk_data;
+	struct device_node *node;
+	struct composite_cfg c_cfg;
+	int n;
+	const char *hse_clk, *lse_clk, *i2s_clk;
+
+	clk_data = kzalloc(sizeof(*clk_data) +
+			sizeof(*clk_data->hws) * STM32H7_MAX_CLKS,
+			GFP_KERNEL);
+	if (!clk_data)
+		return;
+
+	clk_data->num = STM32H7_MAX_CLKS;
+
+	hws = clk_data->hws;
+
+	for (n = 0; n < STM32H7_MAX_CLKS; n++)
+		hws[n] = ERR_PTR(-ENOENT);
+
+	/* get RCC base @ from DT */
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_err("%s: unable to map resource", np->name);
+		goto err_free_clks;
+	}
+
+	pdrm = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
+	if (IS_ERR(pdrm)) {
+		pdrm = NULL;
+		pr_warn("%s: Unable to get syscfg\n", __func__);
+	}
+
+	/* Put parent names from DT */
+	hse_clk = of_clk_get_parent_name(np, 0);
+	lse_clk = of_clk_get_parent_name(np, 1);
+	i2s_clk = of_clk_get_parent_name(np, 2);
+
+	sai_src[3] = i2s_clk;
+	spi_src1[3] = i2s_clk;
+
+	/* Register Internal oscillators */
+	clk_hw_register_fixed_rate(NULL, "clk-hsi", NULL, 0, 64000000);
+	clk_hw_register_fixed_rate(NULL, "clk-csi", NULL, 0, 4000000);
+	clk_hw_register_fixed_rate(NULL, "clk-lsi", NULL, 0, 32000);
+	clk_hw_register_fixed_rate(NULL, "clk-rc48", NULL, 0, 48000);
+
+	/* This clock is coming from outside. Frequencies unknown */
+	hws[CK_DSI_PHY] = clk_hw_register_fixed_rate(NULL, "ck_dsi_phy", NULL,
+			0, 0);
+
+	hws[HSI_DIV] = clk_hw_register_divider(NULL, "hsidiv", "clk-hsi", 0,
+			base + RCC_CR, 3, 2, CLK_DIVIDER_POWER_OF_TWO,
+			&rlock);
+
+	hws[HSE_1M] = clk_hw_register_divider(NULL, "hse_1M", "hse_ck",	0,
+			base + RCC_CFGR, 8, 6, CLK_DIVIDER_ONE_BASED |
+			CLK_DIVIDER_ALLOW_ZERO,
+			&rlock);
+
+	/* Mux system clocks */
+	for (n = 0; n < ARRAY_SIZE(stm32_mclk); n++)
+		hws[MCLK_BANK + n] = clk_hw_register_mux(NULL,
+				stm32_mclk[n].name,
+				stm32_mclk[n].parents,
+				stm32_mclk[n].num_parents,
+				stm32_mclk[n].flags,
+				stm32_mclk[n].offset + base,
+				stm32_mclk[n].shift,
+				stm32_mclk[n].width,
+				0,
+				&rlock);
+
+	register_core_and_bus_clocks();
+
+	/* Oscillary clocks */
+	for (n = 0; n < ARRAY_SIZE(stm32_oclk); n++)
+		hws[OSC_BANK + n] = clk_register_ready_gate(NULL,
+				stm32_oclk[n].name,
+				stm32_oclk[n].parent,
+				stm32_oclk[n].gate_offset + base,
+				stm32_oclk[n].bit_idx,
+				stm32_oclk[n].bit_rdy,
+				0,
+				stm32_oclk[n].flags,
+				&rlock);
+
+	hws[HSE_CK] = clk_register_ready_gate(NULL,
+				"hse_ck",
+				hse_clk,
+				RCC_CR + base,
+				16, 17,
+				0,
+				0,
+				&rlock);
+
+	hws[LSE_CK] = clk_register_ready_gate(NULL,
+				"lse_ck",
+				lse_clk,
+				RCC_BDCR + base,
+				0, 1,
+				1,
+				0,
+				&rlock);
+
+	hws[CSI_KER_DIV122 + n] = clk_hw_register_fixed_factor(NULL,
+			"csi_ker_div122", "csi_ker", 0, 1, 122);
+
+	/* PLLs */
+	for_each_compatible_node(node, NULL, "st,stm32h7-pll")
+		stm32_h7_pll_init(node);
+
+	/* Peripheral clocks */
+	for (n = 0; n < ARRAY_SIZE(pclk); n++)
+		hws[PERIF_BANK + n] = clk_hw_register_gate(NULL, pclk[n].name,
+				pclk[n].parent,
+				pclk[n].flags, base + pclk[n].gate_offset,
+				pclk[n].bit_idx, pclk[n].flags, &rlock);
+
+	/* Kernel clocks */
+	for (n = 0; n < ARRAY_SIZE(kclk); n++) {
+		get_cfg_composite_div(&kernel_clk_cfg, &kclk[n], &c_cfg,
+				&rlock);
+
+		hws[KERN_BANK + n] = clk_hw_register_composite(NULL,
+				kclk[n].name,
+				kclk[n].parent_name,
+				kclk[n].num_parents,
+				c_cfg.mux_hw, c_cfg.mux_ops,
+				c_cfg.div_hw, c_cfg.div_ops,
+				c_cfg.gate_hw, c_cfg.gate_ops,
+				kclk[n].flags);
+	}
+
+	/* RTC clock (default state is off) */
+	clk_hw_register_fixed_rate(NULL, "off", NULL, 0, 0);
+
+	get_cfg_composite_div(&rtc_clk_cfg, &rtc_clk, &c_cfg, &rlock);
+
+	hws[RTC_CK] = clk_hw_register_composite(NULL,
+			rtc_clk.name,
+			rtc_clk.parent_name,
+			rtc_clk.num_parents,
+			c_cfg.mux_hw, c_cfg.mux_ops,
+			c_cfg.div_hw, c_cfg.div_ops,
+			c_cfg.gate_hw, c_cfg.gate_ops,
+			rtc_clk.flags);
+
+	/* Micro-controller clocks */
+	for (n = 0; n < ARRAY_SIZE(mco_clk); n++) {
+		get_cfg_composite_div(&mco_clk_cfg, &mco_clk[n], &c_cfg,
+				&rlock);
+
+		hws[MCO_BANK + n] = clk_hw_register_composite(NULL,
+				mco_clk[n].name,
+				mco_clk[n].parent_name,
+				mco_clk[n].num_parents,
+				c_cfg.mux_hw, c_cfg.mux_ops,
+				c_cfg.div_hw, c_cfg.div_ops,
+				c_cfg.gate_hw, c_cfg.gate_ops,
+				mco_clk[n].flags);
+	}
+
+	of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
+
+	return;
+
+err_free_clks:
+	kfree(clk_data);
+}
+CLK_OF_DECLARE_DRIVER(stm32h7_rcc, "st,stm32h743-rcc", stm32h7_rcc_init);
diff --git a/include/dt-bindings/clock/stm32h7-clks.h b/include/dt-bindings/clock/stm32h7-clks.h
new file mode 100644
index 0000000..6637272
--- /dev/null
+++ b/include/dt-bindings/clock/stm32h7-clks.h
@@ -0,0 +1,165 @@
+/* SYS, CORE AND BUS CLOCKS */
+#define SYS_D1CPRE 0
+#define HCLK 1
+#define PCLK1 2
+#define PCLK2 3
+#define PCLK3 4
+#define PCLK4 5
+#define HSI_DIV 6
+#define HSE_1M 7
+#define I2S_CKIN 8
+#define CK_DSI_PHY 9
+#define HSE_CK 10
+#define LSE_CK 11
+#define CSI_KER_DIV122 12
+#define RTC_CK 13
+#define CPU_SYSTICK 14
+
+/* OSCILLATOR BANK */
+#define OSC_BANK 18
+#define HSI_CK 18
+#define HSI_KER_CK 19
+#define CSI_CK 20
+#define CSI_KER_CK 21
+#define RC48_CK 22
+#define LSI_CK 23
+
+/* MCLOCK BANK */
+#define MCLK_BANK 28
+#define PER_CK 28
+#define PLLSRC 29
+#define SYS_CK 30
+#define TRACEIN_CK 31
+
+/* ODF BANK */
+#define ODF_BANK 32
+#define PLL1_P 32
+#define PLL1_Q 33
+#define PLL1_R 34
+#define PLL2_P 35
+#define PLL2_Q 36
+#define PLL2_R 37
+#define PLL3_P 38
+#define PLL3_Q 39
+#define PLL3_R 40
+
+/* MCO BANK */
+#define MCO_BANK 41
+#define MCO1 41
+#define MCO2 42
+
+/* PERIF BANK */
+#define PERIF_BANK 50
+#define D1SRAM1_CK 50
+#define ITCM_CK 51
+#define DTCM2_CK 52
+#define DTCM1_CK 53
+#define FLITF_CK 54
+#define JPGDEC_CK 55
+#define DMA2D_CK 56
+#define MDMA_CK 57
+#define USB2ULPI_CK 58
+#define USB1ULPI_CK 59
+#define ETH1RX_CK 60
+#define ETH1TX_CK 61
+#define ETH1MAC_CK 62
+#define ART_CK 63
+#define DMA2_CK 64
+#define DMA1_CK 65
+#define D2SRAM3_CK 66
+#define D2SRAM2_CK 67
+#define D2SRAM1_CK 68
+#define HASH_CK 69
+#define CRYPT_CK 70
+#define CAMITF_CK 71
+#define BKPRAM_CK 72
+#define HSEM_CK 73
+#define BDMA_CK 74
+#define CRC_CK 75
+#define GPIOK_CK 76
+#define GPIOJ_CK 77
+#define GPIOI_CK 78
+#define GPIOH_CK 79
+#define GPIOG_CK 80
+#define GPIOF_CK 81
+#define GPIOE_CK 82
+#define GPIOD_CK 83
+#define GPIOC_CK 84
+#define GPIOB_CK 85
+#define GPIOA_CK 86
+#define WWDG1_CK 87
+#define DAC12_CK 88
+#define WWDG2_CK 89
+#define TIM14_CK 90
+#define TIM13_CK 91
+#define TIM12_CK 92
+#define TIM7_CK 93
+#define TIM6_CK 94
+#define TIM5_CK 95
+#define TIM4_CK 96
+#define TIM3_CK 97
+#define TIM2_CK 98
+#define MDIOS_CK 99
+#define OPAMP_CK 100
+#define CRS_CK 101
+#define TIM17_CK 102
+#define TIM16_CK 103
+#define TIM15_CK 104
+#define TIM8_CK 105
+#define TIM1_CK 106
+#define TMPSENS_CK 107
+#define RTCAPB_CK 108
+#define VREF_CK 109
+#define COMP12_CK 110
+#define SYSCFG_CK 111
+
+/* KERNEL BANK */
+#define KERN_BANK 120
+#define SDMMC1_CK 120
+#define QUADSPI_CK 121
+#define FMC_CK 122
+#define USB2OTG_CK 123
+#define USB1OTG_CK 124
+#define ADC12_CK 125
+#define SDMMC2_CK 126
+#define RNG_CK 127
+#define ADC3_CK 128
+#define DSI_CK 129
+#define LTDC_CK 130
+#define USART8_CK 131
+#define USART7_CK 132
+#define HDMICEC_CK 133
+#define I2C3_CK 134
+#define I2C2_CK 135
+#define I2C1_CK 136
+#define UART5_CK 137
+#define UART4_CK 138
+#define USART3_CK 139
+#define USART2_CK 140
+#define SPDIFRX_CK 141
+#define SPI3_CK 142
+#define SPI2_CK 143
+#define LPTIM1_CK 144
+#define FDCAN_CK 145
+#define SWP_CK 146
+#define HRTIM_CK 147
+#define DFSDM1_CK 148
+#define SAI3_CK 149
+#define SAI2_CK 150
+#define SAI1_CK 151
+#define SPI5_CK 152
+#define SPI4_CK 153
+#define SPI1_CK 154
+#define USART6_CK 155
+#define USART1_CK 156
+#define SAI4B_CK 157
+#define SAI4A_CK 158
+#define LPTIM5_CK 159
+#define LPTIM4_CK 160
+#define LPTIM3_CK 161
+#define LPTIM2_CK 162
+#define I2C4_CK 163
+#define SPI6_CK 164
+#define LPUART1_CK 165
+
+#define STM32H7_MAX_CLKS 166
diff --git a/include/dt-bindings/mfd/stm32h7-rcc.h b/include/dt-bindings/mfd/stm32h7-rcc.h
new file mode 100644
index 0000000..3af6a65
--- /dev/null
+++ b/include/dt-bindings/mfd/stm32h7-rcc.h
@@ -0,0 +1,137 @@
+/*
+ * This header provides constants for the STM32H7 RCC IP
+ */
+
+#ifndef _DT_BINDINGS_MFD_STM32H7_RCC_H
+#define _DT_BINDINGS_MFD_STM32H7_RCC_H
+
+/* AHB3 */
+#define STM32H7_RCC_AHB3_MDMA		0
+#define STM32H7_RCC_AHB3_DMA2D		4
+#define STM32H7_RCC_AHB3_JPGDEC		5
+#define STM32H7_RCC_AHB3_FMC		12
+#define STM32H7_RCC_AHB3_QUADSPI	14
+#define STM32H7_RCC_AHB3_SDMMC1		16
+#define STM32H7_RCC_AHB3_CPU		31
+
+#define STM32H7_AHB3_RESET(bit) (STM32H7_RCC_AHB3_##bit + (0x7C * 8))
+
+/* AHB1 */
+#define STM32H7_RCC_AHB1_DMA1		0
+#define STM32H7_RCC_AHB1_DMA2		1
+#define STM32H7_RCC_AHB1_ADC12		5
+#define STM32H7_RCC_AHB1_ART		14
+#define STM32H7_RCC_AHB1_ETH1MAC	15
+#define STM32H7_RCC_AHB1_USB1OTG	25
+#define STM32H7_RCC_AHB1_USB2OTG	27
+
+#define STM32H7_AHB1_RESET(bit) (STM32H7_RCC_AHB1_##bit + (0x80 * 8))
+
+/* AHB2 */
+#define STM32H7_RCC_AHB2_CAMITF		0
+#define STM32H7_RCC_AHB2_CRYPT		4
+#define STM32H7_RCC_AHB2_HASH		5
+#define STM32H7_RCC_AHB2_RNG		6
+#define STM32H7_RCC_AHB2_SDMMC2		9
+
+#define STM32H7_AHB2_RESET(bit) (STM32H7_RCC_AHB2_##bit + (0x84 * 8))
+
+/* AHB4 */
+#define STM32H7_RCC_AHB4_GPIOA		0
+#define STM32H7_RCC_AHB4_GPIOB		1
+#define STM32H7_RCC_AHB4_GPIOC		2
+#define STM32H7_RCC_AHB4_GPIOD		3
+#define STM32H7_RCC_AHB4_GPIOE		4
+#define STM32H7_RCC_AHB4_GPIOF		5
+#define STM32H7_RCC_AHB4_GPIOG		6
+#define STM32H7_RCC_AHB4_GPIOH		7
+#define STM32H7_RCC_AHB4_GPIOI		8
+#define STM32H7_RCC_AHB4_GPIOJ		9
+#define STM32H7_RCC_AHB4_GPIOK		10
+#define STM32H7_RCC_AHB4_CRC		19
+#define STM32H7_RCC_AHB4_BDMA		21
+#define STM32H7_RCC_AHB4_ADC3		24
+#define STM32H7_RCC_AHB4_HSEM		25
+
+#define STM32H7_AHB4_RESET(bit) (STM32H7_RCC_AHB4_##bit + (0x88 * 8))
+
+
+/* APB3 */
+#define STM32H7_RCC_APB3_LTDC		3
+#define STM32H7_RCC_APB3_DSI		4
+
+#define STM32H7_APB3_RESET(bit) (STM32H7_RCC_APB3_##bit + (0x8C * 8))
+
+/* APB1L */
+#define STM32H7_RCC_APB1L_TIM2		0
+#define STM32H7_RCC_APB1L_TIM3		1
+#define STM32H7_RCC_APB1L_TIM4		2
+#define STM32H7_RCC_APB1L_TIM5		3
+#define STM32H7_RCC_APB1L_TIM6		4
+#define STM32H7_RCC_APB1L_TIM7		5
+#define STM32H7_RCC_APB1L_TIM12		6
+#define STM32H7_RCC_APB1L_TIM13		7
+#define STM32H7_RCC_APB1L_TIM14		8
+#define STM32H7_RCC_APB1L_LPTIM1	9
+#define STM32H7_RCC_APB1L_SPI2		14
+#define STM32H7_RCC_APB1L_SPI3		15
+#define STM32H7_RCC_APB1L_SPDIF_RX	16
+#define STM32H7_RCC_APB1L_USART2	17
+#define STM32H7_RCC_APB1L_USART3	18
+#define STM32H7_RCC_APB1L_UART4		19
+#define STM32H7_RCC_APB1L_UART5		20
+#define STM32H7_RCC_APB1L_I2C1		21
+#define STM32H7_RCC_APB1L_I2C2		22
+#define STM32H7_RCC_APB1L_I2C3		23
+#define STM32H7_RCC_APB1L_HDMICEC	27
+#define STM32H7_RCC_APB1L_DAC12		29
+#define STM32H7_RCC_APB1L_USART7	30
+#define STM32H7_RCC_APB1L_USART8	31
+
+#define STM32H7_APB1L_RESET(bit) (STM32H7_RCC_APB1L_##bit + (0x90 * 8))
+
+/* APB1H */
+#define STM32H7_RCC_APB1H_CRS		1
+#define STM32H7_RCC_APB1H_SWP		2
+#define STM32H7_RCC_APB1H_OPAMP		4
+#define STM32H7_RCC_APB1H_MDIOS		5
+#define STM32H7_RCC_APB1H_FDCAN		8
+
+#define STM32H7_APB1H_RESET(bit) (STM32H7_RCC_APB1H_##bit + (0x94 * 8))
+
+/* APB2 */
+#define STM32H7_RCC_APB2_TIM1		0
+#define STM32H7_RCC_APB2_TIM8		1
+#define STM32H7_RCC_APB2_USART1		4
+#define STM32H7_RCC_APB2_USART6		5
+#define STM32H7_RCC_APB2_SPI1		12
+#define STM32H7_RCC_APB2_SPI4		13
+#define STM32H7_RCC_APB2_TIM15		16
+#define STM32H7_RCC_APB2_TIM16		17
+#define STM32H7_RCC_APB2_TIM17		18
+#define STM32H7_RCC_APB2_SPI5		20
+#define STM32H7_RCC_APB2_SAI1		22
+#define STM32H7_RCC_APB2_SAI2		23
+#define STM32H7_RCC_APB2_SAI3		24
+#define STM32H7_RCC_APB2_DFSDM1		28
+#define STM32H7_RCC_APB2_HRTIM		29
+
+#define STM32H7_APB2_RESET(bit) (STM32H7_RCC_APB2_##bit + (0x98 * 8))
+
+/* APB4 */
+#define STM32H7_RCC_APB4_SYSCFG		1
+#define STM32H7_RCC_APB4_LPUART1	3
+#define STM32H7_RCC_APB4_SPI6		5
+#define STM32H7_RCC_APB4_I2C4		7
+#define STM32H7_RCC_APB4_LPTIM2		9
+#define STM32H7_RCC_APB4_LPTIM3		10
+#define STM32H7_RCC_APB4_LPTIM4		11
+#define STM32H7_RCC_APB4_LPTIM5		12
+#define STM32H7_RCC_APB4_COMP12		14
+#define STM32H7_RCC_APB4_VREF		15
+#define STM32H7_RCC_APB4_SAI4		21
+#define STM32H7_RCC_APB4_TMPSENS	26
+
+#define STM32H7_APB4_RESET(bit) (STM32H7_RCC_APB4_##bit + (0x9C * 8))
+
+#endif /* _DT_BINDINGS_MFD_STM32H7_RCC_H */
-- 
1.9.1


^ permalink raw reply related

* Re: [PATCH 2/3] dt-bindings: arm: amlogic: Add SoC information bindings
From: Rob Herring @ 2017-04-04 12:26 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: Arnd Bergmann, Kevin Hilman, Carlo Caione,
	linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Linux ARM,
	Linux Kernel Mailing List,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <265460a5-9295-f58a-f149-030e5dd750a1-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>

On Tue, Apr 4, 2017 at 3:51 AM, Neil Armstrong <narmstrong-rdvid1DuHRBWk0Htik3J/w@public.gmane.org> wrote:
> On 04/03/2017 06:34 PM, Rob Herring wrote:
>> On Fri, Mar 31, 2017 at 04:10:30PM +0200, Neil Armstrong wrote:
>>> On 03/31/2017 03:44 PM, Arnd Bergmann wrote:
>>>> On Fri, Mar 31, 2017 at 10:47 AM, Neil Armstrong
>>>> <narmstrong-rdvid1DuHRBWk0Htik3J/w@public.gmane.org> wrote:
>>>>> Add bindings for the SoC information register of the Amlogic SoCs.
>>>>>
>>>>> Signed-off-by: Neil Armstrong <narmstrong-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
>>>>> ---
>>>>>  Documentation/devicetree/bindings/arm/amlogic.txt | 20 ++++++++++++++++++++
>>>>>  1 file changed, 20 insertions(+)
>>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt
>>>>> index bfd5b55..b850985 100644
>>>>> --- a/Documentation/devicetree/bindings/arm/amlogic.txt
>>>>> +++ b/Documentation/devicetree/bindings/arm/amlogic.txt
>>>>> @@ -52,3 +52,23 @@ Board compatible values:
>>>>>    - "amlogic,q201" (Meson gxm s912)
>>>>>    - "nexbox,a95x" (Meson gxbb or Meson gxl s905x)
>>>>>    - "nexbox,a1" (Meson gxm s912)
>>>>> +
>>>>> +Amlogic Meson GX SoCs Information
>>>>> +----------------------------------
>>>>> +
>>>>> +The Meson SoCs have a Product Register that allows to retrieve SoC type,
>>>>> +package and revision information. If present, a device node for this register
>>>>> +should be added.
>>>>> +
>>>>> +Required properties:
>>>>> +  - compatible: For Meson GX SoCs, must be "amlogic,meson-gx-socinfo".
>>>>> +  - reg: Base address and length of the register block.
>>>>> +
>>>>> +Examples
>>>>> +--------
>>>>> +
>>>>> +       chipid@220 {
>>>>> +               compatible = "amlogic,meson-gx-socinfo";
>>>>> +               reg = <0x0 0x00220 0x0 0x4>;
>>>>> +       };
>>>>> +
>>>>
>>>> The register location would hint that this is in the middle of some block of
>>>> random registers, i.e. a syscon or some unrelated device.
>>>>
>>>> Are you sure that "socinfo" is the actual name of the IP block and that
>>>> it only has a single 32-bit register?
>>>>
>>>>      Arnd
>>>>
>>>
>>> Hi Arnd,
>>>
>>> I'm sorry I did not find any relevant registers in the docs or source code describing
>>> it in a specific block of registers, and no close enough register definitions either.
>>> They may be used by the secure firmware I imagine.
>>>
>>> For the register name, Amlogic refers it to "cpu_version" in their code, but it really
>>> gives some details on the whole SoC and package, and socinfo seems better.
>>
>> A register at address 0x220 seems a bit strange (unless there's ranges
>> you're not showing), but ROM code at this address would be fairly
>> typical. And putting version information into the ROM is also common.
>>
>> Rob
>>
>
> Hi Rob.
>
> Indeed it's part of a larger range :
>                  aobus: aobus@c8100000 {
>                         compatible = "simple-bus";
>                         reg = <0x0 0xc8100000 0x0 0x100000>;
>                         #address-cells = <2>;
>                         #size-cells = <2>;
>                         ranges = <0x0 0x0 0x0 0xc8100000 0x0 0x100000>;
>
>
> While scrubbing on the uboot source, I found a sort of block of registers dedicated to communicate with
> the secure firmware :
> AO_SEC_REG0                                                     0x140
> AO_SEC_REG1                                                     0x144
> AO_SEC_REG2                                                     0x148
> AO_SEC_TMODE_PWD0                                               0x160
> AO_SEC_TMODE_PWD1                                               0x164
> AO_SEC_TMODE_PWD2                                               0x168
> AO_SEC_TMODE_PWD3                                               0x16C
> AO_SEC_SCRATCH                                                  0x17C
> AO_SEC_JTAG_PWD0                                                0x180
> AO_SEC_JTAG_PWD1                                                0x184
> AO_SEC_JTAG_PWD2                                                0x188
> AO_SEC_JTAG_PWD3                                                0x18C
> AO_SEC_JTAG_SEC_CNTL                                            0x190
> AO_SEC_JTAG_PWD_ADDR0                                           0x194
> AO_SEC_JTAG_PWD_ADDR1                                           0x198
> AO_SEC_JTAG_PWD_ADDR2                                           0x19C
> AO_SEC_JTAG_PWD_ADDR3                                           0x1A0
> AO_SEC_SHARED_AHB_SRAM_REG0_0                                   0x1C0
> AO_SEC_SHARED_AHB_SRAM_REG0_1                                   0x1C4
> AO_SEC_SHARED_AHB_SRAM_REG0_2                                   0x1C8
> AO_SEC_SHARED_AHB_SRAM_REG1_0                                   0x1CC
> AO_SEC_SHARED_AHB_SRAM_REG1_1                                   0x1D0
> AO_SEC_SHARED_AHB_SRAM_REG1_2                                   0x1D4
> AO_SEC_SHARED_AHB_SRAM_REG2_0                                   0x1D8
> AO_SEC_SHARED_AHB_SRAM_REG2_1                                   0x1DC
> AO_SEC_SHARED_AHB_SRAM_REG2_2                                   0x1E0
> AO_SEC_SHARED_AHB_SRAM_REG3_0                                   0x1E4
> AO_SEC_SHARED_AHB_SRAM_REG3_1                                   0x1E8
> AO_SEC_SHARED_AHB_SRAM_REG3_2                                   0x1EC
> AO_SEC_AO_AHB_SRAM_REG0_0                                       0x1F0
> AO_SEC_AO_AHB_SRAM_REG0_1                                       0x1F4
> AO_SEC_AO_AHB_SRAM_REG1_0                                       0x1F8
> AO_SEC_AO_AHB_SRAM_REG1_1                                       0x1FC
> AO_SEC_SD_CFG8                                                  0x220
> AO_SEC_SD_CFG9                                                  0x224
> AO_SEC_SD_CFG10                                                 0x228
> AO_SEC_SD_CFG11                                                 0x22C
> AO_SEC_SD_CFG12                                                 0x230
> AO_SEC_SD_CFG13                                                 0x234
> AO_SEC_SD_CFG14                                                 0x238
> AO_SEC_SD_CFG15                                                 0x23C
> AO_SEC_GP_CFG0                                                  0x240
> AO_SEC_GP_CFG1                                                  0x244
> AO_SEC_GP_CFG2                                                  0x248
> AO_SEC_GP_CFG3                                                  0x24C
> AO_SEC_GP_CFG4                                                  0x250
> AO_SEC_GP_CFG5                                                  0x254
> AO_SEC_GP_CFG6                                                  0x258
> AO_SEC_GP_CFG7                                                  0x25C
> AO_SEC_GP_CFG8                                                  0x260
> AO_SEC_GP_CFG9                                                  0x264
> AO_SEC_GP_CFG10                                                 0x268
> AO_SEC_GP_CFG11                                                 0x26C
> AO_SEC_GP_CFG12                                                 0x270
> AO_SEC_GP_CFG13                                                 0x274
> AO_SEC_GP_CFG14                                                 0x278
> AO_SEC_GP_CFG15                                                 0x27C
>
>
> As you see, the register we use here is AO_SEC_SD_CFG8...
>
> Should I define all this block as simple-mfd and refer to it as a regmap ?
>
> aobus: aobus@c8100000 {
>         compatible = "simple-bus";
>         reg = <0x0 0xc8100000 0x0 0x100000>;
>         #address-cells = <2>;
>         #size-cells = <2>;
>         ranges = <0x0 0x0 0x0 0xc8100000 0x0 0x100000>;
>
>         ao_secure: ao-secure@140 {
>                 compatible = "amlogic,meson-gx-ao-secure", "simple-mfd";
>                 reg = <0x0 0x140 0x0 0x140>;
>         };
> };
>
> chipid {
>         compatible = "amlogic,meson-gx-socinfo";
>         ao-secure = <&ao_secure>;
>         chip-info-reg = <0xe0>;

Why even divide it up further in DT? IMO, describing single
registers/address in DT is too fine grained.

Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v2 1/2] dt-bindings: Document the STM32 QSPI bindings
From: Rob Herring @ 2017-04-04 12:20 UTC (permalink / raw)
  To: Ludovic BARRE
  Cc: Cyrille Pitchen, Marek Vasut, David Woodhouse, Brian Norris,
	Boris Brezillon, Richard Weinberger, Alexandre Torgue,
	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <bd7cf1f8-e3b6-5752-47ef-2f54d56f81cc-qxv4g6HH51o@public.gmane.org>

On Tue, Apr 4, 2017 at 2:28 AM, Ludovic BARRE <ludovic.barre-qxv4g6HH51o@public.gmane.org> wrote:
> Hi Rob
>
> thanks for review
> my comments below
>
> br
> Ludo
>
> On 04/03/2017 06:57 PM, Rob Herring wrote:
>>
>> On Fri, Mar 31, 2017 at 07:02:03PM +0200, Ludovic Barre wrote:
>>>
>>> From: Ludovic Barre <ludovic.barre-qxv4g6HH51o@public.gmane.org>
>>>
>>> This patch adds documentation of device tree bindings for the STM32
>>> QSPI controller.
>>>
>>> Signed-off-by: Ludovic Barre <ludovic.barre-qxv4g6HH51o@public.gmane.org>
>>> ---
>>>   .../devicetree/bindings/mtd/stm32-quadspi.txt      | 45
>>> ++++++++++++++++++++++
>>>   1 file changed, 45 insertions(+)
>>>   create mode 100644
>>> Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
>>> b/Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
>>> new file mode 100644
>>> index 0000000..95a8ebd
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
>>> @@ -0,0 +1,45 @@
>>> +* STMicroelectronics Quad Serial Peripheral Interface(QuadSPI)
>>> +
>>> +Required properties:
>>> +- compatible: should be "st,stm32f469-qspi"
>>> +- reg: contains the register location and length.
>>> +  (optional) the memory mapping address and length
>>
>> Why optional? Either the h/w has it or doesn't. If some chips don't,
>> they should have a different compatible string.
>
> in fact, the stm32 qspi controller can operate in any of the following
> modes:
> -indirect mode: all the operations are performed using the qspi registers
> with read/write.
> -read memory-mapped mode: the external Flash memory is mapped to the
>  microcontroller address space and is seen by the system as if it was
>  an internal memory (use memcpy_fromio). this mode improve read throughput
>
> if qspi_mm is defined the qspi controller use read memory-mapped mode
> else the controller transfers in indirect mode.

You should always have the memory region defined because that's what
the h/w has. If you want another property to select the mode, then
perhaps that's fine. But why? Can't the OS figure out which to use?
Why would you ever not use memory mapped mode unless the driver
doesn't yet support it?

Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH V10 07/12] of/acpi: Configure dma operations at probe time for platform/amba/pci bus devices
From: Robin Murphy @ 2017-04-04 12:17 UTC (permalink / raw)
  To: Sricharan R, will.deacon-5wv7dgnIgG8, joro-zLv9SwRftAIdnm+yROfE0A,
	lorenzo.pieralisi-5wv7dgnIgG8,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
	bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, linux-pci-u79uwXL29TY76Z2rM5mHXA,
	linux-acpi-u79uwXL29TY76Z2rM5mHXA, tn-nYOzD4b6Jr9Wk0Htik3J/w,
	hanjun.guo-QSEj5FYQhm4dnm+yROfE0A, okaya-sgV2jX0FEOL9JmXXK+q4OQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, sudeep.holla-5wv7dgnIgG8,
	rjw-LthD3rsA81gm4RdzfppkhA, lenb-DgEjT+Ai2ygdnm+yROfE0A,
	catalin.marinas-5wv7dgnIgG8, arnd-r2nGTMty4D4,
	linux-arch-u79uwXL29TY76Z2rM5mHXA,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r
In-Reply-To: <1491301105-5274-8-git-send-email-sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>

On 04/04/17 11:18, Sricharan R wrote:
> Configuring DMA ops at probe time will allow deferring device probe when
> the IOMMU isn't available yet. The dma_configure for the device is
> now called from the generic device_attach callback just before the
> bus/driver probe is called. This way, configuring the DMA ops for the
> device would be called at the same place for all bus_types, hence the
> deferred probing mechanism should work for all buses as well.
> 
> pci_bus_add_devices    (platform/amba)(_device_create/driver_register)
>        |                         |
> pci_bus_add_device     (device_add/driver_register)
>        |                         |
> device_attach           device_initial_probe
>        |                         |
> __device_attach_driver    __device_attach_driver
>        |
> driver_probe_device
>        |
> really_probe
>        |
> dma_configure
> 
> Similarly on the device/driver_unregister path __device_release_driver is
> called which inturn calls dma_deconfigure.
> 
> This patch changes the dma ops configuration to probe time for
> both OF and ACPI based platform/amba/pci bus devices.

Reviewed-by: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>

It's possible we could subsume {of,acpi}_dma_deconfigure() into
dma_deconfigure() entirely in future if it becomes clear that neither of
them will ever need to do anything firmware-specific, but I think for
now it's probably safer to keep the current symmetry - calling
arch_teardown_dma_ops() twice is benign (and even if it weren't, I'd say
it really should be!)

Robin.

> Tested-by: Marek Szyprowski <m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Tested-by: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Acked-by: Bjorn Helgaas <bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org> (drivers/pci part)
> Acked-by: Rafael J. Wysocki <rafael.j.wysocki-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Sricharan R <sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> ---
> 
>  [V10] Added dummy dma_(de)configure functions in case
>        of !CONFIG_HAS_DMA to avoid build breaks.
> 
>  drivers/acpi/glue.c         |  5 -----
>  drivers/base/dd.c           |  9 +++++++++
>  drivers/base/dma-mapping.c  | 40 ++++++++++++++++++++++++++++++++++++++++
>  drivers/of/platform.c       |  5 +----
>  drivers/pci/probe.c         | 28 ----------------------------
>  include/linux/dma-mapping.h | 12 ++++++++++++
>  6 files changed, 62 insertions(+), 37 deletions(-)
> 
> diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
> index fb19e1c..c05f241 100644
> --- a/drivers/acpi/glue.c
> +++ b/drivers/acpi/glue.c
> @@ -176,7 +176,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
>  	struct list_head *physnode_list;
>  	unsigned int node_id;
>  	int retval = -EINVAL;
> -	enum dev_dma_attr attr;
>  
>  	if (has_acpi_companion(dev)) {
>  		if (acpi_dev) {
> @@ -233,10 +232,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
>  	if (!has_acpi_companion(dev))
>  		ACPI_COMPANION_SET(dev, acpi_dev);
>  
> -	attr = acpi_get_dma_attr(acpi_dev);
> -	if (attr != DEV_DMA_NOT_SUPPORTED)
> -		acpi_dma_configure(dev, attr);
> -
>  	acpi_physnode_link_name(physical_node_name, node_id);
>  	retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
>  				   physical_node_name);
> diff --git a/drivers/base/dd.c b/drivers/base/dd.c
> index a1fbf55..4882f06 100644
> --- a/drivers/base/dd.c
> +++ b/drivers/base/dd.c
> @@ -19,6 +19,7 @@
>  
>  #include <linux/device.h>
>  #include <linux/delay.h>
> +#include <linux/dma-mapping.h>
>  #include <linux/module.h>
>  #include <linux/kthread.h>
>  #include <linux/wait.h>
> @@ -356,6 +357,10 @@ static int really_probe(struct device *dev, struct device_driver *drv)
>  	if (ret)
>  		goto pinctrl_bind_failed;
>  
> +	ret = dma_configure(dev);
> +	if (ret)
> +		goto dma_failed;
> +
>  	if (driver_sysfs_add(dev)) {
>  		printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
>  			__func__, dev_name(dev));
> @@ -417,6 +422,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
>  	goto done;
>  
>  probe_failed:
> +	dma_deconfigure(dev);
> +dma_failed:
>  	if (dev->bus)
>  		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
>  					     BUS_NOTIFY_DRIVER_NOT_BOUND, dev);
> @@ -826,6 +833,8 @@ static void __device_release_driver(struct device *dev, struct device *parent)
>  			drv->remove(dev);
>  
>  		device_links_driver_cleanup(dev);
> +		dma_deconfigure(dev);
> +
>  		devres_release_all(dev);
>  		dev->driver = NULL;
>  		dev_set_drvdata(dev, NULL);
> diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
> index efd71cf..449b948 100644
> --- a/drivers/base/dma-mapping.c
> +++ b/drivers/base/dma-mapping.c
> @@ -7,9 +7,11 @@
>   * This file is released under the GPLv2.
>   */
>  
> +#include <linux/acpi.h>
>  #include <linux/dma-mapping.h>
>  #include <linux/export.h>
>  #include <linux/gfp.h>
> +#include <linux/of_device.h>
>  #include <linux/slab.h>
>  #include <linux/vmalloc.h>
>  
> @@ -341,3 +343,41 @@ void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags)
>  	vunmap(cpu_addr);
>  }
>  #endif
> +
> +/*
> + * Common configuration to enable DMA API use for a device
> + */
> +#include <linux/pci.h>
> +
> +int dma_configure(struct device *dev)
> +{
> +	struct device *bridge = NULL, *dma_dev = dev;
> +	enum dev_dma_attr attr;
> +
> +	if (dev_is_pci(dev)) {
> +		bridge = pci_get_host_bridge_device(to_pci_dev(dev));
> +		dma_dev = bridge;
> +		if (IS_ENABLED(CONFIG_OF) && dma_dev->parent &&
> +		    dma_dev->parent->of_node)
> +			dma_dev = dma_dev->parent;
> +	}
> +
> +	if (dma_dev->of_node) {
> +		of_dma_configure(dev, dma_dev->of_node);
> +	} else if (has_acpi_companion(dma_dev)) {
> +		attr = acpi_get_dma_attr(to_acpi_device_node(dma_dev->fwnode));
> +		if (attr != DEV_DMA_NOT_SUPPORTED)
> +			acpi_dma_configure(dev, attr);
> +	}
> +
> +	if (bridge)
> +		pci_put_host_bridge_device(bridge);
> +
> +	return 0;
> +}
> +
> +void dma_deconfigure(struct device *dev)
> +{
> +	of_dma_deconfigure(dev);
> +	acpi_dma_deconfigure(dev);
> +}
> diff --git a/drivers/of/platform.c b/drivers/of/platform.c
> index 5344db5..2aa4ebb 100644
> --- a/drivers/of/platform.c
> +++ b/drivers/of/platform.c
> @@ -22,6 +22,7 @@
>  #include <linux/slab.h>
>  #include <linux/of_address.h>
>  #include <linux/of_device.h>
> +#include <linux/of_iommu.h>
>  #include <linux/of_irq.h>
>  #include <linux/of_platform.h>
>  #include <linux/platform_device.h>
> @@ -186,11 +187,9 @@ static struct platform_device *of_platform_device_create_pdata(
>  
>  	dev->dev.bus = &platform_bus_type;
>  	dev->dev.platform_data = platform_data;
> -	of_dma_configure(&dev->dev, dev->dev.of_node);
>  	of_msi_configure(&dev->dev, dev->dev.of_node);
>  
>  	if (of_device_add(dev) != 0) {
> -		of_dma_deconfigure(&dev->dev);
>  		platform_device_put(dev);
>  		goto err_clear_flag;
>  	}
> @@ -248,7 +247,6 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
>  		dev_set_name(&dev->dev, "%s", bus_id);
>  	else
>  		of_device_make_bus_id(&dev->dev);
> -	of_dma_configure(&dev->dev, dev->dev.of_node);
>  
>  	/* Allow the HW Peripheral ID to be overridden */
>  	prop = of_get_property(node, "arm,primecell-periphid", NULL);
> @@ -542,7 +540,6 @@ static int of_platform_device_destroy(struct device *dev, void *data)
>  		amba_device_unregister(to_amba_device(dev));
>  #endif
>  
> -	of_dma_deconfigure(dev);
>  	of_node_clear_flag(dev->of_node, OF_POPULATED);
>  	of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
>  	return 0;
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index dfc9a27..5a8dd43 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -1893,33 +1893,6 @@ static void pci_set_msi_domain(struct pci_dev *dev)
>  	dev_set_msi_domain(&dev->dev, d);
>  }
>  
> -/**
> - * pci_dma_configure - Setup DMA configuration
> - * @dev: ptr to pci_dev struct of the PCI device
> - *
> - * Function to update PCI devices's DMA configuration using the same
> - * info from the OF node or ACPI node of host bridge's parent (if any).
> - */
> -static void pci_dma_configure(struct pci_dev *dev)
> -{
> -	struct device *bridge = pci_get_host_bridge_device(dev);
> -
> -	if (IS_ENABLED(CONFIG_OF) &&
> -		bridge->parent && bridge->parent->of_node) {
> -			of_dma_configure(&dev->dev, bridge->parent->of_node);
> -	} else if (has_acpi_companion(bridge)) {
> -		struct acpi_device *adev = to_acpi_device_node(bridge->fwnode);
> -		enum dev_dma_attr attr = acpi_get_dma_attr(adev);
> -
> -		if (attr == DEV_DMA_NOT_SUPPORTED)
> -			dev_warn(&dev->dev, "DMA not supported.\n");
> -		else
> -			acpi_dma_configure(&dev->dev, attr);
> -	}
> -
> -	pci_put_host_bridge_device(bridge);
> -}
> -
>  void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
>  {
>  	int ret;
> @@ -1933,7 +1906,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
>  	dev->dev.dma_mask = &dev->dma_mask;
>  	dev->dev.dma_parms = &dev->dma_parms;
>  	dev->dev.coherent_dma_mask = 0xffffffffull;
> -	pci_dma_configure(dev);
>  
>  	pci_set_dma_max_seg_size(dev, 65536);
>  	pci_set_dma_seg_boundary(dev, 0xffffffff);
> diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
> index 0977317..4f3eece 100644
> --- a/include/linux/dma-mapping.h
> +++ b/include/linux/dma-mapping.h
> @@ -728,6 +728,18 @@ void *dma_mark_declared_memory_occupied(struct device *dev,
>  }
>  #endif /* CONFIG_HAVE_GENERIC_DMA_COHERENT */
>  
> +#ifdef CONFIG_HAS_DMA
> +int dma_configure(struct device *dev);
> +void dma_deconfigure(struct device *dev);
> +#else
> +static inline int dma_configure(struct device *dev)
> +{
> +	return 0;
> +}
> +
> +static inline void dma_deconfigure(struct device *dev) {}
> +#endif
> +
>  /*
>   * Managed DMA API
>   */
> 

^ permalink raw reply

* [PATCH v3 08/11] dt-bindings: Add bindings for the Amlogic Meson dw-hdmi extension
From: Neil Armstrong @ 2017-04-04 12:15 UTC (permalink / raw)
  To: airlied
  Cc: devicetree, Neil Armstrong, linux-kernel, dri-devel,
	linux-amlogic, linux-arm-kernel
In-Reply-To: <1491308131-22071-1-git-send-email-narmstrong@baylibre.com>

This binding describes the Amlogic Meson specific extension to the
Synopsys Designware HDMI Controller.

Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 .../bindings/display/amlogic,meson-dw-hdmi.txt     | 111 +++++++++++++++++++++
 1 file changed, 111 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt

diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt
new file mode 100644
index 0000000..7f040ed
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt
@@ -0,0 +1,111 @@
+Amlogic specific extensions to the Synopsys Designware HDMI Controller
+======================================================================
+
+The Amlogic Meson Synopsys Designware Integration is composed of :
+- A Synopsys DesignWare HDMI Controller IP
+- A TOP control block controlling the Clocks and PHY
+- A custom HDMI PHY in order to convert video to TMDS signal
+ ___________________________________
+|            HDMI TOP               |<= HPD
+|___________________________________|
+|                  |                |
+|  Synopsys HDMI   |   HDMI PHY     |=> TMDS
+|    Controller    |________________|
+|___________________________________|<=> DDC
+
+The HDMI TOP block only supports HPD sensing.
+The Synopsys HDMI Controller interrupt is routed through the
+TOP Block interrupt.
+Communication to the TOP Block and the Synopsys HDMI Controller is done
+via a pair of dedicated addr+read/write registers.
+The HDMI PHY is configured by registers in the HHI register block.
+
+Pixel data arrives in 4:4:4 format from the VENC block and the VPU HDMI mux
+selects either the ENCI encoder for the 576i or 480i formats or the ENCP
+encoder for all the other formats including interlaced HD formats.
+
+The VENC uses a DVI encoder on top of the ENCI or ENCP encoders to generate
+DVI timings for the HDMI controller.
+
+Amlogic Meson GXBB, GXL and GXM SoCs families embeds the Synopsys DesignWare
+HDMI TX IP version 2.01a with HDCP and I2C & S/PDIF
+audio source interfaces.
+
+Required properties:
+- compatible: value should be different for each SoC family as :
+	- GXBB (S905) : "amlogic,meson-gxbb-dw-hdmi"
+	- GXL (S905X, S905D) : "amlogic,meson-gxl-dw-hdmi"
+	- GXM (S912) : "amlogic,meson-gxm-dw-hdmi"
+	followed by the common "amlogic,meson-gx-dw-hdmi"
+- reg: Physical base address and length of the controller's registers.
+- interrupts: The HDMI interrupt number
+- clocks, clock-names : must have the phandles to the HDMI iahb and isfr clocks,
+  and the Amlogic Meson venci clocks as described in
+  Documentation/devicetree/bindings/clock/clock-bindings.txt,
+  the clocks are soc specific, the clock-names should be "iahb", "isfr", "venci"
+- resets, resets-names: must have the phandles to the HDMI apb, glue and phy
+  resets as described in :
+  Documentation/devicetree/bindings/reset/reset.txt,
+  the reset-names should be "hdmitx_apb", "hdmitx", "hdmitx_phy"
+
+Required nodes:
+
+The connections to the HDMI ports are modeled using the OF graph
+bindings specified in Documentation/devicetree/bindings/graph.txt.
+
+The following table lists for each supported model the port number
+corresponding to each HDMI output and input.
+
+		Port 0		Port 1
+-----------------------------------------
+ S905 (GXBB)	VENC Input	TMDS Output
+ S905X (GXL)	VENC Input	TMDS Output
+ S905D (GXL)	VENC Input	TMDS Output
+ S912 (GXM)	VENC Input	TMDS Output
+
+Example:
+
+hdmi-connector {
+	compatible = "hdmi-connector";
+	type = "a";
+
+	port {
+		hdmi_connector_in: endpoint {
+			remote-endpoint = <&hdmi_tx_tmds_out>;
+		};
+	};
+};
+
+hdmi_tx: hdmi-tx@c883a000 {
+	compatible = "amlogic,meson-gxbb-dw-hdmi", "amlogic,meson-gx-dw-hdmi";
+	reg = <0x0 0xc883a000 0x0 0x1c>;
+	interrupts = <GIC_SPI 57 IRQ_TYPE_EDGE_RISING>;
+	resets = <&reset RESET_HDMITX_CAPB3>,
+		 <&reset RESET_HDMI_SYSTEM_RESET>,
+		 <&reset RESET_HDMI_TX>;
+	reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy";
+	clocks = <&clkc CLKID_HDMI_PCLK>,
+		 <&clkc CLKID_CLK81>,
+		 <&clkc CLKID_GCLK_VENCI_INT0>;
+	clock-names = "isfr", "iahb", "venci";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	/* VPU VENC Input */
+	hdmi_tx_venc_port: port@0 {
+		reg = <0>;
+
+		hdmi_tx_in: endpoint {
+			remote-endpoint = <&hdmi_tx_out>;
+		};
+	};
+
+	/* TMDS Output */
+	hdmi_tx_tmds_port: port@1 {
+		reg = <1>;
+
+		hdmi_tx_tmds_out: endpoint {
+			remote-endpoint = <&hdmi_connector_in>;
+		};
+	};
+};
-- 
1.9.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related

* [PATCH 1/3 v5] iio: xoadc: augment DT bindings a bit
From: Linus Walleij @ 2017-04-04 12:08 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio-u79uwXL29TY76Z2rM5mHXA
  Cc: Linus Walleij, devicetree-u79uwXL29TY76Z2rM5mHXA

In order to accommodate in a logical manner for the premuxed channels
in PM8921 and the similarly addressed channels in later PMICs, we
need a twocell arrangement with premux and analog mux setting as
a tuple to uniquely identify a hardware channel.

These bindings are not yet in use, so it should be fine to augment
them before we actually start using it in drivers and device trees.

This scheme came out of lengthy discussions and reverse-engineering
and reading of the few information sources we have.

Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Acked-by: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Suggested-by: Björn Andersson <bjorn.andersson-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Signed-off-by: Linus Walleij <linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
ChangeLog v3->v5:
- Some nitpicky spelling fixes. Added Rob's ACK.
ChangeLog v2->v3:
- Drop leading zeroes on unit addresses.
ChangeLog v1->v2:
- Name nodes with <01 02> in a foo@0102 pattern.
- Minor spelling nits.
- Delete flimsy leftover docs from an interrim development path.
---
 .../bindings/iio/adc/qcom,pm8xxx-xoadc.txt         | 76 ++++++++++++----------
 1 file changed, 42 insertions(+), 34 deletions(-)

diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,pm8xxx-xoadc.txt b/Documentation/devicetree/bindings/iio/adc/qcom,pm8xxx-xoadc.txt
index 53cd146d8096..3ae06127789e 100644
--- a/Documentation/devicetree/bindings/iio/adc/qcom,pm8xxx-xoadc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/qcom,pm8xxx-xoadc.txt
@@ -19,32 +19,42 @@ Required properties:
   with PMIC variant but is typically something like 2.2 or 1.8V.
 
 The following required properties are standard for IO channels, see
-iio-bindings.txt for more details:
+iio-bindings.txt for more details, but notice that this particular
+ADC has a special addressing scheme that require two cells for
+identifying each ADC channel:
 
-- #address-cells: should be set to <1>
+- #address-cells: should be set to <2>, the first cell is the
+  prescaler (on PM8058) or premux (on PM8921) with two valid bits
+  so legal values are 0x00, 0x01 or 0x02. The second cell
+  is the main analog mux setting (0x00..0x0f). The combination
+  of prescaler/premux and analog mux uniquely addresses a hardware
+  channel on all systems.
 
 - #size-cells: should be set to <0>
 
-- #io-channel-cells: should be set to <1>
+- #io-channel-cells: should be set to <2>, again the cells are
+  precaler or premux followed by the analog muxing line.
 
 - interrupts: should refer to the parent PMIC interrupt controller
   and reference the proper ADC interrupt.
 
 Required subnodes:
 
-The ADC channels are configured as subnodes of the ADC. Since some of
-them are used for calibrating the ADC, these nodes are compulsory:
+The ADC channels are configured as subnodes of the ADC.
+
+Since some of them are used for calibrating the ADC, these nodes are
+compulsory:
 
 adc-channel@c {
-	reg = <0x0c>;
+	reg = <0x00 0x0c>;
 };
 
 adc-channel@d {
-	reg = <0x0d>;
+	reg = <0x00 0x0d>;
 };
 
 adc-channel@f {
-	reg = <0x0f>;
+	reg = <0x00 0x0f>;
 };
 
 These three nodes are used for absolute and ratiometric calibration
@@ -52,13 +62,13 @@ and only need to have these reg values: they are by hardware definition
 1:1 ratio converters that sample 625, 1250 and 0 milliV and create
 an interpolation calibration for all other ADCs.
 
-Optional subnodes: any channels other than channel 0x0c, 0x0d and
-0x0f are optional.
+Optional subnodes: any channels other than channels [0x00 0x0c],
+[0x00 0x0d] and [0x00 0x0f] are optional.
 
 Required channel node properties:
 
 - reg: should contain the hardware channel number in the range
-  0 .. 0x0f (4 bits). The hardware only supports 16 channels.
+  0 .. 0xff (8 bits).
 
 Optional channel node properties:
 
@@ -94,56 +104,54 @@ Example:
 xoadc: xoadc@197 {
 	compatible = "qcom,pm8058-adc";
 	reg = <0x197>;
-	interrupt-parent = <&pm8058>;
-	interrupts = <76 1>;
-	#address-cells = <1>;
+	interrupts-extended = <&pm8058 76 IRQ_TYPE_EDGE_RISING>;
+	#address-cells = <2>;
 	#size-cells = <0>;
-	#io-channel-cells = <1>;
+	#io-channel-cells = <2>;
 
 	vcoin: adc-channel@0 {
-		reg = <0x00>;
+		reg = <0x00 0x00>;
 	};
 	vbat: adc-channel@1 {
-		reg = <0x01>;
+		reg = <0x00 0x01>;
 	};
 	dcin: adc-channel@2 {
-		reg = <0x02>;
+		reg = <0x00 0x02>;
 	};
 	ichg: adc-channel@3 {
-		reg = <0x03>;
+		reg = <0x00 0x03>;
 	};
 	vph_pwr: adc-channel@4 {
-		reg = <0x04>;
+		reg = <0x00 0x04>;
 	};
 	usb_vbus: adc-channel@a {
-		reg = <0x0a>;
+		reg = <0x00 0x0a>;
 	};
 	die_temp: adc-channel@b {
-		reg = <0x0b>;
+		reg = <0x00 0x0b>;
 	};
 	ref_625mv: adc-channel@c {
-		reg = <0x0c>;
+		reg = <0x00 0x0c>;
 	};
 	ref_1250mv: adc-channel@d {
-		reg = <0x0d>;
+		reg = <0x00 0x0d>;
 	};
 	ref_325mv: adc-channel@e {
-		reg = <0x0e>;
+		reg = <0x00 0x0e>;
 	};
 	ref_muxoff: adc-channel@f {
-		reg = <0x0f>;
+		reg = <0x00 0x0f>;
 	};
 };
 
-
 /* IIO client node */
 iio-hwmon {
 	compatible = "iio-hwmon";
-	io-channels = <&xoadc 0x01>, /* Battery */
-		    <&xoadc 0x02>, /* DC in (charger) */
-		    <&xoadc 0x04>, /* VPH the main system voltage */
-		    <&xoadc 0x0b>, /* Die temperature */
-		    <&xoadc 0x0c>, /* Reference voltage 1.25V */
-		    <&xoadc 0x0d>, /* Reference voltage 0.625V */
-		    <&xoadc 0x0e>; /* Reference voltage 0.325V */
+	io-channels = <&xoadc 0x00 0x01>, /* Battery */
+		    <&xoadc 0x00 0x02>, /* DC in (charger) */
+		    <&xoadc 0x00 0x04>, /* VPH the main system voltage */
+		    <&xoadc 0x00 0x0b>, /* Die temperature */
+		    <&xoadc 0x00 0x0c>, /* Reference voltage 1.25V */
+		    <&xoadc 0x00 0x0d>, /* Reference voltage 0.625V */
+		    <&xoadc 0x00 0x0e>; /* Reference voltage 0.325V */
 };
-- 
2.9.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Re: [PATCH v2 08/13] ARM64: dts: meson-gx: Add shared CMA dma memory pool
From: Kevin Hilman @ 2017-04-04 11:57 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: devicetree, linux-kernel, dri-devel, linux-amlogic,
	linux-arm-kernel
In-Reply-To: <43dd4aec-7002-5844-2e34-8507860a8268@baylibre.com>

Neil Armstrong <narmstrong@baylibre.com> writes:

> On 03/21/2017 04:25 PM, Neil Armstrong wrote:
>> The HDMI modes needs more CMA memory to be reserved at boot-time.
>> 
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>

[...]

> Hi Kevin,
>
> Please take this one for the amlogic arm-soc DT tree.
>

Applied to v4.12/dt64,

Kevin
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* Re: [PATCH v2 09/13] ARM64: dts: meson-gx: Add support for HDMI output
From: Kevin Hilman @ 2017-04-04 11:57 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: devicetree, linux-kernel, dri-devel, linux-amlogic,
	linux-arm-kernel
In-Reply-To: <be91a6f7-19ad-5d50-4f0c-03e2821493d4@baylibre.com>

Neil Armstrong <narmstrong@baylibre.com> writes:

> On 03/21/2017 04:25 PM, Neil Armstrong wrote:
>> Add HDMI output and connector nodes.
>> 
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>

[...]

>
> Hi Kevin,
>
> Please take this one for the amlogic arm-soc DT tree.
>

Applied to v4.12/dt64,

Kevin
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* Re: [PATCH v3 5/7] mfd: Add Device Tree bindings document for TI tps6105x chip
From: Javier Martinez Canillas @ 2017-04-04 11:48 UTC (permalink / raw)
  To: Lee Jones
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Mark Rutland
In-Reply-To: <20170404082739.6w6ltgdr2mgaqq4l@dell>

Hello Lee,

On 04/04/2017 04:27 AM, Lee Jones wrote:
> On Mon, 03 Apr 2017, Javier Martinez Canillas wrote:
> 
>> Hello Lee,
>>
>> On 04/03/2017 07:15 AM, Lee Jones wrote:
>>
>> [snip]
>>
>>>> +
>>>> +The TP61050/TPS61052 is a high-power "white LED driver". This boost converter
>>>> +is also used for other things than white LEDs, and also contains a GPIO pin.
>>>
>>> What functions does it offer?
>>>
>>
>> Same comment than before, I'm not really familiar with this driver. But I'll
>> look what are the MFD cell instantiated to better understand dev functions
>> and expand this documentation accordingly.
> 
> Writing documentation for H/W you are unfamiliar with is a bad idea IMHO.
>

I just wanted to add an OF device ID table to the driver to make sure the
driver won't have a regression when the I2C core reports an OF modalias
but was asked to also write a DT binding doc in this case...

I'm happy to drop the DT binding doc patch and someone more familiar to do
it as a follow up.

Best regards,
-- 
Javier Martinez Canillas
Open Source Group
Samsung Research America
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH V10 12/12] ACPI/IORT: Remove linker section for IORT entries probing
From: Robin Murphy @ 2017-04-04 11:33 UTC (permalink / raw)
  To: Sricharan R, will.deacon, joro, lorenzo.pieralisi, iommu,
	linux-arm-kernel, linux-arm-msm, m.szyprowski, bhelgaas,
	linux-pci, linux-acpi, tn, hanjun.guo, okaya, robh+dt,
	frowand.list, devicetree, linux-kernel, sudeep.holla, rjw, lenb,
	catalin.marinas, arnd, linux-arch, gregkh
In-Reply-To: <1491301105-5274-13-git-send-email-sricharan@codeaurora.org>

On 04/04/17 11:18, Sricharan R wrote:
> From: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> 
> The IORT linker section introduced by commit 34ceea275f62
> ("ACPI/IORT: Introduce linker section for IORT entries probing")
> was needed to make sure SMMU drivers are registered (and therefore
> probed) in the kernel before devices using the SMMU have a chance
> to probe in turn.
> 
> Through the introduction of deferred IOMMU configuration the linker
> section based IORT probing infrastructure is not needed any longer, in
> that device/SMMU probe dependencies are managed through the probe
> deferral mechanism, making the IORT linker section infrastructure
> unused, so that it can be removed.
> 
> Remove the unused IORT linker section probing infrastructure
> from the kernel to complete the ACPI IORT IOMMU configure probe
> deferral mechanism implementation.

Reviewed-by: Robin Murphy <robin.murphy@arm.com>

> Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Cc: Robin Murphy <robin.murphy@arm.com>
> Cc: Sricharan R <sricharan@codeaurora.org>
> ---
>  drivers/acpi/arm64/iort.c         | 2 --
>  include/asm-generic/vmlinux.lds.h | 1 -
>  include/linux/acpi_iort.h         | 3 ---
>  3 files changed, 6 deletions(-)
> 
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index e323ece..e7b1940 100644
> --- a/drivers/acpi/arm64/iort.c
> +++ b/drivers/acpi/arm64/iort.c
> @@ -1000,6 +1000,4 @@ void __init acpi_iort_init(void)
>  	}
>  
>  	iort_init_platform_devices();
> -
> -	acpi_probe_device_table(iort);
>  }
> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
> index 0968d13..9faa26c 100644
> --- a/include/asm-generic/vmlinux.lds.h
> +++ b/include/asm-generic/vmlinux.lds.h
> @@ -566,7 +566,6 @@
>  	IRQCHIP_OF_MATCH_TABLE()					\
>  	ACPI_PROBE_TABLE(irqchip)					\
>  	ACPI_PROBE_TABLE(clksrc)					\
> -	ACPI_PROBE_TABLE(iort)						\
>  	EARLYCON_TABLE()
>  
>  #define INIT_TEXT							\
> diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
> index 77e0809..f167e1d04 100644
> --- a/include/linux/acpi_iort.h
> +++ b/include/linux/acpi_iort.h
> @@ -52,7 +52,4 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>  { return NULL; }
>  #endif
>  
> -#define IORT_ACPI_DECLARE(name, table_id, fn)		\
> -	ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn)
> -
>  #endif /* __ACPI_IORT_H__ */
> 

^ permalink raw reply

* Re: [PATCH V10 09/12] drivers: acpi: Handle IOMMU lookup failure with deferred probing or error
From: Robin Murphy @ 2017-04-04 11:31 UTC (permalink / raw)
  To: Sricharan R, will.deacon, joro, lorenzo.pieralisi, iommu,
	linux-arm-kernel, linux-arm-msm, m.szyprowski, bhelgaas,
	linux-pci, linux-acpi, tn, hanjun.guo, okaya, robh+dt,
	frowand.list, devicetree, linux-kernel, sudeep.holla, rjw, lenb,
	catalin.marinas, arnd, linux-arch, gregkh
In-Reply-To: <1491301105-5274-10-git-send-email-sricharan@codeaurora.org>

On 04/04/17 11:18, Sricharan R wrote:
> This is an equivalent to the DT's handling of the iommu master's probe
> with deferred probing when the corrsponding iommu is not probed yet.
> The lack of a registered IOMMU can be caused by the lack of a driver for
> the IOMMU, the IOMMU device probe not having been performed yet, having
> been deferred, or having failed.
> 
> The first case occurs when the firmware describes the bus master and
> IOMMU topology correctly but no device driver exists for the IOMMU yet
> or the device driver has not been compiled in. Return NULL, the caller
> will configure the device without an IOMMU.
> 
> The second and third cases are handled by deferring the probe of the bus
> master device which will eventually get reprobed after the IOMMU.
> 
> The last case is currently handled by deferring the probe of the bus
> master device as well. A mechanism to either configure the bus master
> device without an IOMMU or to fail the bus master device probe depending
> on whether the IOMMU is optional or mandatory would be a good
> enhancement.

I think we really have caught everything now...

Reviewed-by: Robin Murphy <robin.murphy@arm.com>

> Tested-by: Hanjun Guo <hanjun.guo@linaro.org>
> [Lorenzo: Added fixes for dma_coherent_mask overflow, acpi_dma_configure
>           called multiple times for same device]
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> ---
> 
>  [V10] Added Lorenzo's ACPI fix for coherent_dma_mask overflow
>        and the fix for dma_configure getting called more than
>        once for the same device.
> 
>  drivers/acpi/arm64/iort.c  | 33 ++++++++++++++++++++++++++++++++-
>  drivers/acpi/scan.c        | 11 ++++++++---
>  drivers/base/dma-mapping.c |  2 +-
>  include/acpi/acpi_bus.h    |  2 +-
>  include/linux/acpi.h       |  7 +++++--
>  5 files changed, 47 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index 3dd9ec3..e323ece 100644
> --- a/drivers/acpi/arm64/iort.c
> +++ b/drivers/acpi/arm64/iort.c
> @@ -543,6 +543,14 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
>  	const struct iommu_ops *ops = NULL;
>  	int ret = -ENODEV;
>  	struct fwnode_handle *iort_fwnode;
> +	struct iommu_fwspec *fwspec = dev->iommu_fwspec;
> +
> +	/*
> +	 * If we already translated the fwspec there
> +	 * is nothing left to do, return the iommu_ops.
> +	 */
> +	if (fwspec && fwspec->ops)
> +		return fwspec->ops;
>  
>  	if (node) {
>  		iort_fwnode = iort_get_fwnode(node);
> @@ -550,8 +558,17 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
>  			return NULL;
>  
>  		ops = iommu_ops_from_fwnode(iort_fwnode);
> +		/*
> +		 * If the ops look-up fails, this means that either
> +		 * the SMMU drivers have not been probed yet or that
> +		 * the SMMU drivers are not built in the kernel;
> +		 * Depending on whether the SMMU drivers are built-in
> +		 * in the kernel or not, defer the IOMMU configuration
> +		 * or just abort it.
> +		 */
>  		if (!ops)
> -			return NULL;
> +			return iort_iommu_driver_enabled(node->type) ?
> +			       ERR_PTR(-EPROBE_DEFER) : NULL;
>  
>  		ret = arm_smmu_iort_xlate(dev, streamid, iort_fwnode, ops);
>  	}
> @@ -625,12 +642,26 @@ const struct iommu_ops *iort_iommu_configure(struct device *dev)
>  
>  		while (parent) {
>  			ops = iort_iommu_xlate(dev, parent, streamid);
> +			if (IS_ERR_OR_NULL(ops))
> +				return ops;
>  
>  			parent = iort_node_get_id(node, &streamid,
>  						  IORT_IOMMU_TYPE, i++);
>  		}
>  	}
>  
> +	/*
> +	 * If we have reason to believe the IOMMU driver missed the initial
> +	 * add_device callback for dev, replay it to get things in order.
> +	 */
> +	if (!IS_ERR_OR_NULL(ops) && ops->add_device &&
> +	    dev->bus && !dev->iommu_group) {
> +		int err = ops->add_device(dev);
> +
> +		if (err)
> +			ops = ERR_PTR(err);
> +	}
> +
>  	return ops;
>  }
>  
> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> index 1926918..2a513cc 100644
> --- a/drivers/acpi/scan.c
> +++ b/drivers/acpi/scan.c
> @@ -1373,20 +1373,25 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
>   * @dev: The pointer to the device
>   * @attr: device dma attributes
>   */
> -void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
> +int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
>  {
>  	const struct iommu_ops *iommu;
> +	u64 size;
>  
>  	iort_set_dma_mask(dev);
>  
>  	iommu = iort_iommu_configure(dev);
> +	if (IS_ERR(iommu))
> +		return PTR_ERR(iommu);
>  
> +	size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1);
>  	/*
>  	 * Assume dma valid range starts at 0 and covers the whole
>  	 * coherent_dma_mask.
>  	 */
> -	arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, iommu,
> -			   attr == DEV_DMA_COHERENT);
> +	arch_setup_dma_ops(dev, 0, size, iommu, attr == DEV_DMA_COHERENT);
> +
> +	return 0;
>  }
>  EXPORT_SYMBOL_GPL(acpi_dma_configure);
>  
> diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
> index 82bd45c..755a2b5 100644
> --- a/drivers/base/dma-mapping.c
> +++ b/drivers/base/dma-mapping.c
> @@ -368,7 +368,7 @@ int dma_configure(struct device *dev)
>  	} else if (has_acpi_companion(dma_dev)) {
>  		attr = acpi_get_dma_attr(to_acpi_device_node(dma_dev->fwnode));
>  		if (attr != DEV_DMA_NOT_SUPPORTED)
> -			acpi_dma_configure(dev, attr);
> +			ret = acpi_dma_configure(dev, attr);
>  	}
>  
>  	if (bridge)
> diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
> index ef0ae8a..2a9a5de 100644
> --- a/include/acpi/acpi_bus.h
> +++ b/include/acpi/acpi_bus.h
> @@ -575,7 +575,7 @@ struct acpi_pci_root {
>  
>  bool acpi_dma_supported(struct acpi_device *adev);
>  enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev);
> -void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr);
> +int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr);
>  void acpi_dma_deconfigure(struct device *dev);
>  
>  struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> index 9b05886..79d06ef6 100644
> --- a/include/linux/acpi.h
> +++ b/include/linux/acpi.h
> @@ -762,8 +762,11 @@ static inline enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
>  	return DEV_DMA_NOT_SUPPORTED;
>  }
>  
> -static inline void acpi_dma_configure(struct device *dev,
> -				      enum dev_dma_attr attr) { }
> +static inline int acpi_dma_configure(struct device *dev,
> +				     enum dev_dma_attr attr)
> +{
> +	return 0;
> +}
>  
>  static inline void acpi_dma_deconfigure(struct device *dev) { }
>  
> 

^ permalink raw reply

* Re: [PATCH V10 08/12] iommu: of: Handle IOMMU lookup failure with deferred probing or error
From: Robin Murphy @ 2017-04-04 11:24 UTC (permalink / raw)
  To: Sricharan R, will.deacon, joro, lorenzo.pieralisi, iommu,
	linux-arm-kernel, linux-arm-msm, m.szyprowski, bhelgaas,
	linux-pci, linux-acpi, tn, hanjun.guo, okaya, robh+dt,
	frowand.list, devicetree, linux-kernel, sudeep.holla, rjw, lenb,
	catalin.marinas, arnd, linux-arch, gregkh
In-Reply-To: <1491301105-5274-9-git-send-email-sricharan@codeaurora.org>

On 04/04/17 11:18, Sricharan R wrote:
> From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> 
> Failures to look up an IOMMU when parsing the DT iommus property need to
> be handled separately from the .of_xlate() failures to support deferred
> probing.
> 
> The lack of a registered IOMMU can be caused by the lack of a driver for
> the IOMMU, the IOMMU device probe not having been performed yet, having
> been deferred, or having failed.
> 
> The first case occurs when the device tree describes the bus master and
> IOMMU topology correctly but no device driver exists for the IOMMU yet
> or the device driver has not been compiled in. Return NULL, the caller
> will configure the device without an IOMMU.
> 
> The second and third cases are handled by deferring the probe of the bus
> master device which will eventually get reprobed after the IOMMU.
> 
> The last case is currently handled by deferring the probe of the bus
> master device as well. A mechanism to either configure the bus master
> device without an IOMMU or to fail the bus master device probe depending
> on whether the IOMMU is optional or mandatory would be a good
> enhancement.

Reviewed-by: Robin Murphy <robin.murphy@arm.com>

> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Signed-off-by: Laurent Pichart <laurent.pinchart+renesas@ideasonboard.com>
> Signed-off-by: Sricharan R <sricharan@codeaurora.org>
> ---
>  drivers/base/dma-mapping.c | 5 +++--
>  drivers/iommu/of_iommu.c   | 4 ++--
>  drivers/of/device.c        | 7 ++++++-
>  include/linux/of_device.h  | 9 ++++++---
>  4 files changed, 17 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c
> index 449b948..82bd45c 100644
> --- a/drivers/base/dma-mapping.c
> +++ b/drivers/base/dma-mapping.c
> @@ -353,6 +353,7 @@ int dma_configure(struct device *dev)
>  {
>  	struct device *bridge = NULL, *dma_dev = dev;
>  	enum dev_dma_attr attr;
> +	int ret = 0;
>  
>  	if (dev_is_pci(dev)) {
>  		bridge = pci_get_host_bridge_device(to_pci_dev(dev));
> @@ -363,7 +364,7 @@ int dma_configure(struct device *dev)
>  	}
>  
>  	if (dma_dev->of_node) {
> -		of_dma_configure(dev, dma_dev->of_node);
> +		ret = of_dma_configure(dev, dma_dev->of_node);
>  	} else if (has_acpi_companion(dma_dev)) {
>  		attr = acpi_get_dma_attr(to_acpi_device_node(dma_dev->fwnode));
>  		if (attr != DEV_DMA_NOT_SUPPORTED)
> @@ -373,7 +374,7 @@ int dma_configure(struct device *dev)
>  	if (bridge)
>  		pci_put_host_bridge_device(bridge);
>  
> -	return 0;
> +	return ret;
>  }
>  
>  void dma_deconfigure(struct device *dev)
> diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
> index c8be889..9f44ee8 100644
> --- a/drivers/iommu/of_iommu.c
> +++ b/drivers/iommu/of_iommu.c
> @@ -236,7 +236,7 @@ const struct iommu_ops *of_iommu_configure(struct device *dev,
>  			ops = ERR_PTR(err);
>  	}
>  
> -	return IS_ERR(ops) ? NULL : ops;
> +	return ops;
>  }
>  
>  static int __init of_iommu_init(void)
> @@ -247,7 +247,7 @@ static int __init of_iommu_init(void)
>  	for_each_matching_node_and_match(np, matches, &match) {
>  		const of_iommu_init_fn init_fn = match->data;
>  
> -		if (init_fn(np))
> +		if (init_fn && init_fn(np))
>  			pr_err("Failed to initialise IOMMU %s\n",
>  				of_node_full_name(np));
>  	}
> diff --git a/drivers/of/device.c b/drivers/of/device.c
> index c2ae6bb..bea8aec 100644
> --- a/drivers/of/device.c
> +++ b/drivers/of/device.c
> @@ -82,7 +82,7 @@ int of_device_add(struct platform_device *ofdev)
>   * can use a platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE events
>   * to fix up DMA configuration.
>   */
> -void of_dma_configure(struct device *dev, struct device_node *np)
> +int of_dma_configure(struct device *dev, struct device_node *np)
>  {
>  	u64 dma_addr, paddr, size;
>  	int ret;
> @@ -129,10 +129,15 @@ void of_dma_configure(struct device *dev, struct device_node *np)
>  		coherent ? " " : " not ");
>  
>  	iommu = of_iommu_configure(dev, np);
> +	if (IS_ERR(iommu))
> +		return PTR_ERR(iommu);
> +
>  	dev_dbg(dev, "device is%sbehind an iommu\n",
>  		iommu ? " " : " not ");
>  
>  	arch_setup_dma_ops(dev, dma_addr, size, iommu, coherent);
> +
> +	return 0;
>  }
>  EXPORT_SYMBOL_GPL(of_dma_configure);
>  
> diff --git a/include/linux/of_device.h b/include/linux/of_device.h
> index af98455..2cacdd8 100644
> --- a/include/linux/of_device.h
> +++ b/include/linux/of_device.h
> @@ -55,7 +55,7 @@ static inline struct device_node *of_cpu_device_node_get(int cpu)
>  	return of_node_get(cpu_dev->of_node);
>  }
>  
> -void of_dma_configure(struct device *dev, struct device_node *np);
> +int of_dma_configure(struct device *dev, struct device_node *np);
>  void of_dma_deconfigure(struct device *dev);
>  #else /* CONFIG_OF */
>  
> @@ -104,8 +104,11 @@ static inline struct device_node *of_cpu_device_node_get(int cpu)
>  {
>  	return NULL;
>  }
> -static inline void of_dma_configure(struct device *dev, struct device_node *np)
> -{}
> +
> +static inline int of_dma_configure(struct device *dev, struct device_node *np)
> +{
> +	return 0;
> +}
>  static inline void of_dma_deconfigure(struct device *dev)
>  {}
>  #endif /* CONFIG_OF */
> 


^ permalink raw reply

* Re: [PATCH V10 06/12] of: device: Fix overflow of coherent_dma_mask
From: Robin Murphy @ 2017-04-04 11:10 UTC (permalink / raw)
  To: Sricharan R, will.deacon-5wv7dgnIgG8, joro-zLv9SwRftAIdnm+yROfE0A,
	lorenzo.pieralisi-5wv7dgnIgG8,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
	bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, linux-pci-u79uwXL29TY76Z2rM5mHXA,
	linux-acpi-u79uwXL29TY76Z2rM5mHXA, tn-nYOzD4b6Jr9Wk0Htik3J/w,
	hanjun.guo-QSEj5FYQhm4dnm+yROfE0A, okaya-sgV2jX0FEOL9JmXXK+q4OQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, sudeep.holla-5wv7dgnIgG8,
	rjw-LthD3rsA81gm4RdzfppkhA, lenb-DgEjT+Ai2ygdnm+yROfE0A,
	catalin.marinas-5wv7dgnIgG8, arnd-r2nGTMty4D4,
	linux-arch-u79uwXL29TY76Z2rM5mHXA,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r
In-Reply-To: <1491301105-5274-7-git-send-email-sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>

On 04/04/17 11:18, Sricharan R wrote:
> Size of the dma-range is calculated as coherent_dma_mask + 1
> and passed to arch_setup_dma_ops further. It overflows when
> the coherent_dma_mask is set for full 64 bits 0xFFFFFFFFFFFFFFFF,
> resulting in size getting passed as 0 wrongly. Fix this by
> passsing in max(mask, mask + 1). Note that in this case
> when the mask is set to full 64bits, we will be passing the mask
> itself to arch_setup_dma_ops instead of the size. The real fix
> for this should be to make arch_setup_dma_ops receive the
> mask and handle it, to be done in the future.

Agreed; in the meantime, this fix is neat and robust enough.

Reviewed-by: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>

> Signed-off-by: Sricharan R <sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> ---
>  drivers/of/device.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/of/device.c b/drivers/of/device.c
> index c17c19d..c2ae6bb 100644
> --- a/drivers/of/device.c
> +++ b/drivers/of/device.c
> @@ -107,7 +107,7 @@ void of_dma_configure(struct device *dev, struct device_node *np)
>  	ret = of_dma_get_range(np, &dma_addr, &paddr, &size);
>  	if (ret < 0) {
>  		dma_addr = offset = 0;
> -		size = dev->coherent_dma_mask + 1;
> +		size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1);
>  	} else {
>  		offset = PFN_DOWN(paddr - dma_addr);
>  		dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", offset);
> 

^ permalink raw reply

* Re: [PATCH v8 1/2] media: i2c/ov5645: add the device tree binding document
From: Todor Tomov @ 2017-04-04 11:06 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: mchehab, laurent.pinchart, hans.verkuil, linux-media,
	linux-kernel, robh+dt, mark.rutland, devicetree
In-Reply-To: <20170404093150.GB3288@valkosipuli.retiisi.org.uk>

Hi Sakari,

Thank you for the time to review this again.

On 04/04/2017 12:31 PM, Sakari Ailus wrote:
> Hi Todor,
> 
> On Mon, Apr 03, 2017 at 05:02:28PM +0300, Todor Tomov wrote:
>> Add the document for ov5645 device tree binding.
>>
>> Signed-off-by: Todor Tomov <todor.tomov@linaro.org>
>> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>> ---
>>  .../devicetree/bindings/media/i2c/ov5645.txt       | 54 ++++++++++++++++++++++
>>  1 file changed, 54 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/media/i2c/ov5645.txt
>>
>> diff --git a/Documentation/devicetree/bindings/media/i2c/ov5645.txt b/Documentation/devicetree/bindings/media/i2c/ov5645.txt
>> new file mode 100644
>> index 0000000..fd7aec9
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/media/i2c/ov5645.txt
>> @@ -0,0 +1,54 @@
>> +* Omnivision 1/4-Inch 5Mp CMOS Digital Image Sensor
>> +
>> +The Omnivision OV5645 is a 1/4-Inch CMOS active pixel digital image sensor with
>> +an active array size of 2592H x 1944V. It is programmable through a serial I2C
>> +interface.
>> +
>> +Required Properties:
>> +- compatible: Value should be "ovti,ov5645".
>> +- clocks: Reference to the xclk clock.
>> +- clock-names: Should be "xclk".
>> +- clock-frequency: Frequency of the xclk clock.
>> +- enable-gpios: Chip enable GPIO. Polarity is GPIO_ACTIVE_HIGH. This corresponds
>> +  to the hardware pin PWDNB which is physically active low.
>> +- reset-gpios: Chip reset GPIO. Polarity is GPIO_ACTIVE_LOW. This corresponds to
>> +  the hardware pin RESETB.
>> +- vdddo-supply: Chip digital IO regulator.
>> +- vdda-supply: Chip analog regulator.
>> +- vddd-supply: Chip digital core regulator.
>> +
>> +The device node must contain one 'port' child node for its digital output
>> +video port, in accordance with the video interface bindings defined in
>> +Documentation/devicetree/bindings/media/video-interfaces.txt.
>> +
>> +Example:
>> +
>> +	&i2c1 {
>> +		...
>> +
>> +		ov5645: ov5645@78 {
>> +			compatible = "ovti,ov5645";
>> +			reg = <0x78>;
>> +
>> +			enable-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>;
>> +			reset-gpios = <&gpio5 20 GPIO_ACTIVE_LOW>;
>> +			pinctrl-names = "default";
>> +			pinctrl-0 = <&camera_rear_default>;
>> +
>> +			clocks = <&clks 200>;
>> +			clock-names = "xclk";
>> +			clock-frequency = <23880000>;
>> +
>> +			vdddo-supply = <&camera_dovdd_1v8>;
>> +			vdda-supply = <&camera_avdd_2v8>;
>> +			vddd-supply = <&camera_dvdd_1v2>;
>> +
>> +			port {
>> +				ov5645_ep: endpoint {
>> +					clock-lanes = <1>;
>> +					data-lanes = <0 2>;
> 
> If the sensor does not support lane reordering, I'd use 0 for the clock lane
> and lanes starting from 1 for data-lanes.

Yes, the sensor doesn't really support lane reordering. I'll keep this in mind for the next time.

> 
> I guess it'd be good to document this but that's definitely out of scope of
> the patchset.
> 
> Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> 
>> +					remote-endpoint = <&csi0_ep>;
>> +				};
>> +			};
>> +		};
>> +	};
> 

-- 
Best regards,
Todor Tomov

^ permalink raw reply

* Re: [PATCH V10 05/12] ACPI/IORT: Add function to check SMMUs drivers presence
From: Robin Murphy @ 2017-04-04 11:04 UTC (permalink / raw)
  To: Sricharan R, will.deacon-5wv7dgnIgG8, joro-zLv9SwRftAIdnm+yROfE0A,
	lorenzo.pieralisi-5wv7dgnIgG8,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
	bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, linux-pci-u79uwXL29TY76Z2rM5mHXA,
	linux-acpi-u79uwXL29TY76Z2rM5mHXA, tn-nYOzD4b6Jr9Wk0Htik3J/w,
	hanjun.guo-QSEj5FYQhm4dnm+yROfE0A, okaya-sgV2jX0FEOL9JmXXK+q4OQ,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, sudeep.holla-5wv7dgnIgG8,
	rjw-LthD3rsA81gm4RdzfppkhA, lenb-DgEjT+Ai2ygdnm+yROfE0A,
	catalin.marinas-5wv7dgnIgG8, arnd-r2nGTMty4D4,
	linux-arch-u79uwXL29TY76Z2rM5mHXA,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r
In-Reply-To: <1491301105-5274-6-git-send-email-sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>

On 04/04/17 11:18, Sricharan R wrote:
> From: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
> 
> The IOMMU probe deferral implementation requires a mechanism to detect
> if drivers for SMMU components are built-in in the kernel to detect
> whether IOMMU configuration for a given device should be deferred (ie
> SMMU drivers present but still not probed) or not (drivers not present).
> 
> Add a simple function to IORT to detect if SMMU drivers for SMMU
> components managed by IORT are built-in in the kernel.

Ah, if only DT could be this neat and tidy :D

Reviewed-by: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>

> Tested-by: Hanjun Guo <hanjun.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi-5wv7dgnIgG8@public.gmane.org>
> Cc: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>
> Cc: Sricharan R <sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> ---
>  drivers/acpi/arm64/iort.c | 13 +++++++++++++
>  1 file changed, 13 insertions(+)
> 
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index 4a5bb96..3dd9ec3 100644
> --- a/drivers/acpi/arm64/iort.c
> +++ b/drivers/acpi/arm64/iort.c
> @@ -523,6 +523,19 @@ static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
>  	return ret;
>  }
>  
> +static inline bool iort_iommu_driver_enabled(u8 type)
> +{
> +	switch (type) {
> +	case ACPI_IORT_NODE_SMMU_V3:
> +		return IS_BUILTIN(CONFIG_ARM_SMMU_V3);
> +	case ACPI_IORT_NODE_SMMU:
> +		return IS_BUILTIN(CONFIG_ARM_SMMU);
> +	default:
> +		pr_warn("IORT node type %u does not describe an SMMU\n", type);
> +		return false;
> +	}
> +}
> +
>  static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
>  					struct acpi_iort_node *node,
>  					u32 streamid)
> 

^ permalink raw reply

* [PATCH v7 9/9] dts: arm64: hip07: Add Hisilicon SoC PMU support
From: Anurup M @ 2017-04-04 10:56 UTC (permalink / raw)
  To: mark.rutland, will.deacon, robh+dt, xuwei5, catalin.marinas
  Cc: devicetree, linux-kernel, linux-arm-kernel, anurup.m,
	zhangshaokun, tanxiaojun, sanil.kumar, john.garry,
	gabriele.paoloni, shiju.jose, huangdaode, linuxarm, dikshit.n,
	shyju.pv, anurupvasu

Add nodes for djtag, L3 cache and MN to support uncore events.

Signed-off-by: Anurup M <anurup.m@huawei.com>
---
 arch/arm64/boot/dts/hisilicon/hip07.dtsi | 87 ++++++++++++++++++++++++++++++++
 1 file changed, 87 insertions(+)

diff --git a/arch/arm64/boot/dts/hisilicon/hip07.dtsi b/arch/arm64/boot/dts/hisilicon/hip07.dtsi
index 5144eb1..1099f6e 100644
--- a/arch/arm64/boot/dts/hisilicon/hip07.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hip07.dtsi
@@ -1056,4 +1056,91 @@
 			status = "disabled";
 		};
 	};
+
+	djtag0: djtag@60010000 {
+		compatible = "hisilicon,hip07-cpu-djtag-v2";
+		reg = <0x0 0x60010000 0x0 0x10000>;
+		hisilicon,scl-id = <0x03>;
+
+		/* L3 cache bank 0 for socket0 CPU die scl#3 */
+		pmul3c0 {
+			compatible = "hisilicon,hip07-pmu-l3c-v2";
+			hisilicon,module-id = <0x01>;
+			hisilicon,instance-id = <0x01>;
+		};
+
+		/* L3 cache bank 1 for socket0 CPU die scl#3 */
+		pmul3c1 {
+			compatible = "hisilicon,hip07-pmu-l3c-v2";
+			hisilicon,module-id = <0x02>;
+			hisilicon,instance-id = <0x01>;
+		};
+
+		/* L3 cache bank 2 for socket0 CPU die scl#3 */
+		pmul3c2 {
+			compatible = "hisilicon,hip07-pmu-l3c-v2";
+			hisilicon,module-id = <0x03>;
+			hisilicon,instance-id = <0x01>;
+		};
+
+		/* L3 cache bank 3 for socket0 CPU die scl#3 */
+		pmul3c3 {
+			compatible = "hisilicon,hip07-pmu-l3c-v2";
+			hisilicon,module-id = <0x04>;
+			hisilicon,instance-id = <0x01>;
+		};
+
+		/*
+		 * Miscellaneous node for socket0
+		 * CPU die scl#3
+		 */
+		pmumn0 {
+			compatible = "hisilicon,hip07-pmu-mn-v2";
+			hisilicon,module-id = <0x21>;
+		};
+	};
+
+	djtag1: djtag@40010000 {
+		compatible = "hisilicon,hip07-cpu-djtag-v2";
+		reg = <0x0 0x40010000 0x0 0x10000>;
+		hisilicon,scl-id = <0x01>;
+
+		/* L3 cache bank 0 for socket0 CPU die scl#1 */
+		pmul3c0 {
+			compatible = "hisilicon,hip07-pmu-l3c-v2";
+			hisilicon,module-id = <0x01>;
+			hisilicon,instance-id = <0x01>;
+		};
+
+		/* L3 cache bank 1 for socket0 CPU die scl#1 */
+		pmul3c1 {
+			compatible = "hisilicon,hip07-pmu-l3c-v2";
+			hisilicon,module-id = <0x02>;
+			hisilicon,instance-id = <0x01>;
+		};
+
+		/* L3 cache bank 2 for socket0 CPU die scl#1 */
+		pmul3c2 {
+			compatible = "hisilicon,hip07-pmu-l3c-v2";
+			hisilicon,module-id = <0x03>;
+			hisilicon,instance-id = <0x01>;
+		};
+
+		/* L3 cache bank 3 for socket0 CPU die scl#1 */
+		pmul3c3 {
+			compatible = "hisilicon,hip07-pmu-l3c-v2";
+			hisilicon,module-id = <0x04>;
+			hisilicon,instance-id = <0x01>;
+		};
+
+		/*
+		 * Miscellaneous node for socket0
+		 * CPU die scl#1
+		 */
+		pmumn1 {
+			compatible = "hisilicon,hip07-pmu-mn-v2";
+			hisilicon,module-id = <0x21>;
+		};
+	};
+
 };
-- 
2.1.4

^ permalink raw reply related

* [PATCH v7 3/9] dt-bindings: perf: hisi: Add Devicetree bindings for Hisilicon SoC PMU
From: Anurup M @ 2017-04-04 10:55 UTC (permalink / raw)
  To: robh+dt, mark.rutland, will.deacon
  Cc: linux-kernel, devicetree, linux-arm-kernel, anurup.m,
	zhangshaokun, tanxiaojun, xuwei5, sanil.kumar, john.garry,
	gabriele.paoloni, shiju.jose, huangdaode, wangkefeng.wang,
	linuxarm, dikshit.n, shyju.pv, anurupvasu

1) Device tree bindings for Hisilicon SoC PMU.
2) Add example for Hisilicon L3 cache and MN PMU.
3) Add child nodes of L3C and MN in djtag bindings example.

Signed-off-by: Anurup M <anurup.m@huawei.com>
Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
---
 .../devicetree/bindings/arm/hisilicon/djtag.txt    | 29 +++++++
 .../devicetree/bindings/arm/hisilicon/pmu.txt      | 93 ++++++++++++++++++++++
 2 files changed, 122 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/pmu.txt

diff --git a/Documentation/devicetree/bindings/arm/hisilicon/djtag.txt b/Documentation/devicetree/bindings/arm/hisilicon/djtag.txt
index fde5bab..27e67cc 100644
--- a/Documentation/devicetree/bindings/arm/hisilicon/djtag.txt
+++ b/Documentation/devicetree/bindings/arm/hisilicon/djtag.txt
@@ -27,6 +27,35 @@ Example 1: Djtag for CPU die in HiP07
 		hisilicon,scl-id = <0x03>;
 
 		/* All connecting components will appear as child nodes */
+
+		pmul3c0 {
+			compatible = "hisilicon,hip07-pmu-l3c-v2";
+			hisilicon,module-id = <0x01>;
+			hisilicon,instance-id = <0x01>;
+		};
+
+		pmul3c1 {
+			compatible = "hisilicon,hip07-pmu-l3c-v2";
+			hisilicon,module-id = <0x02>;
+			hisilicon,instance-id = <0x01>;
+		};
+
+		pmul3c2 {
+			compatible = "hisilicon,hip07-pmu-l3c-v2";
+			hisilicon,module-id = <0x03>;
+			hisilicon,instance-id = <0x01>;
+		};
+
+		pmul3c3 {
+			compatible = "hisilicon,hip07-pmu-l3c-v2";
+			hisilicon,module-id = <0x04>;
+			hisilicon,instance-id = <0x01>;
+		};
+
+		pmumn0 {
+			compatible = "hisilicon,hip07-pmu-mn-v2";
+			hisilicon,module-id = <0x21>;
+		};
 	};
 
 Hisilicon HiP05/06/07 djtag for IO die
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/pmu.txt b/Documentation/devicetree/bindings/arm/hisilicon/pmu.txt
new file mode 100644
index 0000000..488e740
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/hisilicon/pmu.txt
@@ -0,0 +1,93 @@
+Hisilicon SoC HiP05/06/07 ARMv8 PMU
+===================================
+
+The Hisilicon SoC chips like HiP05/06/07 etc. consist of various independent
+system device PMUs such as L3 cache (L3C) and Miscellaneous Nodes(MN). These
+PMU devices are independent and have hardware logic to gather statistics and
+performance information.
+
+HiSilicon SoC chip is encapsulated by multiple CPU and IO dies. The CPU die
+is called as Super CPU cluster (SCCL) which includes 16 cpu-cores. Every SCCL
+in HiP05/06/07 chips are further grouped as CPU clusters (CCL) which includes
+4 cpu-cores each.
+e.g. In the case of HiP05/06/07, each SCCL has 1 L3 cache and 1 MN PMU device.
+The L3 cache is further grouped as 4 L3 cache banks in a SCCL.
+
+The Hisilicon SoC PMU DT node bindings for uncore PMU devices are as below.
+For PMU devices like L3 cache. MN etc. which are accessed using the djtag,
+the parent node will be the djtag node of the corresponding CPU die (SCCL).
+
+L3 cache
+---------
+The L3 cache is dedicated for each SCCL. Each SCCL in HiP05/06/07 chips have 4
+L3 cache banks. Each L3 cache bank have separate DT nodes.
+
+Required properties:
+
+	- compatible : This value should be as follows
+		(a) "hisilicon,hip05-pmu-l3c-v1" for v1 hw in HiP05 chipset
+		(b) "hisilicon,hip06-pmu-l3c-v1" for v1 hw in HiP06 chipset
+		(c) "hisilicon,hip07-pmu-l3c-v2" for v2 hw in HiP07 chipset
+
+	- hisilicon,module-id : This property is the module identifier for djtag.
+		In v1 hw, this value is 0x04 for all L3 cache instances. But
+		in v2 hw, this value is unique for each L3 cache instance.
+
+	- hisilicon,instance-id : This property will identify the L3 cache instance
+		or bank in djtag. In v1 hw, this value is unique for each L3 cache
+		instance. But in v2 hw, it is 0x01 for all L3 cache instances.
+
+	*The counter overflow IRQ is not supported in v1, v2 hardware (HiP05/06/07).
+
+Miscellaneous Node
+------------------
+The MN is dedicated for each SCCL and hence there are separate DT nodes for MN
+for each SCCL.
+
+Required properties:
+
+	- compatible : This value should be as follows
+		(a) "hisilicon,hip05-pmu-mn-v1" for v1 hw in HiP05 chipset
+		(b) "hisilicon,hip06-pmu-mn-v1" for v1 hw in HiP06 chipset
+		(c) "hisilicon,hip07-pmu-mn-v2" for v2 hw in HiP07 chipset
+
+	- hisilicon,module-id : Module ID to input for djtag.
+
+	*The counter overflow IRQ is not supported in v1, v2 hardware (HiP05/06/07).
+
+Example:
+
+	djtag0: djtag@60010000 {
+		compatible = "hisilicon,hip07-cpu-djtag-v2";
+		reg = <0x0 0x60010000 0x0 0x10000>;
+		hisilicon,scl-id = <0x03>;
+
+		pmul3c0 {
+			compatible = "hisilicon,hip07-pmu-l3c-v2";
+			hisilicon,module-id = <0x01>;
+			hisilicon,instance-id = <0x01>;
+		};
+
+		pmul3c1 {
+			compatible = "hisilicon,hip07-pmu-l3c-v2";
+			hisilicon,module-id = <0x02>;
+			hisilicon,instance-id = <0x01>;
+		};
+
+		pmul3c2 {
+			compatible = "hisilicon,hip07-pmu-l3c-v2";
+			hisilicon,module-id = <0x03>;
+			hisilicon,instance-id = <0x01>;
+		};
+
+		pmul3c3 {
+			compatible = "hisilicon,hip07-pmu-l3c-v2";
+			hisilicon,module-id = <0x04>;
+			hisilicon,instance-id = <0x01>;
+		};
+
+		pmumn0 {
+			compatible = "hisilicon,hip07-pmu-mn-v2";
+			hisilicon,module-id = <0x21>;
+		};
+	};
-- 
2.1.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox