Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 06/19] drm/blend: Add a generic alpha property
From: Boris Brezillon @ 2018-01-09 12:31 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <5c765fc730d75cb362dc37bcdb3b3aeacc7bdb30.1515494838.git-series.maxime.ripard@free-electrons.com>

On Tue,  9 Jan 2018 11:56:25 +0100
Maxime Ripard <maxime.ripard@free-electrons.com> wrote:

> Some drivers duplicate the logic to create a property to store a per-plane
> alpha.
> 
> Let's create a helper in order to move that to the core.
> 
> Cc: Boris Brezillon <boris.brezillon@free-electrons.com>

Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>

> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  Documentation/gpu/kms-properties.csv |  2 +-
>  drivers/gpu/drm/drm_atomic.c         |  4 ++++-
>  drivers/gpu/drm/drm_atomic_helper.c  |  1 +-
>  drivers/gpu/drm/drm_blend.c          | 32 +++++++++++++++++++++++++++++-
>  include/drm/drm_blend.h              |  1 +-
>  include/drm/drm_plane.h              |  6 +++++-
>  6 files changed, 45 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/gpu/kms-properties.csv b/Documentation/gpu/kms-properties.csv
> index 927b65e14219..a3c3969c1992 100644
> --- a/Documentation/gpu/kms-properties.csv
> +++ b/Documentation/gpu/kms-properties.csv
> @@ -99,5 +99,5 @@ radeon,DVI-I,?coherent?,RANGE,"Min=0, Max=1",Connector,TBD
>  ,,"""underscan vborder""",RANGE,"Min=0, Max=128",Connector,TBD
>  ,Audio,?audio?,ENUM,"{ ""off"", ""on"", ""auto"" }",Connector,TBD
>  ,FMT Dithering,?dither?,ENUM,"{ ""off"", ""on"" }",Connector,TBD
> -rcar-du,Generic,"""alpha""",RANGE,"Min=0, Max=255",Plane,TBD
> +,,"""alpha""",RANGE,"Min=0, Max=255",Plane,Opacity of the plane from transparent (0) to opaque (255)
>  ,,"""colorkey""",RANGE,"Min=0, Max=0x01ffffff",Plane,TBD
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index c2da5585e201..ade18cf62c89 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -749,6 +749,8 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane,
>  		state->src_w = val;
>  	} else if (property == config->prop_src_h) {
>  		state->src_h = val;
> +	} else if (property == plane->alpha_property) {
> +		state->alpha = val;
>  	} else if (property == plane->rotation_property) {
>  		if (!is_power_of_2(val & DRM_MODE_ROTATE_MASK))
>  			return -EINVAL;
> @@ -810,6 +812,8 @@ drm_atomic_plane_get_property(struct drm_plane *plane,
>  		*val = state->src_w;
>  	} else if (property == config->prop_src_h) {
>  		*val = state->src_h;
> +	} else if (property == plane->alpha_property) {
> +		*val = state->alpha;
>  	} else if (property == plane->rotation_property) {
>  		*val = state->rotation;
>  	} else if (property == plane->zpos_property) {
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 71d712f1b56a..018993df4c18 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -3372,6 +3372,7 @@ void drm_atomic_helper_plane_reset(struct drm_plane *plane)
>  
>  	if (plane->state) {
>  		plane->state->plane = plane;
> +		plane->state->alpha = 255;
>  		plane->state->rotation = DRM_MODE_ROTATE_0;
>  	}
>  }
> diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c
> index 2e5e089dd912..8eea2a8af458 100644
> --- a/drivers/gpu/drm/drm_blend.c
> +++ b/drivers/gpu/drm/drm_blend.c
> @@ -104,6 +104,38 @@
>   */
>  
>  /**
> + * drm_plane_create_alpha_property - create a new alpha property
> + * @plane: drm plane
> + * @alpha: initial value of alpha, from 0 (transparent) to 255 (opaque)
> + *
> + * This function initializes a generic, mutable, alpha property and
> + * enables support for it in the DRM core.
> + *
> + * Drivers can then attach this property to their plane to enable
> + * support for configurable plane alpha.
> + *
> + * Returns:
> + * 0 on success, negative error code on failure.
> + */
> +int drm_plane_create_alpha_property(struct drm_plane *plane, u8 alpha)
> +{
> +	struct drm_property *prop;
> +
> +	prop = drm_property_create_range(plane->dev, 0, "alpha", 0, 255);
> +	if (!prop)
> +		return -ENOMEM;
> +
> +	drm_object_attach_property(&plane->base, prop, alpha);
> +	plane->alpha_property = prop;
> +
> +	if (plane->state)
> +		plane->state->alpha = alpha;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(drm_plane_create_alpha_property);
> +
> +/**
>   * drm_plane_create_rotation_property - create a new rotation property
>   * @plane: drm plane
>   * @rotation: initial value of the rotation property
> diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h
> index 17606026590b..5979a8fce453 100644
> --- a/include/drm/drm_blend.h
> +++ b/include/drm/drm_blend.h
> @@ -36,6 +36,7 @@ static inline bool drm_rotation_90_or_270(unsigned int rotation)
>  	return rotation & (DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270);
>  }
>  
> +int drm_plane_create_alpha_property(struct drm_plane *plane, u8 alpha);
>  int drm_plane_create_rotation_property(struct drm_plane *plane,
>  				       unsigned int rotation,
>  				       unsigned int supported_rotations);
> diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h
> index 571615079230..a5e26064b132 100644
> --- a/include/drm/drm_plane.h
> +++ b/include/drm/drm_plane.h
> @@ -42,6 +42,7 @@ struct drm_modeset_acquire_ctx;
>   *	plane (in 16.16)
>   * @src_w: width of visible portion of plane (in 16.16)
>   * @src_h: height of visible portion of plane (in 16.16)
> + * @alpha: opacity of the plane
>   * @rotation: rotation of the plane
>   * @zpos: priority of the given plane on crtc (optional)
>   *	Note that multiple active planes on the same crtc can have an identical
> @@ -105,6 +106,9 @@ struct drm_plane_state {
>  	uint32_t src_x, src_y;
>  	uint32_t src_h, src_w;
>  
> +	/* Plane opacity */
> +	u8 alpha;
> +
>  	/* Plane rotation */
>  	unsigned int rotation;
>  
> @@ -481,6 +485,7 @@ enum drm_plane_type {
>   * @funcs: helper functions
>   * @properties: property tracking for this plane
>   * @type: type of plane (overlay, primary, cursor)
> + * @alpha_property: alpha property for this plane
>   * @zpos_property: zpos property for this plane
>   * @rotation_property: rotation property for this plane
>   * @helper_private: mid-layer private data
> @@ -546,6 +551,7 @@ struct drm_plane {
>  	 */
>  	struct drm_plane_state *state;
>  
> +	struct drm_property *alpha_property;
>  	struct drm_property *zpos_property;
>  	struct drm_property *rotation_property;
>  };

^ permalink raw reply

* [PATCH 01/19] drm/fourcc: Add a function to tell if the format embeds alpha
From: Laurent Pinchart @ 2018-01-09 12:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <b58c65b26e59dff7917d90846cb797a11ca09efa.1515494838.git-series.maxime.ripard@free-electrons.com>

Hi Maxime,

Thank you for the patch.

On Tuesday, 9 January 2018 12:56:20 EET Maxime Ripard wrote:
> There's a bunch of drivers that duplicate the same function to know if a
> particular format embeds an alpha component or not.
> 
> Let's create a helper to avoid duplicating that logic.
> 
> Cc: Boris Brezillon <boris.brezillon@free-electrons.com>
> Cc: Eric Anholt <eric@anholt.net>
> Cc: Inki Dae <inki.dae@samsung.com>
> Cc: Joonyoung Shim <jy0922.shim@samsung.com>
> Cc: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Cc: Mark Yao <mark.yao@rock-chips.com>
> Cc: Seung-Woo Kim <sw0312.kim@samsung.com>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/drm_fourcc.c | 43 +++++++++++++++++++++++++++++++++++++-
>  include/drm/drm_fourcc.h     |  1 +-
>  2 files changed, 44 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
> index 9c0152df45ad..6e6227d6a46b 100644
> --- a/drivers/gpu/drm/drm_fourcc.c
> +++ b/drivers/gpu/drm/drm_fourcc.c
> @@ -348,3 +348,46 @@ int drm_format_plane_height(int height, uint32_t
> format, int plane) return height / info->vsub;
>  }
>  EXPORT_SYMBOL(drm_format_plane_height);
> +
> +/**
> + * drm_format_has_alpha - get whether the format embeds an alpha component
> + * @format: pixel format (DRM_FORMAT_*)
> + *
> + * Returns:
> + * true if the format embeds an alpha component, false otherwise.
> + */
> +bool drm_format_has_alpha(uint32_t format)
> +{
> +	switch (format) {
> +	case DRM_FORMAT_ARGB4444:
> +	case DRM_FORMAT_ABGR4444:
> +	case DRM_FORMAT_RGBA4444:
> +	case DRM_FORMAT_BGRA4444:
> +	case DRM_FORMAT_ARGB1555:
> +	case DRM_FORMAT_ABGR1555:
> +	case DRM_FORMAT_RGBA5551:
> +	case DRM_FORMAT_BGRA5551:
> +	case DRM_FORMAT_ARGB8888:
> +	case DRM_FORMAT_ABGR8888:
> +	case DRM_FORMAT_RGBA8888:
> +	case DRM_FORMAT_BGRA8888:
> +	case DRM_FORMAT_ARGB2101010:
> +	case DRM_FORMAT_ABGR2101010:
> +	case DRM_FORMAT_RGBA1010102:
> +	case DRM_FORMAT_BGRA1010102:
> +	case DRM_FORMAT_AYUV:
> +	case DRM_FORMAT_XRGB8888_A8:
> +	case DRM_FORMAT_XBGR8888_A8:
> +	case DRM_FORMAT_RGBX8888_A8:
> +	case DRM_FORMAT_BGRX8888_A8:
> +	case DRM_FORMAT_RGB888_A8:
> +	case DRM_FORMAT_BGR888_A8:
> +	case DRM_FORMAT_RGB565_A8:
> +	case DRM_FORMAT_BGR565_A8:
> +		return true;
> +
> +	default:
> +		return false;
> +	}
> +}
> +EXPORT_SYMBOL(drm_format_has_alpha);

How about adding the information to struct drm_format_info instead ? 
drm_format_has_alpha() could then be implemented as

bool drm_format_has_alpha(uint32_t format)
{
	const struct drm_format_info *info;

	info = drm_format_info(format);
	return info ? info->has_alpha : false;
}

although drivers should really use the drm_framebuffer::format field directly 
in most cases, so the helper might not be needed at all.

> diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h
> index 6942e84b6edd..e08fc22c5f78 100644
> --- a/include/drm/drm_fourcc.h
> +++ b/include/drm/drm_fourcc.h
> @@ -69,5 +69,6 @@ int drm_format_vert_chroma_subsampling(uint32_t format);
>  int drm_format_plane_width(int width, uint32_t format, int plane);
>  int drm_format_plane_height(int height, uint32_t format, int plane);
>  const char *drm_get_format_name(uint32_t format, struct drm_format_name_buf
> *buf);
> +bool drm_format_has_alpha(uint32_t format);
> 
>  #endif /* __DRM_FOURCC_H__ */

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* [PATCH 02/19] drm/atmel-hlcdc: Use the alpha format helper
From: Boris Brezillon @ 2018-01-09 12:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <22c5a25fbdd56193ece1de90dc17cfa8747e7136.1515494838.git-series.maxime.ripard@free-electrons.com>

On Tue,  9 Jan 2018 11:56:21 +0100
Maxime Ripard <maxime.ripard@free-electrons.com> wrote:

> Now that the core has a drm format helper to tell if a format embeds an
> alpha component in it, let's use it.
> 
> Cc: Boris Brezillon <boris.brezillon@free-electrons.com>

Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com>

> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 20 ++----------------
>  1 file changed, 3 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
> index 703c2d13603f..1a9318810a29 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
> @@ -194,20 +194,6 @@ static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
>  	return 0;
>  }
>  
> -static bool atmel_hlcdc_format_embeds_alpha(u32 format)
> -{
> -	int i;
> -
> -	for (i = 0; i < sizeof(format); i++) {
> -		char tmp = (format >> (8 * i)) & 0xff;
> -
> -		if (tmp == 'A')
> -			return true;
> -	}
> -
> -	return false;
> -}
> -
>  static u32 heo_downscaling_xcoef[] = {
>  	0x11343311,
>  	0x000000f7,
> @@ -395,7 +381,7 @@ atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
>  		cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
>  		       ATMEL_HLCDC_LAYER_ITER;
>  
> -		if (atmel_hlcdc_format_embeds_alpha(format))
> +		if (drm_format_has_alpha(format))
>  			cfg |= ATMEL_HLCDC_LAYER_LAEN;
>  		else
>  			cfg |= ATMEL_HLCDC_LAYER_GAEN |
> @@ -566,7 +552,7 @@ atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
>  		ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
>  
>  		if (!ovl_s->fb ||
> -		    atmel_hlcdc_format_embeds_alpha(ovl_s->fb->format->format) ||
> +		    drm_format_has_alpha(ovl_s->fb->format->format) ||
>  		    ovl_state->alpha != 255)
>  			continue;
>  
> @@ -769,7 +755,7 @@ static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
>  
>  	if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
>  	    (!desc->layout.memsize ||
> -	     atmel_hlcdc_format_embeds_alpha(state->base.fb->format->format)))
> +	     drm_format_has_alpha(state->base.fb->format->format)))
>  		return -EINVAL;
>  
>  	if (state->crtc_x < 0 || state->crtc_y < 0)

^ permalink raw reply

* [PATCH 01/19] drm/fourcc: Add a function to tell if the format embeds alpha
From: Boris Brezillon @ 2018-01-09 12:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <b58c65b26e59dff7917d90846cb797a11ca09efa.1515494838.git-series.maxime.ripard@free-electrons.com>

On Tue,  9 Jan 2018 11:56:20 +0100
Maxime Ripard <maxime.ripard@free-electrons.com> wrote:

> There's a bunch of drivers that duplicate the same function to know if a
> particular format embeds an alpha component or not.
> 
> Let's create a helper to avoid duplicating that logic.
> 
> Cc: Boris Brezillon <boris.brezillon@free-electrons.com>

Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>

> Cc: Eric Anholt <eric@anholt.net>
> Cc: Inki Dae <inki.dae@samsung.com>
> Cc: Joonyoung Shim <jy0922.shim@samsung.com>
> Cc: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Cc: Mark Yao <mark.yao@rock-chips.com>
> Cc: Seung-Woo Kim <sw0312.kim@samsung.com>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/drm_fourcc.c | 43 +++++++++++++++++++++++++++++++++++++-
>  include/drm/drm_fourcc.h     |  1 +-
>  2 files changed, 44 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
> index 9c0152df45ad..6e6227d6a46b 100644
> --- a/drivers/gpu/drm/drm_fourcc.c
> +++ b/drivers/gpu/drm/drm_fourcc.c
> @@ -348,3 +348,46 @@ int drm_format_plane_height(int height, uint32_t format, int plane)
>  	return height / info->vsub;
>  }
>  EXPORT_SYMBOL(drm_format_plane_height);
> +
> +/**
> + * drm_format_has_alpha - get whether the format embeds an alpha component
> + * @format: pixel format (DRM_FORMAT_*)
> + *
> + * Returns:
> + * true if the format embeds an alpha component, false otherwise.
> + */
> +bool drm_format_has_alpha(uint32_t format)
> +{
> +	switch (format) {
> +	case DRM_FORMAT_ARGB4444:
> +	case DRM_FORMAT_ABGR4444:
> +	case DRM_FORMAT_RGBA4444:
> +	case DRM_FORMAT_BGRA4444:
> +	case DRM_FORMAT_ARGB1555:
> +	case DRM_FORMAT_ABGR1555:
> +	case DRM_FORMAT_RGBA5551:
> +	case DRM_FORMAT_BGRA5551:
> +	case DRM_FORMAT_ARGB8888:
> +	case DRM_FORMAT_ABGR8888:
> +	case DRM_FORMAT_RGBA8888:
> +	case DRM_FORMAT_BGRA8888:
> +	case DRM_FORMAT_ARGB2101010:
> +	case DRM_FORMAT_ABGR2101010:
> +	case DRM_FORMAT_RGBA1010102:
> +	case DRM_FORMAT_BGRA1010102:
> +	case DRM_FORMAT_AYUV:
> +	case DRM_FORMAT_XRGB8888_A8:
> +	case DRM_FORMAT_XBGR8888_A8:
> +	case DRM_FORMAT_RGBX8888_A8:
> +	case DRM_FORMAT_BGRX8888_A8:
> +	case DRM_FORMAT_RGB888_A8:
> +	case DRM_FORMAT_BGR888_A8:
> +	case DRM_FORMAT_RGB565_A8:
> +	case DRM_FORMAT_BGR565_A8:
> +		return true;
> +
> +	default:
> +		return false;
> +	}
> +}
> +EXPORT_SYMBOL(drm_format_has_alpha);
> diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h
> index 6942e84b6edd..e08fc22c5f78 100644
> --- a/include/drm/drm_fourcc.h
> +++ b/include/drm/drm_fourcc.h
> @@ -69,5 +69,6 @@ int drm_format_vert_chroma_subsampling(uint32_t format);
>  int drm_format_plane_width(int width, uint32_t format, int plane);
>  int drm_format_plane_height(int height, uint32_t format, int plane);
>  const char *drm_get_format_name(uint32_t format, struct drm_format_name_buf *buf);
> +bool drm_format_has_alpha(uint32_t format);
>  
>  #endif /* __DRM_FOURCC_H__ */

^ permalink raw reply

* [PATCH 3/9] soc: samsung: pmu: Add the PMU data of exynos5433 to support low-power state
From: Krzysztof Kozlowski @ 2018-01-09 12:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515484746-10656-4-git-send-email-cw00.choi@samsung.com>

On Tue, Jan 9, 2018 at 8:59 AM, Chanwoo Choi <cw00.choi@samsung.com> wrote:
> This patch adds the PMU (Power Management Unit) data of exynos5433 SoC
> in order to support the various power modes. Each power mode has
> the different value for reducing the power-consumption.
>
> Signed-off-by: Jonghwa Lee <jonghwa3.lee@samsung.com>
> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
> ---
>  arch/arm/mach-exynos/common.h               |   2 -
>  drivers/soc/samsung/Makefile                |   3 +-
>  drivers/soc/samsung/exynos-pmu.c            |   1 +
>  drivers/soc/samsung/exynos-pmu.h            |   2 +
>  drivers/soc/samsung/exynos5433-pmu.c        | 286 ++++++++++++++++++++++++++++
>  include/linux/soc/samsung/exynos-regs-pmu.h | 148 ++++++++++++++
>  6 files changed, 439 insertions(+), 3 deletions(-)
>  create mode 100644 drivers/soc/samsung/exynos5433-pmu.c
>
> diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
> index 098f84a149a3..afbc143a3d5d 100644
> --- a/arch/arm/mach-exynos/common.h
> +++ b/arch/arm/mach-exynos/common.h
> @@ -125,8 +125,6 @@ enum {
>  void exynos_set_boot_flag(unsigned int cpu, unsigned int mode);
>  void exynos_clear_boot_flag(unsigned int cpu, unsigned int mode);
>
> -extern u32 exynos_get_eint_wake_mask(void);
> -

This does not look good. Does it compile without warnings on ARMv7 platforms?

>  #ifdef CONFIG_PM_SLEEP
>  extern void __init exynos_pm_init(void);
>  #else
> diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile
> index 29f294baac6e..d2e637339a45 100644
> --- a/drivers/soc/samsung/Makefile
> +++ b/drivers/soc/samsung/Makefile
> @@ -2,5 +2,6 @@
>  obj-$(CONFIG_EXYNOS_PMU)       += exynos-pmu.o
>
>  obj-$(CONFIG_EXYNOS_PMU_ARM_DRIVERS)   += exynos3250-pmu.o exynos4-pmu.o \
> -                                       exynos5250-pmu.o exynos5420-pmu.o
> +                                       exynos5250-pmu.o exynos5420-pmu.o \
> +                                       exynos5433-pmu.o
>  obj-$(CONFIG_EXYNOS_PM_DOMAINS) += pm_domains.o
> diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c
> index cfc9de518344..7112d7b2749b 100644
> --- a/drivers/soc/samsung/exynos-pmu.c
> +++ b/drivers/soc/samsung/exynos-pmu.c
> @@ -97,6 +97,7 @@ void exynos_sys_powerup_conf(enum sys_powerdown mode)
>                 .data = exynos_pmu_data_arm_ptr(exynos5420_pmu_data),
>         }, {
>                 .compatible = "samsung,exynos5433-pmu",
> +               .data = exynos_pmu_data_arm_ptr(exynos5433_pmu_data),
>         },
>         { /*sentinel*/ },
>  };
> diff --git a/drivers/soc/samsung/exynos-pmu.h b/drivers/soc/samsung/exynos-pmu.h
> index efbaf8929252..895c786a2f4c 100644
> --- a/drivers/soc/samsung/exynos-pmu.h
> +++ b/drivers/soc/samsung/exynos-pmu.h
> @@ -28,6 +28,7 @@ struct exynos_pmu_data {
>  };
>
>  extern void __iomem *pmu_base_addr;
> +extern u32 exynos_get_eint_wake_mask(void);
>
>  #ifdef CONFIG_EXYNOS_PMU_ARM_DRIVERS
>  /* list of all exported SoC specific data */
> @@ -36,6 +37,7 @@ struct exynos_pmu_data {
>  extern const struct exynos_pmu_data exynos4412_pmu_data;
>  extern const struct exynos_pmu_data exynos5250_pmu_data;
>  extern const struct exynos_pmu_data exynos5420_pmu_data;
> +extern const struct exynos_pmu_data exynos5433_pmu_data;
>  #endif
>
>  extern void pmu_raw_writel(u32 val, u32 offset);
> diff --git a/drivers/soc/samsung/exynos5433-pmu.c b/drivers/soc/samsung/exynos5433-pmu.c
> new file mode 100644
> index 000000000000..2571e61522f0
> --- /dev/null
> +++ b/drivers/soc/samsung/exynos5433-pmu.c
> @@ -0,0 +1,286 @@
> +// SPDX-License-Identifier: GPL-2.0
> +//
> +// Copyright (c) 2018 Samsung Electronics Co., Ltd.
> +// Copyright (c) Jonghwa Lee <jonghwa3.lee@samsung.com>
> +// Copyright (c) Chanwoo Choi <cw00.choi@samsung.com>

Did you want to add here authorship notice or personal copyrights?

> +//
> +// EXYNOS5433 - CPU PMU (Power Management Unit) support
> +
> +#include <linux/soc/samsung/exynos-regs-pmu.h>
> +#include <linux/soc/samsung/exynos-pmu.h>
> +
> +#include "exynos-pmu.h"
> +
> +static struct exynos_pmu_conf exynos5433_pmu_config[] = {

This should be also const.

> +       /* { .offset = address, .val = { AFTR, LPA, SLEEP } } */
> +       { EXYNOS5433_ATLAS_CPU0_SYS_PWR_REG,                    { 0x0, 0x0, 0x8 } },
> +       { EXYNOS5433_DIS_IRQ_ATLAS_CPU0_CENTRAL_SYS_PWR_REG,    { 0x0, 0x0, 0x0 } },
> +       { EXYNOS5433_ATLAS_CPU1_SYS_PWR_REG,                    { 0x0, 0x0, 0x8 } },
> +       { EXYNOS5433_DIS_IRQ_ATLAS_CPU1_CENTRAL_SYS_PWR_REG,    { 0x0, 0x0, 0x0 } },
> +       { EXYNOS5433_ATLAS_CPU2_SYS_PWR_REG,                    { 0x0, 0x0, 0x8 } },
> +       { EXYNOS5433_DIS_IRQ_ATLAS_CPU2_CENTRAL_SYS_PWR_REG,    { 0x0, 0x0, 0x0 } },
> +       { EXYNOS5433_ATLAS_CPU3_SYS_PWR_REG,                    { 0x0, 0x0, 0x8 } },
> +       { EXYNOS5433_DIS_IRQ_ATLAS_CPU3_CENTRAL_SYS_PWR_REG,    { 0x0, 0x0, 0x0 } },
> +       { EXYNOS5433_APOLLO_CPU0_SYS_PWR_REG,                   { 0x0, 0x0, 0x8 } },
> +       { EXYNOS5433_DIS_IRQ_APOLLO_CPU0_CENTRAL_SYS_PWR_REG,   { 0x0, 0x0, 0x0 } },
> +       { EXYNOS5433_APOLLO_CPU1_SYS_PWR_REG,                   { 0x0, 0x0, 0x8 } },
> +       { EXYNOS5433_DIS_IRQ_APOLLO_CPU1_CENTRAL_SYS_PWR_REG,   { 0x0, 0x0, 0x0 } },
> +       { EXYNOS5433_APOLLO_CPU2_SYS_PWR_REG,                   { 0x0, 0x0, 0x8 } },
> +       { EXYNOS5433_DIS_IRQ_APOLLO_CPU2_CENTRAL_SYS_PWR_REG,   { 0x0, 0x0, 0x0 } },
> +       { EXYNOS5433_APOLLO_CPU3_SYS_PWR_REG,                   { 0x0, 0x0, 0x8 } },
> +       { EXYNOS5433_DIS_IRQ_APOLLO_CPU3_CENTRAL_SYS_PWR_REG,   { 0x0, 0x0, 0x0 } },
> +       { EXYNOS5433_ATLAS_NONCPU_SYS_PWR_REG,                  { 0x0, 0x0, 0x8 } },
> +       { EXYNOS5433_APOLLO_NONCPU_SYS_PWR_REG,                 { 0x0, 0x0, 0x8 } },
> +       { EXYNOS5433_A5IS_SYS_PWR_REG,                          { 0x0, 0x0, 0x0 } },
> +       { EXYNOS5433_DIS_IRQ_A5IS_LOCAL_SYS_PWR_REG,            { 0x0, 0x0, 0x0 } },
> +       { EXYNOS5433_DIS_IRQ_A5IS_CENTRAL_SYS_PWR_REG,          { 0x0, 0x0, 0x0 } },
> +       { EXYNOS5433_ATLAS_L2_SYS_PWR_REG,                      { 0x0, 0x0, 0x7 } },
> +       { EXYNOS5433_APOLLO_L2_SYS_PWR_REG,                     { 0x0, 0x0, 0x7 } },
> +       { EXYNOS5433_CLKSTOP_CMU_TOP_SYS_PWR_REG,               { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_CLKRUN_CMU_TOP_SYS_PWR_REG,                { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_RESET_CMU_TOP_SYS_PWR_REG,                 { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_RESET_CPUCLKSTOP_SYS_PWR_REG,              { 0x1, 0x1, 0x0 } },
> +       { EXYNOS5433_CLKSTOP_CMU_MIF_SYS_PWR_REG,               { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_CLKRUN_CMU_MIF_SYS_PWR_REG,                { 0x1, 0x1, 0x0 } },
> +       { EXYNOS5433_RESET_CMU_MIF_SYS_PWR_REG,                 { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_DDRPHY_DLLLOCK_SYS_PWR_REG,                { 0x1, 0x1, 0x1 } },
> +       { EXYNOS5433_DISABLE_PLL_CMU_TOP_SYS_PWR_REG,           { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_DISABLE_PLL_AUD_PLL_SYS_PWR_REG,           { 0x1, 0x1, 0x0 } },
> +       { EXYNOS5433_DISABLE_PLL_CMU_MIF_SYS_PWR_REG,           { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_TOP_BUS_SYS_PWR_REG,                       { 0x7, 0x0, 0x0 } },
> +       { EXYNOS5433_TOP_RETENTION_SYS_PWR_REG,                 { 0x1, 0x0, 0x1 } },
> +       { EXYNOS5433_TOP_PWR_SYS_PWR_REG,                       { 0x3, 0x0, 0x3 } },
> +       { EXYNOS5433_TOP_BUS_MIF_SYS_PWR_REG,                   { 0x7, 0x0, 0x0 } },
> +       { EXYNOS5433_TOP_RETENTION_MIF_SYS_PWR_REG,             { 0x1, 0x0, 0x1 } },
> +       { EXYNOS5433_TOP_PWR_MIF_SYS_PWR_REG,                   { 0x3, 0x0, 0x3 } },
> +       { EXYNOS5433_LOGIC_RESET_SYS_PWR_REG,                   { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_OSCCLK_GATE_SYS_PWR_REG,                   { 0x1, 0x0, 0x1 } },
> +       { EXYNOS5433_SLEEP_RESET_SYS_PWR_REG,                   { 0x1, 0x1, 0x0 } },
> +       { EXYNOS5433_LOGIC_RESET_MIF_SYS_PWR_REG,               { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_OSCCLK_GATE_MIF_SYS_PWR_REG,               { 0x1, 0x0, 0x1 } },
> +       { EXYNOS5433_SLEEP_RESET_MIF_SYS_PWR_REG,               { 0x1, 0x1, 0x0 } },
> +       { EXYNOS5433_MEMORY_TOP_SYS_PWR_REG,                    { 0x3, 0x0, 0x0 } },
> +       { EXYNOS5433_PAD_RETENTION_LPDDR3_SYS_PWR_REG,          { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_PAD_RETENTION_JTAG_SYS_PWR_REG,            { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_PAD_RETENTION_TOP_SYS_PWR_REG,             { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_PAD_RETENTION_UART_SYS_PWR_REG,            { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_PAD_RETENTION_EBIA_SYS_PWR_REG,            { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_PAD_RETENTION_EBIB_SYS_PWR_REG,            { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_PAD_RETENTION_SPI_SYS_PWR_REG,             { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_PAD_RETENTION_MIF_SYS_PWR_REG,             { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_PAD_ISOLATION_SYS_PWR_REG,                 { 0x1, 0x0, 0x1 } },
> +       { EXYNOS5433_PAD_RETENTION_USBXTI_SYS_PWR_REG,          { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_PAD_RETENTION_BOOTLDO_SYS_PWR_REG,         { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_PAD_ISOLATION_MIF_SYS_PWR_REG,             { 0x1, 0x0, 0x1 } },
> +       { EXYNOS5433_PAD_RETENTION_FSYSGENIO_SYS_PWR_REG,       { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_PAD_ALV_SEL_SYS_PWR_REG,                   { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_XXTI_SYS_PWR_REG,                          { 0x1, 0x1, 0x0 } },
> +       { EXYNOS5433_XXTI26_SYS_PWR_REG,                        { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_EXT_REGULATOR_SYS_PWR_REG,                 { 0x1, 0x1, 0x0 } },
> +       { EXYNOS5433_GPIO_MODE_SYS_PWR_REG,                     { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_GPIO_MODE_FSYS0_SYS_PWR_REG,               { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_GPIO_MODE_MIF_SYS_PWR_REG,                 { 0x1, 0x0, 0x0 } },
> +       { EXYNOS5433_GPIO_MODE_AUD_SYS_PWR_REG,                 { 0x1, 0x1, 0x0 } },
> +       { EXYNOS5433_GSCL_SYS_PWR_REG,                          { 0xF, 0x0, 0x0 } },
> +       { EXYNOS5433_CAM0_SYS_PWR_REG,                          { 0xF, 0x0, 0x0 } },
> +       { EXYNOS5433_MSCL_SYS_PWR_REG,                          { 0xF, 0x0, 0x0 } },
> +       { EXYNOS5433_G3D_SYS_PWR_REG,                           { 0xF, 0x0, 0x0 } },
> +       { EXYNOS5433_DISP_SYS_PWR_REG,                          { 0xF, 0x0, 0x0 } },
> +       { EXYNOS5433_CAM1_SYS_PWR_REG,                          { 0xF, 0x0, 0x0 } },
> +       { EXYNOS5433_AUD_SYS_PWR_REG,                           { 0xF, 0xF, 0x0 } },
> +       { EXYNOS5433_FSYS_SYS_PWR_REG,                          { 0xF, 0x0, 0x0 } },
> +       { EXYNOS5433_BUS2_SYS_PWR_REG,                          { 0xF, 0x0, 0x0 } },
> +       { EXYNOS5433_G2D_SYS_PWR_REG,                           { 0xF, 0x0, 0x0 } },
> +       { EXYNOS5433_ISP0_SYS_PWR_REG,                          { 0xF, 0x0, 0x0 } },
> +       { EXYNOS5433_MFC_SYS_PWR_REG,                           { 0xF, 0x0, 0x0 } },
> +       { EXYNOS5433_HEVC_SYS_PWR_REG,                          { 0xF, 0x0, 0x0 } },
> +       { EXYNOS5433_RESET_SLEEP_FSYS_SYS_PWR_REG,              { 0x1, 0x1, 0x0 } },
> +       { EXYNOS5433_RESET_SLEEP_BUS2_SYS_PWR_REG,              { 0x1, 0x1, 0x0 } },
> +       { PMU_TABLE_END, },
> +};
> +
> +static unsigned int const exynos5433_list_feed[] = {
> +       EXYNOS5433_ATLAS_NONCPU_OPTION,
> +       EXYNOS5433_APOLLO_NONCPU_OPTION,
> +       EXYNOS5433_TOP_PWR_OPTION,
> +       EXYNOS5433_TOP_PWR_MIF_OPTION,
> +       EXYNOS5433_AUD_OPTION,
> +       EXYNOS5433_CAM0_OPTION,
> +       EXYNOS5433_DISP_OPTION,
> +       EXYNOS5433_G2D_OPTION,
> +       EXYNOS5433_G3D_OPTION,
> +       EXYNOS5433_HEVC_OPTION,
> +       EXYNOS5433_MSCL_OPTION,
> +       EXYNOS5433_MFC_OPTION,
> +       EXYNOS5433_GSCL_OPTION,
> +       EXYNOS5433_FSYS_OPTION,
> +       EXYNOS5433_ISP_OPTION,
> +       EXYNOS5433_BUS2_OPTION,
> +};
> +
> +static unsigned int const exynos5433_list_pad_retention[] = {
> +       EXYNOS5433_PAD_RETENTION_LPDDR3_OPTION,
> +       EXYNOS5433_PAD_RETENTION_AUD_OPTION,
> +       EXYNOS5433_PAD_RETENTION_MMC2_OPTION,
> +       EXYNOS5433_PAD_RETENTION_TOP_OPTION,
> +       EXYNOS5433_PAD_RETENTION_UART_OPTION,
> +       EXYNOS5433_PAD_RETENTION_MMC0_OPTION,
> +       EXYNOS5433_PAD_RETENTION_MMC1_OPTION,
> +       EXYNOS5433_PAD_RETENTION_EBIA_OPTION,
> +       EXYNOS5433_PAD_RETENTION_EBIB_OPTION,
> +       EXYNOS5433_PAD_RETENTION_SPI_OPTION,
> +       EXYNOS5433_PAD_RETENTION_MIF_OPTION,
> +       EXYNOS5433_PAD_RETENTION_USBXTI_OPTION,
> +       EXYNOS5433_PAD_RETENTION_BOOTLDO_OPTION,
> +       EXYNOS5433_PAD_RETENTION_UFS_OPTION,
> +       EXYNOS5433_PAD_RETENTION_FSYSGENIO_OPTION,

Looks like conflicting with existing
drivers/pinctrl/samsung/pinctrl-exynos-arm64.c... and probably this
should be part of pinctrl driver's suspend/resume paths.

> +};
> +
> +static void exynos5433_set_wakeupmask(enum sys_powerdown mode)
> +{
> +       u32 intmask = 0;
> +
> +       pmu_raw_writel(exynos_get_eint_wake_mask(),
> +                                       EXYNOS5433_EINT_WAKEUP_MASK);
> +
> +       /* Disable WAKEUP event monitor */
> +       intmask = pmu_raw_readl(EXYNOS5433_WAKEUP_MASK);
> +       intmask &= ~(1 << 31);

This should have a define. Maybe it is an already defined field like
S5P_CORE_AUTOWAKEUP_EN or S5P_PS_HOLD_EN?

> +       pmu_raw_writel(intmask, EXYNOS5433_WAKEUP_MASK);
> +
> +       pmu_raw_writel(0xFFFF0000, EXYNOS5433_WAKEUP_MASK2);
> +       pmu_raw_writel(0xFFFF0000, EXYNOS5433_WAKEUP_MASK3);

Both need explaining what you are masking, preferably by appropriate
comment and maybe also define for raw constants.

> +}
> +
> +static void exynos5433_pmu_central_seq(bool enable)
> +{
> +       unsigned int tmp;
> +
> +       tmp = pmu_raw_readl(EXYNOS5433_CENTRAL_SEQ_CONFIGURATION);
> +       if (enable)
> +               tmp &= ~EXYNOS5433_CENTRALSEQ_PWR_CFG;
> +       else
> +               tmp |= EXYNOS5433_CENTRALSEQ_PWR_CFG;
> +       pmu_raw_writel(tmp, EXYNOS5433_CENTRAL_SEQ_CONFIGURATION);
> +
> +       tmp = pmu_raw_readl(EXYNOS5433_CENTRAL_SEQ_MIF_CONFIGURATION);
> +       if (enable)
> +               tmp &= ~EXYNOS5433_CENTRALSEQ_PWR_CFG;
> +       else
> +               tmp |= EXYNOS5433_CENTRALSEQ_PWR_CFG;
> +       pmu_raw_writel(tmp, EXYNOS5433_CENTRAL_SEQ_MIF_CONFIGURATION);
> +}
> +
> +static void exynos5433_pmu_pad_retention_release(void)
> +{
> +       unsigned int tmp;
> +       int i;

unsigned int i

> +
> +       for (i = 0 ; i < ARRAY_SIZE(exynos5433_list_pad_retention) ; i++) {
> +               tmp = pmu_raw_readl(exynos5433_list_pad_retention[i]);
> +               tmp |= EXYNOS5433_INITIATE_WAKEUP_FROM_LOWPOWER;
> +               pmu_raw_writel(tmp, exynos5433_list_pad_retention[i]);
> +       }
> +}
> +
> +static void exynos5433_pmu_init(void)
> +{
> +       unsigned int tmp;
> +       int i, cluster, cpu;

unsigned int i

> +
> +       /* Enable non retention flip-flop reset for wakeup */
> +       tmp = pmu_raw_readl(EXYNOS5433_PMU_SPARE0);
> +       tmp |= EXYNOS5433_EN_NONRET_RESET;
> +       pmu_raw_writel(tmp, EXYNOS5433_PMU_SPARE0);

This is spare register. Who is using it? Firmware? Please add its
usage also in Documentation/arm/Samsung/Bootloader-interface.txt.

> +
> +        /* Enable only SC_FEEDBACK for the register list */
> +       for (i = 0 ; i < ARRAY_SIZE(exynos5433_list_feed) ; i++) {
> +               tmp = pmu_raw_readl(exynos5433_list_feed[i]);
> +               tmp &= ~EXYNOS5_USE_SC_COUNTER;
> +               tmp |= EXYNOS5_USE_SC_FEEDBACK;
> +               pmu_raw_writel(tmp, exynos5433_list_feed[i]);
> +       }
> +
> +       /*
> +        * Disable automatic L2 flush, Disable L2 retention and
> +        * Enable STANDBYWFIL2, ACE/ACP
> +        */
> +       for (cluster = 0; cluster < 2; cluster++) {
> +               tmp = pmu_raw_readl(EXYNOS5433_ATLAS_L2_OPTION + (cluster * 0x20));

I would prefer to follow the convention for similar registers for cores, like:
EXYNOS_ARM_CORE_CONFIGURATION
EXYNOS_ARM_CORE_STATUS

This moves the offset into the header, along to other register offsets.

> +               tmp &= ~(EXYNOS5433_USE_AUTO_L2FLUSHREQ | EXYNOS5433_USE_RETENTION);
> +
> +               if (cluster == 0) {
> +                       tmp |= (EXYNOS5433_USE_STANDBYWFIL2 |
> +                               EXYNOS5433_USE_DEACTIVATE_ACE |
> +                               EXYNOS5433_USE_DEACTIVATE_ACP);
> +               }
> +               pmu_raw_writel(tmp, EXYNOS5433_ATLAS_L2_OPTION + (cluster * 0x20));
> +       }
> +
> +       /*
> +        * Enable both SC_COUNTER and SC_FEEDBACK for the CPUs
> +        * Use STANDBYWFI and SMPEN to indicate that core is ready to enter
> +        * low power mode
> +        */
> +       for (cpu = 0; cpu < 8; cpu++) {
> +               tmp = pmu_raw_readl(EXYNOS5433_CPU_OPTION(cpu));
> +               tmp |= (EXYNOS5_USE_SC_FEEDBACK | EXYNOS5_USE_SC_COUNTER);
> +               tmp |= EXYNOS5433_USE_SMPEN;
> +               tmp |= EXYNOS5433_USE_STANDBYWFI;
> +               tmp &= ~EXYNOS5433_USE_STANDBYWFE;
> +               pmu_raw_writel(tmp, EXYNOS5433_CPU_OPTION(cpu));
> +
> +               tmp = pmu_raw_readl(EXYNOS5433_CPU_DURATION(cpu));
> +               tmp |= EXYNOS5433_DUR_WAIT_RESET;
> +               tmp &= ~EXYNOS5433_DUR_SCALL;
> +               tmp |= EXYNOS5433_DUR_SCALL_VALUE;
> +               pmu_raw_writel(tmp, EXYNOS5433_CPU_DURATION(cpu));
> +       }
> +
> +       /* Skip atlas block power-off during automatic power down sequence */
> +       tmp = pmu_raw_readl(EXYNOS5433_ATLAS_CPUSEQUENCER_OPTION);
> +       tmp |= EXYNOS5433_SKIP_BLK_PWR_DOWN;
> +       pmu_raw_writel(tmp, EXYNOS5433_ATLAS_CPUSEQUENCER_OPTION);
> +
> +       /* Limit in-rush current during local power up of cores */
> +       tmp = pmu_raw_readl(EXYNOS5433_UP_SCHEDULER);
> +       tmp |= EXYNOS5433_ENABLE_ATLAS_CPU;
> +       pmu_raw_writel(tmp, EXYNOS5433_UP_SCHEDULER);
> +}
> +
> +static void exynos5433_powerdown_conf(enum sys_powerdown mode)
> +{
> +       switch (mode) {
> +       case SYS_SLEEP:
> +               exynos5433_set_wakeupmask(mode);
> +               exynos5433_pmu_central_seq(true);
> +               break;
> +       default:
> +               break;
> +       };
> +}
> +
> +static void exynos5433_powerup_conf(enum sys_powerdown mode)
> +{
> +       unsigned int wakeup;
> +
> +       switch (mode) {
> +       case SYS_SLEEP:
> +               wakeup = pmu_raw_readl(EXYNOS5433_CENTRAL_SEQ_CONFIGURATION);
> +               wakeup &= EXYNOS5433_CENTRALSEQ_PWR_CFG;
> +               if (wakeup)
> +                       exynos5433_pmu_pad_retention_release();
> +               else
> +                       exynos5433_pmu_central_seq(false);

I do not understand what you want to achieve here. Re-suspend?

> +               break;
> +       default:
> +               break;
> +       };
> +}
> +
> +const struct exynos_pmu_data exynos5433_pmu_data = {
> +       .pmu_config             = exynos5433_pmu_config,
> +       .pmu_init               = exynos5433_pmu_init,
> +       .powerdown_conf         = exynos5433_powerdown_conf,
> +       .powerup_conf           = exynos5433_powerup_conf,
> +};
> diff --git a/include/linux/soc/samsung/exynos-regs-pmu.h b/include/linux/soc/samsung/exynos-regs-pmu.h
> index bebdde5dccd6..93a52d133ba1 100644
> --- a/include/linux/soc/samsung/exynos-regs-pmu.h
> +++ b/include/linux/soc/samsung/exynos-regs-pmu.h
> @@ -645,7 +645,110 @@
>                                          | EXYNOS5420_KFC_USE_STANDBY_WFI3)
>
>  /* For EXYNOS5433 */
> +#define EXYNOS5433_UP_SCHEDULER                                        (0x0120)
> +#define EXYNOS5433_CENTRAL_SEQ_CONFIGURATION                   (0x0200)
> +#define EXYNOS5433_CENTRAL_SEQ_MIF_CONFIGURATION               (0x0240)
> +#define EXYNOS5433_EINT_WAKEUP_MASK                            (0x060C)
> +#define EXYNOS5433_WAKEUP_MASK                                 (0x0610)
> +#define EXYNOS5433_WAKEUP_MASK2                                        (0x0614)
> +#define EXYNOS5433_WAKEUP_MASK3                                        (0x0618)
> +#define EXYNOS5433_EINT_WAKEUP_MASK1                           (0x062C)
>  #define EXYNOS5433_USBHOST30_PHY_CONTROL                       (0x0728)
> +#define EXYNOS5433_PMU_SPARE0                                  (0x0900)
> +#define EXYNOS5433_ATLAS_CPU0_SYS_PWR_REG                      (0x1000)
> +#define EXYNOS5433_DIS_IRQ_ATLAS_CPU0_CENTRAL_SYS_PWR_REG      (0x1008)
> +#define EXYNOS5433_ATLAS_CPU1_SYS_PWR_REG                      (0x1010)
> +#define EXYNOS5433_DIS_IRQ_ATLAS_CPU1_CENTRAL_SYS_PWR_REG      (0x1018)
> +#define EXYNOS5433_ATLAS_CPU2_SYS_PWR_REG                      (0x1020)
> +#define EXYNOS5433_DIS_IRQ_ATLAS_CPU2_CENTRAL_SYS_PWR_REG      (0x1028)
> +#define EXYNOS5433_ATLAS_CPU3_SYS_PWR_REG                      (0x1030)
> +#define EXYNOS5433_DIS_IRQ_ATLAS_CPU3_CENTRAL_SYS_PWR_REG      (0x1038)
> +#define EXYNOS5433_APOLLO_CPU0_SYS_PWR_REG                     (0x1040)
> +#define EXYNOS5433_DIS_IRQ_APOLLO_CPU0_CENTRAL_SYS_PWR_REG     (0x1048)
> +#define EXYNOS5433_APOLLO_CPU1_SYS_PWR_REG                     (0x1050)
> +#define EXYNOS5433_DIS_IRQ_APOLLO_CPU1_CENTRAL_SYS_PWR_REG     (0x1058)
> +#define EXYNOS5433_APOLLO_CPU2_SYS_PWR_REG                     (0x1060)
> +#define EXYNOS5433_DIS_IRQ_APOLLO_CPU2_CENTRAL_SYS_PWR_REG     (0x1068)
> +#define EXYNOS5433_APOLLO_CPU3_SYS_PWR_REG                     (0x1070)
> +#define EXYNOS5433_DIS_IRQ_APOLLO_CPU3_CENTRAL_SYS_PWR_REG     (0x1078)
> +#define EXYNOS5433_ATLAS_NONCPU_SYS_PWR_REG                    (0x1080)
> +#define EXYNOS5433_ATLAS_L2_SYS_PWR_REG                                (0x10C0)
> +#define EXYNOS5433_APOLLO_L2_SYS_PWR_REG                       (0x10C4)
> +#define EXYNOS5433_APOLLO_NONCPU_SYS_PWR_REG                   (0x1084)
> +#define EXYNOS5433_A5IS_SYS_PWR_REG                            (0x10B0)
> +#define EXYNOS5433_DIS_IRQ_A5IS_LOCAL_SYS_PWR_REG              (0x10B4)
> +#define EXYNOS5433_DIS_IRQ_A5IS_CENTRAL_SYS_PWR_REG            (0x10B8)
> +#define EXYNOS5433_CLKSTOP_CMU_TOP_SYS_PWR_REG                 (0x1100)
> +#define EXYNOS5433_CLKRUN_CMU_TOP_SYS_PWR_REG                  (0x1104)
> +#define EXYNOS5433_RESET_CMU_TOP_SYS_PWR_REG                   (0x110C)
> +#define EXYNOS5433_RESET_CPUCLKSTOP_SYS_PWR_REG                        (0x111C)
> +#define EXYNOS5433_CLKSTOP_CMU_MIF_SYS_PWR_REG                 (0x1120)
> +#define EXYNOS5433_CLKRUN_CMU_MIF_SYS_PWR_REG                  (0x1124)
> +#define EXYNOS5433_RESET_CMU_MIF_SYS_PWR_REG                   (0x112C)
> +#define EXYNOS5433_DDRPHY_DLLLOCK_SYS_PWR_REG                  (0x1138)
> +#define EXYNOS5433_DISABLE_PLL_CMU_TOP_SYS_PWR_REG             (0x1140)
> +#define EXYNOS5433_DISABLE_PLL_AUD_PLL_SYS_PWR_REG             (0x1144)
> +#define EXYNOS5433_DISABLE_PLL_CMU_MIF_SYS_PWR_REG             (0x1160)
> +#define EXYNOS5433_TOP_BUS_SYS_PWR_REG                         (0x1180)
> +#define EXYNOS5433_TOP_RETENTION_SYS_PWR_REG                   (0x1184)
> +#define EXYNOS5433_TOP_PWR_SYS_PWR_REG                         (0x1188)
> +#define EXYNOS5433_TOP_BUS_MIF_SYS_PWR_REG                     (0x1190)
> +#define EXYNOS5433_TOP_RETENTION_MIF_SYS_PWR_REG               (0x1194)
> +#define EXYNOS5433_TOP_PWR_MIF_SYS_PWR_REG                     (0x1198)
> +#define EXYNOS5433_LOGIC_RESET_SYS_PWR_REG                     (0x11A0)
> +#define EXYNOS5433_OSCCLK_GATE_SYS_PWR_REG                     (0x11A4)
> +#define EXYNOS5433_SLEEP_RESET_SYS_PWR_REG                     (0x11A8)
> +#define EXYNOS5433_LOGIC_RESET_MIF_SYS_PWR_REG                 (0x11B0)
> +#define EXYNOS5433_OSCCLK_GATE_MIF_SYS_PWR_REG                 (0x11B4)
> +#define EXYNOS5433_SLEEP_RESET_MIF_SYS_PWR_REG                 (0x11B8)
> +#define EXYNOS5433_MEMORY_TOP_SYS_PWR_REG                      (0x11C0)
> +#define EXYNOS5433_PAD_RETENTION_LPDDR3_SYS_PWR_REG            (0x1200)
> +#define EXYNOS5433_PAD_RETENTION_JTAG_SYS_PWR_REG              (0x1208)
> +#define EXYNOS5433_PAD_RETENTION_TOP_SYS_PWR_REG               (0x1220)
> +#define EXYNOS5433_PAD_RETENTION_UART_SYS_PWR_REG              (0x1224)
> +#define EXYNOS5433_PAD_RETENTION_EBIA_SYS_PWR_REG              (0x1230)
> +#define EXYNOS5433_PAD_RETENTION_EBIB_SYS_PWR_REG              (0x1234)
> +#define EXYNOS5433_PAD_RETENTION_SPI_SYS_PWR_REG               (0x1238)
> +#define EXYNOS5433_PAD_RETENTION_MIF_SYS_PWR_REG               (0x123C)
> +#define EXYNOS5433_PAD_ISOLATION_SYS_PWR_REG                   (0x1240)
> +#define EXYNOS5433_PAD_RETENTION_USBXTI_SYS_PWR_REG            (0x1244)
> +#define EXYNOS5433_PAD_RETENTION_BOOTLDO_SYS_PWR_REG           (0x1248)
> +#define EXYNOS5433_PAD_ISOLATION_MIF_SYS_PWR_REG               (0x1250)
> +#define EXYNOS5433_PAD_RETENTION_FSYSGENIO_SYS_PWR_REG         (0x1254)
> +#define EXYNOS5433_PAD_ALV_SEL_SYS_PWR_REG                     (0x1260)
> +#define EXYNOS5433_XXTI_SYS_PWR_REG                            (0x1284)
> +#define EXYNOS5433_XXTI26_SYS_PWR_REG                          (0x1288)
> +#define EXYNOS5433_EXT_REGULATOR_SYS_PWR_REG                   (0x12C0)
> +#define EXYNOS5433_GPIO_MODE_SYS_PWR_REG                       (0x1300)
> +#define EXYNOS5433_GPIO_MODE_FSYS0_SYS_PWR_REG                 (0x1304)
> +#define EXYNOS5433_GPIO_MODE_MIF_SYS_PWR_REG                   (0x1320)
> +#define EXYNOS5433_GPIO_MODE_AUD_SYS_PWR_REG                   (0x1340)
> +#define EXYNOS5433_GSCL_SYS_PWR_REG                            (0x1400)
> +#define EXYNOS5433_CAM0_SYS_PWR_REG                            (0x1404)
> +#define EXYNOS5433_MSCL_SYS_PWR_REG                            (0x1408)
> +#define EXYNOS5433_G3D_SYS_PWR_REG                             (0x140C)
> +#define EXYNOS5433_DISP_SYS_PWR_REG                            (0x1410)
> +#define EXYNOS5433_CAM1_SYS_PWR_REG                            (0x1414)
> +#define EXYNOS5433_AUD_SYS_PWR_REG                             (0x1418)
> +#define EXYNOS5433_FSYS_SYS_PWR_REG                            (0x141C)
> +#define EXYNOS5433_BUS2_SYS_PWR_REG                            (0x1420)
> +#define EXYNOS5433_G2D_SYS_PWR_REG                             (0x1424)
> +#define EXYNOS5433_ISP0_SYS_PWR_REG                            (0x1428)
> +#define EXYNOS5433_MFC_SYS_PWR_REG                             (0x1430)
> +#define EXYNOS5433_HEVC_SYS_PWR_REG                            (0x1438)
> +#define EXYNOS5433_RESET_SLEEP_FSYS_SYS_PWR_REG                        (0x15DC)
> +#define EXYNOS5433_RESET_SLEEP_BUS2_SYS_PWR_REG                        (0x15E0)
> +#define EXYNOS5433_ATLAS_CPU0_OPTION                           (0x2008)
> +#define EXYNOS5433_CPU_OPTION(_nr)                             (EXYNOS5433_ATLAS_CPU0_OPTION + (_nr) * 0x80)
> +#define EXYNOS5433_ATLAS_CPU0_DURATION0                                (0x2010)
> +#define EXYNOS5433_CPU_DURATION(_nr)                           (EXYNOS5433_ATLAS_CPU0_DURATION0 + (_nr) * 0x80)
> +#define EXYNOS5433_ATLAS_NONCPU_OPTION                         (0x2408)
> +#define EXYNOS5433_APOLLO_NONCPU_OPTION                                (0x2428)
> +#define EXYNOS5433_ATLAS_CPUSEQUENCER_OPTION                   (0x2488)
> +#define EXYNOS5433_ATLAS_L2_OPTION                             (0x2608)
> +#define EXYNOS5433_TOP_PWR_MIF_OPTION                          (0x2CC8)
> +#define EXYNOS5433_TOP_PWR_OPTION                              (0x2C48)
> +#define EXYNOS5433_PAD_RETENTION_LPDDR3_OPTION                 (0x3008)
>  #define EXYNOS5433_PAD_RETENTION_AUD_OPTION                    (0x3028)
>  #define EXYNOS5433_PAD_RETENTION_MMC2_OPTION                   (0x30C8)
>  #define EXYNOS5433_PAD_RETENTION_TOP_OPTION                    (0x3108)
> @@ -660,5 +763,50 @@
>  #define EXYNOS5433_PAD_RETENTION_BOOTLDO_OPTION                        (0x3248)
>  #define EXYNOS5433_PAD_RETENTION_UFS_OPTION                    (0x3268)
>  #define EXYNOS5433_PAD_RETENTION_FSYSGENIO_OPTION              (0x32A8)
> +#define EXYNOS5433_PS_HOLD_CONTROL                             (0x330C)
> +#define EXYNOS5433_GSCL_OPTION                                 (0x4008)
> +#define EXYNOS5433_CAM0_OPTION                                 (0x4028)
> +#define EXYNOS5433_MSCL_OPTION                                 (0x4048)
> +#define EXYNOS5433_G3D_OPTION                                  (0x4068)
> +#define EXYNOS5433_DISP_OPTION                                 (0x4088)
> +#define EXYNOS5433_AUD_OPTION                                  (0x40C8)
> +#define EXYNOS5433_FSYS_OPTION                                 (0x40E8)
> +#define EXYNOS5433_BUS2_OPTION                                 (0x4108)
> +#define EXYNOS5433_G2D_OPTION                                  (0x4128)
> +#define EXYNOS5433_ISP_OPTION                                  (0x4148)
> +#define EXYNOS5433_MFC_OPTION                                  (0x4188)
> +#define EXYNOS5433_HEVC_OPTION                                 (0x41C8)
> +
> +/* EXYNOS5433_PMU_SPARE0 */
> +#define EXYNOS5433_EN_NONRET_RESET                             (1 << 0)

Use BIT(0) here and in other places.

Best regards,
Krzysztof

> +
> +/* EXYNOS5433_CENTRAL_SEQ_CONFIGURATION */
> +#define EXYNOS5433_CENTRALSEQ_PWR_CFG                          (0x1 << 16)
> +
> +/* EXYNOS5433_ATLAS_L2_OPTION */
> +#define EXYNOS5433_USE_DEACTIVATE_ACE                          (0x1 << 19)
> +#define EXYNOS5433_USE_DEACTIVATE_ACP                          (0x1 << 18)
> +#define EXYNOS5433_USE_AUTO_L2FLUSHREQ                         (0x1 << 17)
> +#define EXYNOS5433_USE_STANDBYWFIL2                            (0x1 << 16)
> +#define EXYNOS5433_USE_RETENTION                               (0x1 << 4)
> +
> +/* EXYNOS5433_CPU_OPTION */
> +#define EXYNOS5433_USE_SMPEN                                   (0x1 << 28)
> +#define EXYNOS5433_USE_STANDBYWFE                              (0x1 << 24)
> +#define EXYNOS5433_USE_STANDBYWFI                              (0x1 << 16)
> +
> +/* EXYNOS5433_PAD_RETENTION_*_OPTION */
> +#define EXYNOS5433_INITIATE_WAKEUP_FROM_LOWPOWER               (0x1 << 28)
> +
> +/* EXYNOS5433_CPU_DURATION */
> +#define EXYNOS5433_DUR_WAIT_RESET                              (0xF << 20)
> +#define EXYNOS5433_DUR_SCALL                                   (0xF << 4)
> +#define EXYNOS5433_DUR_SCALL_VALUE                             (0x1 << 4)
> +
> +/* EXYNOS5433_ATLAS_CPUSEQUENCER_OPTION */
> +#define EXYNOS5433_SKIP_BLK_PWR_DOWN                           (0x1 << 8)
> +
> +/* EXYNOS5433_UP_SCHEDULER */
> +#define EXYNOS5433_ENABLE_ATLAS_CPU                            (0x1 << 0)
>
>  #endif /* __LINUX_SOC_EXYNOS_REGS_PMU_H */
> --
> 1.9.1
>

^ permalink raw reply

* [PATCH] drivers: firmware: xilinx: Add ZynqMP firmware driver
From: Aishwarya Pant @ 2018-01-09 12:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515449227-5096-1-git-send-email-jollys@xilinx.com>

On Mon, Jan 08, 2018 at 02:07:07PM -0800, Jolly Shah wrote:
> This patch is adding communication layer with firmware.
> Firmware driver provides an interface to firmware APIs.
> Interface APIs can be used by any driver to communicate to
> PMUFW(Platform Management Unit). All requests go through ATF.
> Firmware-debug provides debugfs interface to all APIs.
> Firmware-ggs provides read/write interface to
> global storage registers.
> 
> Signed-off-by: Jolly Shah <jollys@xilinx.com>
> Signed-off-by: Rajan Vaja <rajanv@xilinx.com>
> ---
>  .../firmware/xilinx/xlnx,zynqmp-firmware.txt       |   16 +
>  arch/arm64/Kconfig.platforms                       |    1 +
>  drivers/firmware/Kconfig                           |    1 +
>  drivers/firmware/Makefile                          |    1 +
>  drivers/firmware/xilinx/Kconfig                    |    4 +
>  drivers/firmware/xilinx/Makefile                   |    4 +
>  drivers/firmware/xilinx/zynqmp/Kconfig             |   23 +
>  drivers/firmware/xilinx/zynqmp/Makefile            |    5 +
>  drivers/firmware/xilinx/zynqmp/firmware-debug.c    |  540 +++++++++++
>  drivers/firmware/xilinx/zynqmp/firmware-ggs.c      |  298 ++++++
>  drivers/firmware/xilinx/zynqmp/firmware.c          | 1024 ++++++++++++++++++++
>  .../linux/firmware/xilinx/zynqmp/firmware-debug.h  |   32 +
>  include/linux/firmware/xilinx/zynqmp/firmware.h    |  573 +++++++++++
>  13 files changed, 2522 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.txt
>  create mode 100644 drivers/firmware/xilinx/Kconfig
>  create mode 100644 drivers/firmware/xilinx/Makefile
>  create mode 100644 drivers/firmware/xilinx/zynqmp/Kconfig
>  create mode 100644 drivers/firmware/xilinx/zynqmp/Makefile
>  create mode 100644 drivers/firmware/xilinx/zynqmp/firmware-debug.c
>  create mode 100644 drivers/firmware/xilinx/zynqmp/firmware-ggs.c
>  create mode 100644 drivers/firmware/xilinx/zynqmp/firmware.c
>  create mode 100644 include/linux/firmware/xilinx/zynqmp/firmware-debug.h
>  create mode 100644 include/linux/firmware/xilinx/zynqmp/firmware.h
> 
> diff --git a/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.txt b/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.txt
> new file mode 100644
> index 0000000..ace111c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.txt
> @@ -0,0 +1,16 @@
> +Xilinx Zynq MPSoC Firmware Device Tree Bindings
> +
> +The zynqmp-firmware node describes the interface to platform firmware.
> +
> +Required properties:
> + - compatible:	Must contain:  "xlnx,zynqmp-firmware"
> + - method:	The method of calling the PM-API firmware layer.
> +		Permitted values are:
> +		 - "smc" : To be used in configurations without a hypervisor
> +		 - "hvc" : To be used when hypervisor is present
> +
> +Examples:
> +	firmware: firmware {
> +		compatible = "xlnx,zynqmp-firmware";
> +		method = "smc";
> +	};
> diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
> index 2401373..3dd3ae9 100644
> --- a/arch/arm64/Kconfig.platforms
> +++ b/arch/arm64/Kconfig.platforms
> @@ -273,6 +273,7 @@ config ARCH_ZX
>  
>  config ARCH_ZYNQMP
>  	bool "Xilinx ZynqMP Family"
> +	select ZYNQMP_FIRMWARE
>  	help
>  	  This enables support for Xilinx ZynqMP Family
>  
> diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
> index fa87a055..18fc2a8 100644
> --- a/drivers/firmware/Kconfig
> +++ b/drivers/firmware/Kconfig
> @@ -249,5 +249,6 @@ source "drivers/firmware/google/Kconfig"
>  source "drivers/firmware/efi/Kconfig"
>  source "drivers/firmware/meson/Kconfig"
>  source "drivers/firmware/tegra/Kconfig"
> +source "drivers/firmware/xilinx/Kconfig"
>  
>  endmenu
> diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
> index feaa890..43a24b5 100644
> --- a/drivers/firmware/Makefile
> +++ b/drivers/firmware/Makefile
> @@ -30,3 +30,4 @@ obj-$(CONFIG_GOOGLE_FIRMWARE)	+= google/
>  obj-$(CONFIG_EFI)		+= efi/
>  obj-$(CONFIG_UEFI_CPER)		+= efi/
>  obj-y				+= tegra/
> +obj-y				+= xilinx/
> diff --git a/drivers/firmware/xilinx/Kconfig b/drivers/firmware/xilinx/Kconfig
> new file mode 100644
> index 0000000..dd3cddb
> --- /dev/null
> +++ b/drivers/firmware/xilinx/Kconfig
> @@ -0,0 +1,4 @@
> +# SPDX-License-Identifier:	GPL-2.0+
> +# Kconfig for Xilinx firmwares
> +
> +source "drivers/firmware/xilinx/zynqmp/Kconfig"
> diff --git a/drivers/firmware/xilinx/Makefile b/drivers/firmware/xilinx/Makefile
> new file mode 100644
> index 0000000..aba1f86
> --- /dev/null
> +++ b/drivers/firmware/xilinx/Makefile
> @@ -0,0 +1,4 @@
> +# SPDX-License-Identifier:	GPL-2.0+
> +# Makefile for Xilinx firmwares
> +
> +obj-$(CONFIG_ARCH_ZYNQMP) += zynqmp/
> diff --git a/drivers/firmware/xilinx/zynqmp/Kconfig b/drivers/firmware/xilinx/zynqmp/Kconfig
> new file mode 100644
> index 0000000..1f815e0
> --- /dev/null
> +++ b/drivers/firmware/xilinx/zynqmp/Kconfig
> @@ -0,0 +1,23 @@
> +# SPDX-License-Identifier:	GPL-2.0+
> +# Kconfig for Xilinx zynqmp firmware
> +
> +menu "Zynq MPSoC Firmware Drivers"
> +	depends on ARCH_ZYNQMP
> +
> +config ZYNQMP_FIRMWARE
> +	bool "Enable Xilinx Zynq MPSoC firmware interface"
> +	help
> +	  Firmware interface driver is used by different to
> +	  communicate with the firmware for various platform
> +	  management services.
> +	  Say yes to enable zynqmp firmware interface driver.
> +	  In doubt, say N
> +
> +config ZYNQMP_FIRMWARE_DEBUG
> +	bool "Enable Xilinx Zynq MPSoC firmware debug APIs"
> +	depends on ARCH_ZYNQMP && DEBUG_FS
> +	help
> +	  Say yes to enable zynqmp firmware interface debug APIs.
> +	  In doubt, say N
> +
> +endmenu
> diff --git a/drivers/firmware/xilinx/zynqmp/Makefile b/drivers/firmware/xilinx/zynqmp/Makefile
> new file mode 100644
> index 0000000..97086b5
> --- /dev/null
> +++ b/drivers/firmware/xilinx/zynqmp/Makefile
> @@ -0,0 +1,5 @@
> +# SPDX-License-Identifier:	GPL-2.0+
> +# Makefile for Xilinx firmwares
> +
> +obj-$(CONFIG_ZYNQMP_FIRMWARE) += firmware.o firmware-ggs.o
> +obj-$(CONFIG_ZYNQMP_FIRMWARE_DEBUG) += firmware-debug.o
> diff --git a/drivers/firmware/xilinx/zynqmp/firmware-debug.c b/drivers/firmware/xilinx/zynqmp/firmware-debug.c
> new file mode 100644
> index 0000000..83b1c45
> --- /dev/null
> +++ b/drivers/firmware/xilinx/zynqmp/firmware-debug.c
> @@ -0,0 +1,540 @@
> +/*
> + * Xilinx Zynq MPSoC Firmware layer for debugfs APIs
> + *
> + *  Copyright (C) 2014-2017 Xilinx, Inc.
> + *
> + *  Michal Simek <michal.simek@xilinx.com>
> + *  Davorin Mista <davorin.mista@aggios.com>
> + *  Jolly Shah <jollys@xilinx.com>
> + *  Rajan Vaja <rajanv@xilinx.com>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include <linux/compiler.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/debugfs.h>
> +#include <linux/uaccess.h>
> +#include <linux/firmware/xilinx/zynqmp/firmware.h>
> +#include <linux/firmware/xilinx/zynqmp/firmware-debug.h>
> +
> +#define DRIVER_NAME	"zynqmp-firmware"
> +
> +/**
> + * zynqmp_pm_self_suspend - PM call for master to suspend itself
> + * @node:	Node ID of the master or subsystem
> + * @latency:	Requested maximum wakeup latency (not supported)
> + * @state:	Requested state (not supported)
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +int zynqmp_pm_self_suspend(const u32 node,
> +			   const u32 latency,
> +			   const u32 state)
> +{
> +	return invoke_pm_fn(SELF_SUSPEND, node, latency, state, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_abort_suspend - PM call to announce that a prior suspend request
> + *				is to be aborted.
> + * @reason:	Reason for the abort
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +int zynqmp_pm_abort_suspend(const enum zynqmp_pm_abort_reason reason)
> +{
> +	return invoke_pm_fn(ABORT_SUSPEND, reason, 0, 0, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_register_notifier - Register the PU to be notified of PM events
> + * @node:	Node ID of the slave
> + * @event:	The event to be notified about
> + * @wake:	Wake up on event
> + * @enable:	Enable or disable the notifier
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +int zynqmp_pm_register_notifier(const u32 node, const u32 event,
> +				const u32 wake, const u32 enable)
> +{
> +	return invoke_pm_fn(REGISTER_NOTIFIER, node, event,
> +			    wake, enable, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_argument_value - Extract argument value from a PM-API request
> + * @arg:	Entered PM-API argument in string format
> + *
> + * Return:	Argument value in unsigned integer format on success
> + *		0 otherwise
> + */
> +static u64 zynqmp_pm_argument_value(char *arg)
> +{
> +	u64 value;
> +
> +	if (!arg)
> +		return 0;
> +
> +	if (!kstrtou64(arg, 0, &value))
> +		return value;
> +
> +	return 0;
> +}
> +
> +static struct dentry *zynqmp_pm_debugfs_dir;
> +static struct dentry *zynqmp_pm_debugfs_power;
> +static struct dentry *zynqmp_pm_debugfs_api_version;
> +
> +/**
> + * zynqmp_pm_debugfs_api_write - debugfs write function
> + * @file:	User file structure
> + * @ptr:	User entered PM-API string
> + * @len:	Length of the userspace buffer
> + * @off:	Offset within the file
> + *
> + * Return:	Number of bytes copied if PM-API request succeeds,
> + *		the corresponding error code otherwise
> + *
> + * Used for triggering pm api functions by writing
> + * echo <pm_api_id>    > /sys/kernel/debug/zynqmp_pm/power or
> + * echo <pm_api_name>  > /sys/kernel/debug/zynqmp_pm/power
> + */
> +static ssize_t zynqmp_pm_debugfs_api_write(struct file *file,
> +					   const char __user *ptr, size_t len,
> +					   loff_t *off)
> +{
> +	char *kern_buff, *tmp_buff;
> +	char *pm_api_req;
> +	u32 pm_id = 0;
> +	u64 pm_api_arg[4];
> +	/* Return values from PM APIs calls */
> +	u32 pm_api_ret[4] = {0, 0, 0, 0};
> +	u32 pm_api_version;
> +
> +	int ret;
> +	int i = 0;
> +	const struct zynqmp_eemi_ops *eemi_ops = get_eemi_ops();
> +
> +	if (!eemi_ops)
> +		return -ENXIO;
> +
> +	if (*off != 0 || len <= 0)
> +		return -EINVAL;
> +
> +	kern_buff = kzalloc(len, GFP_KERNEL);
> +	if (!kern_buff)
> +		return -ENOMEM;
> +	tmp_buff = kern_buff;
> +
> +	while (i < ARRAY_SIZE(pm_api_arg))
> +		pm_api_arg[i++] = 0;
> +
> +	ret = strncpy_from_user(kern_buff, ptr, len);
> +	if (ret < 0) {
> +		ret = -EFAULT;
> +		goto err;
> +	}
> +
> +	/* Read the API name from a user request */
> +	pm_api_req = strsep(&kern_buff, " ");
> +
> +	if (strncasecmp(pm_api_req, "REQUEST_SUSPEND", 15) == 0)
> +		pm_id = REQUEST_SUSPEND;
> +	else if (strncasecmp(pm_api_req, "SELF_SUSPEND", 12) == 0)
> +		pm_id = SELF_SUSPEND;
> +	else if (strncasecmp(pm_api_req, "FORCE_POWERDOWN", 15) == 0)
> +		pm_id = FORCE_POWERDOWN;
> +	else if (strncasecmp(pm_api_req, "ABORT_SUSPEND", 13) == 0)
> +		pm_id = ABORT_SUSPEND;
> +	else if (strncasecmp(pm_api_req, "REQUEST_WAKEUP", 14) == 0)
> +		pm_id = REQUEST_WAKEUP;
> +	else if (strncasecmp(pm_api_req, "SET_WAKEUP_SOURCE", 17) == 0)
> +		pm_id = SET_WAKEUP_SOURCE;
> +	else if (strncasecmp(pm_api_req, "SYSTEM_SHUTDOWN", 15) == 0)
> +		pm_id = SYSTEM_SHUTDOWN;
> +	else if (strncasecmp(pm_api_req, "REQUEST_NODE", 12) == 0)
> +		pm_id = REQUEST_NODE;
> +	else if (strncasecmp(pm_api_req, "RELEASE_NODE", 12) == 0)
> +		pm_id = RELEASE_NODE;
> +	else if (strncasecmp(pm_api_req, "SET_REQUIREMENT", 15) == 0)
> +		pm_id = SET_REQUIREMENT;
> +	else if (strncasecmp(pm_api_req, "SET_MAX_LATENCY", 15) == 0)
> +		pm_id = SET_MAX_LATENCY;
> +	else if (strncasecmp(pm_api_req, "GET_API_VERSION", 15) == 0)
> +		pm_id = GET_API_VERSION;
> +	else if (strncasecmp(pm_api_req, "SET_CONFIGURATION", 17) == 0)
> +		pm_id = SET_CONFIGURATION;
> +	else if (strncasecmp(pm_api_req, "GET_NODE_STATUS", 15) == 0)
> +		pm_id = GET_NODE_STATUS;
> +	else if (strncasecmp(pm_api_req,
> +			     "GET_OPERATING_CHARACTERISTIC", 28) == 0)
> +		pm_id = GET_OPERATING_CHARACTERISTIC;
> +	else if (strncasecmp(pm_api_req, "REGISTER_NOTIFIER", 17) == 0)
> +		pm_id = REGISTER_NOTIFIER;
> +	else if (strncasecmp(pm_api_req, "RESET_ASSERT", 12) == 0)
> +		pm_id = RESET_ASSERT;
> +	else if (strncasecmp(pm_api_req, "RESET_GET_STATUS", 16) == 0)
> +		pm_id = RESET_GET_STATUS;
> +	else if (strncasecmp(pm_api_req, "MMIO_READ", 9) == 0)
> +		pm_id = MMIO_READ;
> +	else if (strncasecmp(pm_api_req, "MMIO_WRITE", 10) == 0)
> +		pm_id = MMIO_WRITE;
> +	else if (strncasecmp(pm_api_req, "GET_CHIPID", 9) == 0)
> +		pm_id = GET_CHIPID;
> +	else if (strncasecmp(pm_api_req, "PINCTRL_GET_FUNCTION", 21) == 0)
> +		pm_id = PINCTRL_GET_FUNCTION;
> +	else if (strncasecmp(pm_api_req, "PINCTRL_SET_FUNCTION", 21) == 0)
> +		pm_id = PINCTRL_SET_FUNCTION;
> +	else if (strncasecmp(pm_api_req,
> +			     "PINCTRL_CONFIG_PARAM_GET", 25) == 0)
> +		pm_id = PINCTRL_CONFIG_PARAM_GET;
> +	else if (strncasecmp(pm_api_req,
> +			     "PINCTRL_CONFIG_PARAM_SET", 25) == 0)
> +		pm_id = PINCTRL_CONFIG_PARAM_SET;
> +	else if (strncasecmp(pm_api_req, "IOCTL", 6) == 0)
> +		pm_id = IOCTL;
> +	else if (strncasecmp(pm_api_req, "CLOCK_ENABLE", 12) == 0)
> +		pm_id = CLOCK_ENABLE;
> +	else if (strncasecmp(pm_api_req, "CLOCK_DISABLE", 13) == 0)
> +		pm_id = CLOCK_DISABLE;
> +	else if (strncasecmp(pm_api_req, "CLOCK_GETSTATE", 14) == 0)
> +		pm_id = CLOCK_GETSTATE;
> +	else if (strncasecmp(pm_api_req, "CLOCK_SETDIVIDER", 16) == 0)
> +		pm_id = CLOCK_SETDIVIDER;
> +	else if (strncasecmp(pm_api_req, "CLOCK_GETDIVIDER", 16) == 0)
> +		pm_id = CLOCK_GETDIVIDER;
> +	else if (strncasecmp(pm_api_req, "CLOCK_SETRATE", 13) == 0)
> +		pm_id = CLOCK_SETRATE;
> +	else if (strncasecmp(pm_api_req, "CLOCK_GETRATE", 13) == 0)
> +		pm_id = CLOCK_GETRATE;
> +	else if (strncasecmp(pm_api_req, "CLOCK_SETPARENT", 15) == 0)
> +		pm_id = CLOCK_SETPARENT;
> +	else if (strncasecmp(pm_api_req, "CLOCK_GETPARENT", 15) == 0)
> +		pm_id = CLOCK_GETPARENT;
> +	else if (strncasecmp(pm_api_req, "QUERY_DATA", 22) == 0)
> +		pm_id = QUERY_DATA;
> +
> +	/* If no name was entered look for PM-API ID instead */
> +	else if (kstrtouint(pm_api_req, 10, &pm_id))
> +		ret = -EINVAL;
> +
> +	/* Read node_id and arguments from the PM-API request */
> +	i = 0;
> +	pm_api_req = strsep(&kern_buff, " ");
> +	while ((i < ARRAY_SIZE(pm_api_arg)) && pm_api_req) {
> +		pm_api_arg[i++] = zynqmp_pm_argument_value(pm_api_req);
> +		pm_api_req = strsep(&kern_buff, " ");
> +	}
> +
> +	switch (pm_id) {
> +	case GET_API_VERSION:
> +		eemi_ops->get_api_version(&pm_api_version);
> +		pr_info("%s PM-API Version = %d.%d\n", __func__,
> +			pm_api_version >> 16, pm_api_version & 0xffff);
> +		break;
> +	case REQUEST_SUSPEND:
> +		ret = eemi_ops->request_suspend(pm_api_arg[0],
> +						pm_api_arg[1] ? pm_api_arg[1] :
> +						ZYNQMP_PM_REQUEST_ACK_NO,
> +						pm_api_arg[2] ? pm_api_arg[2] :
> +						ZYNQMP_PM_MAX_LATENCY, 0);
> +		break;
> +	case SELF_SUSPEND:
> +		ret = zynqmp_pm_self_suspend(pm_api_arg[0],
> +					     pm_api_arg[1] ? pm_api_arg[1] :
> +					     ZYNQMP_PM_MAX_LATENCY, 0);
> +		break;
> +	case FORCE_POWERDOWN:
> +		ret = eemi_ops->force_powerdown(pm_api_arg[0],
> +						pm_api_arg[1] ? pm_api_arg[1] :
> +						ZYNQMP_PM_REQUEST_ACK_NO);
> +		break;
> +	case ABORT_SUSPEND:
> +		ret = zynqmp_pm_abort_suspend(pm_api_arg[0] ? pm_api_arg[0] :
> +					      ZYNQMP_PM_ABORT_REASON_UNKNOWN);
> +		break;
> +	case REQUEST_WAKEUP:
> +		ret = eemi_ops->request_wakeup(pm_api_arg[0],
> +					       pm_api_arg[1], pm_api_arg[2],
> +					       pm_api_arg[3] ? pm_api_arg[3] :
> +					       ZYNQMP_PM_REQUEST_ACK_NO);
> +		break;
> +	case SET_WAKEUP_SOURCE:
> +		ret = eemi_ops->set_wakeup_source(pm_api_arg[0], pm_api_arg[1],
> +						  pm_api_arg[2]);
> +		break;
> +	case SYSTEM_SHUTDOWN:
> +		ret = eemi_ops->system_shutdown(pm_api_arg[0], pm_api_arg[1]);
> +		break;
> +	case REQUEST_NODE:
> +		ret = eemi_ops->request_node(pm_api_arg[0],
> +					     pm_api_arg[1] ? pm_api_arg[1] :
> +					     ZYNQMP_PM_CAPABILITY_ACCESS,
> +					     pm_api_arg[2] ? pm_api_arg[2] : 0,
> +					     pm_api_arg[3] ? pm_api_arg[3] :
> +					     ZYNQMP_PM_REQUEST_ACK_BLOCKING);
> +		break;
> +	case RELEASE_NODE:
> +		ret = eemi_ops->release_node(pm_api_arg[0]);
> +		break;
> +	case SET_REQUIREMENT:
> +		ret = eemi_ops->set_requirement(pm_api_arg[0],
> +						pm_api_arg[1] ? pm_api_arg[1] :
> +						ZYNQMP_PM_CAPABILITY_CONTEXT,
> +						pm_api_arg[2] ?
> +						pm_api_arg[2] : 0,
> +						pm_api_arg[3] ? pm_api_arg[3] :
> +						ZYNQMP_PM_REQUEST_ACK_BLOCKING);
> +		break;
> +	case SET_MAX_LATENCY:
> +		ret = eemi_ops->set_max_latency(pm_api_arg[0],
> +						pm_api_arg[1] ? pm_api_arg[1] :
> +						ZYNQMP_PM_MAX_LATENCY);
> +		break;
> +	case SET_CONFIGURATION:
> +		ret = eemi_ops->set_configuration(pm_api_arg[0]);
> +		break;
> +	case GET_NODE_STATUS:
> +		ret = eemi_ops->get_node_status(pm_api_arg[0],
> +						&pm_api_ret[0],
> +						&pm_api_ret[1],
> +						&pm_api_ret[2]);
> +		if (!ret)
> +			pr_info("GET_NODE_STATUS:\n\tNodeId: %llu\n\tStatus: %u\n\tRequirements: %u\n\tUsage: %u\n",
> +				pm_api_arg[0], pm_api_ret[0],
> +				pm_api_ret[1], pm_api_ret[2]);
> +		break;
> +	case GET_OPERATING_CHARACTERISTIC:
> +		ret = eemi_ops->get_operating_characteristic(pm_api_arg[0],
> +				pm_api_arg[1] ? pm_api_arg[1] :
> +				ZYNQMP_PM_OPERATING_CHARACTERISTIC_POWER,
> +				&pm_api_ret[0]);
> +		if (!ret)
> +			pr_info("GET_OPERATING_CHARACTERISTIC:\n\tNodeId: %llu\n\tType: %llu\n\tResult: %u\n",
> +				pm_api_arg[0], pm_api_arg[1], pm_api_ret[0]);
> +		break;
> +	case REGISTER_NOTIFIER:
> +		ret = zynqmp_pm_register_notifier(pm_api_arg[0],
> +						  pm_api_arg[1] ?
> +						  pm_api_arg[1] : 0,
> +						  pm_api_arg[2] ?
> +						  pm_api_arg[2] : 0,
> +						  pm_api_arg[3] ?
> +						  pm_api_arg[3] : 0);
> +		break;
> +	case RESET_ASSERT:
> +		ret = eemi_ops->reset_assert(pm_api_arg[0], pm_api_arg[1]);
> +		break;
> +	case RESET_GET_STATUS:
> +		ret = eemi_ops->reset_get_status(pm_api_arg[0], &pm_api_ret[0]);
> +		pr_info("%s Reset status: %u\n", __func__, pm_api_ret[0]);
> +		break;
> +	case GET_CHIPID:
> +		ret = eemi_ops->get_chipid(&pm_api_ret[0], &pm_api_ret[1]);
> +		pr_info("%s idcode: %#x, version:%#x\n",
> +			__func__, pm_api_ret[0], pm_api_ret[1]);
> +		break;
> +	case PINCTRL_GET_FUNCTION:
> +		ret = eemi_ops->pinctrl_get_function(pm_api_arg[0],
> +						     &pm_api_ret[0]);
> +		pr_info("%s Current set function for the pin: %u\n",
> +			__func__, pm_api_ret[0]);
> +		break;
> +	case PINCTRL_SET_FUNCTION:
> +		ret = eemi_ops->pinctrl_set_function(pm_api_arg[0],
> +						     pm_api_arg[1]);
> +		break;
> +	case PINCTRL_CONFIG_PARAM_GET:
> +		ret = eemi_ops->pinctrl_get_config(pm_api_arg[0], pm_api_arg[1],
> +						   &pm_api_ret[0]);
> +		pr_info("%s pin: %llu, param: %llu, value: %u\n",
> +			__func__, pm_api_arg[0], pm_api_arg[1],
> +			pm_api_ret[0]);
> +		break;
> +	case PINCTRL_CONFIG_PARAM_SET:
> +		ret = eemi_ops->pinctrl_set_config(pm_api_arg[0],
> +						   pm_api_arg[1],
> +						   pm_api_arg[2]);
> +		break;
> +	case IOCTL:
> +		ret = eemi_ops->ioctl(pm_api_arg[0], pm_api_arg[1],
> +				      pm_api_arg[2], pm_api_arg[3],
> +				      &pm_api_ret[0]);
> +		if (pm_api_arg[1] == IOCTL_GET_RPU_OPER_MODE ||
> +		    pm_api_arg[1] == IOCTL_GET_PLL_FRAC_MODE ||
> +		    pm_api_arg[1] == IOCTL_GET_PLL_FRAC_DATA ||
> +		    pm_api_arg[1] == IOCTL_READ_GGS ||
> +		    pm_api_arg[1] == IOCTL_READ_PGGS)
> +			pr_info("%s Value: %u\n",
> +				__func__, pm_api_ret[1]);
> +		break;
> +	case CLOCK_ENABLE:
> +		ret = eemi_ops->clock_enable(pm_api_arg[0]);
> +		break;
> +	case CLOCK_DISABLE:
> +		ret = eemi_ops->clock_disable(pm_api_arg[0]);
> +		break;
> +	case CLOCK_GETSTATE:
> +		ret = eemi_ops->clock_getstate(pm_api_arg[0], &pm_api_ret[0]);
> +		pr_info("%s state: %u\n", __func__, pm_api_ret[0]);
> +		break;
> +	case CLOCK_SETDIVIDER:
> +		ret = eemi_ops->clock_setdivider(pm_api_arg[0], pm_api_arg[1]);
> +		break;
> +	case CLOCK_GETDIVIDER:
> +		ret = eemi_ops->clock_getdivider(pm_api_arg[0], &pm_api_ret[0]);
> +		pr_info("%s Divider Value: %d\n", __func__, pm_api_ret[0]);
> +		break;
> +	case CLOCK_SETRATE:
> +		ret = eemi_ops->clock_setrate(pm_api_arg[0], pm_api_arg[1]);
> +		break;
> +	case CLOCK_GETRATE:
> +		ret = eemi_ops->clock_getrate(pm_api_arg[0], &pm_api_ret[0]);
> +		pr_info("%s Rate Value: %u\n", __func__, pm_api_ret[0]);
> +		break;
> +	case CLOCK_SETPARENT:
> +		ret = eemi_ops->clock_setparent(pm_api_arg[0], pm_api_arg[1]);
> +		break;
> +	case CLOCK_GETPARENT:
> +		ret = eemi_ops->clock_getparent(pm_api_arg[0], &pm_api_ret[0]);
> +		pr_info("%s Parent Index: %u\n", __func__, pm_api_ret[0]);
> +		break;
> +	case QUERY_DATA:
> +	{
> +		struct zynqmp_pm_query_data qdata = {0};
> +
> +		qdata.qid = pm_api_arg[0];
> +		qdata.arg1 = pm_api_arg[1];
> +		qdata.arg2 = pm_api_arg[2];
> +		qdata.arg3 = pm_api_arg[3];
> +
> +		ret = eemi_ops->query_data(qdata, pm_api_ret);
> +
> +		pr_info("%s: data[0] = 0x%08x\n", __func__, pm_api_ret[0]);
> +		pr_info("%s: data[1] = 0x%08x\n", __func__, pm_api_ret[1]);
> +		pr_info("%s: data[2] = 0x%08x\n", __func__, pm_api_ret[2]);
> +		pr_info("%s: data[3] = 0x%08x\n", __func__, pm_api_ret[3]);
> +		break;
> +	}
> +	default:
> +		pr_err("%s Unsupported PM-API request\n", __func__);
> +		ret = -EINVAL;
> +	}
> +
> +err:
> +	kfree(tmp_buff);
> +	if (ret)
> +		return ret;
> +
> +	return len;
> +}
> +
> +/**
> + * zynqmp_pm_debugfs_api_version_read - debugfs read function
> + * @file:	User file structure
> + * @ptr:	Requested pm_api_version string
> + * @len:	Length of the userspace buffer
> + * @off:	Offset within the file
> + *
> + * Return:	Length of the version string on success
> + *		-EFAULT otherwise
> + *
> + * Used to display the pm api version.
> + * cat /sys/kernel/debug/zynqmp_pm/pm_api_version
> + */
> +static ssize_t zynqmp_pm_debugfs_api_version_read(struct file *file,
> +						  char __user *ptr, size_t len,
> +						  loff_t *off)
> +{
> +	char *kern_buff;
> +	int ret;
> +	int kern_buff_len;
> +	u32 pm_api_version;
> +	const struct zynqmp_eemi_ops *eemi_ops = get_eemi_ops();
> +
> +	if (!eemi_ops || !eemi_ops->get_api_version)
> +		return -ENXIO;
> +
> +	if (len <= 0)
> +		return -EINVAL;
> +
> +	if (*off != 0)
> +		return 0;
> +
> +	kern_buff = kzalloc(len, GFP_KERNEL);
> +	if (!kern_buff)
> +		return -ENOMEM;
> +
> +	eemi_ops->get_api_version(&pm_api_version);
> +	sprintf(kern_buff, "PM-API Version = %d.%d\n",
> +		pm_api_version >> 16, pm_api_version & 0xffff);
> +	kern_buff_len = strlen(kern_buff) + 1;
> +
> +	if (len > kern_buff_len)
> +		len = kern_buff_len;
> +	ret = copy_to_user(ptr, kern_buff, len);
> +
> +	kfree(kern_buff);
> +	if (ret)
> +		return -EFAULT;
> +
> +	*off = len + 1;
> +
> +	return len;
> +}
> +
> +/* Setup debugfs fops */
> +static const struct file_operations fops_zynqmp_pm_dbgfs = {
> +	.owner  =	THIS_MODULE,
> +	.write  =	zynqmp_pm_debugfs_api_write,
> +	.read   =	zynqmp_pm_debugfs_api_version_read,
> +};
> +
> +/**
> + * zynqmp_pm_api_debugfs_init - Initialize debugfs interface
> + *
> + * Return:      Returns 0 on success
> + *		Corresponding error code otherwise
> + */
> +int zynqmp_pm_api_debugfs_init(void)
> +{
> +	int err;
> +
> +	/* Initialize debugfs interface */
> +	zynqmp_pm_debugfs_dir = debugfs_create_dir(DRIVER_NAME, NULL);
> +	if (!zynqmp_pm_debugfs_dir) {
> +		pr_err("debugfs_create_dir failed\n");
> +		return -ENODEV;
> +	}
> +
> +	zynqmp_pm_debugfs_power =
> +		debugfs_create_file("pm", 0220,
> +				    zynqmp_pm_debugfs_dir, NULL,
> +				    &fops_zynqmp_pm_dbgfs);
> +	if (!zynqmp_pm_debugfs_power) {
> +		pr_err("debugfs_create_file power failed\n");
> +		err = -ENODEV;
> +		goto err_dbgfs;
> +	}
> +
> +	zynqmp_pm_debugfs_api_version =
> +		debugfs_create_file("api_version", 0444,
> +				    zynqmp_pm_debugfs_dir, NULL,
> +				    &fops_zynqmp_pm_dbgfs);
> +	if (!zynqmp_pm_debugfs_api_version) {
> +		pr_err("debugfs_create_file api_version failed\n");
> +		err = -ENODEV;
> +		goto err_dbgfs;
> +	}
> +
> +	return 0;
> +
> +err_dbgfs:
> +	debugfs_remove_recursive(zynqmp_pm_debugfs_dir);
> +	zynqmp_pm_debugfs_dir = NULL;
> +
> +	return err;
> +}
> diff --git a/drivers/firmware/xilinx/zynqmp/firmware-ggs.c b/drivers/firmware/xilinx/zynqmp/firmware-ggs.c
> new file mode 100644
> index 0000000..feb6148
> --- /dev/null
> +++ b/drivers/firmware/xilinx/zynqmp/firmware-ggs.c
> @@ -0,0 +1,298 @@
> +/*
> + * Xilinx Zynq MPSoC Firmware layer
> + *
> + *  Copyright (C) 2014-2017 Xilinx, Inc.
> + *
> + *  Rajan Vaja <rajanv@xilinx.com>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include <linux/compiler.h>
> +#include <linux/of.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/uaccess.h>
> +#include <linux/slab.h>
> +#include <linux/platform_device.h>
> +
> +#include <linux/firmware/xilinx/zynqmp/firmware.h>
> +
> +static ssize_t read_register(char *buf, u32 ioctl_id, u32 reg)
> +{
> +	int ret;
> +	u32 ret_payload[PAYLOAD_ARG_CNT];
> +	const struct zynqmp_eemi_ops *eemi_ops = get_eemi_ops();
> +
> +	if (!eemi_ops || !eemi_ops->ioctl)
> +		return 0;
> +
> +	ret = eemi_ops->ioctl(0, ioctl_id, reg, 0, ret_payload);
> +	if (ret)
> +		return ret;
> +
> +	return snprintf(buf, PAGE_SIZE, "0x%x\n", ret_payload[1]);
> +}
> +
> +static ssize_t write_register(const char *buf, size_t count,
> +			      u32 ioctl_id, u32 reg)
> +{
> +	char *kern_buff;
> +	char *inbuf;
> +	char *tok;
> +	long mask;
> +	long value;
> +	int ret;
> +	u32 ret_payload[PAYLOAD_ARG_CNT];
> +	const struct zynqmp_eemi_ops *eemi_ops = get_eemi_ops();
> +
> +	if (!eemi_ops || !eemi_ops->ioctl)
> +		return -EFAULT;
> +
> +	kern_buff = kzalloc(count, GFP_KERNEL);
> +	if (!kern_buff)
> +		return -ENOMEM;
> +
> +	ret = strlcpy(kern_buff, buf, count);
> +	if (ret < 0) {
> +		ret = -EFAULT;
> +		goto err;
> +	}
> +
> +	inbuf = kern_buff;
> +
> +	/* Read the write mask */
> +	tok = strsep(&inbuf, " ");
> +	if (!tok) {
> +		ret = -EFAULT;
> +		goto err;
> +	}
> +
> +	ret = kstrtol(tok, 16, &mask);
> +	if (ret) {
> +		ret = -EFAULT;
> +		goto err;
> +	}
> +
> +	/* Read the write value */
> +	tok = strsep(&inbuf, " ");
> +	if (!tok) {
> +		ret = -EFAULT;
> +		goto err;
> +	}
> +
> +	ret = kstrtol(tok, 16, &value);
> +	if (ret) {
> +		ret = -EFAULT;
> +		goto err;
> +	}
> +
> +	ret = eemi_ops->ioctl(0, ioctl_id, reg, 0, ret_payload);
> +	if (ret) {
> +		ret = -EFAULT;
> +		goto err;
> +	}
> +	ret_payload[1] &= ~mask;
> +	value &= mask;
> +	value |= ret_payload[1];
> +
> +	ret = eemi_ops->ioctl(0, ioctl_id, reg, value, NULL);
> +	if (ret)
> +		ret = -EFAULT;
> +
> +err:
> +	kfree(kern_buff);
> +	if (ret)
> +		return ret;
> +
> +	return count;
> +}
> +
> +/**
> + * ggs_show - Show global general storage (ggs) sysfs attribute
> + * @dev: Device structure
> + * @attr: Device attribute structure
> + * @buf: Requested available shutdown_scope attributes string
> + * @reg: Register number
> + *
> + * Return:Number of bytes printed into the buffer.
> + *
> + * Helper function for viewing a ggs register value.
> + *
> + * User-space interface for viewing the content of the ggs0 register.
> + * cat /sys/devices/platform/firmware/ggs0
> + */
> +static ssize_t ggs_show(struct device *dev,
> +			struct device_attribute *attr,
> +			char *buf,
> +			u32 reg)
> +{
> +	return read_register(buf, IOCTL_READ_GGS, reg);
> +}
> +
> +/**
> + * ggs_store - Store global general storage (ggs) sysfs attribute
> + * @dev: Device structure
> + * @attr: Device attribute structure
> + * @buf: User entered shutdown_scope attribute string
> + * @count: Size of buf
> + * @reg: Register number
> + *
> + * Return: count argument if request succeeds, the corresponding
> + * error code otherwise
> + *
> + * Helper function for storing a ggs register value.
> + *
> + * For example, the user-space interface for storing a value to the
> + * ggs0 register:
> + * echo 0xFFFFFFFF 0x1234ABCD > /sys/devices/platform/firmware/ggs0
> + */
> +static ssize_t ggs_store(struct device *dev,
> +			 struct device_attribute *attr,
> +			 const char *buf,
> +			 size_t count,
> +			 u32 reg)
> +{
> +	if (!dev || !attr || !buf || !count || reg >= GSS_NUM_REGS)
> +		return -EINVAL;
> +
> +	return write_register(buf, count, IOCTL_WRITE_GGS, reg);
> +}
> +
> +/* GGS register show functions */
> +#define GGS0_SHOW(N) \
> +	ssize_t ggs##N##_show(struct device *dev, \
> +			 struct device_attribute *attr, \
> +			 char *buf) \
> +	{ \
> +		return ggs_show(dev, attr, buf, N); \
> +	}
> +
> +static GGS0_SHOW(0);
> +static GGS0_SHOW(1);
> +static GGS0_SHOW(2);
> +static GGS0_SHOW(3);
> +
> +/* GGS register store function */
> +#define GGS0_STORE(N) \
> +	ssize_t ggs##N##_store(struct device *dev, \
> +				   struct device_attribute *attr, \
> +				   const char *buf, \
> +				   size_t count) \
> +	{ \
> +		return ggs_store(dev, attr, buf, count, N); \
> +	}
> +
> +static GGS0_STORE(0);
> +static GGS0_STORE(1);
> +static GGS0_STORE(2);
> +static GGS0_STORE(3);
> +
> +/* GGS register device attributes */
> +static DEVICE_ATTR_RW(ggs0);
> +static DEVICE_ATTR_RW(ggs1);
> +static DEVICE_ATTR_RW(ggs2);
> +static DEVICE_ATTR_RW(ggs3);

Hi

You added some files to the sysfs ABI. These interfaces should be documented in
Documentation/ABI.

> +
> +#define CREATE_GGS_DEVICE(dev, N) \
> +do { \
> +	if (device_create_file(dev, &dev_attr_ggs##N)) \
> +		dev_err(dev, "unable to create ggs%d attribute\n", N); \
> +} while (0)
> +
> +/**
> + * pggs_show - Show persistent global general storage (pggs) sysfs attribute
> + * @dev: Device structure
> + * @attr: Device attribute structure
> + * @buf: Requested available shutdown_scope attributes string
> + * @reg: Register number
> + *
> + * Return:Number of bytes printed into the buffer.
> + *
> + * Helper function for viewing a pggs register value.
> + */
> +static ssize_t pggs_show(struct device *dev,
> +			 struct device_attribute *attr,
> +			 char *buf,
> +			 u32 reg)
> +{
> +	return read_register(buf, IOCTL_READ_GGS, reg);
> +}
> +
> +/**
> + * pggs_store - Store persistent global general storage (pggs) sysfs attribute
> + * @dev: Device structure
> + * @attr: Device attribute structure
> + * @buf: User entered shutdown_scope attribute string
> + * @count: Size of buf
> + * @reg: Register number
> + *
> + * Return: count argument if request succeeds, the corresponding
> + * error code otherwise
> + *
> + * Helper function for storing a pggs register value.
> + */
> +static ssize_t pggs_store(struct device *dev,
> +			  struct device_attribute *attr,
> +			  const char *buf,
> +			  size_t count,
> +			  u32 reg)
> +{
> +	return write_register(buf, count, IOCTL_WRITE_PGGS, reg);
> +}
> +
> +#define PGGS0_SHOW(N) \
> +	ssize_t pggs##N##_show(struct device *dev, \
> +			 struct device_attribute *attr, \
> +			 char *buf) \
> +	{ \
> +		return pggs_show(dev, attr, buf, N); \
> +	}
> +
> +/* PGGS register show functions */
> +static PGGS0_SHOW(0);
> +static PGGS0_SHOW(1);
> +static PGGS0_SHOW(2);
> +static PGGS0_SHOW(3);
> +
> +#define PGGS0_STORE(N) \
> +	ssize_t pggs##N##_store(struct device *dev, \
> +				   struct device_attribute *attr, \
> +				   const char *buf, \
> +				   size_t count) \
> +	{ \
> +		return pggs_store(dev, attr, buf, count, N); \
> +	}
> +
> +/* PGGS register store functions */
> +static PGGS0_STORE(0);
> +static PGGS0_STORE(1);
> +static PGGS0_STORE(2);
> +static PGGS0_STORE(3);
> +
> +/* PGGS register device attributes */
> +static DEVICE_ATTR_RW(pggs0);
> +static DEVICE_ATTR_RW(pggs1);
> +static DEVICE_ATTR_RW(pggs2);
> +static DEVICE_ATTR_RW(pggs3);
> +
> +#define CREATE_PGGS_DEVICE(dev, N) \
> +do { \
> +	if (device_create_file(dev, &dev_attr_pggs##N)) \
> +		dev_err(dev, "unable to create pggs%d attribute\n", N); \
> +} while (0)
> +
> +void zynqmp_pm_ggs_init(struct device *dev)
> +{
> +	/* Create Global General Storage register. */
> +	CREATE_GGS_DEVICE(dev, 0);
> +	CREATE_GGS_DEVICE(dev, 1);
> +	CREATE_GGS_DEVICE(dev, 2);
> +	CREATE_GGS_DEVICE(dev, 3);
> +
> +	/* Create Persistent Global General Storage register. */
> +	CREATE_PGGS_DEVICE(dev, 0);
> +	CREATE_PGGS_DEVICE(dev, 1);
> +	CREATE_PGGS_DEVICE(dev, 2);
> +	CREATE_PGGS_DEVICE(dev, 3);
> +}
> diff --git a/drivers/firmware/xilinx/zynqmp/firmware.c b/drivers/firmware/xilinx/zynqmp/firmware.c
> new file mode 100644
> index 0000000..edce5eb
> --- /dev/null
> +++ b/drivers/firmware/xilinx/zynqmp/firmware.c
> @@ -0,0 +1,1024 @@
> +/*
> + * Xilinx Zynq MPSoC Firmware layer
> + *
> + *  Copyright (C) 2014-2017 Xilinx, Inc.
> + *
> + *  Michal Simek <michal.simek@xilinx.com>
> + *  Davorin Mista <davorin.mista@aggios.com>
> + *  Jolly Shah <jollys@xilinx.com>
> + *  Rajan Vaja <rajanv@xilinx.com>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include <linux/compiler.h>
> +#include <linux/arm-smccc.h>
> +#include <linux/of.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/interrupt.h>
> +#include <linux/uaccess.h>
> +#include <linux/pinctrl/consumer.h>
> +#include <linux/platform_device.h>
> +
> +#include <linux/firmware/xilinx/zynqmp/firmware.h>
> +#include <linux/firmware/xilinx/zynqmp/firmware-debug.h>
> +
> +#define DRIVER_NAME	"zynqmp_firmware"
> +
> +/**
> + * zynqmp_pm_ret_code - Convert PMU-FW error codes to Linux error codes
> + * @ret_status:		PMUFW return code
> + *
> + * Return:		corresponding Linux error code
> + */
> +int zynqmp_pm_ret_code(u32 ret_status)
> +{
> +	switch (ret_status) {
> +	case XST_PM_SUCCESS:
> +	case XST_PM_DOUBLE_REQ:
> +		return 0;
> +	case XST_PM_NO_ACCESS:
> +		return -EACCES;
> +	case XST_PM_ABORT_SUSPEND:
> +		return -ECANCELED;
> +	case XST_PM_INTERNAL:
> +	case XST_PM_CONFLICT:
> +	case XST_PM_INVALID_NODE:
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static noinline int do_fw_call_fail(u64 arg0, u64 arg1, u64 arg2,
> +				    u32 *ret_payload)
> +{
> +	return -ENODEV;
> +}
> +
> +/*
> + * PM function call wrapper
> + * Invoke do_fw_call_smc or do_fw_call_hvc, depending on the configuration
> + */
> +static int (*do_fw_call)(u64, u64, u64, u32 *ret_payload) = do_fw_call_fail;
> +
> +/**
> + * do_fw_call_smc - Call system-level power management layer (SMC)
> + * @arg0:		Argument 0 to SMC call
> + * @arg1:		Argument 1 to SMC call
> + * @arg2:		Argument 2 to SMC call
> + * @ret_payload:	Returned value array
> + *
> + * Return:		Returns status, either success or error+reason
> + *
> + * Invoke power management function via SMC call (no hypervisor present)
> + */
> +static noinline int do_fw_call_smc(u64 arg0, u64 arg1, u64 arg2,
> +				   u32 *ret_payload)
> +{
> +	struct arm_smccc_res res;
> +
> +	arm_smccc_smc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res);
> +
> +	if (ret_payload) {
> +		ret_payload[0] = lower_32_bits(res.a0);
> +		ret_payload[1] = upper_32_bits(res.a0);
> +		ret_payload[2] = lower_32_bits(res.a1);
> +		ret_payload[3] = upper_32_bits(res.a1);
> +		ret_payload[4] = lower_32_bits(res.a2);
> +	}
> +
> +	return zynqmp_pm_ret_code((enum pm_ret_status)res.a0);
> +}
> +
> +/**
> + * do_fw_call_hvc - Call system-level power management layer (HVC)
> + * @arg0:		Argument 0 to HVC call
> + * @arg1:		Argument 1 to HVC call
> + * @arg2:		Argument 2 to HVC call
> + * @ret_payload:	Returned value array
> + *
> + * Return:		Returns status, either success or error+reason
> + *
> + * Invoke power management function via HVC
> + * HVC-based for communication through hypervisor
> + * (no direct communication with ATF)
> + */
> +static noinline int do_fw_call_hvc(u64 arg0, u64 arg1, u64 arg2,
> +				   u32 *ret_payload)
> +{
> +	struct arm_smccc_res res;
> +
> +	arm_smccc_hvc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res);
> +
> +	if (ret_payload) {
> +		ret_payload[0] = lower_32_bits(res.a0);
> +		ret_payload[1] = upper_32_bits(res.a0);
> +		ret_payload[2] = lower_32_bits(res.a1);
> +		ret_payload[3] = upper_32_bits(res.a1);
> +		ret_payload[4] = lower_32_bits(res.a2);
> +	}
> +
> +	return zynqmp_pm_ret_code((enum pm_ret_status)res.a0);
> +}
> +
> +/**
> + * invoke_pm_fn - Invoke the system-level power management layer caller
> + *			function depending on the configuration
> + * @pm_api_id:         Requested PM-API call
> + * @arg0:              Argument 0 to requested PM-API call
> + * @arg1:              Argument 1 to requested PM-API call
> + * @arg2:              Argument 2 to requested PM-API call
> + * @arg3:              Argument 3 to requested PM-API call
> + * @ret_payload:       Returned value array
> + *
> + * Return:             Returns status, either success or error+reason
> + *
> + * Invoke power management function for SMC or HVC call, depending on
> + * configuration
> + * Following SMC Calling Convention (SMCCC) for SMC64:
> + * Pm Function Identifier,
> + * PM_SIP_SVC + PM_API_ID =
> + *     ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT)
> + *     ((SMC_64) << FUNCID_CC_SHIFT)
> + *     ((SIP_START) << FUNCID_OEN_SHIFT)
> + *     ((PM_API_ID) & FUNCID_NUM_MASK))
> + *
> + * PM_SIP_SVC  - Registered ZynqMP SIP Service Call
> + * PM_API_ID   - Power Management API ID
> + */
> +int invoke_pm_fn(u32 pm_api_id, u32 arg0, u32 arg1, u32 arg2, u32 arg3,
> +		 u32 *ret_payload)
> +{
> +	/*
> +	 * Added SIP service call Function Identifier
> +	 * Make sure to stay in x0 register
> +	 */
> +	u64 smc_arg[4];
> +
> +	smc_arg[0] = PM_SIP_SVC | pm_api_id;
> +	smc_arg[1] = ((u64)arg1 << 32) | arg0;
> +	smc_arg[2] = ((u64)arg3 << 32) | arg2;
> +
> +	return do_fw_call(smc_arg[0], smc_arg[1], smc_arg[2], ret_payload);
> +}
> +
> +static u32 pm_api_version;
> +
> +/**
> + * zynqmp_pm_get_api_version - Get version number of PMU PM firmware
> + * @version:	Returned version value
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_get_api_version(u32 *version)
> +{
> +	u32 ret_payload[PAYLOAD_ARG_CNT];
> +
> +	if (!version)
> +		return zynqmp_pm_ret_code(XST_PM_CONFLICT);
> +
> +	/* Check is PM API version already verified */
> +	if (pm_api_version > 0) {
> +		*version = pm_api_version;
> +		return XST_PM_SUCCESS;
> +	}
> +	invoke_pm_fn(GET_API_VERSION, 0, 0, 0, 0, ret_payload);
> +	*version = ret_payload[1];
> +
> +	return zynqmp_pm_ret_code((enum pm_ret_status)ret_payload[0]);
> +}
> +
> +/**
> + * zynqmp_pm_get_chipid - Get silicon ID registers
> + * @idcode:	IDCODE register
> + * @version:	version register
> + *
> + * Return:	Returns the status of the operation and the idcode and version
> + *		registers in @idcode and @version.
> + */
> +static int zynqmp_pm_get_chipid(u32 *idcode, u32 *version)
> +{
> +	u32 ret_payload[PAYLOAD_ARG_CNT];
> +
> +	if (!idcode || !version)
> +		return -EINVAL;
> +
> +	invoke_pm_fn(GET_CHIPID, 0, 0, 0, 0, ret_payload);
> +	*idcode = ret_payload[1];
> +	*version = ret_payload[2];
> +
> +	return zynqmp_pm_ret_code((enum pm_ret_status)ret_payload[0]);
> +}
> +
> +/**
> + * get_set_conduit_method - Choose SMC or HVC based communication
> + * @np:	Pointer to the device_node structure
> + *
> + * Use SMC or HVC-based functions to communicate with EL2/EL3
> + */
> +static int get_set_conduit_method(struct device_node *np)
> +{
> +	const char *method;
> +
> +	if (of_property_read_string(np, "method", &method)) {
> +		pr_warn("%s missing \"method\" property\n", __func__);
> +		return -ENXIO;
> +	}
> +
> +	if (!strcmp("hvc", method)) {
> +		do_fw_call = do_fw_call_hvc;
> +	} else if (!strcmp("smc", method)) {
> +		do_fw_call = do_fw_call_smc;
> +	} else {
> +		pr_warn("%s Invalid \"method\" property: %s\n",
> +			__func__, method);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * zynqmp_pm_reset_assert - Request setting of reset (1 - assert, 0 - release)
> + * @reset:		Reset to be configured
> + * @assert_flag:	Flag stating should reset be asserted (1) or
> + *			released (0)
> + *
> + * Return:		Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_reset_assert(const enum zynqmp_pm_reset reset,
> +			   const enum zynqmp_pm_reset_action assert_flag)
> +{
> +	return invoke_pm_fn(RESET_ASSERT, reset, assert_flag, 0, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_reset_get_status - Get status of the reset
> + * @reset:	Reset whose status should be returned
> + * @status:	Returned status
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset,
> +				      u32 *status)
> +{
> +	u32 ret_payload[PAYLOAD_ARG_CNT];
> +
> +	if (!status)
> +		return zynqmp_pm_ret_code(XST_PM_CONFLICT);
> +
> +	invoke_pm_fn(RESET_GET_STATUS, reset, 0, 0, 0, ret_payload);
> +	*status = ret_payload[1];
> +
> +	return zynqmp_pm_ret_code((enum pm_ret_status)ret_payload[0]);
> +}
> +
> +/**
> + * zynqmp_pm_fpga_load - Perform the fpga load
> + * @address:    Address to write to
> + * @size:       pl bitstream size
> + * @flags:
> + *	BIT(0) - Bit-stream type.
> + *		 0 - Full Bit-stream.
> + *		 1 - Partial Bit-stream.
> + *	BIT(1) - Authentication.
> + *		 1 - Enable.
> + *		 0 - Disable.
> + *	BIT(2) - Encryption.
> + *		 1 - Enable.
> + *		 0 - Disable.
> + * NOTE -
> + *	The current implementation supports only Full Bit-stream.
> + *
> + * This function provides access to xilfpga library to transfer
> + * the required bitstream into PL.
> + *
> + * Return:      Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_fpga_load(const u64 address, const u32 size,
> +			       const u32 flags)
> +{
> +	return invoke_pm_fn(FPGA_LOAD, (u32)address,
> +			    ((u32)(address >> 32)), size, flags, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_fpga_get_status - Read value from PCAP status register
> + * @value:      Value to read
> + *
> + *This function provides access to the xilfpga library to get
> + *the PCAP status
> + *
> + * Return:      Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_fpga_get_status(u32 *value)
> +{
> +	u32 ret_payload[PAYLOAD_ARG_CNT];
> +
> +	if (!value)
> +		return -EINVAL;
> +
> +	invoke_pm_fn(FPGA_GET_STATUS, 0, 0, 0, 0, ret_payload);
> +	*value = ret_payload[1];
> +
> +	return zynqmp_pm_ret_code((enum pm_ret_status)ret_payload[0]);
> +}
> +
> +/**
> + * zynqmp_pm_request_suspend - PM call to request for another PU or subsystem to
> + *					be suspended gracefully.
> + * @node:	Node ID of the targeted PU or subsystem
> + * @ack:	Flag to specify whether acknowledge is requested
> + * @latency:	Requested wakeup latency (not supported)
> + * @state:	Requested state (not supported)
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_request_suspend(const u32 node,
> +			      const enum zynqmp_pm_request_ack ack,
> +			      const u32 latency,
> +			      const u32 state)
> +{
> +	return invoke_pm_fn(REQUEST_SUSPEND, node, ack,
> +			    latency, state, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_force_powerdown - PM call to request for another PU or subsystem to
> + *				be powered down forcefully
> + * @target:	Node ID of the targeted PU or subsystem
> + * @ack:	Flag to specify whether acknowledge is requested
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_force_powerdown(const u32 target,
> +				     const enum zynqmp_pm_request_ack ack)
> +{
> +	return invoke_pm_fn(FORCE_POWERDOWN, target, ack, 0, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_request_wakeup - PM call to wake up selected master or subsystem
> + * @node:	Node ID of the master or subsystem
> + * @set_addr:	Specifies whether the address argument is relevant
> + * @address:	Address from which to resume when woken up
> + * @ack:	Flag to specify whether acknowledge requested
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_request_wakeup(const u32 node,
> +				    const bool set_addr,
> +				    const u64 address,
> +				    const enum zynqmp_pm_request_ack ack)
> +{
> +	/* set_addr flag is encoded into 1st bit of address */
> +	return invoke_pm_fn(REQUEST_WAKEUP, node, address | set_addr,
> +			    address >> 32, ack, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_set_wakeup_source - PM call to specify the wakeup source
> + *					while suspended
> + * @target:	Node ID of the targeted PU or subsystem
> + * @wakeup_node:Node ID of the wakeup peripheral
> + * @enable:	Enable or disable the specified peripheral as wake source
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_set_wakeup_source(const u32 target,
> +				       const u32 wakeup_node,
> +				       const u32 enable)
> +{
> +	return invoke_pm_fn(SET_WAKEUP_SOURCE, target,
> +			    wakeup_node, enable, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_system_shutdown - PM call to request a system shutdown or restart
> + * @type:	Shutdown or restart? 0 for shutdown, 1 for restart
> + * @subtype:	Specifies which system should be restarted or shut down
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_system_shutdown(const u32 type, const u32 subtype)
> +{
> +	return invoke_pm_fn(SYSTEM_SHUTDOWN, type, subtype, 0, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_request_node - PM call to request a node with specific capabilities
> + * @node:		Node ID of the slave
> + * @capabilities:	Requested capabilities of the slave
> + * @qos:		Quality of service (not supported)
> + * @ack:		Flag to specify whether acknowledge is requested
> + *
> + * Return:		Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_request_node(const u32 node, const u32 capabilities,
> +				  const u32 qos,
> +				  const enum zynqmp_pm_request_ack ack)
> +{
> +	return invoke_pm_fn(REQUEST_NODE, node, capabilities,
> +			    qos, ack, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_release_node - PM call to release a node
> + * @node:	Node ID of the slave
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_release_node(const u32 node)
> +{
> +	return invoke_pm_fn(RELEASE_NODE, node, 0, 0, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_set_requirement - PM call to set requirement for PM slaves
> + * @node:		Node ID of the slave
> + * @capabilities:	Requested capabilities of the slave
> + * @qos:		Quality of service (not supported)
> + * @ack:		Flag to specify whether acknowledge is requested
> + *
> + * This API function is to be used for slaves a PU already has requested
> + *
> + * Return:		Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_set_requirement(const u32 node, const u32 capabilities,
> +				     const u32 qos,
> +				     const enum zynqmp_pm_request_ack ack)
> +{
> +	return invoke_pm_fn(SET_REQUIREMENT, node, capabilities,
> +			    qos, ack, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_set_max_latency - PM call to set wakeup latency requirements
> + * @node:	Node ID of the slave
> + * @latency:	Requested maximum wakeup latency
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_set_max_latency(const u32 node, const u32 latency)
> +{
> +	return invoke_pm_fn(SET_MAX_LATENCY, node, latency, 0, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_set_configuration - PM call to set system configuration
> + * @physical_addr:	Physical 32-bit address of data structure in memory
> + *
> + * Return:		Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_set_configuration(const u32 physical_addr)
> +{
> +	return invoke_pm_fn(SET_CONFIGURATION, physical_addr, 0, 0, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_get_node_status - PM call to request a node's current power state
> + * @node:		ID of the component or sub-system in question
> + * @status:		Current operating state of the requested node
> + * @requirements:	Current requirements asserted on the node,
> + *			used for slave nodes only.
> + * @usage:		Usage information, used for slave nodes only:
> + *			0 - No master is currently using the node
> + *			1 - Only requesting master is currently using the node
> + *			2 - Only other masters are currently using the node
> + *			3 - Both the current and at least one other master
> + *			is currently using the node
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_get_node_status(const u32 node, u32 *const status,
> +				     u32 *const requirements, u32 *const usage)
> +{
> +	u32 ret_payload[PAYLOAD_ARG_CNT];
> +
> +	if (!status)
> +		return -EINVAL;
> +
> +	invoke_pm_fn(GET_NODE_STATUS, node, 0, 0, 0, ret_payload);
> +	if (ret_payload[0] == XST_PM_SUCCESS) {
> +		*status = ret_payload[1];
> +		if (requirements)
> +			*requirements = ret_payload[2];
> +		if (usage)
> +			*usage = ret_payload[3];
> +	}
> +
> +	return zynqmp_pm_ret_code((enum pm_ret_status)ret_payload[0]);
> +}
> +
> +/**
> + * zynqmp_pm_get_operating_characteristic - PM call to request operating
> + *						characteristic information
> + * @node:	Node ID of the slave
> + * @type:	Type of the operating characteristic requested
> + * @result:	Used to return the requsted operating characteristic
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_get_operating_characteristic(const u32 node,
> +						const enum zynqmp_pm_opchar_type
> +						type, u32 *const result)
> +{
> +	u32 ret_payload[PAYLOAD_ARG_CNT];
> +
> +	if (!result)
> +		return -EINVAL;
> +
> +	invoke_pm_fn(GET_OPERATING_CHARACTERISTIC,
> +		     node, type, 0, 0, ret_payload);
> +	if (ret_payload[0] == XST_PM_SUCCESS)
> +		*result = ret_payload[1];
> +
> +	return zynqmp_pm_ret_code((enum pm_ret_status)ret_payload[0]);
> +}
> +
> +/**
> + * zynqmp_pm_init_finalize - PM call to informi firmware that the caller master
> + *				has initialized its own power management
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_init_finalize(void)
> +{
> +	return invoke_pm_fn(PM_INIT_FINALIZE, 0, 0, 0, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_get_callback_data - Get callback data from firmware
> + * @buf:	Buffer to store payload data
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_get_callback_data(u32 *buf)
> +{
> +	return invoke_pm_fn(GET_CALLBACK_DATA, 0, 0, 0, 0, buf);
> +}
> +
> +/**
> + * zynqmp_pm_set_suspend_mode	- Set system suspend mode
> + *
> + * @mode:	Mode to set for system suspend
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_set_suspend_mode(u32 mode)
> +{
> +	return invoke_pm_fn(SET_SUSPEND_MODE, mode, 0, 0, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_sha_hash - Access the SHA engine to calculate the hash
> + * @address:	Address of the data/ Address of output buffer where
> + *		hash should be stored.
> + * @size:	Size of the data.
> + * @flags:
> + *	BIT(0) - Sha3 init (Here address and size inputs can be NULL)
> + *	BIT(1) - Sha3 update (address should holds the )
> + *	BIT(2) - Sha3 final (address should hold the address of
> + *		 buffer to store hash)
> + *
> + * Return:	Returns status, either success or error code.
> + */
> +static int zynqmp_pm_sha_hash(const u64 address, const u32 size,
> +			      const u32 flags)
> +{
> +	u32 lower_32_bits = (u32)address;
> +	u32 upper_32_bits = (u32)(address >> 32);
> +
> +	return invoke_pm_fn(SECURE_SHA, upper_32_bits, lower_32_bits,
> +			    size, flags, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_rsa - Access RSA hardware to encrypt/decrypt the data with RSA.
> + * @address:	Address of the data
> + * @size:	Size of the data.
> + * @flags:
> + *		BIT(0) - Encryption/Decryption
> + *			 0 - RSA decryption with private key
> + *			 1 - RSA encryption with public key.
> + *
> + * Return:	Returns status, either success or error code.
> + */
> +static int zynqmp_pm_rsa(const u64 address, const u32 size, const u32 flags)
> +{
> +	u32 lower_32_bits = (u32)address;
> +	u32 upper_32_bits = (u32)(address >> 32);
> +
> +	return invoke_pm_fn(SECURE_RSA, upper_32_bits, lower_32_bits,
> +			    size, flags, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_pinctrl_request - Request Pin from firmware
> + * @pin:	Pin number to request
> + *
> + * This function requests pin from firmware.
> + *
> + * Return:	Returns status, either success or error+reason.
> + */
> +static int zynqmp_pm_pinctrl_request(const u32 pin)
> +{
> +	return invoke_pm_fn(PINCTRL_REQUEST, pin, 0, 0, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_pinctrl_release - Inform firmware that Pin control is released
> + * @pin:	Pin number to release
> + *
> + * This function release pin from firmware.
> + *
> + * Return:	Returns status, either success or error+reason.
> + */
> +static int zynqmp_pm_pinctrl_release(const u32 pin)
> +{
> +	return invoke_pm_fn(PINCTRL_RELEASE, pin, 0, 0, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_pinctrl_get_function() - Read function id set for the given pin
> + * @pin:	Pin number
> + * @node:	Buffer to store node ID matching current function
> + *
> + * This function provides the function currently set for the given pin.
> + *
> + * Return:	Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_pinctrl_get_function(const u32 pin, u32 *node)
> +{
> +	u32 ret_payload[PAYLOAD_ARG_CNT];
> +
> +	if (!node)
> +		return -EINVAL;
> +
> +	invoke_pm_fn(PINCTRL_GET_FUNCTION, pin, 0, 0, 0, ret_payload);
> +	*node = ret_payload[1];
> +
> +	return zynqmp_pm_ret_code((enum pm_ret_status)ret_payload[0]);
> +}
> +
> +/**
> + * zynqmp_pm_pinctrl_set_function - Set requested function for the pin
> + * @pin:	Pin number
> + * @node:	Node ID mapped with the requested function
> + *
> + * This function sets requested function for the given pin.
> + *
> + * Return:	Returns status, either success or error+reason.
> + */
> +static int zynqmp_pm_pinctrl_set_function(const u32 pin, const u32 node)
> +{
> +	return invoke_pm_fn(PINCTRL_SET_FUNCTION, pin, node, 0, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_pinctrl_get_config - Get configuration parameter for the pin
> + * @pin:	Pin number
> + * @param:	Parameter to get
> + * @value:	Buffer to store parameter value
> + *
> + * This function gets requested configuration parameter for the given pin.
> + *
> + * Return:	Returns status, either success or error+reason.
> + */
> +static int zynqmp_pm_pinctrl_get_config(const u32 pin, const u32 param,
> +					u32 *value)
> +{
> +	u32 ret_payload[PAYLOAD_ARG_CNT];
> +
> +	if (!value)
> +		return -EINVAL;
> +
> +	invoke_pm_fn(PINCTRL_CONFIG_PARAM_GET, pin,
> +		     param, 0, 0, ret_payload);
> +	*value = ret_payload[1];
> +
> +	return zynqmp_pm_ret_code((enum pm_ret_status)ret_payload[0]);
> +}
> +
> +/**
> + * zynqmp_pm_pinctrl_set_config - Set configuration parameter for the pin
> + * @pin:	Pin number
> + * @param:	Parameter to set
> + * @value:	Parameter value to set
> + *
> + * This function sets requested configuration parameter for the given pin.
> + *
> + * Return:	Returns status, either success or error+reason.
> + */
> +static int zynqmp_pm_pinctrl_set_config(const u32 pin, const u32 param,
> +					u32 value)
> +{
> +	return invoke_pm_fn(PINCTRL_CONFIG_PARAM_SET, pin,
> +			    param, value, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_ioctl - PM IOCTL API for device control and configs
> + * @node_id:	Node ID of the device
> + * @ioctl_id:	ID of the requested IOCTL
> + * @arg1:	Argument 1 to requested IOCTL call
> + * @arg2:	Argument 2 to requested IOCTL call
> + * @out:	Returned output value
> + *
> + * This function calls IOCTL to firmware for device control and configuration.
> + */
> +static int zynqmp_pm_ioctl(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2,
> +			   u32 *out)
> +{
> +	return invoke_pm_fn(IOCTL, node_id, ioctl_id, arg1, arg2, out);
> +}
> +
> +static int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata, u32 *out)
> +{
> +	return invoke_pm_fn(QUERY_DATA, qdata.qid, qdata.arg1,
> +			    qdata.arg2, qdata.arg3, out);
> +}
> +
> +/**
> + * zynqmp_pm_clock_enable - Enable the clock for given id
> + * @clock_id:	ID of the clock to be enabled
> + *
> + * This function is used by master to enable the clock
> + * including peripherals and PLL clocks.
> + *
> + * Return:	Returns status, either success or error+reason.
> + */
> +static int zynqmp_pm_clock_enable(u32 clock_id)
> +{
> +	return invoke_pm_fn(CLOCK_ENABLE, clock_id, 0, 0, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_clock_disable - Disable the clock for given id
> + * @clock_id:	ID of the clock to be disable
> + *
> + * This function is used by master to disable the clock
> + * including peripherals and PLL clocks.
> + *
> + * Return:	Returns status, either success or error+reason.
> + */
> +static int zynqmp_pm_clock_disable(u32 clock_id)
> +{
> +	return invoke_pm_fn(CLOCK_DISABLE, clock_id, 0, 0, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_clock_getstate - Get the clock state for given id
> + * @clock_id:	ID of the clock to be queried
> + * @state:	1/0 (Enabled/Disabled)
> + *
> + * This function is used by master to get the state of clock
> + * including peripherals and PLL clocks.
> + *
> + * Return:	Returns status, either success or error+reason.
> + */
> +static int zynqmp_pm_clock_getstate(u32 clock_id, u32 *state)
> +{
> +	u32 ret_payload[PAYLOAD_ARG_CNT];
> +
> +	invoke_pm_fn(CLOCK_GETSTATE, clock_id, 0, 0, 0, ret_payload);
> +	*state = ret_payload[1];
> +
> +	return zynqmp_pm_ret_code((enum pm_ret_status)ret_payload[0]);
> +}
> +
> +/**
> + * zynqmp_pm_clock_setdivider - Set the clock divider for given id
> + * @clock_id:	ID of the clock
> + * @div_type:	TYPE_DIV1: div1
> + *		TYPE_DIV2: div2
> + * @divider:	divider value.
> + *
> + * This function is used by master to set divider for any clock
> + * to achieve desired rate.
> + *
> + * Return:	Returns status, either success or error+reason.
> + */
> +static int zynqmp_pm_clock_setdivider(u32 clock_id, u32 divider)
> +{
> +	return invoke_pm_fn(CLOCK_SETDIVIDER, clock_id, divider, 0, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_clock_getdivider - Get the clock divider for given id
> + * @clock_id:	ID of the clock
> + * @div_type:	TYPE_DIV1: div1
> + *		TYPE_DIV2: div2
> + * @divider:	divider value.
> + *
> + * This function is used by master to get divider values
> + * for any clock.
> + *
> + * Return:	Returns status, either success or error+reason.
> + */
> +static int zynqmp_pm_clock_getdivider(u32 clock_id, u32 *divider)
> +{
> +	u32 ret_payload[PAYLOAD_ARG_CNT];
> +
> +	invoke_pm_fn(CLOCK_GETDIVIDER, clock_id, 0, 0, 0, ret_payload);
> +	*divider = ret_payload[1];
> +
> +	return zynqmp_pm_ret_code((enum pm_ret_status)ret_payload[0]);
> +}
> +
> +/**
> + * zynqmp_pm_clock_setrate - Set the clock rate for given id
> + * @clock_id:	ID of the clock
> + * @rate:	rate value in hz
> + *
> + * This function is used by master to set rate for any clock.
> + *
> + * Return:	Returns status, either success or error+reason.
> + */
> +static int zynqmp_pm_clock_setrate(u32 clock_id, u32 rate)
> +{
> +	return invoke_pm_fn(CLOCK_SETRATE, clock_id, rate, 0, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_clock_getrate - Get the clock rate for given id
> + * @clock_id:	ID of the clock
> + * @rate:	rate value in hz
> + *
> + * This function is used by master to get rate
> + * for any clock.
> + *
> + * Return:	Returns status, either success or error+reason.
> + */
> +static int zynqmp_pm_clock_getrate(u32 clock_id, u32 *rate)
> +{
> +	u32 ret_payload[PAYLOAD_ARG_CNT];
> +
> +	invoke_pm_fn(CLOCK_GETRATE, clock_id, 0, 0, 0, ret_payload);
> +	*rate = ret_payload[1];
> +
> +	return zynqmp_pm_ret_code((enum pm_ret_status)ret_payload[0]);
> +}
> +
> +/**
> + * zynqmp_pm_clock_setparent - Set the clock parent for given id
> + * @clock_id:	ID of the clock
> + * @parent_id:	parent id
> + *
> + * This function is used by master to set parent for any clock.
> + *
> + * Return:	Returns status, either success or error+reason.
> + */
> +static int zynqmp_pm_clock_setparent(u32 clock_id, u32 parent_id)
> +{
> +	return invoke_pm_fn(CLOCK_SETPARENT, clock_id, parent_id, 0, 0, NULL);
> +}
> +
> +/**
> + * zynqmp_pm_clock_getparent - Get the clock parent for given id
> + * @clock_id:	ID of the clock
> + * @parent_id:	parent id
> + *
> + * This function is used by master to get parent index
> + * for any clock.
> + *
> + * Return:	Returns status, either success or error+reason.
> + */
> +static int zynqmp_pm_clock_getparent(u32 clock_id, u32 *parent_id)
> +{
> +	u32 ret_payload[PAYLOAD_ARG_CNT];
> +
> +	invoke_pm_fn(CLOCK_GETPARENT, clock_id, 0, 0, 0, ret_payload);
> +	*parent_id = ret_payload[1];
> +
> +	return zynqmp_pm_ret_code((enum pm_ret_status)ret_payload[0]);
> +}
> +
> +static const struct zynqmp_eemi_ops eemi_ops  = {
> +	.get_api_version = zynqmp_pm_get_api_version,
> +	.get_chipid = zynqmp_pm_get_chipid,
> +	.reset_assert = zynqmp_pm_reset_assert,
> +	.reset_get_status = zynqmp_pm_reset_get_status,
> +	.fpga_load = zynqmp_pm_fpga_load,
> +	.fpga_get_status = zynqmp_pm_fpga_get_status,
> +	.sha_hash = zynqmp_pm_sha_hash,
> +	.rsa = zynqmp_pm_rsa,
> +	.request_suspend = zynqmp_pm_request_suspend,
> +	.force_powerdown = zynqmp_pm_force_powerdown,
> +	.request_wakeup = zynqmp_pm_request_wakeup,
> +	.set_wakeup_source = zynqmp_pm_set_wakeup_source,
> +	.system_shutdown = zynqmp_pm_system_shutdown,
> +	.request_node = zynqmp_pm_request_node,
> +	.release_node = zynqmp_pm_release_node,
> +	.set_requirement = zynqmp_pm_set_requirement,
> +	.set_max_latency = zynqmp_pm_set_max_latency,
> +	.set_configuration = zynqmp_pm_set_configuration,
> +	.get_node_status = zynqmp_pm_get_node_status,
> +	.get_operating_characteristic = zynqmp_pm_get_operating_characteristic,
> +	.init_finalize = zynqmp_pm_init_finalize,
> +	.get_callback_data = zynqmp_pm_get_callback_data,
> +	.set_suspend_mode = zynqmp_pm_set_suspend_mode,
> +	.ioctl = zynqmp_pm_ioctl,
> +	.query_data = zynqmp_pm_query_data,
> +	.pinctrl_request = zynqmp_pm_pinctrl_request,
> +	.pinctrl_release = zynqmp_pm_pinctrl_release,
> +	.pinctrl_get_function = zynqmp_pm_pinctrl_get_function,
> +	.pinctrl_set_function = zynqmp_pm_pinctrl_set_function,
> +	.pinctrl_get_config = zynqmp_pm_pinctrl_get_config,
> +	.pinctrl_set_config = zynqmp_pm_pinctrl_set_config,
> +	.clock_enable = zynqmp_pm_clock_enable,
> +	.clock_disable = zynqmp_pm_clock_disable,
> +	.clock_getstate = zynqmp_pm_clock_getstate,
> +	.clock_setdivider = zynqmp_pm_clock_setdivider,
> +	.clock_getdivider = zynqmp_pm_clock_getdivider,
> +	.clock_setrate = zynqmp_pm_clock_setrate,
> +	.clock_getrate = zynqmp_pm_clock_getrate,
> +	.clock_setparent = zynqmp_pm_clock_setparent,
> +	.clock_getparent = zynqmp_pm_clock_getparent,
> +};
> +
> +/**
> + * get_eemi_ops	- Get eemi ops functions
> + *
> + * Return:	- pointer of eemi_ops structure
> + */
> +const struct zynqmp_eemi_ops *get_eemi_ops(void)
> +{
> +	return &eemi_ops;
> +}
> +EXPORT_SYMBOL_GPL(get_eemi_ops);
> +
> +static int __init zynqmp_plat_init(void)
> +{
> +	struct device_node *np;
> +	int ret = 0;
> +
> +	np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp");
> +	if (!np)
> +		return 0;
> +	of_node_put(np);
> +
> +	/* We're running on a ZynqMP machine, the PM node is mandatory. */
> +	np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp-firmware");
> +	if (!np) {
> +		pr_warn("%s: pm node not found\n", __func__);
> +		return -ENXIO;
> +	}
> +
> +	ret = get_set_conduit_method(np);
> +	if (ret) {
> +		of_node_put(np);
> +		return ret;
> +	}
> +
> +	/* Check PM API version number */
> +	zynqmp_pm_get_api_version(&pm_api_version);
> +	if (pm_api_version != ZYNQMP_PM_VERSION) {
> +		panic("%s power management API version error. Expected: v%d.%d - Found: v%d.%d\n",
> +		      __func__,
> +		      ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR,
> +		      pm_api_version >> 16, pm_api_version & 0xffff);
> +	}
> +
> +	pr_info("%s Power management API v%d.%d\n", __func__,
> +		ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR);
> +
> +	of_node_put(np);
> +
> +	return ret;
> +}
> +
> +static const struct of_device_id firmware_of_match[] = {
> +	{ .compatible = "xlnx,zynqmp-firmware", },
> +	{ /* end of table */ },
> +};
> +
> +MODULE_DEVICE_TABLE(of, firmware_of_match);
> +
> +static int zynqmp_firmware_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +
> +	ret = zynqmp_pm_api_debugfs_init();
> +	if (ret) {
> +		pr_err("%s() debugfs init fail with error %d\n", __func__, ret);
> +		return ret;
> +	}
> +
> +	zynqmp_pm_ggs_init(&pdev->dev);
> +
> +	return ret;
> +}
> +
> +static struct platform_driver zynqmp_firmware_platform_driver = {
> +	.probe   = zynqmp_firmware_probe,
> +	.driver  = {
> +			.name             = DRIVER_NAME,
> +			.of_match_table   = firmware_of_match,
> +		   },
> +};
> +builtin_platform_driver(zynqmp_firmware_platform_driver);
> +
> +early_initcall(zynqmp_plat_init);
> diff --git a/include/linux/firmware/xilinx/zynqmp/firmware-debug.h b/include/linux/firmware/xilinx/zynqmp/firmware-debug.h
> new file mode 100644
> index 0000000..a388621
> --- /dev/null
> +++ b/include/linux/firmware/xilinx/zynqmp/firmware-debug.h
> @@ -0,0 +1,32 @@
> +/*
> + * Xilinx Zynq MPSoC Firmware layer
> + *
> + *  Copyright (C) 2014-2017 Xilinx
> + *
> + *  Michal Simek <michal.simek@xilinx.com>
> + *  Davorin Mista <davorin.mista@aggios.com>
> + *  Jolly Shah <jollys@xilinx.com>
> + *  Rajan Vaja <rajanv@xilinx.com>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#ifndef __SOC_ZYNQMP_FIRMWARE_DEBUG_H__
> +#define __SOC_ZYNQMP_FIRMWARE_DEBUG_H__
> +
> +#include <linux/firmware/xilinx/zynqmp/firmware.h>
> +
> +int zynqmp_pm_self_suspend(const u32 node,
> +			   const u32 latency,
> +			   const u32 state);
> +int zynqmp_pm_abort_suspend(const enum zynqmp_pm_abort_reason reason);
> +int zynqmp_pm_register_notifier(const u32 node, const u32 event,
> +				const u32 wake, const u32 enable);
> +
> +#if IS_REACHABLE(CONFIG_ZYNQMP_FIRMWARE_DEBUG)
> +int zynqmp_pm_api_debugfs_init(void);
> +#else
> +static inline int zynqmp_pm_api_debugfs_init(void) { return 0; }
> +#endif
> +
> +#endif /* __SOC_ZYNQMP_FIRMWARE_DEBUG_H__ */
> diff --git a/include/linux/firmware/xilinx/zynqmp/firmware.h b/include/linux/firmware/xilinx/zynqmp/firmware.h
> new file mode 100644
> index 0000000..2088b15
> --- /dev/null
> +++ b/include/linux/firmware/xilinx/zynqmp/firmware.h
> @@ -0,0 +1,573 @@
> +/*
> + * Xilinx Zynq MPSoC Firmware layer
> + *
> + *  Copyright (C) 2014-2017 Xilinx
> + *
> + *  Michal Simek <michal.simek@xilinx.com>
> + *  Davorin Mista <davorin.mista@aggios.com>
> + *  Jolly Shah <jollys@xilinx.com>
> + *  Rajan Vaja <rajanv@xilinx.com>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#ifndef __SOC_ZYNQMP_FIRMWARE_H__
> +#define __SOC_ZYNQMP_FIRMWARE_H__
> +
> +#include <linux/device.h>
> +
> +#define ZYNQMP_PM_VERSION_MAJOR	1
> +#define ZYNQMP_PM_VERSION_MINOR	0
> +
> +#define ZYNQMP_PM_VERSION	((ZYNQMP_PM_VERSION_MAJOR << 16) | \
> +					ZYNQMP_PM_VERSION_MINOR)
> +
> +#define ZYNQMP_PM_MAX_LATENCY	(~0U)
> +#define ZYNQMP_PM_MAX_QOS	100U
> +
> +/* SMC SIP service Call Function Identifier Prefix */
> +#define PM_SIP_SVC	0xC2000000
> +#define GET_CALLBACK_DATA 0xa01
> +#define SET_SUSPEND_MODE  0xa02
> +
> +/* Number of 32bits values in payload */
> +#define PAYLOAD_ARG_CNT	5U
> +
> +/* Number of arguments for a callback */
> +#define CB_ARG_CNT	4
> +
> +/* Payload size (consists of callback API ID + arguments) */
> +#define CB_PAYLOAD_SIZE	(CB_ARG_CNT + 1)
> +
> +/* Global general storage register base address */
> +#define GGS_BASEADDR	(0xFFD80030U)
> +#define GSS_NUM_REGS	(4)
> +
> +/* Persistent global general storage register base address */
> +#define PGGS_BASEADDR	(0xFFD80050U)
> +#define PGSS_NUM_REGS	(4)
> +
> +/* Capabilities for RAM */
> +#define	ZYNQMP_PM_CAPABILITY_ACCESS	0x1U
> +#define	ZYNQMP_PM_CAPABILITY_CONTEXT	0x2U
> +#define	ZYNQMP_PM_CAPABILITY_WAKEUP	0x4U
> +#define	ZYNQMP_PM_CAPABILITY_POWER	0x8U
> +
> +/* Clock APIs payload parameters */
> +#define CLK_GET_NAME_RESP_LEN				16
> +#define CLK_GET_TOPOLOGY_RESP_WORDS			3
> +#define CLK_GET_FIXEDFACTOR_RESP_WORDS			2
> +#define CLK_GET_PARENTS_RESP_WORDS			3
> +#define CLK_GET_ATTR_RESP_WORDS				1
> +
> +enum pm_api_id {
> +	/* Miscellaneous API functions: */
> +	GET_API_VERSION = 1,
> +	SET_CONFIGURATION,
> +	GET_NODE_STATUS,
> +	GET_OPERATING_CHARACTERISTIC,
> +	REGISTER_NOTIFIER,
> +	/* API for suspending of PUs: */
> +	REQUEST_SUSPEND,
> +	SELF_SUSPEND,
> +	FORCE_POWERDOWN,
> +	ABORT_SUSPEND,
> +	REQUEST_WAKEUP,
> +	SET_WAKEUP_SOURCE,
> +	SYSTEM_SHUTDOWN,
> +	/* API for managing PM slaves: */
> +	REQUEST_NODE,
> +	RELEASE_NODE,
> +	SET_REQUIREMENT,
> +	SET_MAX_LATENCY,
> +	/* Direct control API functions: */
> +	RESET_ASSERT,
> +	RESET_GET_STATUS,
> +	MMIO_WRITE,
> +	MMIO_READ,
> +	PM_INIT_FINALIZE,
> +	FPGA_LOAD,
> +	FPGA_GET_STATUS,
> +	GET_CHIPID,
> +	/* ID 25 is been used by U-boot to process secure boot images */
> +	/* Secure library generic API functions */
> +	SECURE_SHA = 26,
> +	SECURE_RSA,
> +	/* Pin control API functions */
> +	PINCTRL_REQUEST,
> +	PINCTRL_RELEASE,
> +	PINCTRL_GET_FUNCTION,
> +	PINCTRL_SET_FUNCTION,
> +	PINCTRL_CONFIG_PARAM_GET,
> +	PINCTRL_CONFIG_PARAM_SET,
> +	/* PM IOCTL API */
> +	IOCTL,
> +	/* API to query information from firmware */
> +	QUERY_DATA,
> +	/* Clock control API functions */
> +	CLOCK_ENABLE,
> +	CLOCK_DISABLE,
> +	CLOCK_GETSTATE,
> +	CLOCK_SETDIVIDER,
> +	CLOCK_GETDIVIDER,
> +	CLOCK_SETRATE,
> +	CLOCK_GETRATE,
> +	CLOCK_SETPARENT,
> +	CLOCK_GETPARENT,
> +};
> +
> +/* PMU-FW return status codes */
> +enum pm_ret_status {
> +	XST_PM_SUCCESS = 0,
> +	XST_PM_INTERNAL	= 2000,
> +	XST_PM_CONFLICT,
> +	XST_PM_NO_ACCESS,
> +	XST_PM_INVALID_NODE,
> +	XST_PM_DOUBLE_REQ,
> +	XST_PM_ABORT_SUSPEND,
> +};
> +
> +enum zynqmp_pm_reset_action {
> +	PM_RESET_ACTION_RELEASE,
> +	PM_RESET_ACTION_ASSERT,
> +	PM_RESET_ACTION_PULSE,
> +};
> +
> +enum zynqmp_pm_reset {
> +	ZYNQMP_PM_RESET_START = 999,
> +	ZYNQMP_PM_RESET_PCIE_CFG,
> +	ZYNQMP_PM_RESET_PCIE_BRIDGE,
> +	ZYNQMP_PM_RESET_PCIE_CTRL,
> +	ZYNQMP_PM_RESET_DP,
> +	ZYNQMP_PM_RESET_SWDT_CRF,
> +	ZYNQMP_PM_RESET_AFI_FM5,
> +	ZYNQMP_PM_RESET_AFI_FM4,
> +	ZYNQMP_PM_RESET_AFI_FM3,
> +	ZYNQMP_PM_RESET_AFI_FM2,
> +	ZYNQMP_PM_RESET_AFI_FM1,
> +	ZYNQMP_PM_RESET_AFI_FM0,
> +	ZYNQMP_PM_RESET_GDMA,
> +	ZYNQMP_PM_RESET_GPU_PP1,
> +	ZYNQMP_PM_RESET_GPU_PP0,
> +	ZYNQMP_PM_RESET_GPU,
> +	ZYNQMP_PM_RESET_GT,
> +	ZYNQMP_PM_RESET_SATA,
> +	ZYNQMP_PM_RESET_ACPU3_PWRON,
> +	ZYNQMP_PM_RESET_ACPU2_PWRON,
> +	ZYNQMP_PM_RESET_ACPU1_PWRON,
> +	ZYNQMP_PM_RESET_ACPU0_PWRON,
> +	ZYNQMP_PM_RESET_APU_L2,
> +	ZYNQMP_PM_RESET_ACPU3,
> +	ZYNQMP_PM_RESET_ACPU2,
> +	ZYNQMP_PM_RESET_ACPU1,
> +	ZYNQMP_PM_RESET_ACPU0,
> +	ZYNQMP_PM_RESET_DDR,
> +	ZYNQMP_PM_RESET_APM_FPD,
> +	ZYNQMP_PM_RESET_SOFT,
> +	ZYNQMP_PM_RESET_GEM0,
> +	ZYNQMP_PM_RESET_GEM1,
> +	ZYNQMP_PM_RESET_GEM2,
> +	ZYNQMP_PM_RESET_GEM3,
> +	ZYNQMP_PM_RESET_QSPI,
> +	ZYNQMP_PM_RESET_UART0,
> +	ZYNQMP_PM_RESET_UART1,
> +	ZYNQMP_PM_RESET_SPI0,
> +	ZYNQMP_PM_RESET_SPI1,
> +	ZYNQMP_PM_RESET_SDIO0,
> +	ZYNQMP_PM_RESET_SDIO1,
> +	ZYNQMP_PM_RESET_CAN0,
> +	ZYNQMP_PM_RESET_CAN1,
> +	ZYNQMP_PM_RESET_I2C0,
> +	ZYNQMP_PM_RESET_I2C1,
> +	ZYNQMP_PM_RESET_TTC0,
> +	ZYNQMP_PM_RESET_TTC1,
> +	ZYNQMP_PM_RESET_TTC2,
> +	ZYNQMP_PM_RESET_TTC3,
> +	ZYNQMP_PM_RESET_SWDT_CRL,
> +	ZYNQMP_PM_RESET_NAND,
> +	ZYNQMP_PM_RESET_ADMA,
> +	ZYNQMP_PM_RESET_GPIO,
> +	ZYNQMP_PM_RESET_IOU_CC,
> +	ZYNQMP_PM_RESET_TIMESTAMP,
> +	ZYNQMP_PM_RESET_RPU_R50,
> +	ZYNQMP_PM_RESET_RPU_R51,
> +	ZYNQMP_PM_RESET_RPU_AMBA,
> +	ZYNQMP_PM_RESET_OCM,
> +	ZYNQMP_PM_RESET_RPU_PGE,
> +	ZYNQMP_PM_RESET_USB0_CORERESET,
> +	ZYNQMP_PM_RESET_USB1_CORERESET,
> +	ZYNQMP_PM_RESET_USB0_HIBERRESET,
> +	ZYNQMP_PM_RESET_USB1_HIBERRESET,
> +	ZYNQMP_PM_RESET_USB0_APB,
> +	ZYNQMP_PM_RESET_USB1_APB,
> +	ZYNQMP_PM_RESET_IPI,
> +	ZYNQMP_PM_RESET_APM_LPD,
> +	ZYNQMP_PM_RESET_RTC,
> +	ZYNQMP_PM_RESET_SYSMON,
> +	ZYNQMP_PM_RESET_AFI_FM6,
> +	ZYNQMP_PM_RESET_LPD_SWDT,
> +	ZYNQMP_PM_RESET_FPD,
> +	ZYNQMP_PM_RESET_RPU_DBG1,
> +	ZYNQMP_PM_RESET_RPU_DBG0,
> +	ZYNQMP_PM_RESET_DBG_LPD,
> +	ZYNQMP_PM_RESET_DBG_FPD,
> +	ZYNQMP_PM_RESET_APLL,
> +	ZYNQMP_PM_RESET_DPLL,
> +	ZYNQMP_PM_RESET_VPLL,
> +	ZYNQMP_PM_RESET_IOPLL,
> +	ZYNQMP_PM_RESET_RPLL,
> +	ZYNQMP_PM_RESET_GPO3_PL_0,
> +	ZYNQMP_PM_RESET_GPO3_PL_1,
> +	ZYNQMP_PM_RESET_GPO3_PL_2,
> +	ZYNQMP_PM_RESET_GPO3_PL_3,
> +	ZYNQMP_PM_RESET_GPO3_PL_4,
> +	ZYNQMP_PM_RESET_GPO3_PL_5,
> +	ZYNQMP_PM_RESET_GPO3_PL_6,
> +	ZYNQMP_PM_RESET_GPO3_PL_7,
> +	ZYNQMP_PM_RESET_GPO3_PL_8,
> +	ZYNQMP_PM_RESET_GPO3_PL_9,
> +	ZYNQMP_PM_RESET_GPO3_PL_10,
> +	ZYNQMP_PM_RESET_GPO3_PL_11,
> +	ZYNQMP_PM_RESET_GPO3_PL_12,
> +	ZYNQMP_PM_RESET_GPO3_PL_13,
> +	ZYNQMP_PM_RESET_GPO3_PL_14,
> +	ZYNQMP_PM_RESET_GPO3_PL_15,
> +	ZYNQMP_PM_RESET_GPO3_PL_16,
> +	ZYNQMP_PM_RESET_GPO3_PL_17,
> +	ZYNQMP_PM_RESET_GPO3_PL_18,
> +	ZYNQMP_PM_RESET_GPO3_PL_19,
> +	ZYNQMP_PM_RESET_GPO3_PL_20,
> +	ZYNQMP_PM_RESET_GPO3_PL_21,
> +	ZYNQMP_PM_RESET_GPO3_PL_22,
> +	ZYNQMP_PM_RESET_GPO3_PL_23,
> +	ZYNQMP_PM_RESET_GPO3_PL_24,
> +	ZYNQMP_PM_RESET_GPO3_PL_25,
> +	ZYNQMP_PM_RESET_GPO3_PL_26,
> +	ZYNQMP_PM_RESET_GPO3_PL_27,
> +	ZYNQMP_PM_RESET_GPO3_PL_28,
> +	ZYNQMP_PM_RESET_GPO3_PL_29,
> +	ZYNQMP_PM_RESET_GPO3_PL_30,
> +	ZYNQMP_PM_RESET_GPO3_PL_31,
> +	ZYNQMP_PM_RESET_RPU_LS,
> +	ZYNQMP_PM_RESET_PS_ONLY,
> +	ZYNQMP_PM_RESET_PL,
> +	ZYNQMP_PM_RESET_END
> +};
> +
> +enum zynqmp_pm_request_ack {
> +	ZYNQMP_PM_REQUEST_ACK_NO = 1,
> +	ZYNQMP_PM_REQUEST_ACK_BLOCKING,
> +	ZYNQMP_PM_REQUEST_ACK_NON_BLOCKING,
> +};
> +
> +enum zynqmp_pm_abort_reason {
> +	ZYNQMP_PM_ABORT_REASON_WAKEUP_EVENT = 100,
> +	ZYNQMP_PM_ABORT_REASON_POWER_UNIT_BUSY,
> +	ZYNQMP_PM_ABORT_REASON_NO_POWERDOWN,
> +	ZYNQMP_PM_ABORT_REASON_UNKNOWN,
> +};
> +
> +enum zynqmp_pm_suspend_reason {
> +	ZYNQMP_PM_SUSPEND_REASON_POWER_UNIT_REQUEST = 201,
> +	ZYNQMP_PM_SUSPEND_REASON_ALERT,
> +	ZYNQMP_PM_SUSPEND_REASON_SYSTEM_SHUTDOWN,
> +};
> +
> +enum zynqmp_pm_ram_state {
> +	ZYNQMP_PM_RAM_STATE_OFF = 1,
> +	ZYNQMP_PM_RAM_STATE_RETENTION,
> +	ZYNQMP_PM_RAM_STATE_ON,
> +};
> +
> +enum zynqmp_pm_opchar_type {
> +	ZYNQMP_PM_OPERATING_CHARACTERISTIC_POWER = 1,
> +	ZYNQMP_PM_OPERATING_CHARACTERISTIC_ENERGY,
> +	ZYNQMP_PM_OPERATING_CHARACTERISTIC_TEMPERATURE,
> +};
> +
> +enum pm_node_id {
> +	NODE_UNKNOWN = 0,
> +	NODE_APU,
> +	NODE_APU_0,
> +	NODE_APU_1,
> +	NODE_APU_2,
> +	NODE_APU_3,
> +	NODE_RPU,
> +	NODE_RPU_0,
> +	NODE_RPU_1,
> +	NODE_PLD,
> +	NODE_FPD,
> +	NODE_OCM_BANK_0,
> +	NODE_OCM_BANK_1,
> +	NODE_OCM_BANK_2,
> +	NODE_OCM_BANK_3,
> +	NODE_TCM_0_A,
> +	NODE_TCM_0_B,
> +	NODE_TCM_1_A,
> +	NODE_TCM_1_B,
> +	NODE_L2,
> +	NODE_GPU_PP_0,
> +	NODE_GPU_PP_1,
> +	NODE_USB_0,
> +	NODE_USB_1,
> +	NODE_TTC_0,
> +	NODE_TTC_1,
> +	NODE_TTC_2,
> +	NODE_TTC_3,
> +	NODE_SATA,
> +	NODE_ETH_0,
> +	NODE_ETH_1,
> +	NODE_ETH_2,
> +	NODE_ETH_3,
> +	NODE_UART_0,
> +	NODE_UART_1,
> +	NODE_SPI_0,
> +	NODE_SPI_1,
> +	NODE_I2C_0,
> +	NODE_I2C_1,
> +	NODE_SD_0,
> +	NODE_SD_1,
> +	NODE_DP,
> +	NODE_GDMA,
> +	NODE_ADMA,
> +	NODE_NAND,
> +	NODE_QSPI,
> +	NODE_GPIO,
> +	NODE_CAN_0,
> +	NODE_CAN_1,
> +	NODE_EXTERN,
> +	NODE_APLL,
> +	NODE_VPLL,
> +	NODE_DPLL,
> +	NODE_RPLL,
> +	NODE_IOPLL,
> +	NODE_DDR,
> +	NODE_IPI_APU,
> +	NODE_IPI_RPU_0,
> +	NODE_GPU,
> +	NODE_PCIE,
> +	NODE_PCAP,
> +	NODE_RTC,
> +	NODE_LPD,
> +	NODE_VCU,
> +	NODE_IPI_RPU_1,
> +	NODE_IPI_PL_0,
> +	NODE_IPI_PL_1,
> +	NODE_IPI_PL_2,
> +	NODE_IPI_PL_3,
> +	NODE_PL,
> +	NODE_GEM_TSU,
> +	NODE_SWDT_0,
> +	NODE_SWDT_1,
> +	NODE_CSU,
> +	NODE_PJTAG,
> +	NODE_TRACE,
> +	NODE_TESTSCAN,
> +	NODE_PMU,
> +	NODE_MAX,
> +};
> +
> +enum pm_pinctrl_config_param {
> +	PM_PINCTRL_CONFIG_SLEW_RATE,
> +	PM_PINCTRL_CONFIG_BIAS_STATUS,
> +	PM_PINCTRL_CONFIG_PULL_CTRL,
> +	PM_PINCTRL_CONFIG_SCHMITT_CMOS,
> +	PM_PINCTRL_CONFIG_DRIVE_STRENGTH,
> +	PM_PINCTRL_CONFIG_VOLTAGE_STATUS,
> +	PM_PINCTRL_CONFIG_MAX,
> +};
> +
> +enum pm_pinctrl_slew_rate {
> +	PM_PINCTRL_SLEW_RATE_FAST,
> +	PM_PINCTRL_SLEW_RATE_SLOW,
> +};
> +
> +enum pm_pinctrl_bias_status {
> +	PM_PINCTRL_BIAS_DISABLE,
> +	PM_PINCTRL_BIAS_ENABLE,
> +};
> +
> +enum pm_pinctrl_pull_ctrl {
> +	PM_PINCTRL_BIAS_PULL_DOWN,
> +	PM_PINCTRL_BIAS_PULL_UP,
> +};
> +
> +enum pm_pinctrl_schmitt_cmos {
> +	PM_PINCTRL_INPUT_TYPE_CMOS,
> +	PM_PINCTRL_INPUT_TYPE_SCHMITT,
> +};
> +
> +enum pm_pinctrl_drive_strength {
> +	PM_PINCTRL_DRIVE_STRENGTH_2MA,
> +	PM_PINCTRL_DRIVE_STRENGTH_4MA,
> +	PM_PINCTRL_DRIVE_STRENGTH_8MA,
> +	PM_PINCTRL_DRIVE_STRENGTH_12MA,
> +};
> +
> +enum pm_ioctl_id {
> +	IOCTL_GET_RPU_OPER_MODE,
> +	IOCTL_SET_RPU_OPER_MODE,
> +	IOCTL_RPU_BOOT_ADDR_CONFIG,
> +	IOCTL_TCM_COMB_CONFIG,
> +	IOCTL_SET_TAPDELAY_BYPASS,
> +	IOCTL_SET_SGMII_MODE,
> +	IOCTL_SD_DLL_RESET,
> +	IOCTL_SET_SD_TAPDELAY,
> +	/* Ioctl for clock driver */
> +	IOCTL_SET_PLL_FRAC_MODE,
> +	IOCTL_GET_PLL_FRAC_MODE,
> +	IOCTL_SET_PLL_FRAC_DATA,
> +	IOCTL_GET_PLL_FRAC_DATA,
> +	IOCTL_WRITE_GGS,
> +	IOCTL_READ_GGS,
> +	IOCTL_WRITE_PGGS,
> +	IOCTL_READ_PGGS,
> +};
> +
> +enum rpu_oper_mode {
> +	PM_RPU_MODE_LOCKSTEP,
> +	PM_RPU_MODE_SPLIT,
> +};
> +
> +enum rpu_boot_mem {
> +	PM_RPU_BOOTMEM_LOVEC,
> +	PM_RPU_BOOTMEM_HIVEC,
> +};
> +
> +enum rpu_tcm_comb {
> +	PM_RPU_TCM_SPLIT,
> +	PM_RPU_TCM_COMB,
> +};
> +
> +enum tap_delay_signal_type {
> +	PM_TAPDELAY_NAND_DQS_IN,
> +	PM_TAPDELAY_NAND_DQS_OUT,
> +	PM_TAPDELAY_QSPI,
> +	PM_TAPDELAY_MAX,
> +};
> +
> +enum tap_delay_bypass_ctrl {
> +	PM_TAPDELAY_BYPASS_DISABLE,
> +	PM_TAPDELAY_BYPASS_ENABLE,
> +};
> +
> +enum sgmii_mode {
> +	PM_SGMII_DISABLE,
> +	PM_SGMII_ENABLE,
> +};
> +
> +enum tap_delay_type {
> +	PM_TAPDELAY_INPUT,
> +	PM_TAPDELAY_OUTPUT,
> +};
> +
> +enum dll_reset_type {
> +	PM_DLL_RESET_ASSERT,
> +	PM_DLL_RESET_RELEASE,
> +	PM_DLL_RESET_PULSE,
> +};
> +
> +enum topology_type {
> +	TYPE_INVALID,
> +	TYPE_MUX,
> +	TYPE_PLL,
> +	TYPE_FIXEDFACTOR,
> +	TYPE_DIV1,
> +	TYPE_DIV2,
> +	TYPE_GATE,
> +};
> +
> +enum pm_query_id {
> +	PM_QID_INVALID,
> +	PM_QID_CLOCK_GET_NAME,
> +	PM_QID_CLOCK_GET_TOPOLOGY,
> +	PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS,
> +	PM_QID_CLOCK_GET_PARENTS,
> +	PM_QID_CLOCK_GET_ATTRIBUTES,
> +};
> +
> +struct zynqmp_pm_query_data {
> +	u32 qid;
> +	u32 arg1;
> +	u32 arg2;
> +	u32 arg3;
> +};
> +
> +struct zynqmp_eemi_ops {
> +	int (*get_api_version)(u32 *version);
> +	int (*get_chipid)(u32 *idcode, u32 *version);
> +	int (*reset_assert)(const enum zynqmp_pm_reset reset,
> +			    const enum zynqmp_pm_reset_action assert_flag);
> +	int (*reset_get_status)(const enum zynqmp_pm_reset reset, u32 *status);
> +	int (*fpga_load)(const u64 address, const u32 size, const u32 flags);
> +	int (*fpga_get_status)(u32 *value);
> +	int (*sha_hash)(const u64 address, const u32 size, const u32 flags);
> +	int (*rsa)(const u64 address, const u32 size, const u32 flags);
> +	int (*request_suspend)(const u32 node,
> +			       const enum zynqmp_pm_request_ack ack,
> +			       const u32 latency,
> +			       const u32 state);
> +	int (*force_powerdown)(const u32 target,
> +			       const enum zynqmp_pm_request_ack ack);
> +	int (*request_wakeup)(const u32 node,
> +			      const bool set_addr,
> +			      const u64 address,
> +			      const enum zynqmp_pm_request_ack ack);
> +	int (*set_wakeup_source)(const u32 target,
> +				 const u32 wakeup_node,
> +				 const u32 enable);
> +	int (*system_shutdown)(const u32 type, const u32 subtype);
> +	int (*request_node)(const u32 node,
> +			    const u32 capabilities,
> +			    const u32 qos,
> +			    const enum zynqmp_pm_request_ack ack);
> +	int (*release_node)(const u32 node);
> +	int (*set_requirement)(const u32 node,
> +			       const u32 capabilities,
> +			       const u32 qos,
> +			       const enum zynqmp_pm_request_ack ack);
> +	int (*set_max_latency)(const u32 node, const u32 latency);
> +	int (*set_configuration)(const u32 physical_addr);
> +	int (*get_node_status)(const u32 node, u32 *const status,
> +			       u32 *const requirements, u32 *const usage);
> +	int (*get_operating_characteristic)(const u32 node,
> +					    const enum zynqmp_pm_opchar_type
> +					    type, u32 *const result);
> +	int (*init_finalize)(void);
> +	int (*get_callback_data)(u32 *buf);
> +	int (*set_suspend_mode)(u32 mode);
> +	int (*ioctl)(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2, u32 *out);
> +	int (*query_data)(struct zynqmp_pm_query_data qdata, u32 *out);
> +	int (*pinctrl_request)(const u32 pin);
> +	int (*pinctrl_release)(const u32 pin);
> +	int (*pinctrl_get_function)(const u32 pin, u32 *node);
> +	int (*pinctrl_set_function)(const u32 pin, const u32 node);
> +	int (*pinctrl_get_config)(const u32 pin, const u32 param, u32 *value);
> +	int (*pinctrl_set_config)(const u32 pin, const u32 param, u32 value);
> +	int (*clock_enable)(u32 clock_id);
> +	int (*clock_disable)(u32 clock_id);
> +	int (*clock_getstate)(u32 clock_id, u32 *state);
> +	int (*clock_setdivider)(u32 clock_id, u32 divider);
> +	int (*clock_getdivider)(u32 clock_id, u32 *divider);
> +	int (*clock_setrate)(u32 clock_id, u32 rate);
> +	int (*clock_getrate)(u32 clock_id, u32 *rate);
> +	int (*clock_setparent)(u32 clock_id, u32 parent_id);
> +	int (*clock_getparent)(u32 clock_id, u32 *parent_id);
> +};
> +
> +/*
> + * Internal functions
> + */
> +int invoke_pm_fn(u32 pm_api_id, u32 arg0, u32 arg1, u32 arg2, u32 arg3,
> +		 u32 *ret_payload);
> +int zynqmp_pm_ret_code(u32 ret_status);
> +
> +void zynqmp_pm_ggs_init(struct device *dev);
> +
> +#if IS_REACHABLE(CONFIG_ARCH_ZYNQMP)
> +const struct zynqmp_eemi_ops *get_eemi_ops(void);
> +#else
> +static inline struct zynqmp_eemi_ops *get_eemi_ops(void) { return NULL; }
> +#endif
> +
> +#endif /* __SOC_ZYNQMP_FIRMWARE_H__ */
> -- 
> 2.7.4
> 

^ permalink raw reply

* [PATCH 05/10] perf tools: Add support for decoding CoreSight trace data
From: Mike Leach @ 2018-01-09 12:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171230003359.GD600@leoy-linaro>

Hi Leo,

The OCSD_GEN_TRC_ELEM_ADDR_NACC element indicates that the decoder
does not have an code image mapping for the address contained in the
trace, at the location described by this element. the payload for the
NACC element is the memory location it could not address.
This means that it cannot correctly follow the instruction execution
sequence described by the individual trace packets.

The dump option works because we do not need to follow the execution
sequence to dump raw trace packets.

It is not clear to me if the perf script option as you specified is
mapping the vmlinux image into the decoder.

Regards

Mike

On 30 December 2017 at 00:33, Leo Yan <leo.yan@linaro.org> wrote:
> Hi Mathieu, Mike,
>
> On Fri, Dec 15, 2017 at 09:44:54AM -0700, Mathieu Poirier wrote:
>> Adding functionality to create a CoreSight trace decoder capable
>> of decoding trace data pushed by a client application.
>>
>> Co-authored-by: Tor Jeremiassen <tor@ti.com>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>> ---
>>  tools/perf/util/cs-etm-decoder/cs-etm-decoder.c | 119 ++++++++++++++++++++++++
>>  1 file changed, 119 insertions(+)
>>
>> diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
>> index 6a4c86b1431f..57b020b0b36f 100644
>> --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
>> +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
>> @@ -200,6 +200,121 @@ static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder)
>>       }
>>  }
>>
>> +static ocsd_datapath_resp_t
>> +cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
>> +                           const ocsd_generic_trace_elem *elem,
>> +                           const u8 trace_chan_id,
>> +                           enum cs_etm_sample_type sample_type)
>> +{
>> +     u32 et = 0;
>> +     struct int_node *inode = NULL;
>> +
>> +     if (decoder->packet_count >= MAX_BUFFER - 1)
>> +             return OCSD_RESP_FATAL_SYS_ERR;
>> +
>> +     /* Search the RB tree for the cpu associated with this traceID */
>> +     inode = intlist__find(traceid_list, trace_chan_id);
>> +     if (!inode)
>> +             return OCSD_RESP_FATAL_SYS_ERR;
>> +
>> +     et = decoder->tail;
>> +     decoder->packet_buffer[et].sample_type = sample_type;
>> +     decoder->packet_buffer[et].start_addr = elem->st_addr;
>> +     decoder->packet_buffer[et].end_addr = elem->en_addr;
>> +     decoder->packet_buffer[et].exc = false;
>> +     decoder->packet_buffer[et].exc_ret = false;
>> +     decoder->packet_buffer[et].cpu = *((int *)inode->priv);
>> +
>> +     /* Wrap around if need be */
>> +     et = (et + 1) & (MAX_BUFFER - 1);
>> +
>> +     decoder->tail = et;
>> +     decoder->packet_count++;
>> +
>> +     if (decoder->packet_count == MAX_BUFFER - 1)
>> +             return OCSD_RESP_WAIT;
>> +
>> +     return OCSD_RESP_CONT;
>> +}
>> +
>> +static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
>> +                             const void *context,
>> +                             const ocsd_trc_index_t indx __maybe_unused,
>> +                             const u8 trace_chan_id __maybe_unused,
>> +                             const ocsd_generic_trace_elem *elem)
>> +{
>> +     ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
>> +     struct cs_etm_decoder *decoder = (struct cs_etm_decoder *) context;
>
> After apply this patch set and build 'perf' tool with linking
> OpenCSDv0.8.0 libs, I can everytime OpenCSD parses 'elem->elem_type'
> is OCSD_GEN_TRC_ELEM_ADDR_NACC but not OCSD_GEN_TRC_ELEM_INSTR_RANGE.
>
> As result, the 'perf' tool can dump the raw data with '-D' option but
> it cannot analyze the symbol and symbol offset with below command:
>
> ./perf script -v -a -F cpu,event,ip,sym,symoff -i ./perf.data -k vmlinux
> --kallsyms ./System.map
>
> Have uploaded perf.data/vmlinux/System.map in the folder:
> http://people.linaro.org/~leo.yan/binaries/perf_4.15_r4/
>
> Thanks,
> Leo Yan
>
>> +     switch (elem->elem_type) {
>> +     case OCSD_GEN_TRC_ELEM_UNKNOWN:
>> +             break;
>> +     case OCSD_GEN_TRC_ELEM_NO_SYNC:
>> +             decoder->trace_on = false;
>> +             break;
>> +     case OCSD_GEN_TRC_ELEM_TRACE_ON:
>> +             decoder->trace_on = true;
>> +             break;
>> +     case OCSD_GEN_TRC_ELEM_INSTR_RANGE:
>> +             resp = cs_etm_decoder__buffer_packet(decoder, elem,
>> +                                                  trace_chan_id,
>> +                                                  CS_ETM_RANGE);
>> +             break;
>> +     case OCSD_GEN_TRC_ELEM_EXCEPTION:
>> +             decoder->packet_buffer[decoder->tail].exc = true;
>> +             break;
>> +     case OCSD_GEN_TRC_ELEM_EXCEPTION_RET:
>> +             decoder->packet_buffer[decoder->tail].exc_ret = true;
>> +             break;
>> +     case OCSD_GEN_TRC_ELEM_PE_CONTEXT:
>> +     case OCSD_GEN_TRC_ELEM_EO_TRACE:
>> +     case OCSD_GEN_TRC_ELEM_ADDR_NACC:
>> +     case OCSD_GEN_TRC_ELEM_TIMESTAMP:
>> +     case OCSD_GEN_TRC_ELEM_CYCLE_COUNT:
>> +     case OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN:
>> +     case OCSD_GEN_TRC_ELEM_EVENT:
>> +     case OCSD_GEN_TRC_ELEM_SWTRACE:
>> +     case OCSD_GEN_TRC_ELEM_CUSTOM:
>> +     default:
>> +             break;
>> +     }
>> +
>> +     return resp;
>> +}
>> +
>> +static int cs_etm_decoder__create_etm_packet_decoder(
>> +                                     struct cs_etm_trace_params *t_params,
>> +                                     struct cs_etm_decoder *decoder)
>> +{
>> +     const char *decoder_name;
>> +     ocsd_etmv4_cfg trace_config_etmv4;
>> +     void *trace_config;
>> +     u8 csid;
>> +
>> +     switch (t_params->protocol) {
>> +     case CS_ETM_PROTO_ETMV4i:
>> +             cs_etm_decoder__gen_etmv4_config(t_params, &trace_config_etmv4);
>> +             decoder_name = OCSD_BUILTIN_DCD_ETMV4I;
>> +             trace_config = &trace_config_etmv4;
>> +             break;
>> +     default:
>> +             return -1;
>> +     }
>> +
>> +     if (ocsd_dt_create_decoder(decoder->dcd_tree,
>> +                                  decoder_name,
>> +                                  OCSD_CREATE_FLG_FULL_DECODER,
>> +                                  trace_config, &csid))
>> +             return -1;
>> +
>> +     if (ocsd_dt_set_gen_elem_outfn(decoder->dcd_tree,
>> +                                    cs_etm_decoder__gen_trace_elem_printer,
>> +                                    decoder))
>> +             return -1;
>> +
>> +     return 0;
>> +}
>> +
>>  static int
>>  cs_etm_decoder__create_etm_decoder(struct cs_etm_decoder_params *d_params,
>>                                  struct cs_etm_trace_params *t_params,
>> @@ -208,6 +323,10 @@ cs_etm_decoder__create_etm_decoder(struct cs_etm_decoder_params *d_params,
>>       if (d_params->operation == CS_ETM_OPERATION_PRINT)
>>               return cs_etm_decoder__create_etm_packet_printer(t_params,
>>                                                                decoder);
>> +     else if (d_params->operation == CS_ETM_OPERATION_DECODE)
>> +             return cs_etm_decoder__create_etm_packet_decoder(t_params,
>> +                                                              decoder);
>> +
>>       return -1;
>>  }
>>
>> --
>> 2.7.4
>>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel



-- 
Mike Leach
Principal Engineer, ARM Ltd.
Blackburn Design Centre. UK

^ permalink raw reply

* [PATCH v3] dt: psci: Update DT bindings to support hierarchical PSCI states
From: Sudeep Holla @ 2018-01-09 12:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515498913-24291-1-git-send-email-ulf.hansson@linaro.org>

(Removed Brendan Jackman as he is no longer works in ARM)

On 09/01/18 11:55, Ulf Hansson wrote:
> From: Lina Iyer <lina.iyer@linaro.org>
> 
> Update DT bindings to represent hierarchical CPU and CPU domain idle states
> for PSCI. Also update the PSCI examples to clearly show how flattened and
> hierarchical idle states can be represented in DT.
> 

It now looks good to me :)

Reviewed-by: Sudeep Holla <sudeep.holla@arm.com>

-- 
Regards,
Sudeep

^ permalink raw reply

* [PATCH] iommu/exynos: Don't unconditionally steal bus ops
From: Robin Murphy @ 2018-01-09 11:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <878c7791-ef37-adc7-8186-27455f2ef67f@samsung.com>

On 09/01/18 09:59, Marek Szyprowski wrote:
> Hi Robin,
> 
> On 2018-01-08 20:27, Robin Murphy wrote:
>> Removing the early device registration hook overlooked the fact that
>> it only ran conditionally on a compatible device being present in the
>> DT. With exynos_iommu_init() now running as an unconditional initcall,
>> problems arise on non-Exynos systems when other IOMMU drivers find
>> themselves unable to install their ops on the platform bus, or at worst
>> the Exynos ops get called with someone else's domain and all hell breaks
>> loose.
>>
>> Fix this by delaying the setting of bus ops until an Exynos IOMMU is
>> actually found, to replicate the previous order of events.
>>
>> Fixes: 928055a01b3f ("iommu/exynos: Remove custom platform device 
>> registration code")
>> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> 
> Right, my fault. However I will prefer to resurrect code added initially
> by commit a7b67cd5d9af "iommu/exynos: Play nice in multi-platform builds".
> There is no need to do all the things done in the exynos_iommu_init on
> non-Exynos platforms.

Yeah; I had a moment of doubt and left the rest as-is, but I guess all 
of that global setup could in fact be delayed until the first probe, as 
with dma_dev. Anyway, I'll respin just the minimal fix to un-break 
multiplatform, and leave any further refactoring up to you.

Thanks,
Robin.

>> ---
>> ? drivers/iommu/exynos-iommu.c | 16 +++++++---------
>> ? 1 file changed, 7 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
>> index 6a96a4c42153..e9e756156429 100644
>> --- a/drivers/iommu/exynos-iommu.c
>> +++ b/drivers/iommu/exynos-iommu.c
>> @@ -574,6 +574,12 @@ static int __init exynos_sysmmu_probe(struct 
>> platform_device *pdev)
>> ????? struct sysmmu_drvdata *data;
>> ????? struct resource *res;
>> +??? if (platform_bus_type->iommu_ops != &exynos_iommu_ops) {
>> +??????? ret = bus_set_iommu(&platform_bus_type, &exynos_iommu_ops);
>> +??????? if (ret)
>> +??????????? return ret;
>> +??? }
>> +
>> ????? data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
>> ????? if (!data)
>> ????????? return -ENOMEM;
>> @@ -1367,16 +1373,8 @@ static int __init exynos_iommu_init(void)
>> ????????? goto err_zero_lv2;
>> ????? }
>> -??? ret = bus_set_iommu(&platform_bus_type, &exynos_iommu_ops);
>> -??? if (ret) {
>> -??????? pr_err("%s: Failed to register exynos-iommu driver.\n",
>> -??????????????????????????????? __func__);
>> -??????? goto err_set_iommu;
>> -??? }
>> -
>> ????? return 0;
>> -err_set_iommu:
>> -??? kmem_cache_free(lv2table_kmem_cache, zero_lv2_table);
>> +
>> ? err_zero_lv2:
>> ????? platform_driver_unregister(&exynos_sysmmu_driver);
>> ? err_reg_driver:
> 
> Best regards

^ permalink raw reply

* [RFC PATCH 0/9] soc: samsung: Add support of suspend-to-RAM on Exynos5433
From: Krzysztof Kozlowski @ 2018-01-09 11:56 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515484746-10656-1-git-send-email-cw00.choi@samsung.com>

On Tue, Jan 9, 2018 at 8:58 AM, Chanwoo Choi <cw00.choi@samsung.com> wrote:
> In the mainline, there is no case to support the suspend-to-RAM for Samsung
> Exynos SoC. This patchset support the suspend-to-RAM for 64bit Exynos SoC.
>
> For 32bit, arch/arm/mach-exynos/* directoy contains the suspend-related
> codes such as suspend.c/exynos.c. But, 64bit Exynos should contain
> the suspend-related codes in the drivers/soc/samsung/*. So, this patchset
> develop the patch4/5 for drivers/soc/samsung/exynos-pm.c. to support suspend
> 64bit Exynos SoC.
>
> But, I'm not sure what is proper approach for both 32/64bit Exynos.
> - Approach1 : Split out the supend-related codes between 32/64bit.
>   : arch/arm/mach-exynos/* contains the suspend-related codes for 32bit.
>   : drivers/soc/samsung/* contains the suspend-related codes for 64bit.
> - Approach2 : Consolidate the all suspend-related codes to drivers/soc/samsung/.

I prefer approach #2 - consolidate the code... unless this creates
some unmaintainable monster :)

Best regards,
Krzysztof

>
> Please let us know your opinion.
>
> The patch1/2/3 and 6/7/8/9 is just general patch. So, I add 'RFC' prefix to
> only cover-letter, patch4/5. If you want to add the 'RFC' prefix to all
> patches, I'll add 'RFC' prefix on v2.
>
> Based on:
> - git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git (branch: for-next)
>
> Need to discuss patch4/5:
> - patch4: soc: samsung: Add generic power-management driver for Exynos
> - patch5: soc: samsung: pm: Add support for suspend-to-ram of Exynos5433
>
> [Remaining Issues]
> - The hang-out happen when disabling the MMC clocks on dw_mmc.c.
>   I reported to Jaehoon Chung. He is checking this issue. To test the
>   suspend-to-ram temporarily, you need to add CLK_IS_CRITICAL flag to
>   'aclk_mmc2/aclk_mmc0/sclk_mmc2/sclk_mmc0'.
> - I enabled the at least kernel configuration in order to test
>   the suspend-to-RAM. So, I need to test it more time with DRM/Multimedia
>   and other. But, the suspend-to-RAM of cpu is successful.
> - Exynos5433 SoC has two EXYNOS5433_EINT_WAKEUP_MASKx registers. The
>   pinctr-exynos.c need to handle the extra EINT_WAKEUP_MASKx for Exynos5433.
>   The suspend-to-ram test is failed on first time and then next tryout is ok.
>   I'm developing it.
>
> Chanwoo Choi (9):
>   clk: samsung: exynos5433: Add clock flag to support suspend-to-ram
>   soc: samsung: pmu: Add powerup_conf callback
>   soc: samsung: pmu: Add the PMU data of exynos5433 to support low-power state
>   soc: samsung: Add generic power-management driver for Exynos
>   soc: samsung: pm: Add support for suspend-to-ram of Exynos5433
>   arm64: dts: exynos: Add iRAM device-tree node for Exynos5433
>   arm64: dts: exynos: Use power key as a wakeup source on TM2/TM2E board
>   arm64: dts: exynos: Add cpu_suspend property of PSCI for exynos5433
>   arm64: dts: exynos: Add cpu topology information for Exynos5433 SoC
>
>  arch/arm/mach-exynos/common.h                      |   3 -
>  arch/arm/mach-exynos/exynos.c                      |  23 +-
>  .../boot/dts/exynos/exynos5433-tm2-common.dtsi     |   1 +
>  arch/arm64/boot/dts/exynos/exynos5433.dtsi         |  47 ++++
>  drivers/clk/samsung/clk-exynos5433.c               |  22 +-
>  drivers/soc/samsung/Makefile                       |   5 +-
>  drivers/soc/samsung/exynos-pm.c                    | 214 +++++++++++++++
>  drivers/soc/samsung/exynos-pmu.c                   |   9 +
>  drivers/soc/samsung/exynos-pmu.h                   |   3 +
>  drivers/soc/samsung/exynos5433-pmu.c               | 286 +++++++++++++++++++++
>  include/linux/soc/samsung/exynos-pm.h              |  21 ++
>  include/linux/soc/samsung/exynos-pmu.h             |   1 +
>  include/linux/soc/samsung/exynos-regs-pmu.h        | 148 +++++++++++
>  13 files changed, 745 insertions(+), 38 deletions(-)
>  create mode 100644 drivers/soc/samsung/exynos-pm.c
>  create mode 100644 drivers/soc/samsung/exynos5433-pmu.c
>  create mode 100644 include/linux/soc/samsung/exynos-pm.h
>
> --
> 1.9.1
>

^ permalink raw reply

* [PATCH v3] dt: psci: Update DT bindings to support hierarchical PSCI states
From: Ulf Hansson @ 2018-01-09 11:55 UTC (permalink / raw)
  To: linux-arm-kernel

From: Lina Iyer <lina.iyer@linaro.org>

Update DT bindings to represent hierarchical CPU and CPU domain idle states
for PSCI. Also update the PSCI examples to clearly show how flattened and
hierarchical idle states can be represented in DT.

Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---

Changes in v3:
	- Added Rob's reviewed-by-tag.
	- Addressed comments from Sudeep. 

Changes in v2:
        - Addressed comments from Rob.
        - Updated some labels in the examples to get more consistency.

For your information, I have picked up the work from Lina Iyer around the so
called CPU cluster idling series [1,2] and I working on new versions. However,
I decided to post the updates to the PSCI DT bindings first, as they will be
needed to be agreed upon before further changes can be done to the PSCI
firmware driver.

Note, these bindings have been discussed over and over again, at LKML, but
especially also at various Linux conferences, like LPC and Linaro Connect. We
finally came to a conclusion and the changes we agreed upon, should be
reflected in this update.

Of course, it's a while ago since the latest discussions, but hopefully people
don't have too hard time to remember.

Kind regards
Uffe

[1]
https://www.spinics.net/lists/arm-kernel/msg566200.html

[2]
https://lwn.net/Articles/716300/

---
 Documentation/devicetree/bindings/arm/psci.txt | 156 +++++++++++++++++++++++++
 1 file changed, 156 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/psci.txt b/Documentation/devicetree/bindings/arm/psci.txt
index a2c4f1d..17aa3d3 100644
--- a/Documentation/devicetree/bindings/arm/psci.txt
+++ b/Documentation/devicetree/bindings/arm/psci.txt
@@ -105,7 +105,163 @@ Case 3: PSCI v0.2 and PSCI v0.1.
 		...
 	};
 
+ARM systems can have multiple cores sometimes in hierarchical arrangement.
+This often, but not always, maps directly to the processor power topology of
+the system. Individual nodes in a topology have their own specific power states
+and can be better represented in DT hierarchically.
+
+For these cases, the definitions of the idle states for the CPUs and the CPU
+topology, must conform to the domain idle state specification [3]. The domain
+idle states themselves, must be compatible with the defined 'domain-idle-state'
+binding [1], and also need to specify the arm,psci-suspend-param property for
+each idle state.
+
+DT allows representing CPUs and CPU idle states in two different ways -
+
+The flattened model as given in Example 1, lists CPU's idle states followed by
+the domain idle state that the CPUs may choose. Note that the idle states are
+all compatible with "arm,idle-state".
+
+Example 2 represents the hierarchical model of CPUs and domain idle states.
+CPUs define their domain provider in their psci DT node. The domain controls
+the power to the CPU and possibly other h/w blocks that would enter an idle
+state along with the CPU. The CPU's idle states may therefore be considered as
+the domain's idle states and have the compatible "arm,idle-state". Such domains
+may also be embedded within another domain that may represent common h/w blocks
+between these CPUs. The idle states of the CPU topology shall be represented as
+the domain's idle states.
+
+In PSCI firmware v1.0, the OS-Initiated mode is introduced. In order to use it,
+the hierarchical representation must be used.
+
+Example 1: Flattened representation of CPU and domain idle states
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		CPU0: cpu at 0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53", "arm,armv8";
+			reg = <0x0>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_PWRDN>, <&CLUSTER_RET>,
+					  <&CLUSTER_PWRDN>;
+		};
+
+		CPU1: cpu at 1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a57", "arm,armv8";
+			reg = <0x100>;
+			enable-method = "psci";
+			cpu-idle-states = <&CPU_PWRDN>, <&CLUSTER_RET>,
+					  <&CLUSTER_PWRDN>;
+		};
+
+		idle-states {
+			CPU_PWRDN: cpu-power-down {
+				compatible = "arm,idle-state";
+				arm,psci-suspend-param = <0x000001>;
+				entry-latency-us = <10>;
+				exit-latency-us = <10>;
+				min-residency-us = <100>;
+			};
+
+			CLUSTER_RET: cluster-retention {
+				compatible = "arm,idle-state";
+				arm,psci-suspend-param = <0x1000010>;
+				entry-latency-us = <500>;
+				exit-latency-us = <500>;
+				min-residency-us = <2000>;
+			};
+
+			CLUSTER_PWRDN: cluster-power-down {
+				compatible = "arm,idle-state";
+				arm,psci-suspend-param = <0x1000030>;
+				entry-latency-us = <2000>;
+				exit-latency-us = <2000>;
+				min-residency-us = <6000>;
+			};
+	};
+
+	psci {
+		compatible = "arm,psci-0.2";
+		method = "smc";
+	};
+
+Example 2: Hierarchical representation of CPU and domain idle states
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		CPU0: cpu at 0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53", "arm,armv8";
+			reg = <0x0>;
+			enable-method = "psci";
+			power-domains = <&CPU_PD0>;
+		};
+
+		CPU1: cpu at 1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a57", "arm,armv8";
+			reg = <0x100>;
+			enable-method = "psci";
+			power-domains = <&CPU_PD1>;
+		};
+
+		idle-states {
+			CPU_PWRDN: cpu-power-down {
+				compatible = "arm,idle-state";
+				arm,psci-suspend-param = <0x000001>;
+				entry-latency-us = <10>;
+				exit-latency-us = <10>;
+				min-residency-us = <100>;
+			};
+
+			CLUSTER_RET: cluster-retention {
+				compatible = "domain-idle-state";
+				arm,psci-suspend-param = <0x1000010>;
+				entry-latency-us = <500>;
+				exit-latency-us = <500>;
+				min-residency-us = <2000>;
+			};
+
+			CLUSTER_PWRDN: cluster-power-down {
+				compatible = "domain-idle-state";
+				arm,psci-suspend-param = <0x1000030>;
+				entry-latency-us = <2000>;
+				exit-latency-us = <2000>;
+				min-residency-us = <6000>;
+			};
+		};
+	};
+
+	psci {
+		compatible = "arm,psci-1.0";
+		method = "smc";
+
+		CPU_PD0: cpu-pd0 {
+			#power-domain-cells = <0>;
+			domain-idle-states = <&CPU_PWRDN>;
+			power-domains = <&CLUSTER_PD>;
+		};
+
+		CPU_PD1: cpu-pd1 {
+			#power-domain-cells = <0>;
+			domain-idle-states =  <&CPU_PWRDN>;
+			power-domains = <&CLUSTER_PD>;
+		};
+
+		CLUSTER_PD: cluster-pd {
+			#power-domain-cells = <0>;
+			domain-idle-states = <&CLUSTER_RET>, <&CLUSTER_PWRDN>;
+		};
+	};
+
 [1] Kernel documentation - ARM idle states bindings
     Documentation/devicetree/bindings/arm/idle-states.txt
 [2] Power State Coordination Interface (PSCI) specification
     http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf
+[3]. PM Domains description
+    Documentation/devicetree/bindings/power/power_domain.txt
-- 
2.7.4

^ permalink raw reply related

* [Letux-kernel] [PATCH v5 3/5] misc serdev: Add w2sg0004 (gps receiver) power control driver
From: H. Nikolaus Schaller @ 2018-01-09 11:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <91850CC3-B280-4701-9D07-96AFF3A79A6F@goldelico.com>

Hi Johan,

> Am 22.12.2017 um 15:40 schrieb H. Nikolaus Schaller <hns@goldelico.com>:
> 
> Hi Johan,
> 
>> Am 22.12.2017 um 13:44 schrieb Johan Hovold <johan@kernel.org>:
>> 
>> On Fri, Dec 01, 2017 at 08:49:36AM +0100, H. Nikolaus Schaller wrote:
>>> Add driver for Wi2Wi W2SG0004/84 GPS module connected to some SoC UART.
>>> 
>>> It uses serdev API hooks to monitor and forward the UART traffic to /dev/ttyGPSn
>>> and turn on/off the module. It also detects if the module is turned on (sends data)
>>> but should be off, e.g. if it was already turned on during boot or power-on-reset.
>>> 
>>> Additionally, rfkill block/unblock can be used to control an external LNA
>>> (and power down the module if not needed).
>>> 
>>> The driver concept is based on code developed by Neil Brown <neilb@suse.de>
>>> but simplified and adapted to use the new serdev API introduced in v4.11.
>> 
>> I'm sorry (and I know this discussion has been going on for a long
>> time),but this still feels like too much of a hack.

Happy new year ... Happy new attempt...

Let's restart this discussion and focus on the main roadblock (others are minor
details which can be sorted out later).

If it feels like a hack, the key issue seems to me to be the choice of
the API to present the GPS data to user space. Right?

I see three reasonable options how this presentation can be done:

1. char device
2. tty device
3. some new gps interface API (similar to network, bluetooth interfaces)
4. no driver and use the UART tty directly

Pros and cons:

1. char device
+ seems to save resources (but IMHO doesn't if we look deeper to handle select, blocking, buffer overflow)
- the standard function of buffering a character stream has to be done by this driver again, although tty subsystem already has proper buffering
- no line disciplines (e.g. if some gps client wants to translate CR and NL or use canonical/noncanonical mode)
- capabilities of the interface change if same chip is connected through USB or Bluetooth serial interface

2. tty device
+ full tty port like USB, Bluetooth or UART connection (w/o driver)
+ handles tcsetattr like USB, Bluetooth or UART
+ buffering and line disciplines come for free (at least wrt. driver code)
+ tested
- seems to appear to be complex and overkill and a hack (but IMHO is neither)

3. some new gps interface API
+ could become very elegant and general
- does not exist (AFAIK not even a plan but I am not aware of everything)
- no user-space daemons and applications exist which use it

4. no driver and use UART directly
+ a non-solution seems to be attractive
- must turn on/off chip by gpio hacks from user-space
- can not guarantee (!) to power off the chip if the last user-space process using it is killed
  (which is essential for power-management of a handheld, battery operated device)

I would clearly prefer 3 over 2 over 1 over 4.

So do you see a chance that the kernel core team provides something useable
(not perfect) for variant 3 in reasonable time (let's say 3-6 months)?

If not, I want to suggest to accept the second-best choice 2. for now and we
will update the driver as soon as 3. appears. IMHO it would be a good test case
for a new subsystem.

Please advise how you want to proceed.

BR and thanks,
Nikolaus

^ permalink raw reply

* [PATCH, v2] arm: omap2: timer: fix a kmemleak caused in omap_get_timer_dt
From: Ladislav Michl @ 2018-01-09 11:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515489861-1474-1-git-send-email-qi.hou@windriver.com>

On Tue, Jan 09, 2018 at 05:24:21PM +0800, Qi Hou wrote:
> When more than one GP timers are used as kernel system timers and the
> corresponding nodes in device-tree are marked with the same "disabled"
> property, then the "attr" field of the property will be initialized
> more than once as the property being added to sys file system via
> __of_add_property_sysfs().
> 
> In __of_add_property_sysfs(), the "name" field of pp->attr.attr is set
> directly to the return value of safe_name(), without taking care of
> whether it's already a valid pointer to a memory block. If it is, its
> old value will always be overwritten by the new one and the memory block
> allocated before will a "ghost", then a kmemleak happened.

As timers does not seem to be deallocated, this does not matter in practice.
Fix eats a bit more from heap.

> That the same "disabled" property being added to different nodes of device
> tree would cause that kind of kmemleak overhead, at leat once.
> 
> To fix it, allocate the property dynamically, and delete static one.
>
> Signed-off-by: Qi Hou <qi.hou@windriver.com>
> ---
>  arch/arm/mach-omap2/timer.c | 19 +++++++++++--------
>  1 file changed, 11 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
> index ece09c9..206ae8d 100644
> --- a/arch/arm/mach-omap2/timer.c
> +++ b/arch/arm/mach-omap2/timer.c
> @@ -156,12 +156,6 @@ static struct clock_event_device clockevent_gpt = {
>  	.tick_resume		= omap2_gp_timer_shutdown,
>  };
>  
> -static struct property device_disabled = {
> -	.name = "status",
> -	.length = sizeof("disabled"),
> -	.value = "disabled",
> -};
> -
>  static const struct of_device_id omap_timer_match[] __initconst = {
>  	{ .compatible = "ti,omap2420-timer", },
>  	{ .compatible = "ti,omap3430-timer", },
> @@ -203,8 +197,17 @@ static struct device_node * __init omap_get_timer_dt(const struct of_device_id *
>  				  of_get_property(np, "ti,timer-secure", NULL)))
>  			continue;
>  
> -		if (!of_device_is_compatible(np, "ti,omap-counter32k"))
> -			of_add_property(np, &device_disabled);
> +		if (!of_device_is_compatible(np, "ti,omap-counter32k")) {
> +			struct property *prop;
> +
> +			prop = kzalloc(sizeof(*prop), GFP_KERNEL);
> +			if (!prop)
> +				return NULL;
> +			prop->name = "status";
> +			prop->length = sizeof("disabled");
> +			prop->value = "disabled";

How about (see drivers/of/unittest.c)?
prop->value = "disabled";
prop->length = strlen(prop->value);

> +			of_add_property(np, prop);
> +		}
>  		return np;
>  	}
>  
> -- 
> 2.7.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH 2/9] soc: samsung: pmu: Add powerup_conf callback
From: Krzysztof Kozlowski @ 2018-01-09 11:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515484746-10656-3-git-send-email-cw00.choi@samsung.com>

On Tue, Jan 9, 2018 at 8:58 AM, Chanwoo Choi <cw00.choi@samsung.com> wrote:
> This patch adds the powerup_conf callback which is used to re-initialize

Do not describe every patch as this patch. It does not bring any
information because I am already looking at this patch.
http://elixir.free-electrons.com/linux/latest/source/Documentation/process/submitting-patches.rst#L151

> the PMU registers during the resume state.
>
> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
> ---
>  drivers/soc/samsung/exynos-pmu.c       | 8 ++++++++
>  drivers/soc/samsung/exynos-pmu.h       | 1 +
>  include/linux/soc/samsung/exynos-pmu.h | 1 +
>  3 files changed, 10 insertions(+)
>
> diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c
> index f56adbd9fb8b..cfc9de518344 100644
> --- a/drivers/soc/samsung/exynos-pmu.c
> +++ b/drivers/soc/samsung/exynos-pmu.c
> @@ -58,6 +58,14 @@ void exynos_sys_powerdown_conf(enum sys_powerdown mode)
>                 pmu_data->powerdown_conf_extra(mode);
>  }
>
> +void exynos_sys_powerup_conf(enum sys_powerdown mode)
> +{
> +       const struct exynos_pmu_data *pmu_data = pmu_context->pmu_data;
> +

Follow the existing pattern of exynos_sys_powerdown_conf() to check if
pmu_context was initialized. At this commit, for Exynos5433 it is not
being set.

Best regards,
Krzysztof

> +       if (pmu_data->powerup_conf)
> +               pmu_data->powerup_conf(mode);
> +}
> +
>  /*
>   * Split the data between ARM architectures because it is relatively big
>   * and useless on other arch.
> diff --git a/drivers/soc/samsung/exynos-pmu.h b/drivers/soc/samsung/exynos-pmu.h
> index 977e4daf5a0f..efbaf8929252 100644
> --- a/drivers/soc/samsung/exynos-pmu.h
> +++ b/drivers/soc/samsung/exynos-pmu.h
> @@ -24,6 +24,7 @@ struct exynos_pmu_data {
>         void (*pmu_init)(void);
>         void (*powerdown_conf)(enum sys_powerdown);
>         void (*powerdown_conf_extra)(enum sys_powerdown);
> +       void (*powerup_conf)(enum sys_powerdown);
>  };
>
>  extern void __iomem *pmu_base_addr;
> diff --git a/include/linux/soc/samsung/exynos-pmu.h b/include/linux/soc/samsung/exynos-pmu.h
> index e57eb4b6cc5a..3aacf7b18401 100644
> --- a/include/linux/soc/samsung/exynos-pmu.h
> +++ b/include/linux/soc/samsung/exynos-pmu.h
> @@ -22,6 +22,7 @@ enum sys_powerdown {
>  };
>
>  extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
> +extern void exynos_sys_powerup_conf(enum sys_powerdown mode);
>  #ifdef CONFIG_EXYNOS_PMU
>  extern struct regmap *exynos_get_pmu_regmap(void);
>  #else
> --
> 1.9.1
>

^ permalink raw reply

* [PATCH 3/3] ARM: dts: imx7d-sdb: Add support for mpl3115 sensor
From: Marco Franchi @ 2018-01-09 11:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515498385-23198-1-git-send-email-marco.franchi@nxp.com>

The i.MX 7D SDB has a MPL3115 Pressure sensor.
Add support for this sensor, which is included in the trivial i2c devices 
and according to the bindings documentation, just need a compatible field 
and an address.

Signed-off-by: Marco Franchi <marco.franchi@nxp.com>
---
 arch/arm/boot/dts/imx7d-sdb.dts | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/boot/dts/imx7d-sdb.dts b/arch/arm/boot/dts/imx7d-sdb.dts
index a7a5dc7..a20c942 100644
--- a/arch/arm/boot/dts/imx7d-sdb.dts
+++ b/arch/arm/boot/dts/imx7d-sdb.dts
@@ -336,6 +336,11 @@
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_i2c2>;
 	status = "okay";
+
+	mpl3115 at 60 {
+		compatible = "fsl,mpl3115";
+		reg = <0x60>;
+	};
 };
 
 &i2c3 {
-- 
2.7.4

^ permalink raw reply related

* [PATCH 2/3] ARM: imx: Update imx_v6_v7_defconfig for mag3110 support
From: Marco Franchi @ 2018-01-09 11:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515498385-23198-1-git-send-email-marco.franchi@nxp.com>

The i.MX 6UL EVK has support for the MAG3110 Magnetometer sensor, included 
in its base board by default.

So add support for this Magnetometer in the imx_v6_v7_defconfig.

Signed-off-by: Marco Franchi <marco.franchi@nxp.com>
---
 arch/arm/configs/imx_v6_v7_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 4cb9829..ebff980 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -369,6 +369,7 @@ CONFIG_COMMON_CLK_PWM=y
 CONFIG_IIO=y
 CONFIG_IMX7D_ADC=y
 CONFIG_VF610_ADC=y
+CONFIG_MAG3110=y
 CONFIG_MPL3115=y
 CONFIG_PWM=y
 CONFIG_PWM_FSL_FTM=y
-- 
2.7.4

^ permalink raw reply related

* [PATCH 1/3] ARM: dts: imx6ul-evk: Add support for mag3110 sensor
From: Marco Franchi @ 2018-01-09 11:46 UTC (permalink / raw)
  To: linux-arm-kernel

The i.MX 6UL EVK has a MAG3110 Magnetometer sensor in its base board.
Add support for this sensor, which is included in the trivial i2c devices 
and according to the bindings documentation, just need a compatible field 
and an address.

Signed-off-by: Marco Franchi <marco.franchi@nxp.com>
---
 arch/arm/boot/dts/imx6ul-14x14-evk.dts | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk.dts b/arch/arm/boot/dts/imx6ul-14x14-evk.dts
index 18fdb08..cb33baa 100644
--- a/arch/arm/boot/dts/imx6ul-14x14-evk.dts
+++ b/arch/arm/boot/dts/imx6ul-14x14-evk.dts
@@ -140,6 +140,17 @@
 	};
 };
 
+&i2c1 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	status = "okay";
+
+	mag3110 at e {
+		compatible = "fsl,mag3110";
+		reg = <0x0e>;
+	};
+};
 
 &lcdif {
 	assigned-clocks = <&clks IMX6UL_CLK_LCDIF_PRE_SEL>;
-- 
2.7.4

^ permalink raw reply related

* arm64 crashkernel fails to boot on acpi-only machines due to ACPI regions being no longer mapped as NOMAP
From: Bhupesh Sharma @ 2018-01-09 11:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180109030717.GA18820@linaro.org>

On Tue, Jan 9, 2018 at 10:12 AM, AKASHI Takahiro
<takahiro.akashi@linaro.org> wrote:
> Bhupesh,
>
> On Tue, Jan 09, 2018 at 01:30:07AM +0530, Bhupesh Sharma wrote:
>> Hello Akashi,
>>
>> On Tue, Dec 26, 2017 at 8:26 AM, Bhupesh Sharma <bhsharma@redhat.com> wrote:
>> > On Tue, Dec 26, 2017 at 7:58 AM, AKASHI Takahiro
>> > <takahiro.akashi@linaro.org> wrote:
>> >> On Tue, Dec 26, 2017 at 09:35:17AM +0800, Dave Young wrote:
>> >>> [snip]
>> >>> > > > Well, we may be able to change pr_warn() to pr_warn_once() here, but
>> >>> > > > I hope that adding "numa=off" to kernel command line should also work.
>> >>> > >
>> >>> > > Hmm, adding "numa=off" to crashkernel bootargs works, and TBH it was
>> >>> > > my initial thought process as well, but I am not sure if this will
>> >>> > > cause any regressions on aarch64 systems which use crashdump feature.
>> >>> >
>> >>> > It should be fine since we use numa=off by default for all other arches
>> >>> > ie. x86, ppc64 and s390. Actually disabling numa in kdump kernel can save
>> >>> > mm component memory usage.
>> >>> >
>> >>>
>> >>> Forgot to say I means in RHEL and Fedora we use numa=off for kdump..
>> >>
>> >> Thank you for the clarification.
>> >> (It might be better to make numa off automatically if maxcpus == 0 (and 1?).)
>> >>
>> >
>> > Not sure if we can leave this to the distribution-specific kdump
>> > scripts (as the crashkernel boot can be held up for sufficient time
>> > and may appear stuck). The distribution scripts may be different (for
>> > e.g. ubuntu and RHEL/fedora) across distributions and may have
>> > different bootarg options.
>> >
>> > So how about considering a kernel fix only which doesn't require
>> > relying on changing the distribution-specific kdump scripts, as we
>> > should avoid introducing a regression while trying to fix a regression
>> > :)
>> >
>> > Just my 2 cents.
>> >
>>
>> Sorry for the delay but I was on holidays in the last week.
>>
>> Are you planning to send a patch to fix this issue or do you want me
>> to send a RFC version instead?
>
> I should have submitted my own patch before my new year holidays,
> but I will do so as soon as possible.

Thanks for the confirmation.
I will look forward to the patches and give them a go on the arm64
boards available with me.

Regards,
Bhupesh

>
>> i think this is a blocking issue for aarch64 kdump support on newer
>> kernels (v4.14) and we are already hearing about this issue from other
>> users as well, so it would be great to get this fixed now that we have
>> root-caused the issue and found a possible way around.
>>
>> Regards,
>> Bhupesh

^ permalink raw reply

* [PATCH 1/9] clk: samsung: exynos5433: Add clock flag to support suspend-to-ram
From: Krzysztof Kozlowski @ 2018-01-09 11:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515484746-10656-2-git-send-email-cw00.choi@samsung.com>

On Tue, Jan 9, 2018 at 8:58 AM, Chanwoo Choi <cw00.choi@samsung.com> wrote:
> This patch adds the CLK_IS_CRITICAL and CLK_IGNORE_UNUSED flag
> to some clocks in order to avoid the hang-out in the suspend mode.
>
> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
> Cc: Tomasz Figa <tomasz.figa@gmail.com>
> Cc: Michael Turquette <mturquette@baylibre.com>
> Cc: Stephen Boyd <sboyd@codeaurora.org>
> Cc: linux-clk at vger.kernel.org
> ---
>  drivers/clk/samsung/clk-exynos5433.c | 22 +++++++++++-----------
>  1 file changed, 11 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c
> index db270908037a..3dc53cd0c730 100644
> --- a/drivers/clk/samsung/clk-exynos5433.c
> +++ b/drivers/clk/samsung/clk-exynos5433.c
> @@ -583,25 +583,25 @@
>                         CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
>         GATE(CLK_ACLK_CAM1_333, "aclk_cam1_333", "div_aclk_cam1_333",
>                         ENABLE_ACLK_TOP, 13,
> -                       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
> +                       CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0),
>         GATE(CLK_ACLK_CAM1_400, "aclk_cam1_400", "div_aclk_cam1_400",
>                         ENABLE_ACLK_TOP, 12,
>                         CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0),
>         GATE(CLK_ACLK_CAM1_552, "aclk_cam1_552", "div_aclk_cam1_552",
>                         ENABLE_ACLK_TOP, 11,
> -                       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
> +                       CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0),
>         GATE(CLK_ACLK_CAM0_333, "aclk_cam0_333", "div_aclk_cam0_333",
>                         ENABLE_ACLK_TOP, 10,
> -                       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
> +                       CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0),
>         GATE(CLK_ACLK_CAM0_400, "aclk_cam0_400", "div_aclk_cam0_400",
>                         ENABLE_ACLK_TOP, 9,
>                         CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0),
>         GATE(CLK_ACLK_CAM0_552, "aclk_cam0_552", "div_aclk_cam0_552",
>                         ENABLE_ACLK_TOP, 8,
> -                       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
> +                       CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0),
>         GATE(CLK_ACLK_ISP_DIS_400, "aclk_isp_dis_400", "div_aclk_isp_dis_400",
>                         ENABLE_ACLK_TOP, 7,
> -                       CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, 0),
> +                       CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0),
>         GATE(CLK_ACLK_ISP_400, "aclk_isp_400", "div_aclk_isp_400",
>                         ENABLE_ACLK_TOP, 6,
>                         CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0),
> @@ -624,11 +624,11 @@
>
>         /* ENABLE_SCLK_TOP_CAM1 */
>         GATE(CLK_SCLK_ISP_SENSOR2, "sclk_isp_sensor2", "div_sclk_isp_sensor2_b",
> -                       ENABLE_SCLK_TOP_CAM1, 7, 0, 0),
> +                       ENABLE_SCLK_TOP_CAM1, 7, CLK_IGNORE_UNUSED, 0),
>         GATE(CLK_SCLK_ISP_SENSOR1, "sclk_isp_sensor1", "div_sclk_isp_sensor1_b",
>                         ENABLE_SCLK_TOP_CAM1, 6, 0, 0),
>         GATE(CLK_SCLK_ISP_SENSOR0, "sclk_isp_sensor0", "div_sclk_isp_sensor0_b",
> -                       ENABLE_SCLK_TOP_CAM1, 5, 0, 0),
> +                       ENABLE_SCLK_TOP_CAM1, 5, CLK_IGNORE_UNUSED, 0),

Marking this and few others related to ISP as ignore_unused or
is_critical looks like a hacky workaround for wrong topology or
missing clock users. The real cause should be fixed instead marking
all the clocks as critical or ignore_unused.

Best regards,
Krzysztof

>         GATE(CLK_SCLK_ISP_MCTADC_CAM1, "sclk_isp_mctadc_cam1", "oscclk",
>                         ENABLE_SCLK_TOP_CAM1, 4, 0, 0),
>         GATE(CLK_SCLK_ISP_UART_CAM1, "sclk_isp_uart_cam1", "div_sclk_isp_uart",
> @@ -636,7 +636,7 @@
>         GATE(CLK_SCLK_ISP_SPI1_CAM1, "sclk_isp_spi1_cam1", "div_sclk_isp_spi1_b",
>                         ENABLE_SCLK_TOP_CAM1, 1, 0, 0),
>         GATE(CLK_SCLK_ISP_SPI0_CAM1, "sclk_isp_spi0_cam1", "div_sclk_isp_spi0_b",
> -                       ENABLE_SCLK_TOP_CAM1, 0, 0, 0),
> +                       ENABLE_SCLK_TOP_CAM1, 0, CLK_IGNORE_UNUSED, 0),
>
>         /* ENABLE_SCLK_TOP_DISP */
>         GATE(CLK_SCLK_HDMI_SPDIF_DISP, "sclk_hdmi_spdif_disp",
> @@ -654,7 +654,7 @@
>                         ENABLE_SCLK_TOP_FSYS, 4, CLK_SET_RATE_PARENT, 0),
>         GATE(CLK_SCLK_UFSUNIPRO_FSYS, "sclk_ufsunipro_fsys",
>                         "div_sclk_ufsunipro", ENABLE_SCLK_TOP_FSYS,
> -                       3, CLK_SET_RATE_PARENT, 0),
> +                       3, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0),
>         GATE(CLK_SCLK_USBHOST30_FSYS, "sclk_usbhost30_fsys",
>                         "div_sclk_usbhost30", ENABLE_SCLK_TOP_FSYS,
>                         1, CLK_SET_RATE_PARENT, 0),
> @@ -2982,7 +2982,7 @@ static void __init exynos5433_cmu_peris_init(struct device_node *np)
>         GATE(CLK_PCLK_AUD_SLIMBUS, "pclk_aud_slimbus", "div_aclk_aud",
>                         ENABLE_PCLK_AUD, 6, 0, 0),
>         GATE(CLK_PCLK_AUD_UART, "pclk_aud_uart", "div_aclk_aud",
> -                       ENABLE_PCLK_AUD, 5, 0, 0),
> +                       ENABLE_PCLK_AUD, 5, CLK_IS_CRITICAL, 0),
>         GATE(CLK_PCLK_AUD_PCM, "pclk_aud_pcm", "div_aclk_aud",
>                         ENABLE_PCLK_AUD, 4, 0, 0),
>         GATE(CLK_PCLK_AUD_I2S, "pclk_aud_i2s", "div_aclk_aud",
> @@ -3008,7 +3008,7 @@ static void __init exynos5433_cmu_peris_init(struct device_node *np)
>         GATE(CLK_SCLK_AUD_SLIMBUS, "sclk_aud_slimbus", "div_sclk_aud_slimbus",
>                         ENABLE_SCLK_AUD1, 4, 0, 0),
>         GATE(CLK_SCLK_AUD_UART, "sclk_aud_uart", "div_sclk_aud_uart",
> -                       ENABLE_SCLK_AUD1, 3, CLK_IGNORE_UNUSED, 0),
> +                       ENABLE_SCLK_AUD1, 3, CLK_IS_CRITICAL, 0),
>         GATE(CLK_SCLK_AUD_PCM, "sclk_aud_pcm", "div_sclk_aud_pcm",
>                         ENABLE_SCLK_AUD1, 2, 0, 0),
>         GATE(CLK_SCLK_I2S_BCLK, "sclk_i2s_bclk", "ioclk_i2s_bclk",
> --
> 1.9.1
>

^ permalink raw reply

* arm: Is VFP hotplug notifiers wrong?
From: Russell King - ARM Linux @ 2018-01-09 11:40 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180109.201221.1319754994300492102.okuno.kohji@jp.panasonic.com>

On Tue, Jan 09, 2018 at 08:12:21PM +0900, Kohji Okuno wrote:
> Dear Thomas and all,
> 
> Could you please confirm about the following commit, again?
> 
> http://git.armlinux.org.uk/cgit/linux-arm.git/commit/arch/arm/vfp/vfpmodule.c?id=e5b61bafe70477e05e1dce0d6ca4ec181e23cb2a
> 
> 
> The avobe commit eliminated the following fix, I think.
> 
> http://git.armlinux.org.uk/cgit/linux-arm.git/commit/arch/arm/vfp/vfpmodule.c?id=384b38b66947b06999b3e39a596d4f2fb94f77e4
> 
> 
> vfp_force_reload() called from vfp_dying_cpu() does not clear
> vfp_current_hw_state[cpu], because cpu stopper task does not own the
> context held in the VFP hardware.

You are correct, tglx's patch was wrong, since the state in the CPU may
not be the current thread's state, so vfp_force_reload() may not do
anything.

vfp_force_reload() forces the reload of the specified state for the
specified CPU.  What the original hotplug code did was to ensure that
the CPU's state would be reloaded when it came back up.

I do wish that people wouldn't combine functional changes and cleanups
into one patch - it makes this kind of thing harder to spot in review
and also means when we encounter crap like this, it means we can't
simply revert the cleanup.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up

^ permalink raw reply

* arm: Is VFP hotplug notifiers wrong?
From: Kohji Okuno @ 2018-01-09 11:12 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Thomas and all,

Could you please confirm about the following commit, again?

http://git.armlinux.org.uk/cgit/linux-arm.git/commit/arch/arm/vfp/vfpmodule.c?id=e5b61bafe70477e05e1dce0d6ca4ec181e23cb2a


The avobe commit eliminated the following fix, I think.

http://git.armlinux.org.uk/cgit/linux-arm.git/commit/arch/arm/vfp/vfpmodule.c?id=384b38b66947b06999b3e39a596d4f2fb94f77e4


vfp_force_reload() called from vfp_dying_cpu() does not clear
vfp_current_hw_state[cpu], because cpu stopper task does not own the
context held in the VFP hardware.

Best regards,
 Kohji Okuno

^ permalink raw reply

* [PATCH] ARM: imx: Improve the soc revision calculation flow
From: A.s. Dong @ 2018-01-09 11:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <HE1PR04MB311350113E67477E2D0A55D187100@HE1PR04MB3113.eurprd04.prod.outlook.com>

> -----Original Message-----
> From: Jacky Bai
> Sent: Tuesday, January 09, 2018 7:07 PM
> To: A.s. Dong <aisheng.dong@nxp.com>; shawnguo at kernel.org;
> kernel at pengutronix.de; Fabio Estevam <fabio.estevam@nxp.com>
> Cc: linux-arm-kernel at lists.infradead.org; dl-linux-imx <linux-imx@nxp.com>;
> jacky.baip at gmail.com
> Subject: RE: [PATCH] ARM: imx: Improve the soc revision calculation flow
> 
> 
> 
> > -----Original Message-----
> > From: A.s. Dong
> > Sent: 2018?1?9? 18:59
> > To: Jacky Bai <ping.bai@nxp.com>; shawnguo at kernel.org;
> > kernel at pengutronix.de; Fabio Estevam <fabio.estevam@nxp.com>
> > Cc: linux-arm-kernel at lists.infradead.org; dl-linux-imx
> > <linux-imx@nxp.com>; jacky.baip at gmail.com
> > Subject: RE: [PATCH] ARM: imx: Improve the soc revision calculation
> > flow
> >
> > Hi Jacky,
> >
> > > -----Original Message-----
> > > From: Jacky Bai
> > > Sent: Tuesday, January 09, 2018 4:31 PM
> > > To: shawnguo at kernel.org; kernel at pengutronix.de; Fabio Estevam
> > > <fabio.estevam@nxp.com>
> > > Cc: linux-arm-kernel at lists.infradead.org; dl-linux-imx
> > > <linux-imx@nxp.com>; A.s. Dong <aisheng.dong@nxp.com>;
> > > jacky.baip at gmail.com
> > > Subject: [PATCH] ARM: imx: Improve the soc revision calculation flow
> > >
> > > On our i.MX6 SOC, the DIGPROG register is used for representing the
> > > SOC ID and silicon revision. The revision has two part: MAJOR and
> > > MINOR. each is represented in 8 bits in the register.
> > >
> > > bits [15:8]: reflect the MAJOR part of the revision; bits [7:0]:
> > > reflect the MINOR part of the revision;
> > >
> > > In our linux kernel, the soc revision is represented in 8 bits.
> > > MAJOR part and MINOR each occupy 4 bits.
> > >
> > > previous method does NOT take care about the MAJOR part in DIGPROG
> > > register. So reformat the revision read from the HW to be compatible
> > > with the revision format used in kernel.
> > >
> >
> > It would be better if there's more clarification on the real effect of
> > this patch in commit message.
> > e.g. what real issue it could be if without this patch?
> >
> > I guess it would show rev over 2.x correctly, right?
> 
> 
> Yes, this patch is mainly for fix the >= 2.1 revision issue we meet on QP.
> 
> >
> > BTW, since this patch totally remove the using of already defined rev
> > macros, I wonder if it's a good idea.
> >
> > Just a thought, how about do something like mx3 which keeps using the
> macros?
> >
> 
> As anatop module is common for all i.MX 6SL, SLL, Solo, DL, DQ, DQP and 7D, If
> we use the way like mx3, Maybe we need to add many static struct to cover all
> the above platform?

Yes, as the data you used actually are according to rev macros. So a bit strange not use.

Shawn,
Or what your suggestion?

Regards
Dong Aisheng

> 
> BR
> Jacky Bai
> > static struct {
> >         u8 srev;
> >         const char *name;
> >         unsigned int rev;
> > } mx31_cpu_type[] = {
> >         { .srev = 0x00, .name = "i.MX31(L)", .rev = IMX_CHIP_REVISION_1_0 },
> >         { .srev = 0x10, .name = "i.MX31",    .rev =
> > IMX_CHIP_REVISION_1_1 },
> >         { .srev = 0x11, .name = "i.MX31L",   .rev =
> > IMX_CHIP_REVISION_1_1 },
> >         { .srev = 0x12, .name = "i.MX31",    .rev =
> > IMX_CHIP_REVISION_1_1 },
> >         { .srev = 0x13, .name = "i.MX31L",   .rev =
> > IMX_CHIP_REVISION_1_1 },
> >         { .srev = 0x14, .name = "i.MX31",    .rev =
> > IMX_CHIP_REVISION_1_2 },
> >         { .srev = 0x15, .name = "i.MX31L",   .rev =
> > IMX_CHIP_REVISION_1_2 },
> >         { .srev = 0x28, .name = "i.MX31",    .rev =
> > IMX_CHIP_REVISION_2_0 },
> >         { .srev = 0x29, .name = "i.MX31L",   .rev =
> > IMX_CHIP_REVISION_2_0 },
> > };
> > static int mx31_read_cpu_rev(void)
> >
> > Regards
> > Dong Aisheng
> >
> >
> > > Signed-off-by: Bai Ping <ping.bai@nxp.com>
> > > ---
> > >  arch/arm/mach-imx/anatop.c | 58
> > > +++++++++++++++++--------------------------
> > > ---
> > >  1 file changed, 21 insertions(+), 37 deletions(-)
> > >
> > > diff --git a/arch/arm/mach-imx/anatop.c b/arch/arm/mach-imx/anatop.c
> > > index
> > > 649a84c..170cb30 100644
> > > --- a/arch/arm/mach-imx/anatop.c
> > > +++ b/arch/arm/mach-imx/anatop.c
> > > @@ -1,5 +1,6 @@
> > >  /*
> > >   * Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
> > > + * Copyright NXP 2017.
> > >   *
> > >   * The code contained herein is licensed under the GNU General Public
> > >   * License. You may obtain a copy of the GNU General Public License
> > > @@ -
> > > 116,6 +117,8 @@ void __init imx_init_revision_from_anatop(void)
> > >  	unsigned int revision;
> > >  	u32 digprog;
> > >  	u16 offset = ANADIG_DIGPROG;
> > > +	u16 major_part, minor_part;
> > > +
> > >
> > >  	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
> > >  	anatop_base = of_iomap(np, 0);
> > > @@ -127,45 +130,26 @@ void __init imx_init_revision_from_anatop(void)
> > >  	digprog = readl_relaxed(anatop_base + offset);
> > >  	iounmap(anatop_base);
> > >
> > > -	switch (digprog & 0xff) {
> > > -	case 0:
> > > -		/*
> > > -		 * For i.MX6QP, most of the code for i.MX6Q can be resued,
> > > -		 * so internally, we identify it as i.MX6Q Rev 2.0
> > > -		 */
> > > -		if (digprog >> 8 & 0x01)
> > > -			revision = IMX_CHIP_REVISION_2_0;
> > > -		else
> > > -			revision = IMX_CHIP_REVISION_1_0;
> > > -		break;
> > > -	case 1:
> > > -		revision = IMX_CHIP_REVISION_1_1;
> > > -		break;
> > > -	case 2:
> > > -		revision = IMX_CHIP_REVISION_1_2;
> > > -		break;
> > > -	case 3:
> > > -		revision = IMX_CHIP_REVISION_1_3;
> > > -		break;
> > > -	case 4:
> > > -		revision = IMX_CHIP_REVISION_1_4;
> > > -		break;
> > > -	case 5:
> > > -		/*
> > > -		 * i.MX6DQ TO1.5 is defined as Rev 1.3 in Data Sheet, marked
> > > -		 * as 'D' in Part Number last character.
> > > -		 */
> > > -		revision = IMX_CHIP_REVISION_1_5;
> > > -		break;
> > > -	default:
> > > -		/*
> > > -		 * Fail back to return raw register value instead of 0xff.
> > > -		 * It will be easy to know version information in SOC if it
> > > -		 * can't be recognized by known version. And some chip's
> > > (i.MX7D)
> > > -		 * digprog value match linux version format, so it needn't map
> > > -		 * again and we can use register value directly.
> > > +	/*
> > > +	 * On i.MX7D digprog value match linux version format, so
> > > +	 * it needn't map again and we can use register value directly.
> > > +	 */
> > > +	if (of_device_is_compatible(np, "fsl,imx7d-anatop")) {
> > > +		revision = digprog & 0xff;
> > > +	} else {
> > > +
> > > +		/* MAJOR: [15:8], the major silicon revison;
> > > +		 * MINOR: [7: 0], the minor silicon revison;
> > > +		 *
> > > +		 * please refer to the i.MX RM for the detailed
> > > +		 * silicon revison bit define.
> > > +		 * format the major part and minor part to match the
> > > +		 * linux kernel soc version format.
> > >  		 */
> > >  		revision = digprog & 0xff;
> > > +		major_part = (digprog >> 8) & 0xf;
> > > +		minor_part = digprog & 0xf;
> > > +		revision = ((major_part + 1) << 4) | minor_part;
> > >  	}
> > >
> > >  	mxc_set_cpu_type(digprog >> 16 & 0xff);
> > > --
> > > 1.9.1

^ permalink raw reply

* [PATCH] ARM: imx: Improve the soc revision calculation flow
From: Jacky Bai @ 2018-01-09 11:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <AM3PR04MB30614F10E6938D057D83A8180100@AM3PR04MB306.eurprd04.prod.outlook.com>



> -----Original Message-----
> From: A.s. Dong
> Sent: 2018?1?9? 18:59
> To: Jacky Bai <ping.bai@nxp.com>; shawnguo at kernel.org;
> kernel at pengutronix.de; Fabio Estevam <fabio.estevam@nxp.com>
> Cc: linux-arm-kernel at lists.infradead.org; dl-linux-imx <linux-imx@nxp.com>;
> jacky.baip at gmail.com
> Subject: RE: [PATCH] ARM: imx: Improve the soc revision calculation flow
> 
> Hi Jacky,
> 
> > -----Original Message-----
> > From: Jacky Bai
> > Sent: Tuesday, January 09, 2018 4:31 PM
> > To: shawnguo at kernel.org; kernel at pengutronix.de; Fabio Estevam
> > <fabio.estevam@nxp.com>
> > Cc: linux-arm-kernel at lists.infradead.org; dl-linux-imx
> > <linux-imx@nxp.com>; A.s. Dong <aisheng.dong@nxp.com>;
> > jacky.baip at gmail.com
> > Subject: [PATCH] ARM: imx: Improve the soc revision calculation flow
> >
> > On our i.MX6 SOC, the DIGPROG register is used for representing the
> > SOC ID and silicon revision. The revision has two part: MAJOR and
> > MINOR. each is represented in 8 bits in the register.
> >
> > bits [15:8]: reflect the MAJOR part of the revision; bits [7:0]:
> > reflect the MINOR part of the revision;
> >
> > In our linux kernel, the soc revision is represented in 8 bits.
> > MAJOR part and MINOR each occupy 4 bits.
> >
> > previous method does NOT take care about the MAJOR part in DIGPROG
> > register. So reformat the revision read from the HW to be compatible
> > with the revision format used in kernel.
> >
> 
> It would be better if there's more clarification on the real effect of this patch in
> commit message.
> e.g. what real issue it could be if without this patch?
> 
> I guess it would show rev over 2.x correctly, right?


Yes, this patch is mainly for fix the >= 2.1 revision issue we meet on QP.

> 
> BTW, since this patch totally remove the using of already defined rev macros, I
> wonder if it's a good idea.
> 
> Just a thought, how about do something like mx3 which keeps using the macros?
> 

As anatop module is common for all i.MX 6SL, SLL, Solo, DL, DQ, DQP and 7D, If we use the way like mx3,
Maybe we need to add many static struct to cover all the above platform?

BR
Jacky Bai
> static struct {
>         u8 srev;
>         const char *name;
>         unsigned int rev;
> } mx31_cpu_type[] = {
>         { .srev = 0x00, .name = "i.MX31(L)", .rev = IMX_CHIP_REVISION_1_0 },
>         { .srev = 0x10, .name = "i.MX31",    .rev =
> IMX_CHIP_REVISION_1_1 },
>         { .srev = 0x11, .name = "i.MX31L",   .rev =
> IMX_CHIP_REVISION_1_1 },
>         { .srev = 0x12, .name = "i.MX31",    .rev =
> IMX_CHIP_REVISION_1_1 },
>         { .srev = 0x13, .name = "i.MX31L",   .rev =
> IMX_CHIP_REVISION_1_1 },
>         { .srev = 0x14, .name = "i.MX31",    .rev =
> IMX_CHIP_REVISION_1_2 },
>         { .srev = 0x15, .name = "i.MX31L",   .rev =
> IMX_CHIP_REVISION_1_2 },
>         { .srev = 0x28, .name = "i.MX31",    .rev =
> IMX_CHIP_REVISION_2_0 },
>         { .srev = 0x29, .name = "i.MX31L",   .rev =
> IMX_CHIP_REVISION_2_0 },
> };
> static int mx31_read_cpu_rev(void)
> 
> Regards
> Dong Aisheng
> 
> 
> > Signed-off-by: Bai Ping <ping.bai@nxp.com>
> > ---
> >  arch/arm/mach-imx/anatop.c | 58
> > +++++++++++++++++--------------------------
> > ---
> >  1 file changed, 21 insertions(+), 37 deletions(-)
> >
> > diff --git a/arch/arm/mach-imx/anatop.c b/arch/arm/mach-imx/anatop.c
> > index
> > 649a84c..170cb30 100644
> > --- a/arch/arm/mach-imx/anatop.c
> > +++ b/arch/arm/mach-imx/anatop.c
> > @@ -1,5 +1,6 @@
> >  /*
> >   * Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
> > + * Copyright NXP 2017.
> >   *
> >   * The code contained herein is licensed under the GNU General Public
> >   * License. You may obtain a copy of the GNU General Public License
> > @@ -
> > 116,6 +117,8 @@ void __init imx_init_revision_from_anatop(void)
> >  	unsigned int revision;
> >  	u32 digprog;
> >  	u16 offset = ANADIG_DIGPROG;
> > +	u16 major_part, minor_part;
> > +
> >
> >  	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
> >  	anatop_base = of_iomap(np, 0);
> > @@ -127,45 +130,26 @@ void __init imx_init_revision_from_anatop(void)
> >  	digprog = readl_relaxed(anatop_base + offset);
> >  	iounmap(anatop_base);
> >
> > -	switch (digprog & 0xff) {
> > -	case 0:
> > -		/*
> > -		 * For i.MX6QP, most of the code for i.MX6Q can be resued,
> > -		 * so internally, we identify it as i.MX6Q Rev 2.0
> > -		 */
> > -		if (digprog >> 8 & 0x01)
> > -			revision = IMX_CHIP_REVISION_2_0;
> > -		else
> > -			revision = IMX_CHIP_REVISION_1_0;
> > -		break;
> > -	case 1:
> > -		revision = IMX_CHIP_REVISION_1_1;
> > -		break;
> > -	case 2:
> > -		revision = IMX_CHIP_REVISION_1_2;
> > -		break;
> > -	case 3:
> > -		revision = IMX_CHIP_REVISION_1_3;
> > -		break;
> > -	case 4:
> > -		revision = IMX_CHIP_REVISION_1_4;
> > -		break;
> > -	case 5:
> > -		/*
> > -		 * i.MX6DQ TO1.5 is defined as Rev 1.3 in Data Sheet, marked
> > -		 * as 'D' in Part Number last character.
> > -		 */
> > -		revision = IMX_CHIP_REVISION_1_5;
> > -		break;
> > -	default:
> > -		/*
> > -		 * Fail back to return raw register value instead of 0xff.
> > -		 * It will be easy to know version information in SOC if it
> > -		 * can't be recognized by known version. And some chip's
> > (i.MX7D)
> > -		 * digprog value match linux version format, so it needn't map
> > -		 * again and we can use register value directly.
> > +	/*
> > +	 * On i.MX7D digprog value match linux version format, so
> > +	 * it needn't map again and we can use register value directly.
> > +	 */
> > +	if (of_device_is_compatible(np, "fsl,imx7d-anatop")) {
> > +		revision = digprog & 0xff;
> > +	} else {
> > +
> > +		/* MAJOR: [15:8], the major silicon revison;
> > +		 * MINOR: [7: 0], the minor silicon revison;
> > +		 *
> > +		 * please refer to the i.MX RM for the detailed
> > +		 * silicon revison bit define.
> > +		 * format the major part and minor part to match the
> > +		 * linux kernel soc version format.
> >  		 */
> >  		revision = digprog & 0xff;
> > +		major_part = (digprog >> 8) & 0xf;
> > +		minor_part = digprog & 0xf;
> > +		revision = ((major_part + 1) << 4) | minor_part;
> >  	}
> >
> >  	mxc_set_cpu_type(digprog >> 16 & 0xff);
> > --
> > 1.9.1

^ permalink raw reply

* [PATCH 00/12] Marvell NAND controller rework with ->exec_op()
From: Miquel RAYNAL @ 2018-01-09 11:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <87zi5nbh14.fsf@belgarion.home>

Hello Robert,

On Tue, 09 Jan 2018 08:57:59 +0100
Robert Jarzmik <robert.jarzmik@free.fr> wrote:

> Boris Brezillon <boris.brezillon@free-electrons.com> writes:
> 
> Ok I recovered my NAND.
> 
> For the next try, I'd like you to provide another "temporary patch"
> to disable BBT actual writing, just to be sure. Once the driver is
> working properly, I'll make another try without the temporary patch.

The best way to do it is to avoid using the BBT at all, and while I was
looking for the right line to comment in the Zylonite's board file I
found out that the boolean flash_bbt is not actually set and then I
remembered an old mail from you, then you should:

----->8-----
diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
index 0534949d63f6..d247ef01dc62 100644
--- a/arch/arm/mach-pxa/zylonite.c
+++ b/arch/arm/mach-pxa/zylonite.c
@@ -378,6 +378,8 @@ static struct mtd_partition
zylonite_nand_partitions[] = { static struct pxa3xx_nand_platform_data
zylonite_nand_info = { .parts		= zylonite_nand_partitions,
 	.nr_parts	= ARRAY_SIZE(zylonite_nand_partitions),
-	.flash_bbt	= 1,
	.keep_config	= 1,
 };
 
 static void __init zylonite_init_nand(void)
-----8<-----

Then, do not forget to resize the partition that stores the BBT to
remove the last 4 erase blocks from it to avoid UBI/UBIFS smashing it.

Then you should be fine.

You can test this branch (updated with last version I sent earlier):
https://github.com/miquelraynal/linux/tree/marvell/nand-next/nfc


Thanks,
Miqu?l

^ permalink raw reply related

* [PATCH] arm64: Implement branch predictor hardening for Falkor
From: Catalin Marinas @ 2018-01-09 11:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180109094146.GB4297@arm.com>

On Tue, Jan 09, 2018 at 09:41:46AM +0000, Will Deacon wrote:
> You'll need to send a fixup patch. for-next/core is non-rebasing.

I haven't pushed it out yet (will do this morning) but note that
for-next/core is based on 4.15-rc3.

-- 
Catalin

^ permalink raw reply


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