Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 2/5] drm/modes: Support modes names on the command line
From: Sean Paul @ 2016-11-16 17:21 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <853193fdf9ec1af94056d9fa2c276079c779aaf4.1476779323.git-series.maxime.ripard@free-electrons.com>

On Tue, Oct 18, 2016 at 4:29 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> The drm subsystem also uses the video= kernel parameter, and in the
> documentation refers to the fbdev documentation for that parameter.
>
> However, that documentation also says that instead of giving the mode using
> its resolution we can also give a name. However, DRM doesn't handle that
> case at the moment. Even though in most case it shouldn't make any
> difference, it might be useful for analog modes, where different standards
> might have the same resolution, but still have a few different parameters
> that are not encoded in the modes (NTSC vs NTSC-J vs PAL-M for example).
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/drm_connector.c |  3 +-
>  drivers/gpu/drm/drm_fb_helper.c |  4 +++-
>  drivers/gpu/drm/drm_modes.c     | 49 +++++++++++++++++++++++-----------
>  include/drm/drm_connector.h     |  1 +-
>  4 files changed, 41 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index 2db7fb510b6c..27a8a511257c 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -147,8 +147,9 @@ static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
>                 connector->force = mode->force;
>         }
>
> -       DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
> +       DRM_DEBUG_KMS("cmdline mode for connector %s %s %dx%d@%dHz%s%s%s\n",
>                       connector->name,
> +                     mode->name ? mode->name : "",
>                       mode->xres, mode->yres,
>                       mode->refresh_specified ? mode->refresh : 60,
>                       mode->rb ? " reduced blanking" : "",
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 03414bde1f15..20a68305fb45 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -1748,6 +1748,10 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
>         prefer_non_interlace = !cmdline_mode->interlace;
>  again:
>         list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
> +               /* Check (optional) mode name first */
> +               if (!strcmp(mode->name, cmdline_mode->name))
> +                       return mode;
> +
>                 /* check width/height */
>                 if (mode->hdisplay != cmdline_mode->xres ||
>                     mode->vdisplay != cmdline_mode->yres)
> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
> index 7d5bdca276f2..fdbf541a5978 100644
> --- a/drivers/gpu/drm/drm_modes.c
> +++ b/drivers/gpu/drm/drm_modes.c
> @@ -1413,7 +1413,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
>                                                struct drm_cmdline_mode *mode)
>  {
>         const char *name;
> -       bool parse_extras = false;
> +       bool named_mode = false, parse_extras = false;
>         unsigned int bpp_off = 0, refresh_off = 0;
>         unsigned int mode_end = 0;
>         char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
> @@ -1432,8 +1432,14 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
>
>         name = mode_option;
>
> +       /*
> +        * If the first character is not a digit, then it means that
> +        * we have a named mode.
> +        */
>         if (!isdigit(name[0]))
> -               return false;
> +               named_mode = true;
> +       else
> +               named_mode = false;

named_mode = isalpha(name[0]); might be more succinct (and covers
special characters).

>
>         /* Try to locate the bpp and refresh specifiers, if any */
>         bpp_ptr = strchr(name, '-');
> @@ -1460,12 +1466,16 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
>                 parse_extras = true;
>         }
>
> -       ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
> -                                             parse_extras,
> -                                             connector,
> -                                             mode);
> -       if (ret)
> -               return false;
> +       if (named_mode) {
> +               strncpy(mode->name, name, mode_end);
> +       } else {
> +               ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
> +                                                     parse_extras,
> +                                                     connector,
> +                                                     mode);
> +               if (ret)
> +                       return false;
> +       }
>         mode->specified = true;
>
>         if (bpp_ptr) {
> @@ -1493,14 +1503,23 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
>                 extra_ptr = refresh_end_ptr;
>
>         if (extra_ptr) {
> -               int remaining = strlen(name) - (extra_ptr - name);
> +               if (!named_mode) {
> +                       int len = strlen(name) - (extra_ptr - name);
>
> -               /*
> -                * We still have characters to process, while
> -                * we shouldn't have any
> -                */
> -               if (remaining > 0)
> -                       return false;
> +                       ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
> +                                                          connector, mode);
> +                       if (ret)
> +                               return false;
> +               } else {
> +                       int remaining = strlen(name) - (extra_ptr - name);
> +
> +                       /*
> +                        * We still have characters to process, while
> +                        * we shouldn't have any
> +                        */
> +                       if (remaining > 0)
> +                               return false;

Correct me if I'm wrong, but this shouldn't ever happen. AFAICT, the
only way it could would be if we parsed bpp or refresh in the named
mode (since those are the only cases where we don't copy the whole
string over). Shouldn't that be invalid anyways?

Perhaps you can just avoid all of this code and just do a
strcpy/return when you first detect a named mode.

Sean


> +               }
>         }
>
>         return true;
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> index ac9d7d8e0e43..dce3d4b2fd33 100644
> --- a/include/drm/drm_connector.h
> +++ b/include/drm/drm_connector.h
> @@ -485,6 +485,7 @@ struct drm_connector_funcs {
>
>  /* mode specified on the command line */
>  struct drm_cmdline_mode {
> +       char name[DRM_DISPLAY_MODE_LEN];
>         bool specified;
>         bool refresh_specified;
>         bool bpp_specified;
> --
> git-series 0.8.10

^ permalink raw reply

* [PATCH V7 1/3] ACPI: Retry IRQ conversion if it failed previously
From: Lorenzo Pieralisi @ 2016-11-16 17:18 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <0b6358b4c723bb08623c322051bb4c77@codeaurora.org>

On Tue, Nov 15, 2016 at 12:43:38PM -0500, Agustin Vega-Frias wrote:
> Hi Lorenzo,
> 
> On 2016-11-15 10:48, Lorenzo Pieralisi wrote:
> >On Sun, Nov 13, 2016 at 04:59:33PM -0500, Agustin Vega-Frias wrote:
> >>This allows probe deferral to work properly when a dependent device
> >>fails to get a valid IRQ because the IRQ domain was not registered
> >>at the time the resources were added to the platform_device.
> >>
> >>Signed-off-by: Agustin Vega-Frias <agustinv@codeaurora.org>
> >>---
> >> drivers/acpi/resource.c | 59
> >>+++++++++++++++++++++++++++++++++++++++++++++++++
> >> drivers/base/platform.c |  9 +++++++-
> >> include/linux/acpi.h    |  7 ++++++
> >> 3 files changed, 74 insertions(+), 1 deletion(-)
> >>
> >>diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
> >>index 56241eb..4beda15 100644
> >>--- a/drivers/acpi/resource.c
> >>+++ b/drivers/acpi/resource.c
> >>@@ -664,3 +664,62 @@ int acpi_dev_filter_resource_type(struct
> >>acpi_resource *ares,
> >> 	return (type & types) ? 0 : 1;
> >> }
> >> EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type);
> >>+
> >>+struct acpi_irq_get_ctx {
> >>+	unsigned int index;
> >>+	struct resource *res;
> >>+};
> >>+
> >>+static acpi_status acpi_irq_get_cb(struct acpi_resource *ares,
> >>void *context)
> >>+{
> >>+	struct acpi_irq_get_ctx *ctx = context;
> >>+	struct acpi_resource_irq *irq;
> >>+	struct acpi_resource_extended_irq *ext_irq;
> >>+
> >>+	switch (ares->type) {
> >>+	case ACPI_RESOURCE_TYPE_IRQ:
> >>+		irq = &ares->data.irq;
> >>+		if (ctx->index < irq->interrupt_count) {
> >>+			acpi_dev_resource_interrupt(ares, ctx->index, ctx->res);
> >>+			return AE_CTRL_TERMINATE;
> >>+		}
> >>+		ctx->index -= irq->interrupt_count;
> >
> >I do not understand this code, mind explaining what it is meant to do ?
> >
> >In particular I do not understand the logic behind the index decrement,
> >I think I am missing something here.
> >
> 
> ACPI IRQ resources can be encoded into two types of structures:
> 
>    struct acpi_resource_irq,
>    struct acpi_resource_extended_irq.
> 
> In theory only the extended version can contain multiple IRQs, but
> the Linux
> ACPI core accommodates non-compliant DSDT tables that have regular
> IRQ resources
> contain multiple IRQs.
> 
> To better explain, suppose you have a device that handles two GSIs
> and one
> other IRQ form a separate device:
> 
>    Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, 0x00, )
>    { 130, 131 }
> 
>    Interrupt (ResourceConsumer, Level, ActiveHigh, Exclusive, 0x00,
> "\\_SB.TCS0.QIC0", )
>    { 4 }
> 
> These are encoded into two separate structures with their own
> interrupts array:
> 
>   res0.interrupts[] = { 130, 131 }
>   res1.interrupts[] = { 4 }
> 
> However, from the perspective of a client driver these are indexed
> into a flat space:
> 
>   [0] -> 130
>   [1] -> 131
>   [2] -> 4
> 
> Now say mapping of IRQ 4 failed during bus scan. When acpi_irq_get
> retries to map it, the client code will pass index 2.
> acpi_walk_resources will call acpi_irq_get_cb with the first IRQ
> resource. If the index is less than the number of IRQs, we know this
> IRQ resource contains the IRQ we want so we call
> acpi_dev_resource_interrupt to do the actual mapping and return
> AE_CTRL_TERMINATE so acpi_walk_resources does not continue walking the
> resource buffer. On the other hand if the index is equal or larger it
> means we need to skip this IRQ resource and look at the next one, but
> we need to adjust the lookup index to that of the next IRQ resource.
> 
> Makes sense?

Yes, basically it is to create a linear index out of multiple resources,
the DT case is simpler since you get the interrupt out of a single
property that we can easily index (ie we have to know which firmware
entry corresponds to the resource that we are retrying). That deserves
a comment.

Thanks for explaining.

Lorenzo

> >>+		break;
> >>+	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
> >>+		ext_irq = &ares->data.extended_irq;
> >>+		if (ctx->index < ext_irq->interrupt_count) {
> >>+			acpi_dev_resource_interrupt(ares, ctx->index, ctx->res);
> >>+			return AE_CTRL_TERMINATE;
> >>+		}
> >>+		ctx->index -= ext_irq->interrupt_count;
> >
> >Ditto.
> 
> The same logic is used for both types of resources because they are
> handled in
> the same way by the ACPI core when it comes to indexing.
> 
> Thanks,
> Agustin
> 
> >
> >Thanks,
> >Lorenzo
> >
> >>+		break;
> >>+	}
> >>+
> >>+	return AE_OK;
> >>+}
> >>+
> >>+/**
> >>+ * acpi_irq_get - Look for the ACPI IRQ resource with the given
> >>index and
> >>+ *                use it to initialize the given Linux IRQ resource.
> >>+ * @handle ACPI device handle
> >>+ * @index  ACPI IRQ resource index to lookup
> >>+ * @res    Linux IRQ resource to initialize
> >>+ *
> >>+ * Return: 0 on success
> >>+ *         -EINVAL if an error occurs
> >>+ *         -EPROBE_DEFER if the IRQ lookup/conversion failed
> >>+ */
> >>+int acpi_irq_get(acpi_handle handle, unsigned int index, struct
> >>resource *res)
> >>+{
> >>+	struct acpi_irq_get_ctx ctx = { index, res };
> >>+	acpi_status status;
> >>+
> >>+	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
> >>+				     acpi_irq_get_cb, &ctx);
> >>+	if (ACPI_FAILURE(status))
> >>+		return -EINVAL;
> >>+	if (res->flags & IORESOURCE_DISABLED)
> >>+		return -EPROBE_DEFER;
> >>+	return 0;
> >>+}
> >>+EXPORT_SYMBOL_GPL(acpi_irq_get);
> >>diff --git a/drivers/base/platform.c b/drivers/base/platform.c
> >>index c4af003..61423d2 100644
> >>--- a/drivers/base/platform.c
> >>+++ b/drivers/base/platform.c
> >>@@ -102,6 +102,14 @@ int platform_get_irq(struct platform_device
> >>*dev, unsigned int num)
> >> 	}
> >>
> >> 	r = platform_get_resource(dev, IORESOURCE_IRQ, num);
> >>+	if (r && r->flags & IORESOURCE_DISABLED &&
> >>ACPI_COMPANION(&dev->dev)) {
> >>+		int ret;
> >>+
> >>+		ret = acpi_irq_get(ACPI_HANDLE(&dev->dev), num, r);
> >>+		if (ret)
> >>+			return ret;
> >>+	}
> >>+
> >> 	/*
> >> 	 * The resources may pass trigger flags to the irqs that need
> >> 	 * to be set up. It so happens that the trigger flags for
> >>@@ -1450,4 +1458,3 @@ void __init early_platform_cleanup(void)
> >> 		memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
> >> 	}
> >> }
> >>-
> >>diff --git a/include/linux/acpi.h b/include/linux/acpi.h
> >>index 689a8b9..325bdb9 100644
> >>--- a/include/linux/acpi.h
> >>+++ b/include/linux/acpi.h
> >>@@ -406,6 +406,7 @@ bool
> >>acpi_dev_resource_ext_address_space(struct acpi_resource *ares,
> >> unsigned int acpi_dev_get_irq_type(int triggering, int polarity);
> >> bool acpi_dev_resource_interrupt(struct acpi_resource *ares,
> >>int index,
> >> 				 struct resource *res);
> >>+int acpi_irq_get(acpi_handle handle, unsigned int index, struct
> >>resource *res);
> >>
> >> void acpi_dev_free_resource_list(struct list_head *list);
> >> int acpi_dev_get_resources(struct acpi_device *adev, struct
> >>list_head *list,
> >>@@ -763,6 +764,12 @@ static inline int
> >>acpi_reconfig_notifier_unregister(struct notifier_block *nb)
> >> 	return -EINVAL;
> >> }
> >>
> >>+static inline int acpi_irq_get(acpi_handle handle, unsigned int
> >>index,
> >>+			       struct resource *res)
> >>+{
> >>+	return -EINVAL;
> >>+}
> >>+
> >> #endif	/* !CONFIG_ACPI */
> >>
> >> #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
> >>--
> >>Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm
> >>Technologies, Inc.
> >>Qualcomm Technologies, Inc. is a member of the Code Aurora
> >>Forum, a Linux Foundation Collaborative Project.
> >>
> >>--
> >>To unsubscribe from this list: send the line "unsubscribe
> >>linux-acpi" in
> >>the body of a message to majordomo at vger.kernel.org
> >>More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> -- 
> Qualcomm Datacenter Technologies, Inc. on behalf of the Qualcomm
> Technologies, Inc.
> Qualcomm Technologies, Inc. is a member of the Code Aurora Forum, a
> Linux Foundation Collaborative Project.

^ permalink raw reply

* [PATCH 1/5] drm/modes: Rewrite the command line parser
From: Sean Paul @ 2016-11-16 17:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <cf494b4e9585e720b2640705e3b2102c19d193c2.1476779323.git-series.maxime.ripard@free-electrons.com>

On Tue, Oct 18, 2016 at 4:29 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Rewrite the command line parser in order to get away from the state machine
> parsing the video mode lines.
>
> Hopefully, this will allow to extend it more easily to support named modes
> and / or properties set directly on the command line.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/drm_modes.c | 305 +++++++++++++++++++++++--------------
>  1 file changed, 190 insertions(+), 115 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
> index 53f07ac7c174..7d5bdca276f2 100644
> --- a/drivers/gpu/drm/drm_modes.c
> +++ b/drivers/gpu/drm/drm_modes.c
> @@ -30,6 +30,7 @@
>   * authorization from the copyright holder(s) and author(s).
>   */
>
> +#include <linux/ctype.h>
>  #include <linux/list.h>
>  #include <linux/list_sort.h>
>  #include <linux/export.h>
> @@ -1261,6 +1262,131 @@ void drm_mode_connector_list_update(struct drm_connector *connector)
>  }
>  EXPORT_SYMBOL(drm_mode_connector_list_update);
>
> +static int drm_mode_parse_cmdline_bpp(const char *str, char **end_ptr,
> +                                     struct drm_cmdline_mode *mode)
> +{
> +       if (str[0] != '-')
> +               return -EINVAL;
> +
> +       mode->bpp = simple_strtol(str + 1, end_ptr, 10);
> +       mode->bpp_specified = true;
> +
> +       return 0;
> +}
> +
> +static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr,
> +                                         struct drm_cmdline_mode *mode)
> +{
> +       if (str[0] != '@')
> +               return -EINVAL;
> +
> +       mode->refresh = simple_strtol(str + 1, end_ptr, 10);
> +       mode->refresh_specified = true;
> +
> +       return 0;
> +}
> +
> +static int drm_mode_parse_cmdline_extra(const char *str, int length,
> +                                       struct drm_connector *connector,
> +                                       struct drm_cmdline_mode *mode)
> +{
> +       int i;
> +
> +       for (i = 0; i < length; i++) {
> +               switch (str[i]) {
> +               case 'i':
> +                       mode->interlace = true;
> +                       break;
> +               case 'm':
> +                       mode->margins = true;
> +                       break;
> +               case 'D':
> +                       if (mode->force != DRM_FORCE_UNSPECIFIED)
> +                               return -EINVAL;
> +
> +                       if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
> +                           (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
> +                               mode->force = DRM_FORCE_ON;
> +                       else
> +                               mode->force = DRM_FORCE_ON_DIGITAL;
> +                       break;
> +               case 'd':
> +                       if (mode->force != DRM_FORCE_UNSPECIFIED)
> +                               return -EINVAL;
> +
> +                       mode->force = DRM_FORCE_OFF;
> +                       break;
> +               case 'e':
> +                       if (mode->force != DRM_FORCE_UNSPECIFIED)
> +                               return -EINVAL;
> +
> +                       mode->force = DRM_FORCE_ON;
> +                       break;
> +               default:
> +                       return -EINVAL;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
> +                                          bool extras,
> +                                          struct drm_connector *connector,
> +                                          struct drm_cmdline_mode *mode)
> +{
> +       bool rb = false, cvt = false;
> +       int xres = 0, yres = 0;
> +       int remaining, i;
> +       char *end_ptr;
> +
> +       xres = simple_strtol(str, &end_ptr, 10);
> +

checkpatch is telling me to use kstrtol instead, as simple_strtol is deprecated

> +       if (end_ptr[0] != 'x')

check that end_ptr != NULL? you should probably also check that xres
isn't an error (ie: -ERANGE or -EINVAL)

> +               return -EINVAL;
> +       end_ptr++;
> +
> +       yres = simple_strtol(end_ptr, &end_ptr, 10);

check end_ptr != NULL and yres sane

> +
> +       remaining = length - (end_ptr - str);
> +       if (remaining < 0)

right, so if end_ptr is NULL here, we'll end up with a huge positive
value for remaining :)

> +               return -EINVAL;
> +
> +       for (i = 0; i < remaining; i++) {
> +               switch (end_ptr[i]) {
> +               case 'M':
> +                       cvt = true;

the previous code ensured proper ordering as well as parsing, whereas
yours will take these in any order (and accepts duplicates). i don't
think this should cause any issues, but perhaps something to verify.

> +                       break;
> +               case 'R':
> +                       rb = true;
> +                       break;
> +               default:
> +                       /*
> +                        * Try to pass that to our extras parsing
> +                        * function to handle the case where the
> +                        * extras are directly after the resolution
> +                        */
> +                       if (extras) {
> +                               int ret = drm_mode_parse_cmdline_extra(end_ptr + i,
> +                                                                      1,
> +                                                                      connector,
> +                                                                      mode);
> +                               if (ret)
> +                                       return ret;
> +                       } else {
> +                               return -EINVAL;
> +                       }
> +               }
> +       }
> +
> +       mode->xres = xres;
> +       mode->yres = yres;
> +       mode->cvt = cvt;
> +       mode->rb = rb;
> +
> +       return 0;
> +}
> +
>  /**
>   * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
>   * @mode_option: optional per connector mode option
> @@ -1287,13 +1413,12 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
>                                                struct drm_cmdline_mode *mode)
>  {
>         const char *name;
> -       unsigned int namelen;
> -       bool res_specified = false, bpp_specified = false, refresh_specified = false;
> -       unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
> -       bool yres_specified = false, cvt = false, rb = false;
> -       bool interlace = false, margins = false, was_digit = false;
> -       int i;
> -       enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
> +       bool parse_extras = false;
> +       unsigned int bpp_off = 0, refresh_off = 0;
> +       unsigned int mode_end = 0;
> +       char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
> +       char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
> +       int ret;
>
>  #ifdef CONFIG_FB
>         if (!mode_option)
> @@ -1306,127 +1431,77 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
>         }
>
>         name = mode_option;
> -       namelen = strlen(name);
> -       for (i = namelen-1; i >= 0; i--) {
> -               switch (name[i]) {
> -               case '@':
> -                       if (!refresh_specified && !bpp_specified &&
> -                           !yres_specified && !cvt && !rb && was_digit) {
> -                               refresh = simple_strtol(&name[i+1], NULL, 10);
> -                               refresh_specified = true;
> -                               was_digit = false;
> -                       } else
> -                               goto done;
> -                       break;
> -               case '-':
> -                       if (!bpp_specified && !yres_specified && !cvt &&
> -                           !rb && was_digit) {
> -                               bpp = simple_strtol(&name[i+1], NULL, 10);
> -                               bpp_specified = true;
> -                               was_digit = false;
> -                       } else
> -                               goto done;
> -                       break;
> -               case 'x':
> -                       if (!yres_specified && was_digit) {
> -                               yres = simple_strtol(&name[i+1], NULL, 10);
> -                               yres_specified = true;
> -                               was_digit = false;
> -                       } else
> -                               goto done;
> -                       break;
> -               case '0' ... '9':
> -                       was_digit = true;
> -                       break;
> -               case 'M':
> -                       if (yres_specified || cvt || was_digit)
> -                               goto done;
> -                       cvt = true;
> -                       break;
> -               case 'R':
> -                       if (yres_specified || cvt || rb || was_digit)
> -                               goto done;
> -                       rb = true;
> -                       break;
> -               case 'm':
> -                       if (cvt || yres_specified || was_digit)
> -                               goto done;
> -                       margins = true;
> -                       break;
> -               case 'i':
> -                       if (cvt || yres_specified || was_digit)
> -                               goto done;
> -                       interlace = true;
> -                       break;
> -               case 'e':
> -                       if (yres_specified || bpp_specified || refresh_specified ||
> -                           was_digit || (force != DRM_FORCE_UNSPECIFIED))
> -                               goto done;
>
> -                       force = DRM_FORCE_ON;
> -                       break;
> -               case 'D':
> -                       if (yres_specified || bpp_specified || refresh_specified ||
> -                           was_digit || (force != DRM_FORCE_UNSPECIFIED))
> -                               goto done;
> +       if (!isdigit(name[0]))
> +               return false;
>
> -                       if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
> -                           (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
> -                               force = DRM_FORCE_ON;
> -                       else
> -                               force = DRM_FORCE_ON_DIGITAL;
> -                       break;
> -               case 'd':
> -                       if (yres_specified || bpp_specified || refresh_specified ||
> -                           was_digit || (force != DRM_FORCE_UNSPECIFIED))
> -                               goto done;
> +       /* Try to locate the bpp and refresh specifiers, if any */
> +       bpp_ptr = strchr(name, '-');
> +       if (bpp_ptr) {
> +               bpp_off = bpp_ptr - name;
> +               mode->bpp_specified = true;
> +       }
>
> -                       force = DRM_FORCE_OFF;
> -                       break;
> -               default:
> -                       goto done;
> -               }
> +       refresh_ptr = strchr(name, '@');
> +       if (refresh_ptr) {
> +               refresh_off = refresh_ptr - name;
> +               mode->refresh_specified = true;
>         }
>
> -       if (i < 0 && yres_specified) {
> -               char *ch;
> -               xres = simple_strtol(name, &ch, 10);
> -               if ((ch != NULL) && (*ch == 'x'))
> -                       res_specified = true;
> -               else
> -                       i = ch - name;
> -       } else if (!yres_specified && was_digit) {
> -               /* catch mode that begins with digits but has no 'x' */
> -               i = 0;
> +       /* Locate the end of the name / resolution, and parse it */
> +       if (bpp_ptr && refresh_ptr) {
> +               mode_end = min(bpp_off, refresh_off);
> +       } else if (bpp_ptr) {
> +               mode_end = bpp_off;
> +       } else if (refresh_ptr) {
> +               mode_end = refresh_off;
> +       } else {
> +               mode_end = strlen(name);
> +               parse_extras = true;
>         }
> -done:
> -       if (i >= 0) {
> -               pr_warn("[drm] parse error at position %i in video mode '%s'\n",
> -                       i, name);
> -               mode->specified = false;
> +
> +       ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
> +                                             parse_extras,
> +                                             connector,
> +                                             mode);
> +       if (ret)
>                 return false;
> -       }
> +       mode->specified = true;
>
> -       if (res_specified) {
> -               mode->specified = true;
> -               mode->xres = xres;
> -               mode->yres = yres;
> +       if (bpp_ptr) {
> +               ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
> +               if (ret)
> +                       return false;
>         }
>
> -       if (refresh_specified) {
> -               mode->refresh_specified = true;
> -               mode->refresh = refresh;
> +       if (refresh_ptr) {
> +               ret = drm_mode_parse_cmdline_refresh(refresh_ptr,
> +                                                    &refresh_end_ptr, mode);
> +               if (ret)
> +                       return false;
>         }
>
> -       if (bpp_specified) {
> -               mode->bpp_specified = true;
> -               mode->bpp = bpp;
> +       /*
> +        * Locate the end of the bpp / refresh, and parse the extras
> +        * if relevant
> +        */
> +       if (bpp_ptr && refresh_ptr)

Perhaps I'm paranoid, but I think it'd be better to check bpp_end_ptr
&& refresh_end_ptr in this conditional.

Sean

> +               extra_ptr = max(bpp_end_ptr, refresh_end_ptr);
> +       else if (bpp_ptr)
> +               extra_ptr = bpp_end_ptr;
> +       else if (refresh_ptr)
> +               extra_ptr = refresh_end_ptr;
> +
> +       if (extra_ptr) {
> +               int remaining = strlen(name) - (extra_ptr - name);
> +
> +               /*
> +                * We still have characters to process, while
> +                * we shouldn't have any
> +                */
> +               if (remaining > 0)
> +                       return false;
>         }
> -       mode->rb = rb;
> -       mode->cvt = cvt;
> -       mode->interlace = interlace;
> -       mode->margins = margins;
> -       mode->force = force;
>
>         return true;
>  }
> --
> git-series 0.8.10

^ permalink raw reply

* [PATCH v3 6/9] mtd: spi-nor: Support R/W for S25FS-S family flash
From: Han Xu @ 2016-11-16 17:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <AM4PR0701MB21308B262DB7B94E0F7FC34EFEF00@AM4PR0701MB2130.eurprd07.prod.outlook.com>

On Thu, Sep 15, 2016 at 06:50:55AM +0000, Krzeminski, Marcin (Nokia - PL/Wroclaw) wrote:
> Hello,
> 
> > -----Original Message-----
> > From: linux-mtd [mailto:linux-mtd-bounces at lists.infradead.org] On Behalf
> > Of Han Xu
> > Sent: Wednesday, September 14, 2016 9:49 PM
> > To: Yunhui Cui <B56489@freescale.com>
> > Cc: Yunhui Cui <yunhui.cui@nxp.com>; David Woodhouse
> > <dwmw2@infradead.org>; linux-kernel at vger.kernel.org; linux-
> > mtd at lists.infradead.org; han.xu at freescale.com; Brian Norris
> > <computersforpeace@gmail.com>; jagannadh.teki at gmail.com; linux-arm-
> > kernel at lists.infradead.org; Yao Yuan <yao.yuan@nxp.com>
> > Subject: Re: [PATCH v3 6/9] mtd: spi-nor: Support R/W for S25FS-S family
> > flash
> > 
> > On Thu, Aug 18, 2016 at 2:38 AM, Yunhui Cui <B56489@freescale.com>
> > wrote:
> > > From: Yunhui Cui <yunhui.cui@nxp.com>
> > >
> > > With the physical sectors combination, S25FS-S family flash requires
> > > some special operations for read/write functions.
> > >
> > > Signed-off-by: Yunhui Cui <yunhui.cui@nxp.com>
> > > ---
> > >  drivers/mtd/spi-nor/spi-nor.c | 56
> > > +++++++++++++++++++++++++++++++++++++++++++
> > >  1 file changed, 56 insertions(+)
> > >
> > > diff --git a/drivers/mtd/spi-nor/spi-nor.c
> > > b/drivers/mtd/spi-nor/spi-nor.c index d0fc165..495d0bb 100644
> > > --- a/drivers/mtd/spi-nor/spi-nor.c
> > > +++ b/drivers/mtd/spi-nor/spi-nor.c
> > > @@ -39,6 +39,10 @@
> > >
> > >  #define SPI_NOR_MAX_ID_LEN     6
> > >  #define SPI_NOR_MAX_ADDR_WIDTH 4
> > > +/* Added for S25FS-S family flash */
> > > +#define SPINOR_CONFIG_REG3_OFFSET      0x800004
> > > +#define CR3V_4KB_ERASE_UNABLE  0x8
> > > +#define SPINOR_S25FS_FAMILY_EXT_JEDEC  0x81
> > >
> > >  struct flash_info {
> > >         char            *name;
> > > @@ -78,6 +82,7 @@ struct flash_info {
> > >  };
> > >
> > >  #define JEDEC_MFR(info)        ((info)->id[0])
> > > +#define EXT_JEDEC(info)        ((info)->id[5])
> > >
> > >  static const struct flash_info *spi_nor_match_id(const char *name);
> > >
> > > @@ -899,6 +904,7 @@ static const struct flash_info spi_nor_ids[] = {
> > >          */
> > >         { "s25sl032p",  INFO(0x010215, 0x4d00,  64 * 1024,  64,
> > SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
> > >         { "s25sl064p",  INFO(0x010216, 0x4d00,  64 * 1024, 128,
> > > SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
> > > +       { "s25fs256s1", INFO6(0x010219, 0x4d0181, 64 * 1024, 512, 0)},
> > >         { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) },
> > >         { "s25fl256s1", INFO(0x010219, 0x4d01,  64 * 1024, 512,
> > SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
> > >         { "s25fl512s",  INFO(0x010220, 0x4d00, 256 * 1024, 256,
> > > SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, @@ -1036,6 +1042,50
> > @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor)
> > >         return ERR_PTR(-ENODEV);
> > >  }
> > >
> > > +/*
> > > + * The S25FS-S family physical sectors may be configured as a
> > > + * hybrid combination of eight 4-kB parameter sectors
> > > + * at the top or bottom of the address space with all
> > > + * but one of the remaining sectors being uniform size.
> > > + * The Parameter Sector Erase commands (20h or 21h) must
> > > + * be used to erase the 4-kB parameter sectors individually.
> > > + * The Sector (uniform sector) Erase commands (D8h or DCh)
> > > + * must be used to erase any of the remaining
> > > + * sectors, including the portion of highest or lowest address
> > > + * sector that is not overlaid by the parameter sectors.
> > > + * The uniform sector erase command has no effect on parameter
> > sectors.
> > > + */
> > > +static int spansion_s25fs_disable_4kb_erase(struct spi_nor *nor) {
> > > +       u32 cr3v_addr  = SPINOR_CONFIG_REG3_OFFSET;
> > > +       u8 cr3v = 0x0;
> > > +       int ret = 0x0;
> > > +
> > > +       nor->cmd_buf[2] = cr3v_addr >> 16;
> > > +       nor->cmd_buf[1] = cr3v_addr >> 8;
> > > +       nor->cmd_buf[0] = cr3v_addr >> 0;
> > > +
> > > +       ret = nor->read_reg(nor, SPINOR_OP_SPANSION_RDAR, &cr3v, 1);
> > > +       if (ret)
> > > +               return ret;
> > > +       if (cr3v & CR3V_4KB_ERASE_UNABLE)
> > > +               return 0;
> > > +       ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0);
> > > +       if (ret)
> > > +               return ret;
> > > +       cr3v = CR3V_4KB_ERASE_UNABLE;
> > > +       nor->program_opcode = SPINOR_OP_SPANSION_WRAR;
> > > +       nor->write(nor, cr3v_addr, 1, &cr3v);
> > > +
> > > +       ret = nor->read_reg(nor, SPINOR_OP_SPANSION_RDAR, &cr3v, 1);
> > > +       if (ret)
> > > +               return ret;
> > > +       if (!(cr3v & CR3V_4KB_ERASE_UNABLE))
> > > +               return -EPERM;
> > > +
> > > +       return 0;
> > > +}
> > > +
> > >  static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
> > >                         size_t *retlen, u_char *buf)  { @@ -1361,6
> > > +1411,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
> > enum read_mode mode)
> > >                 spi_nor_wait_till_ready(nor);
> > >         }
> > >
> > > +       if (EXT_JEDEC(info) == SPINOR_S25FS_FAMILY_EXT_JEDEC) {
> > > +               ret = spansion_s25fs_disable_4kb_erase(nor);
> > > +               if (ret)
> > > +                       return ret;
> > > +       }
> > > +
> > >         if (!mtd->name)
> > >                 mtd->name = dev_name(dev);
> > >         mtd->priv = nor;
> > > --
> > > 2.1.0.27.g96db324
> > >
> > >
> > Hi Brian, I will ack this change but still feel it's kind of hacking code.
> > 
> > Acked-by: Han xu <han.xu@nxp.com>
> 
> I am new on the list so I am not sure if this topic has been discussed.
> Generally our product functionality relay on those 4KiB sectors.
> I know that this hack is already in u-boot, but if you mainstream this
> you will force users of those 4KiB sectors to do hack the hack...
> I believe the proper solution here is to use erase regions functionality,
> I send and RFS about that some time ago.

Do you mind to send me a link for reference?

Sincerely,
Han XU

> 
> Thanks,
> Marcin
> 
> > > ______________________________________________________
> > > Linux MTD discussion mailing list
> > > http://lists.infradead.org/mailman/listinfo/linux-mtd/
> > 
> > 
> > 
> > --
> > Sincerely,
> > 
> > Han XU
> > 
> > ______________________________________________________
> > Linux MTD discussion mailing list
> > http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply

* [PATCH v3 1/1] KVM: ARM64: Fix the issues when guest PMCCFILTR is configured
From: Wei Huang @ 2016-11-16 17:09 UTC (permalink / raw)
  To: linux-arm-kernel

KVM calls kvm_pmu_set_counter_event_type() when PMCCFILTR is configured.
But this function can't deals with PMCCFILTR correctly because the evtCount
bits of PMCCFILTR, which is reserved 0, conflits with the SW_INCR event
type of other PMXEVTYPER<n> registers. To fix it, when eventsel == 0, this
function shouldn't return immediately; instead it needs to check further
if select_idx is ARMV8_PMU_CYCLE_IDX.

Another issue is that KVM shouldn't copy the eventsel bits of PMCCFILTER
blindly to attr.config. Instead it ought to convert the request to the
"cpu cycle" event type (i.e. 0x11).

To support this patch and to prevent duplicated definitions, a limited
set of ARMv8 perf event types were relocated from perf_event.c to
asm/perf_event.h.

Signed-off-by: Wei Huang <wei@redhat.com>
---
 arch/arm64/include/asm/perf_event.h | 10 +++++++++-
 arch/arm64/kernel/perf_event.c      | 10 +---------
 virt/kvm/arm/pmu.c                  |  8 +++++---
 3 files changed, 15 insertions(+), 13 deletions(-)

diff --git a/arch/arm64/include/asm/perf_event.h b/arch/arm64/include/asm/perf_event.h
index 2065f46..38b6a2b 100644
--- a/arch/arm64/include/asm/perf_event.h
+++ b/arch/arm64/include/asm/perf_event.h
@@ -46,7 +46,15 @@
 #define	ARMV8_PMU_EVTYPE_MASK	0xc800ffff	/* Mask for writable bits */
 #define	ARMV8_PMU_EVTYPE_EVENT	0xffff		/* Mask for EVENT bits */
 
-#define ARMV8_PMU_EVTYPE_EVENT_SW_INCR	0	/* Software increment event */
+/*
+ * PMUv3 event types: required events
+ */
+#define ARMV8_PMUV3_PERFCTR_SW_INCR				0x00
+#define ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL			0x03
+#define ARMV8_PMUV3_PERFCTR_L1D_CACHE				0x04
+#define ARMV8_PMUV3_PERFCTR_BR_MIS_PRED				0x10
+#define ARMV8_PMUV3_PERFCTR_CPU_CYCLES				0x11
+#define ARMV8_PMUV3_PERFCTR_BR_PRED				0x12
 
 /*
  * Event filters for PMUv3
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index a9310a6..57ae9d9 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -31,17 +31,9 @@
 
 /*
  * ARMv8 PMUv3 Performance Events handling code.
- * Common event types.
+ * Common event types (some are defined in asm/perf_event.h).
  */
 
-/* Required events. */
-#define ARMV8_PMUV3_PERFCTR_SW_INCR				0x00
-#define ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL			0x03
-#define ARMV8_PMUV3_PERFCTR_L1D_CACHE				0x04
-#define ARMV8_PMUV3_PERFCTR_BR_MIS_PRED				0x10
-#define ARMV8_PMUV3_PERFCTR_CPU_CYCLES				0x11
-#define ARMV8_PMUV3_PERFCTR_BR_PRED				0x12
-
 /* At least one of the following is required. */
 #define ARMV8_PMUV3_PERFCTR_INST_RETIRED			0x08
 #define ARMV8_PMUV3_PERFCTR_INST_SPEC				0x1B
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index 6e9c40e..69ccce3 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -305,7 +305,7 @@ void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
 			continue;
 		type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
 		       & ARMV8_PMU_EVTYPE_EVENT;
-		if ((type == ARMV8_PMU_EVTYPE_EVENT_SW_INCR)
+		if ((type == ARMV8_PMUV3_PERFCTR_SW_INCR)
 		    && (enable & BIT(i))) {
 			reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
 			reg = lower_32_bits(reg);
@@ -379,7 +379,8 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 	eventsel = data & ARMV8_PMU_EVTYPE_EVENT;
 
 	/* Software increment event does't need to be backed by a perf event */
-	if (eventsel == ARMV8_PMU_EVTYPE_EVENT_SW_INCR)
+	if (eventsel == ARMV8_PMUV3_PERFCTR_SW_INCR &&
+	    select_idx != ARMV8_PMU_CYCLE_IDX)
 		return;
 
 	memset(&attr, 0, sizeof(struct perf_event_attr));
@@ -391,7 +392,8 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 	attr.exclude_kernel = data & ARMV8_PMU_EXCLUDE_EL1 ? 1 : 0;
 	attr.exclude_hv = 1; /* Don't count EL2 events */
 	attr.exclude_host = 1; /* Don't count host events */
-	attr.config = eventsel;
+	attr.config = (select_idx == ARMV8_PMU_CYCLE_IDX) ?
+		ARMV8_PMUV3_PERFCTR_CPU_CYCLES : eventsel;
 
 	counter = kvm_pmu_get_counter_value(vcpu, select_idx);
 	/* The initial sample period (overflow count) of an event. */
-- 
2.7.4

^ permalink raw reply related

* [PATCH net 1/3] net: phy: realtek: add eee advertisement disable options
From: Anand Moon @ 2016-11-16 17:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479220154-25851-2-git-send-email-jbrunet@baylibre.com>

 Hi Jerome.

On 15 November 2016 at 19:59, Jerome Brunet <jbrunet@baylibre.com> wrote:
> On some platforms, energy efficient ethernet with rtl8211 devices is
> causing issue, like throughput drop or broken link.
>
> This was reported on the OdroidC2 (DWMAC + RTL8211F). While the issue root
> cause is not fully understood yet, disabling EEE advertisement prevent auto
> negotiation from enabling EEE.
>
> This patch provides options to disable 1000T and 100TX EEE advertisement
> individually for the realtek phys supporting this feature.
>
> Reported-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
> Cc: Alexandre TORGUE <alexandre.torgue@st.com>
> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> Tested-by: Andre Roth <neolynx@gmail.com>
> ---
>  drivers/net/phy/realtek.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 64 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
> index aadd6e9f54ad..77235fd5faaf 100644
> --- a/drivers/net/phy/realtek.c
> +++ b/drivers/net/phy/realtek.c
> @@ -15,6 +15,12 @@
>   */
>  #include <linux/phy.h>
>  #include <linux/module.h>
> +#include <linux/of.h>
> +
> +struct rtl8211x_phy_priv {
> +       bool eee_1000t_disable;
> +       bool eee_100tx_disable;
> +};
>
>  #define RTL821x_PHYSR          0x11
>  #define RTL821x_PHYSR_DUPLEX   0x2000
> @@ -93,12 +99,44 @@ static int rtl8211f_config_intr(struct phy_device *phydev)
>         return err;
>  }
>
> +static void rtl8211x_clear_eee_adv(struct phy_device *phydev)
> +{
> +       struct rtl8211x_phy_priv *priv = phydev->priv;
> +       u16 val;
> +
> +       if (priv->eee_1000t_disable || priv->eee_100tx_disable) {
> +               val = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
> +                                           MDIO_MMD_AN);
> +
> +               if (priv->eee_1000t_disable)
> +                       val &= ~MDIO_AN_EEE_ADV_1000T;
> +               if (priv->eee_100tx_disable)
> +                       val &= ~MDIO_AN_EEE_ADV_100TX;
> +
> +               phy_write_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
> +                                      MDIO_MMD_AN, val);
> +       }
> +}
> +
> +static int rtl8211x_config_init(struct phy_device *phydev)
> +{
> +       int ret;
> +
> +       ret = genphy_config_init(phydev);
> +       if (ret < 0)
> +               return ret;
> +
> +       rtl8211x_clear_eee_adv(phydev);
> +
> +       return 0;
> +}
> +
>  static int rtl8211f_config_init(struct phy_device *phydev)
>  {
>         int ret;
>         u16 reg;
>
> -       ret = genphy_config_init(phydev);
> +       ret = rtl8211x_config_init(phydev);
>         if (ret < 0)
>                 return ret;
>
> @@ -115,6 +153,26 @@ static int rtl8211f_config_init(struct phy_device *phydev)
>         return 0;
>  }
>
> +static int rtl8211x_phy_probe(struct phy_device *phydev)
> +{
> +       struct device *dev = &phydev->mdio.dev;
> +       struct device_node *of_node = dev->of_node;
> +       struct rtl8211x_phy_priv *priv;
> +
> +       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +       if (!priv)
> +               return -ENOMEM;
> +
> +       priv->eee_1000t_disable =
> +               of_property_read_bool(of_node, "realtek,disable-eee-1000t");
> +       priv->eee_100tx_disable =
> +               of_property_read_bool(of_node, "realtek,disable-eee-100tx");
> +
> +       phydev->priv = priv;
> +
> +       return 0;
> +}
> +
>  static struct phy_driver realtek_drvs[] = {
>         {
>                 .phy_id         = 0x00008201,
> @@ -140,7 +198,9 @@ static struct phy_driver realtek_drvs[] = {
>                 .phy_id_mask    = 0x001fffff,
>                 .features       = PHY_GBIT_FEATURES,
>                 .flags          = PHY_HAS_INTERRUPT,
> +               .probe          = &rtl8211x_phy_probe,
>                 .config_aneg    = genphy_config_aneg,
> +               .config_init    = &rtl8211x_config_init,
>                 .read_status    = genphy_read_status,
>                 .ack_interrupt  = rtl821x_ack_interrupt,
>                 .config_intr    = rtl8211e_config_intr,
> @@ -152,7 +212,9 @@ static struct phy_driver realtek_drvs[] = {
>                 .phy_id_mask    = 0x001fffff,
>                 .features       = PHY_GBIT_FEATURES,
>                 .flags          = PHY_HAS_INTERRUPT,
> +               .probe          = &rtl8211x_phy_probe,
>                 .config_aneg    = &genphy_config_aneg,
> +               .config_init    = &rtl8211x_config_init,
>                 .read_status    = &genphy_read_status,
>                 .ack_interrupt  = &rtl821x_ack_interrupt,
>                 .config_intr    = &rtl8211e_config_intr,
> @@ -164,6 +226,7 @@ static struct phy_driver realtek_drvs[] = {
>                 .phy_id_mask    = 0x001fffff,
>                 .features       = PHY_GBIT_FEATURES,
>                 .flags          = PHY_HAS_INTERRUPT,
> +               .probe          = &rtl8211x_phy_probe,
>                 .config_aneg    = &genphy_config_aneg,
>                 .config_init    = &rtl8211f_config_init,
>                 .read_status    = &genphy_read_status,
> --
> 2.7.4
>

How about adding callback functionality for .soft_reset to handle BMCR
where we update the Auto-Negotiation for the phy,
as per the datasheet of the rtl8211f.

-Best Regard
Anand Moon

>
> _______________________________________________
> linux-amlogic mailing list
> linux-amlogic at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-amlogic

^ permalink raw reply

* [PATCH 0/8] DMA: s3c64xx: Conversion to the new channel request API
From: Krzysztof Kozlowski @ 2016-11-16 17:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161116032620.GV3000@localhost>

On Wed, Nov 16, 2016 at 08:56:20AM +0530, Vinod Koul wrote:
> On Thu, Nov 10, 2016 at 04:17:48PM +0100, Sylwester Nawrocki wrote:
> > This patch series aims to convert the s3c64xx platform to use
> > the new DMA channel request API, i.e. this is only meaningful 
> > for non-dt systems using s3c64xx SoCs.
> > 
> > Presumably the first 2 or 4 patches in this series could be queued 
> > for v4.10-rc1 and the remaining patches could be left for subsequent
> > release, to avoid non-trivial conflict with patches already applied 
> > in the ASoC tree.
> 
> I am fine with dma patch (expect the subsystem tag) and others except arm
> ones have acks, so I think we can merge this for v4.10-rc1. I cna create a
> immutable tag and people can merge into their tree in case they have
> dependencies.
> 
> Btw need acks on ARM patches before I can apply

First two ARM acked. Vinod, could you prepare a tag with them?

As I understood, everything won't be applied because ASoC tree already
contains some work around this?

Best regards,
Krzysztof

^ permalink raw reply

* [PATCH net 1/3] net: phy: realtek: add eee advertisement disable options
From: Florian Fainelli @ 2016-11-16 17:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479310731.17538.53.camel@baylibre.com>

On 11/16/2016 07:38 AM, Jerome Brunet wrote:
> On Wed, 2016-11-16 at 16:06 +0100, Andrew Lunn wrote:
>> On Wed, Nov 16, 2016 at 03:51:30PM +0100, Jerome Brunet wrote:
>>>
>>> On Wed, 2016-11-16 at 14:23 +0100, Andrew Lunn wrote:
>>>>
>>>>>
>>>>>
>>>>> There two kind of PHYs supporting eee, the one advertising eee
>>>>> by
>>>>> default (like realtek) and the one not advertising it (like
>>>>> micrel).
>>>
>>> This is just the default register value.
>>>
>>>>
>>>>
>>>> I don't know too much about EEE. So maybe a dumb question. Does
>>>> the
>>>> MAC need to be involved? Or is it just the PHY?
>>>>
>>>> If the MAC needs to be involved, the PHY should not be
>>>> advertising
>>>> EEE
>>>> unless the MAC asks for it by calling phy_init_eee(). If this is
>>>> true,
>>>> maybe we need to change the realtek driver, and others in that
>>>> class.
>>>
>>> As far I understand, the advertised capabilities are exchanged
>>> during
>>> the auto-negotiation.
>>>
>>> At this stage, if the advertisement is disabled (regarless of the
>>> actual support) on either side of the link, there will be no low
>>> power
>>> idle state on the Tx nor the Rx path.
>>>
>>> If the advertisement is enabled on both side but we don't call
>>> phy_init_eee, I suppose Tx won't enter LPI, but Rx could.
>>
>> What i was trying to find out is, if the MAC needs to support EEE as
>> well as the PHY, what happens when the MAC does not support EEE, but
>> the PHYs do negotiate EEE? Does it break?
> 
> Interesting question. In a regular case, I suppose it should be fine.
> As you would have LPI only on the Rx path this should be transparent to
> the MAC. That's my understanding. Maybe people knowing EEE better than
> me could confirm (or not) ? Peppe? Alexandre?

EEE is a MAC and PHY feature, and both need to agree on what is enabled,
especially in the transmit path because the way packets may be
transmitted with or without EEE can be done differently at the HW level
(faster/slower return to idle, different clock source).

> 
> I just checked with the OdroidC2, I disabled eee support by forcing
> "dma_cap.eee = 0" in stmmac_get_hw_features. As expected, no tx_LPI
> interrupts but plenty of rx_LPI interrupts.
> 
> What was not expected is test failing like before.
> So in our case, having LPI on the Rx path is fine for receiving data,
> but not for sending.

OK, which really sounds like a potential interoperability problem, or
just the Realtek PHY with EEE enabled acting funky (irrespective of
being attached to stmmac).
-- 
Florian

^ permalink raw reply

* [PATCH 4/8] ARM: s3c64xx: Drop unused DMA fields from struct s3c64xx_spi_csinfo
From: Krzysztof Kozlowski @ 2016-11-16 16:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478791076-19528-5-git-send-email-s.nawrocki@samsung.com>

On Thu, Nov 10, 2016 at 04:17:52PM +0100, Sylwester Nawrocki wrote:
> There is no drivers using those fields so remove them and
> the remaining initializations.
> 
> Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> Tested-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
> ---
>  arch/arm/plat-samsung/devs.c              | 24 ------------------------
>  include/linux/platform_data/spi-s3c64xx.h |  3 ---
>  2 files changed, 27 deletions(-)

Acked-by: Krzysztof Kozlowski <krzk@kernel.org>

Best regards,
Krzysztof

^ permalink raw reply

* [PATCH 2/8] ARM: s3c64xx: Add DMA slave maps for PL080 devices
From: Krzysztof Kozlowski @ 2016-11-16 16:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478791076-19528-3-git-send-email-s.nawrocki@samsung.com>

On Thu, Nov 10, 2016 at 04:17:50PM +0100, Sylwester Nawrocki wrote:
> This patch adds DMA slave map tables to the pl080 devices's
> platform_data in order to support the new channel request API.
> A few devices for which there was no DMA support with current
> code are omitted in the tables.
> 
> Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> ---
>  arch/arm/mach-s3c64xx/pl080.c | 32 ++++++++++++++++++++++++++++++++
>  1 file changed, 32 insertions(+)

Acked-by: Krzysztof Kozlowski <krzk@kernel.org>

Best regards,
Krzysztof

^ permalink raw reply

* [PATCH] bus: vexpress-config: fix device reference leak
From: Sudeep Holla @ 2016-11-16 16:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1477997017-29103-1-git-send-email-johan@kernel.org>



On 01/11/16 10:43, Johan Hovold wrote:
> Make sure to drop the reference to the parent device taken by
> class_find_device() after populating the bus.
>

Thanks for the fix. I somehow missed this patch, sorry for that.
Not sure if arm-soc guys take this as a fix for v4.9, and I have already
sent PR for v4.10. I will repost this along with the ack and check with
them.

-- 
Regards,
Sudeep

^ permalink raw reply

* [PATCH] ARM: davinci: PM: fix build when da850 not compiled in
From: Kevin Hilman @ 2016-11-16 16:44 UTC (permalink / raw)
  To: linux-arm-kernel

Currently, suspend/resume support is only available on da850 platforms,
and the platform PM code has dependencies on da850 functions.  However,
CONFIG_SUSPEND might be enabled even when da850 support is not, causing
build failure:

arch/arm/mach-davinci/built-in.o: In function `davinci_pm_init':
pm_domain.c:(.init.text+0x1fb8): undefined reference to `da8xx_get_mem_ctlr'
pm_domain.c:(.init.text+0x20b0): undefined reference to `da8xx_syscfg1_base'

Fix this by only building the PM core when da850 is enabled.

Reported-by: Sekhar Nori <nsekhar@ti.com>
Fixes: aa9aa1ec2df6 ARM: davinci: PM: rework init, remove platform device
Signed-off-by: Kevin Hilman <khilman@baylibre.com>
---
 arch/arm/mach-davinci/Makefile | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
index da4c336b4637..0a2e6da45f28 100644
--- a/arch/arm/mach-davinci/Makefile
+++ b/arch/arm/mach-davinci/Makefile
@@ -36,5 +36,7 @@ obj-$(CONFIG_MACH_OMAPL138_HAWKBOARD)	+= board-omapl138-hawk.o
 
 # Power Management
 obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o
-obj-$(CONFIG_SUSPEND)			+= pm.o sleep.o
 obj-$(CONFIG_HAVE_CLK)			+= pm_domain.o
+ifeq ($(CONFIG_SUSPEND),y)
+obj-$(CONFIG_ARCH_DAVINCI_DA850)	+= pm.o sleep.o
+endif
-- 
2.9.3

^ permalink raw reply related

* [PATCH RFT] irqchip: mxs: Enable SKIP_SET_WAKE and MASK_ON_SUSPEND
From: Stefan Wahren @ 2016-11-16 16:40 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <40c3be7e-08c3-955c-746a-6906160e1e0a@rempel-privat.de>


> Oleksij Rempel <linux@rempel-privat.de> hat am 12. November 2016 um 20:24
> geschrieben:
> 
> 
> Am 11.11.2016 um 18:26 schrieb Stefan Wahren:
> > The ICOLL controller doesn't provide any facility to configure the
> > wakeup sources. That's the reason why this implementation lacks
> > the irq_set_wake implementation. But this prevent us from properly
> > entering power management states like "suspend to idle".
> > 
> > So enable the flags IRQCHIP_SKIP_SET_WAKE and IRQCHIP_MASK_ON_SUSPEND
> > to let the irqchip core allows and handles the power management.
> > 
> > This patch has been tested with a MX23 and a MX28 board. Any further
> > tests especially with ASM9260 would be appreciated.
> 
> Hi, I wont be able to test this patch on ASM9260 until March.
> Please roll it out, so far it looks ok for me.

Is this an "Acked-by" ?

> 
> 
> > Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
> > ---
> >  drivers/irqchip/irq-mxs.c |    4 ++++
> >  1 file changed, 4 insertions(+)
> > 
> > diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c
> > index 1730470..05fa9f7 100644
> > --- a/drivers/irqchip/irq-mxs.c
> > +++ b/drivers/irqchip/irq-mxs.c
> > @@ -131,12 +131,16 @@ static void asm9260_unmask_irq(struct irq_data *d)
> >  	.irq_ack = icoll_ack_irq,
> >  	.irq_mask = icoll_mask_irq,
> >  	.irq_unmask = icoll_unmask_irq,
> > +	.flags = IRQCHIP_MASK_ON_SUSPEND |
> > +		 IRQCHIP_SKIP_SET_WAKE,
> >  };
> >  
> >  static struct irq_chip asm9260_icoll_chip = {
> >  	.irq_ack = icoll_ack_irq,
> >  	.irq_mask = asm9260_mask_irq,
> >  	.irq_unmask = asm9260_unmask_irq,
> > +	.flags = IRQCHIP_MASK_ON_SUSPEND |
> > +		 IRQCHIP_SKIP_SET_WAKE,
> >  };
> >  
> >  asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs
> > *regs)
> > 
> 
> 
> -- 
> Regards,
> Oleksij
>

^ permalink raw reply

* [PATCH 2/2] ARM: bcm2835: Add names for the Raspberry Pi Zero GPIO lines
From: Stefan Wahren @ 2016-11-16 16:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <87zil0r71o.fsf@eliezer.anholt.net>


> Eric Anholt <eric@anholt.net> hat am 15. November 2016 um 18:23 geschrieben:
> 
> 
> Stefan Wahren <stefan.wahren@i2se.com> writes:
> 
> > This adds the GPIO names for the Raspberry Pi Zero. Since there are no
> > schematics for the RPi Zero use the same as the Model A+.
> 
> These look good to me. I don't have a Zero schematic, but I compared to
> dt-blob.
> 
> I've pulled these two to -next.

Thanks. Unfortunately the link to the dt-blob is outdated. The newer ones [1]
contains the definition of the Raspberry Pi Zero and it differs from Model A+

Please drop the complete series and i'll send a V2. Sorry about this.

[1] - https://github.com/raspberrypi/firmware/blob/master/extra/dt-blob.dts

Stefan

^ permalink raw reply

* [PATCH v27 1/9] memblock: add memblock_cap_memory_range()
From: Will Deacon @ 2016-11-16 16:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161114055515.GH381@linaro.org>

Hi Akashi,

On Mon, Nov 14, 2016 at 02:55:16PM +0900, AKASHI Takahiro wrote:
> On Fri, Nov 11, 2016 at 11:19:04AM +0800, Dennis Chen wrote:
> > On Fri, Nov 11, 2016 at 11:50:50AM +0900, AKASHI Takahiro wrote:
> > > On Thu, Nov 10, 2016 at 05:27:20PM +0000, Will Deacon wrote:
> > > > On Wed, Nov 02, 2016 at 01:51:53PM +0900, AKASHI Takahiro wrote:
> > > > > +void __init memblock_cap_memory_range(phys_addr_t base, phys_addr_t size)
> > > > > +{
> > > > > +	int start_rgn, end_rgn;
> > > > > +	int i, ret;
> > > > > +
> > > > > +	if (!size)
> > > > > +		return;
> > > > > +
> > > > > +	ret = memblock_isolate_range(&memblock.memory, base, size,
> > > > > +						&start_rgn, &end_rgn);
> > > > > +	if (ret)
> > > > > +		return;
> > > > > +
> > > > > +	/* remove all the MAP regions */
> > > > > +	for (i = memblock.memory.cnt - 1; i >= end_rgn; i--)
> > > > > +		if (!memblock_is_nomap(&memblock.memory.regions[i]))
> > > > > +			memblock_remove_region(&memblock.memory, i);
> > > > > +
> > > > > +	for (i = start_rgn - 1; i >= 0; i--)
> > > > > +		if (!memblock_is_nomap(&memblock.memory.regions[i]))
> > > > > +			memblock_remove_region(&memblock.memory, i);
> > > > > +
> > > > > +	/* truncate the reserved regions */
> > > > > +	memblock_remove_range(&memblock.reserved, 0, base);
> > > > > +	memblock_remove_range(&memblock.reserved,
> > > > > +			base + size, (phys_addr_t)ULLONG_MAX);
> > > > > +}
> > > > 
> > > > This duplicates a bunch of the logic in memblock_mem_limit_remove_map. Can
> > > > you not implement that in terms of your new, more general, function? e.g.
> > > > by passing base == 0, and size == limit?
> > > 
> > > Obviously it's possible.
> > > I actually talked to Dennis before about merging them,
> > > but he was against my idea.
> > >
> > Oops! I thought we have reached agreement in the thread:http://lists.infradead.org/pipermail/linux-arm-kernel/2016-July/442817.html
> > So feel free to do that as Will'll do
> 
> OK, but I found that the two functions have a bit different semantics
> in clipping memory range, in particular, when the range [base,base+size)
> goes across several regions with a gap.
> (This does not happen in my arm64 kdump, though.)
> That is, 'limit' in memblock_mem_limit_remove_map() means total size of
> available memory, while 'size' in memblock_cap_memory_range() indicates
> the size of _continuous_ memory range.

I thought limit was just a physical address, and then
memblock_mem_limit_remove_map operated on the end of the nearest memblock?
You could leave the __find_max_addr call in memblock_mem_limit_remove_map,
given that I don't think you need/want it for memblock_cap_memory_range.

> So I added an extra argument, exact, to a common function to specify
> distinct behaviors. Confusing? Please see the patch below.

Oh yikes, this certainly wasn't what I had in mind! My observation was
just that memblock_mem_limit_remove_map(limit) does:


  1. memblock_isolate_range(limit - limit+ULLONG_MAX)
  2. memblock_remove_region(all non-nomap regions in the isolated region)
  3. truncate reserved regions to limit

and your memblock_cap_memory_range(base, size) does:

  1. memblock_isolate_range(base - base+size)
  2, memblock_remove_region(all non-nomap regions above and below the
     isolated region)
  3. truncate reserved regions around the isolated region

so, assuming we can invert the isolation in one of the cases, then they
could share the same underlying implementation.

I'm probably just missing something here, because the patch you've ended
up with is far more involved than I anticipated...

Will

^ permalink raw reply

* [PATCH] ARM: dts: imx: add SPI to GW54xx
From: Tim Harvey @ 2016-11-16 16:26 UTC (permalink / raw)
  To: linux-arm-kernel

The GW54xx revision E adds SPI via an off-board connector.

Signed-off-by: Tim Harvey <tharvey@gateworks.com>
---
 arch/arm/boot/dts/imx6qdl-gw54xx.dtsi | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
index b6982959..6eb4fc9 100644
--- a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
@@ -149,6 +149,14 @@
 				 <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
 };
 
+&ecspi2 {
+	fsl,spi-num-chipselects = <1>;
+	cs-gpios = <&gpio2 26 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_ecspi2>;
+	status = "okay";
+};
+
 &fec {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_enet>;
@@ -511,6 +519,15 @@
 			>;
 		};
 
+		pinctrl_ecspi2: escpi2grp {
+			fsl,pins = <
+				MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK	0x100b1
+				MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI	0x100b1
+				MX6QDL_PAD_EIM_OE__ECSPI2_MISO	0x100b1
+				MX6QDL_PAD_EIM_RW__GPIO2_IO26	0x100b1
+			>;
+		};
+
 		pinctrl_flexcan1: flexcan1grp {
 			fsl,pins = <
 				MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX	0x1b0b1
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 0/3] ARM: davinci: PM: cleanup init, add DT support
From: Kevin Hilman @ 2016-11-16 16:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <c0f1cfa2-4086-72fc-783b-d0d8c837cb08@ti.com>

Sekhar Nori <nsekhar@ti.com> writes:

> Hi Kevin,
>
> On Wednesday 16 November 2016 01:24 AM, Kevin Hilman wrote:
>> This series removes the fake platform_device used to initialize PM on
>> legacy davinci platforms, and also adds PM support for DT platforms.
>> 
>> Tested with legacy boot on da850-evm, and DT boot on da850-lcdk.  Used
>> RTC to wake from suspend-to-RAM: e.g. rtcwake -m mem -s 4 -d /dev/rtc0
>
> With these patches applied, I saw the following randconfig build error.
>
> arch/arm/mach-davinci/built-in.o: In function `davinci_pm_init':
> pm_domain.c:(.init.text+0x13d8): undefined reference to `da8xx_get_mem_ctlr'
> pm_domain.c:(.init.text+0x14bc): undefined reference to `da8xx_syscfg1_base'
> make: *** [vmlinux] Error 1
>
> Attached is the defconfig. I did not check to see if your patches 
> introduced it or if this is something that always existed and never 
> caught.

It looks like a new problem caused by moving those calls into pm.c.

The problem is that currently pm.o can be built even when da850 support
is not enabled, which is the case in your defconfig.

I'll hae a look at how to cleanup that dependency.

Kevin

^ permalink raw reply

* [PATCH 1/2] ahci: qoriq: added a condition to enable dma coherence
From: Robin Murphy @ 2016-11-16 16:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479265879-48840-1-git-send-email-yuantian.tang@nxp.com>

On 16/11/16 03:11, yuantian.tang at nxp.com wrote:
> From: Tang Yuantian <Yuantian.Tang@nxp.com>
> 
> Enable DMA coherence in SATA controller on condition that
> dma-coherent property exists in sata node in DTS.
> 
> Signed-off-by: Tang Yuantian <yuantian.tang@nxp.com>
> ---
>  drivers/ata/ahci_qoriq.c | 15 +++++++++++----
>  1 file changed, 11 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c
> index 9884c8c..45c88de 100644
> --- a/drivers/ata/ahci_qoriq.c
> +++ b/drivers/ata/ahci_qoriq.c
> @@ -59,6 +59,7 @@ struct ahci_qoriq_priv {
>  	struct ccsr_ahci *reg_base;
>  	enum ahci_qoriq_type type;
>  	void __iomem *ecc_addr;
> +	bool is_dmacoherent;
>  };
>  
>  static const struct of_device_id ahci_qoriq_of_match[] = {
> @@ -164,26 +165,31 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
>  		writel(LS1021A_PORT_PHY4, reg_base + PORT_PHY4);
>  		writel(LS1021A_PORT_PHY5, reg_base + PORT_PHY5);
>  		writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
> -		writel(AHCI_PORT_AXICC_CFG, reg_base + LS1021A_AXICC_ADDR);
> +		if (qpriv->is_dmacoherent)
> +			writel(AHCI_PORT_AXICC_CFG,
> +					reg_base + LS1021A_AXICC_ADDR);
>  		break;
>  
>  	case AHCI_LS1043A:
>  		writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
>  		writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
> -		writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
> +		if (qpriv->is_dmacoherent)
> +			writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
>  		break;
>  
>  	case AHCI_LS2080A:
>  		writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
>  		writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
> -		writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
> +		if (qpriv->is_dmacoherent)
> +			writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
>  		break;
>  
>  	case AHCI_LS1046A:
>  		writel(LS1046A_SATA_ECC_DIS, qpriv->ecc_addr);
>  		writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
>  		writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
> -		writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
> +		if (qpriv->is_dmacoherent)
> +			writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
>  		break;
>  	}
>  
> @@ -221,6 +227,7 @@ static int ahci_qoriq_probe(struct platform_device *pdev)
>  		if (IS_ERR(qoriq_priv->ecc_addr))
>  			return PTR_ERR(qoriq_priv->ecc_addr);
>  	}
> +	qoriq_priv->is_dmacoherent = of_property_read_bool(np, "dma-coherent");

Better to use of_dma_is_coherent(np) rather than open-coding it.

Robin.

>  
>  	rc = ahci_platform_enable_resources(hpriv);
>  	if (rc)
> 

^ permalink raw reply

* [PATCH v7 0/7] Add DRM driver for Hisilicon Hibmc
From: Sean Paul @ 2016-11-16 16:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAOw6vbLgDwiVs8zC5bEhdhJUvVZh2toG_d+FgkzV7vUJjU=3RQ@mail.gmail.com>

On Wed, Nov 16, 2016 at 11:01 AM, Sean Paul <seanpaul@chromium.org> wrote:
> On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>> This patch set adds a new drm driver for Hisilicon Hibmc. Hibmc is a
>> BMC SoC with a display controller intergrated, usually it is used on
>> server for Out-of-band management purpose. In this patch set, we just
>> support basic function for Hibmc display subsystem. Hibmc display
>> subsystem is connected to host CPU by PCIe as blow:
>>
>> +----------+       +----------+
>> |          | PCIe  |  Hibmc   |
>> |host CPU( |<----->| display  |
>> |arm64,x86)|       |subsystem |
>> +----------+       +----------+
>>
>> Hardware Detail for Hibmc display subsystem
>> -----------
>>
>>   The display subsystem of Hibmc is show as bellow:
>>   +----+      +----+      +----+     +--------+
>>   |    |      |    |      |    |     |        |
>>   | FB |----->| DE |----->|VDAC|---->|external|
>>   |    |      |    |      |    |     | VGA    |
>>   +----+      +----+      +----+     +--------+
>>
>>   -DE(Display Engine) is the display controller.
>>   -VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
>>   stream from DE to VGA analog signals.
>>
>
> For the whole series/driver:
>
> Acked-by: Sean Paul <seanpaul@chromium.org>
>
>

Also, please send those fixups for the other ttm drivers ;)

>
>> Change History
>> ------------
>> Changes in v7:
>>   -remove hibmc_drm_power.c/hibmc_drm_power.h, move the functions to
>>    hibmc_drm_drv.c.
>>   -remove hibmc_drm_de.h and move the struct defined in head file to
>>    hibmc_drm_de.c.
>>   -plane is initialized inside crtc, not in hibmc_kms_init().
>>   -connector is initialized inside encoder, not in hibmc_kms_init().
>>   -remove plane/crtc/encoder/connector from hibmc_drm_private struct.
>>   -call drm_atomic_helper_suspend/resume in hibmc_pm_suspend/resume.
>>   -remove these empty stubs because caller will do NULL check.
>>     hibmc_plane_atomic_disable
>>     hibmc_crtc_atomic_check
>>     hibmc_encoder_disable
>>     hibmc_encoder_enable
>>     hibmc_encoder_atomic_check
>>   -clean up in all error paths of creating driver-private framebuffer.
>>
>> Changes in v6:
>>   -remove the embedded framebuffer and use a pointer of hibmc_framebuffer
>>    instead.
>>   -remove the deprecated drm_framebuffer_unregister_private(),
>>    drm_framebuffer_unreference() will be called in hibmc_fbdev_destroy().
>>   -uninstall irq in hibmc_unload().
>>
>> Changes in v5:
>>   -rebase on v4.9-rc2.
>>   -replace drm_fb_helper_set_suspend with drm_fb_helper_set_suspend_unlocked.
>>    and remove redundant console_lock and console_unlock.
>>
>> Changes in v4:
>>   -remove unused include files, and include header file when it is needed.
>>   -remove unused FLAG in Kconfig: DRM_GEM_CMA_HELPER/DRM_KMS_CMA_HELPER.
>>   -remove drm_helper_disable_unused_functions, since we use DRIVER_ATOMIC.
>>
>> Changes in v3:
>>   -enable KMS, in v2, only fbdev is enabled.
>>   -management video memory with ttm.
>>   -add vblank interrupt.
>>   -remove drm_connector_register_all() and drm_connector_unregister_all().
>>   -I have a basic test with igt.
>>
>> Changes in v2:
>>   -Remove self-defined macros for bit operations.
>>   -Remove unused register.
>>   -Replace those deprecated functions with new version of them.
>>   -use drm_connector_register_all() to register connector after
>>    drm_dev_register().
>>
>> The patch v2 is at
>> https://lists.freedesktop.org/archives/dri-devel/2016-May/108661.html
>>
>> Rongrong Zou (7):
>>   drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
>>   drm/hisilicon/hibmc: Add video memory management
>>   drm/hisilicon/hibmc: Add support for frame buffer
>>   drm/hisilicon/hibmc: Add support for display engine
>>   drm/hisilicon/hibmc: Add support for VDAC
>>   drm/hisilicon/hibmc: Add support for vblank interrupt
>>   MAINTAINERS: Update HISILICON DRM entries
>>
>>  MAINTAINERS                                       |   1 +
>>  drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
>>  drivers/gpu/drm/hisilicon/Makefile                |   1 +
>>  drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   9 +
>>  drivers/gpu/drm/hisilicon/hibmc/Makefile          |   4 +
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c    | 477 ++++++++++++++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 456 ++++++++++++++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   | 114 +++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 +++++++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 196 ++++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c  | 147 ++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       | 558 ++++++++++++++++++++++
>>  12 files changed, 2231 insertions(+)
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>
>> --
>> 1.9.1
>>

^ permalink raw reply

* [PATCH v7 0/7] Add DRM driver for Hisilicon Hibmc
From: Sean Paul @ 2016-11-16 16:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479303831-74134-1-git-send-email-zourongrong@gmail.com>

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> This patch set adds a new drm driver for Hisilicon Hibmc. Hibmc is a
> BMC SoC with a display controller intergrated, usually it is used on
> server for Out-of-band management purpose. In this patch set, we just
> support basic function for Hibmc display subsystem. Hibmc display
> subsystem is connected to host CPU by PCIe as blow:
>
> +----------+       +----------+
> |          | PCIe  |  Hibmc   |
> |host CPU( |<----->| display  |
> |arm64,x86)|       |subsystem |
> +----------+       +----------+
>
> Hardware Detail for Hibmc display subsystem
> -----------
>
>   The display subsystem of Hibmc is show as bellow:
>   +----+      +----+      +----+     +--------+
>   |    |      |    |      |    |     |        |
>   | FB |----->| DE |----->|VDAC|---->|external|
>   |    |      |    |      |    |     | VGA    |
>   +----+      +----+      +----+     +--------+
>
>   -DE(Display Engine) is the display controller.
>   -VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
>   stream from DE to VGA analog signals.
>

For the whole series/driver:

Acked-by: Sean Paul <seanpaul@chromium.org>



> Change History
> ------------
> Changes in v7:
>   -remove hibmc_drm_power.c/hibmc_drm_power.h, move the functions to
>    hibmc_drm_drv.c.
>   -remove hibmc_drm_de.h and move the struct defined in head file to
>    hibmc_drm_de.c.
>   -plane is initialized inside crtc, not in hibmc_kms_init().
>   -connector is initialized inside encoder, not in hibmc_kms_init().
>   -remove plane/crtc/encoder/connector from hibmc_drm_private struct.
>   -call drm_atomic_helper_suspend/resume in hibmc_pm_suspend/resume.
>   -remove these empty stubs because caller will do NULL check.
>     hibmc_plane_atomic_disable
>     hibmc_crtc_atomic_check
>     hibmc_encoder_disable
>     hibmc_encoder_enable
>     hibmc_encoder_atomic_check
>   -clean up in all error paths of creating driver-private framebuffer.
>
> Changes in v6:
>   -remove the embedded framebuffer and use a pointer of hibmc_framebuffer
>    instead.
>   -remove the deprecated drm_framebuffer_unregister_private(),
>    drm_framebuffer_unreference() will be called in hibmc_fbdev_destroy().
>   -uninstall irq in hibmc_unload().
>
> Changes in v5:
>   -rebase on v4.9-rc2.
>   -replace drm_fb_helper_set_suspend with drm_fb_helper_set_suspend_unlocked.
>    and remove redundant console_lock and console_unlock.
>
> Changes in v4:
>   -remove unused include files, and include header file when it is needed.
>   -remove unused FLAG in Kconfig: DRM_GEM_CMA_HELPER/DRM_KMS_CMA_HELPER.
>   -remove drm_helper_disable_unused_functions, since we use DRIVER_ATOMIC.
>
> Changes in v3:
>   -enable KMS, in v2, only fbdev is enabled.
>   -management video memory with ttm.
>   -add vblank interrupt.
>   -remove drm_connector_register_all() and drm_connector_unregister_all().
>   -I have a basic test with igt.
>
> Changes in v2:
>   -Remove self-defined macros for bit operations.
>   -Remove unused register.
>   -Replace those deprecated functions with new version of them.
>   -use drm_connector_register_all() to register connector after
>    drm_dev_register().
>
> The patch v2 is at
> https://lists.freedesktop.org/archives/dri-devel/2016-May/108661.html
>
> Rongrong Zou (7):
>   drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
>   drm/hisilicon/hibmc: Add video memory management
>   drm/hisilicon/hibmc: Add support for frame buffer
>   drm/hisilicon/hibmc: Add support for display engine
>   drm/hisilicon/hibmc: Add support for VDAC
>   drm/hisilicon/hibmc: Add support for vblank interrupt
>   MAINTAINERS: Update HISILICON DRM entries
>
>  MAINTAINERS                                       |   1 +
>  drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
>  drivers/gpu/drm/hisilicon/Makefile                |   1 +
>  drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   9 +
>  drivers/gpu/drm/hisilicon/hibmc/Makefile          |   4 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c    | 477 ++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 456 ++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   | 114 +++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 +++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 196 ++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c  | 147 ++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       | 558 ++++++++++++++++++++++
>  12 files changed, 2231 insertions(+)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>
> --
> 1.9.1
>

^ permalink raw reply

* [PATCH v7 7/7] MAINTAINERS: Update HISILICON DRM entries
From: Sean Paul @ 2016-11-16 16:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479303831-74134-8-git-send-email-zourongrong@gmail.com>

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  MAINTAINERS | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 2a58eea..84a7296 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4123,6 +4123,7 @@ F:        drivers/gpu/drm/gma500/
>
>  DRM DRIVERS FOR HISILICON
>  M:     Xinliang Liu <z.liuxinliang@hisilicon.com>
> +M:     Rongrong Zou <zourongrong@gmail.com>
>  R:     Xinwei Kong <kong.kongxinwei@hisilicon.com>
>  R:     Chen Feng <puck.chen@hisilicon.com>
>  L:     dri-devel at lists.freedesktop.org
> --
> 1.9.1
>

^ permalink raw reply

* [PATCH v7 6/7] drm/hisilicon/hibmc: Add support for vblank interrupt
From: Sean Paul @ 2016-11-16 16:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479303831-74134-7-git-send-email-zourongrong@gmail.com>

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add vblank interrupt.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 56 ++++++++++++++++++++++++-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  1 +
>  2 files changed, 56 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index c133644..73ba8b0 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -39,16 +39,45 @@
>
>  static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
>  {
> +       struct hibmc_drm_private *priv =
> +               (struct hibmc_drm_private *)dev->dev_private;
> +
> +       writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(1),
> +              priv->mmio + HIBMC_RAW_INTERRUPT_EN);
> +
>         return 0;
>  }
>
>  static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>  {
> +       struct hibmc_drm_private *priv =
> +               (struct hibmc_drm_private *)dev->dev_private;
> +
> +       writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(0),
> +              priv->mmio + HIBMC_RAW_INTERRUPT_EN);
> +}
> +
> +irqreturn_t hibmc_drm_interrupt(int irq, void *arg)
> +{
> +       struct drm_device *dev = (struct drm_device *)arg;
> +       struct hibmc_drm_private *priv =
> +               (struct hibmc_drm_private *)dev->dev_private;
> +       u32 status;
> +
> +       status = readl(priv->mmio + HIBMC_RAW_INTERRUPT);
> +
> +       if (status & HIBMC_RAW_INTERRUPT_VBLANK(1)) {
> +               writel(HIBMC_RAW_INTERRUPT_VBLANK(1),
> +                      priv->mmio + HIBMC_RAW_INTERRUPT);
> +               drm_handle_vblank(dev, 0);
> +       }
> +
> +       return IRQ_HANDLED;
>  }
>
>  static struct drm_driver hibmc_driver = {
>         .driver_features        = DRIVER_GEM | DRIVER_MODESET |
> -                                 DRIVER_ATOMIC,
> +                                 DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
>         .fops                   = &hibmc_fops,
>         .name                   = "hibmc",
>         .date                   = "20160828",
> @@ -62,6 +91,7 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>         .dumb_create            = hibmc_dumb_create,
>         .dumb_map_offset        = hibmc_dumb_mmap_offset,
>         .dumb_destroy           = drm_gem_dumb_destroy,
> +       .irq_handler            = hibmc_drm_interrupt,
>  };
>
>  static int hibmc_pm_suspend(struct device *dev)
> @@ -268,6 +298,13 @@ static int hibmc_unload(struct drm_device *dev)
>         struct hibmc_drm_private *priv = dev->dev_private;
>
>         hibmc_fbdev_fini(priv);
> +
> +       if (dev->irq_enabled)
> +               drm_irq_uninstall(dev);
> +       if (priv->msi_enabled)
> +               pci_disable_msi(dev->pdev);
> +       drm_vblank_cleanup(dev);
> +
>         hibmc_kms_fini(priv);
>         hibmc_mm_fini(priv);
>         dev->dev_private = NULL;
> @@ -299,6 +336,23 @@ static int hibmc_load(struct drm_device *dev)
>         if (ret)
>                 goto err;
>
> +       ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
> +       if (ret) {
> +               DRM_ERROR("failed to initialize vblank: %d\n", ret);
> +               goto err;
> +       }
> +
> +       priv->msi_enabled = 0;
> +       ret = pci_enable_msi(dev->pdev);
> +       if (ret) {
> +               DRM_WARN("enabling MSI failed: %d\n", ret);
> +       } else {
> +               priv->msi_enabled = 1;
> +               ret = drm_irq_install(dev, dev->pdev->irq);
> +               if (ret)
> +                       DRM_WARN("install irq failed: %d\n", ret);
> +       }
> +
>         /* reset all the states of crtc/plane/encoder/connector */
>         drm_mode_config_reset(dev);
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index b626caf..e195521 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -42,6 +42,7 @@ struct hibmc_drm_private {
>         void __iomem   *fb_map;
>         unsigned long  fb_base;
>         unsigned long  fb_size;
> +       bool msi_enabled;
>
>         /* drm */
>         struct drm_device  *dev;
> --
> 1.9.1
>

^ permalink raw reply

* [PATCH v7 5/7] drm/hisilicon/hibmc: Add support for VDAC
From: Sean Paul @ 2016-11-16 15:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479303831-74134-6-git-send-email-zourongrong@gmail.com>

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
> stream from DE to VGA analog signals.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/hisilicon/hibmc/Makefile         |   2 +-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c  |   6 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h  |   1 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 147 +++++++++++++++++++++++
>  4 files changed, 155 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> index 8e0cf72..f2e04c0 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,4 +1,4 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_ttm.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_fbdev.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index 9de3564..c133644 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -123,6 +123,12 @@ static int hibmc_kms_init(struct hibmc_drm_private *priv)
>                 return ret;
>         }
>
> +       ret = hibmc_vdac_init(priv);
> +       if (ret) {
> +               DRM_ERROR("failed to init vdac: %d\n", ret);
> +               return ret;
> +       }
> +
>         return 0;
>  }
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index 87af1eb..b626caf 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -86,6 +86,7 @@ void hibmc_set_current_gate(struct hibmc_drm_private *priv,
>                             unsigned int gate);
>
>  int hibmc_de_init(struct hibmc_drm_private *priv);
> +int hibmc_vdac_init(struct hibmc_drm_private *priv);
>  int hibmc_fbdev_init(struct hibmc_drm_private *priv);
>  void hibmc_fbdev_fini(struct hibmc_drm_private *priv);
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
> new file mode 100644
> index 0000000..d1f67a9
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
> @@ -0,0 +1,147 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +
> +#include "hibmc_drm_drv.h"
> +#include "hibmc_drm_regs.h"
> +
> +static int hibmc_connector_get_modes(struct drm_connector *connector)
> +{
> +       return drm_add_modes_noedid(connector, 800, 600);
> +}
> +
> +static int hibmc_connector_mode_valid(struct drm_connector *connector,
> +                                     struct drm_display_mode *mode)
> +{
> +       return MODE_OK;
> +}
> +
> +static struct drm_encoder *
> +hibmc_connector_best_encoder(struct drm_connector *connector)
> +{
> +       return drm_encoder_find(connector->dev, connector->encoder_ids[0]);
> +}
> +
> +static enum drm_connector_status hibmc_connector_detect(struct drm_connector
> +                                                *connector, bool force)
> +{
> +       return connector_status_connected;
> +}
> +
> +static const struct drm_connector_helper_funcs
> +       hibmc_connector_helper_funcs = {
> +       .get_modes = hibmc_connector_get_modes,
> +       .mode_valid = hibmc_connector_mode_valid,
> +       .best_encoder = hibmc_connector_best_encoder,
> +};
> +
> +static const struct drm_connector_funcs hibmc_connector_funcs = {
> +       .dpms = drm_atomic_helper_connector_dpms,
> +       .detect = hibmc_connector_detect,
> +       .fill_modes = drm_helper_probe_single_connector_modes,
> +       .destroy = drm_connector_cleanup,
> +       .reset = drm_atomic_helper_connector_reset,
> +       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> +       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static struct drm_connector *
> +hibmc_connector_init(struct hibmc_drm_private *priv)
> +{
> +       struct drm_device *dev = priv->dev;
> +       struct drm_connector *connector;
> +       int ret;
> +
> +       connector = devm_kzalloc(dev->dev, sizeof(*connector), GFP_KERNEL);
> +       if (!connector) {
> +               DRM_ERROR("failed to alloc memory when init connector\n");
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       ret = drm_connector_init(dev, connector,
> +                                &hibmc_connector_funcs,
> +                                DRM_MODE_CONNECTOR_VGA);
> +       if (ret) {
> +               DRM_ERROR("failed to init connector: %d\n", ret);
> +               return ERR_PTR(ret);
> +       }
> +       drm_connector_helper_add(connector,
> +                                &hibmc_connector_helper_funcs);
> +
> +       return connector;
> +}
> +
> +static void hibmc_encoder_mode_set(struct drm_encoder *encoder,
> +                                  struct drm_display_mode *mode,
> +                                  struct drm_display_mode *adj_mode)
> +{
> +       u32 reg;
> +       struct drm_device *dev = encoder->dev;
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +
> +       reg = readl(priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE);
> +       reg |= HIBMC_DISPLAY_CONTROL_FPVDDEN(1);
> +       reg |= HIBMC_DISPLAY_CONTROL_PANELDATE(1);
> +       reg |= HIBMC_DISPLAY_CONTROL_FPEN(1);
> +       reg |= HIBMC_DISPLAY_CONTROL_VBIASEN(1);
> +       writel(reg, priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE);
> +}
> +
> +static const struct drm_encoder_helper_funcs hibmc_encoder_helper_funcs = {
> +       .mode_set = hibmc_encoder_mode_set,
> +};
> +
> +static const struct drm_encoder_funcs hibmc_encoder_funcs = {
> +       .destroy = drm_encoder_cleanup,
> +};
> +
> +int hibmc_vdac_init(struct hibmc_drm_private *priv)
> +{
> +       struct drm_device *dev = priv->dev;
> +       struct drm_encoder *encoder;
> +       struct drm_connector *connector;
> +       int ret;
> +
> +       connector = hibmc_connector_init(priv);
> +       if (IS_ERR(connector)) {
> +               DRM_ERROR("failed to create connector: %ld\n",
> +                         PTR_ERR(connector));
> +               return PTR_ERR(connector);
> +       }
> +
> +       encoder = devm_kzalloc(dev->dev, sizeof(*encoder), GFP_KERNEL);
> +       if (!encoder) {
> +               DRM_ERROR("failed to alloc memory when init encoder\n");
> +               return -ENOMEM;
> +       }
> +
> +       encoder->possible_crtcs = 0x1;
> +       ret = drm_encoder_init(dev, encoder, &hibmc_encoder_funcs,
> +                              DRM_MODE_ENCODER_DAC, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to init encoder: %d\n", ret);
> +               return ret;
> +       }
> +
> +       drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
> +       drm_mode_connector_attach_encoder(connector, encoder);
> +
> +       return 0;
> +}
> --
> 1.9.1
>

^ permalink raw reply

* [PATCH v7 4/7] drm/hisilicon/hibmc: Add support for display engine
From: Sean Paul @ 2016-11-16 15:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479303831-74134-5-git-send-email-zourongrong@gmail.com>

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add display engine function, crtc/plane is initialized here.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 477 ++++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  69 +++-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   6 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     |   6 +
>  5 files changed, 558 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> index ff77a7e..8e0cf72 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,4 +1,4 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_ttm.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
> new file mode 100644
> index 0000000..2a1386e
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
> @@ -0,0 +1,477 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + */
> +
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_plane_helper.h>
> +
> +#include "hibmc_drm_drv.h"
> +#include "hibmc_drm_regs.h"
> +
> +struct hibmc_display_panel_pll {
> +       unsigned long M;
> +       unsigned long N;
> +       unsigned long OD;
> +       unsigned long POD;
> +};
> +
> +struct hibmc_dislay_pll_config {
> +       unsigned long hdisplay;
> +       unsigned long vdisplay;
> +       u32 pll1_config_value;
> +       u32 pll2_config_value;
> +};
> +
> +static const struct hibmc_dislay_pll_config hibmc_pll_table[] = {
> +       {800, 600, CRT_PLL1_HS_40MHZ, CRT_PLL2_HS_40MHZ},
> +       {1024, 768, CRT_PLL1_HS_65MHZ, CRT_PLL2_HS_65MHZ},
> +       {1152, 864, CRT_PLL1_HS_80MHZ_1152, CRT_PLL2_HS_80MHZ},
> +       {1280, 768, CRT_PLL1_HS_80MHZ, CRT_PLL2_HS_80MHZ},
> +       {1280, 720, CRT_PLL1_HS_74MHZ, CRT_PLL2_HS_74MHZ},
> +       {1280, 960, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ},
> +       {1280, 1024, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ},
> +       {1600, 1200, CRT_PLL1_HS_162MHZ, CRT_PLL2_HS_162MHZ},
> +       {1920, 1080, CRT_PLL1_HS_148MHZ, CRT_PLL2_HS_148MHZ},
> +       {1920, 1200, CRT_PLL1_HS_193MHZ, CRT_PLL2_HS_193MHZ},
> +};
> +
> +#define PADDING(align, data) (((data) + (align) - 1) & (~((align) - 1)))
> +
> +static int hibmc_plane_atomic_check(struct drm_plane *plane,
> +                                   struct drm_plane_state *state)
> +{
> +       struct drm_framebuffer *fb = state->fb;
> +       struct drm_crtc *crtc = state->crtc;
> +       struct drm_crtc_state *crtc_state;
> +       u32 src_w = state->src_w >> 16;
> +       u32 src_h = state->src_h >> 16;
> +
> +       if (!crtc || !fb)
> +               return 0;
> +
> +       crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
> +       if (IS_ERR(crtc_state))
> +               return PTR_ERR(crtc_state);
> +
> +       if (src_w != state->crtc_w || src_h != state->crtc_h) {
> +               DRM_DEBUG_ATOMIC("scale not support\n");
> +               return -EINVAL;
> +       }
> +
> +       if (state->crtc_x < 0 || state->crtc_y < 0) {
> +               DRM_DEBUG_ATOMIC("crtc_x/y of drm_plane state is invalid\n");
> +               return -EINVAL;
> +       }
> +
> +       if (state->crtc_x + state->crtc_w >
> +           crtc_state->adjusted_mode.hdisplay ||
> +           state->crtc_y + state->crtc_h >
> +           crtc_state->adjusted_mode.vdisplay) {
> +               DRM_DEBUG_ATOMIC("visible portion of plane is invalid\n");
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static void hibmc_plane_atomic_update(struct drm_plane *plane,
> +                                     struct drm_plane_state *old_state)
> +{
> +       struct drm_plane_state  *state  = plane->state;
> +       u32 reg;
> +       int ret;
> +       u64 gpu_addr = 0;
> +       unsigned int line_l;
> +       struct hibmc_drm_private *priv = plane->dev->dev_private;
> +       struct hibmc_framebuffer *hibmc_fb;
> +       struct hibmc_bo *bo;
> +
> +       if (!state->fb)
> +               return;
> +
> +       hibmc_fb = to_hibmc_framebuffer(state->fb);
> +       bo = gem_to_hibmc_bo(hibmc_fb->obj);
> +       ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to reserve ttm_bo: %d", ret);
> +               return;
> +       }
> +
> +       ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
> +       ttm_bo_unreserve(&bo->bo);
> +       if (ret) {
> +               DRM_ERROR("failed to pin hibmc_bo: %d", ret);
> +               return;
> +       }
> +
> +       writel(gpu_addr, priv->mmio + HIBMC_CRT_FB_ADDRESS);
> +
> +       reg = state->fb->width * (state->fb->bits_per_pixel / 8);
> +       /* now line_pad is 16 */
> +       reg = PADDING(16, reg);
> +
> +       line_l = state->fb->width * state->fb->bits_per_pixel / 8;
> +       line_l = PADDING(16, line_l);
> +       writel(HIBMC_FIELD(HIBMC_CRT_FB_WIDTH_WIDTH, reg) |
> +              HIBMC_FIELD(HIBMC_CRT_FB_WIDTH_OFFS, line_l),
> +              priv->mmio + HIBMC_CRT_FB_WIDTH);
> +
> +       /* SET PIXEL FORMAT */
> +       reg = readl(priv->mmio + HIBMC_CRT_DISP_CTL);
> +       reg &= ~HIBMC_CRT_DISP_CTL_FORMAT_MASK;
> +       reg |= HIBMC_FIELD(HIBMC_CRT_DISP_CTL_FORMAT,
> +                          state->fb->bits_per_pixel / 16);
> +       writel(reg, priv->mmio + HIBMC_CRT_DISP_CTL);
> +}
> +
> +static const u32 channel_formats1[] = {
> +       DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888,
> +       DRM_FORMAT_BGR888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888,
> +       DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_ARGB8888,
> +       DRM_FORMAT_ABGR8888
> +};
> +
> +static struct drm_plane_funcs hibmc_plane_funcs = {
> +       .update_plane   = drm_atomic_helper_update_plane,
> +       .disable_plane  = drm_atomic_helper_disable_plane,
> +       .set_property = drm_atomic_helper_plane_set_property,
> +       .destroy = drm_plane_cleanup,
> +       .reset = drm_atomic_helper_plane_reset,
> +       .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
> +       .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
> +};
> +
> +static const struct drm_plane_helper_funcs hibmc_plane_helper_funcs = {
> +       .atomic_check = hibmc_plane_atomic_check,
> +       .atomic_update = hibmc_plane_atomic_update,
> +};
> +
> +static struct drm_plane *hibmc_plane_init(struct hibmc_drm_private *priv)
> +{
> +       struct drm_device *dev = priv->dev;
> +       struct drm_plane *plane;
> +       int ret = 0;
> +
> +       plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
> +       if (!plane) {
> +               DRM_ERROR("failed to alloc memory when init plane\n");
> +               return ERR_PTR(-ENOMEM);
> +       }
> +       /*
> +        * plane init
> +        * TODO: Now only support primary plane, overlay planes
> +        * need to do.
> +        */
> +       ret = drm_universal_plane_init(dev, plane, 1, &hibmc_plane_funcs,
> +                                      channel_formats1,
> +                                      ARRAY_SIZE(channel_formats1),
> +                                      DRM_PLANE_TYPE_PRIMARY,
> +                                      NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to init plane: %d\n", ret);
> +               return ERR_PTR(ret);
> +       }
> +
> +       drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
> +       return plane;
> +}
> +
> +static void hibmc_crtc_enable(struct drm_crtc *crtc)
> +{
> +       unsigned int reg;
> +       struct hibmc_drm_private *priv = crtc->dev->dev_private;
> +
> +       hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(1);
> +       reg |= HIBMC_CURR_GATE_DISPLAY(1);
> +       hibmc_set_current_gate(priv, reg);
> +       drm_crtc_vblank_on(crtc);
> +}
> +
> +static void hibmc_crtc_disable(struct drm_crtc *crtc)
> +{
> +       unsigned int reg;
> +       struct hibmc_drm_private *priv = crtc->dev->dev_private;
> +
> +       drm_crtc_vblank_off(crtc);
> +
> +       hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_SLEEP);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(0);
> +       reg |= HIBMC_CURR_GATE_DISPLAY(0);
> +       hibmc_set_current_gate(priv, reg);
> +}
> +
> +static unsigned int format_pll_reg(void)
> +{
> +       unsigned int pllreg = 0;
> +       struct hibmc_display_panel_pll pll = {0};
> +
> +       /*
> +        * Note that all PLL's have the same format. Here,
> +        * we just use Panel PLL parameter to work out the bit
> +        * fields in the register.On returning a 32 bit number, the value can
> +        * be applied to any PLL in the calling function.
> +        */
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_BYPASS, 0);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_POWER, 1);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_INPUT, 0);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_POD, pll.POD);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_OD, pll.OD);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_N, pll.N);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_M, pll.M);
> +
> +       return pllreg;
> +}
> +
> +static void set_vclock_hisilicon(struct drm_device *dev, unsigned long pll)
> +{
> +       u32 val;
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +
> +       val = readl(priv->mmio + CRT_PLL1_HS);
> +       val &= ~(CRT_PLL1_HS_OUTER_BYPASS(1));
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +
> +       val = CRT_PLL1_HS_INTER_BYPASS(1) | CRT_PLL1_HS_POWERON(1);
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +
> +       writel(pll, priv->mmio + CRT_PLL1_HS);
> +
> +       usleep_range(1000, 2000);
> +
> +       val = pll & ~(CRT_PLL1_HS_POWERON(1));
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +
> +       usleep_range(1000, 2000);
> +
> +       val &= ~(CRT_PLL1_HS_INTER_BYPASS(1));
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +
> +       usleep_range(1000, 2000);
> +
> +       val |= CRT_PLL1_HS_OUTER_BYPASS(1);
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +}
> +
> +static void get_pll_config(unsigned long x, unsigned long y,
> +                          u32 *pll1, u32 *pll2)
> +{
> +       int i;
> +       int count = ARRAY_SIZE(hibmc_pll_table);
> +
> +       for (i = 0; i < count; i++) {
> +               if (hibmc_pll_table[i].hdisplay == x &&
> +                   hibmc_pll_table[i].vdisplay == y) {
> +                       *pll1 = hibmc_pll_table[i].pll1_config_value;
> +                       *pll2 = hibmc_pll_table[i].pll2_config_value;
> +                       return;
> +               }
> +       }
> +
> +       /* if found none, we use default value */
> +       *pll1 = CRT_PLL1_HS_25MHZ;
> +       *pll2 = CRT_PLL2_HS_25MHZ;
> +}
> +
> +/*
> + * This function takes care the extra registers and bit fields required to
> + * setup a mode in board.
> + * Explanation about Display Control register:
> + * FPGA only supports 7 predefined pixel clocks, and clock select is
> + * in bit 4:0 of new register 0x802a8.
> + */
> +static unsigned int display_ctrl_adjust(struct drm_device *dev,
> +                                       struct drm_display_mode *mode,
> +                                       unsigned int ctrl)
> +{
> +       unsigned long x, y;
> +       u32 pll1; /* bit[31:0] of PLL */
> +       u32 pll2; /* bit[63:32] of PLL */
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +
> +       x = mode->hdisplay;
> +       y = mode->vdisplay;
> +
> +       get_pll_config(x, y, &pll1, &pll2);
> +       writel(pll2, priv->mmio + CRT_PLL2_HS);
> +       set_vclock_hisilicon(dev, pll1);
> +
> +       /*
> +        * Hisilicon has to set up the top-left and bottom-right
> +        * registers as well.
> +        * Note that normal chip only use those two register for
> +        * auto-centering mode.
> +        */
> +       writel(HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_TL_TOP, 0) |
> +              HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_TL_LEFT, 0),
> +              priv->mmio + HIBMC_CRT_AUTO_CENTERING_TL);
> +
> +       writel(HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM, y - 1) |
> +              HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_BR_RIGHT, x - 1),
> +              priv->mmio + HIBMC_CRT_AUTO_CENTERING_BR);
> +
> +       /*
> +        * Assume common fields in ctrl have been properly set before
> +        * calling this function.
> +        * This function only sets the extra fields in ctrl.
> +        */
> +
> +       /* Set bit 25 of display controller: Select CRT or VGA clock */
> +       ctrl &= ~HIBMC_CRT_DISP_CTL_CRTSELECT_MASK;
> +       ctrl &= ~HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK;
> +
> +       ctrl |= HIBMC_CRT_DISP_CTL_CRTSELECT(HIBMC_CRTSELECT_CRT);
> +
> +       /* clock_phase_polarity is 0 */
> +       ctrl |= HIBMC_CRT_DISP_CTL_CLOCK_PHASE(0);
> +
> +       writel(ctrl, priv->mmio + HIBMC_CRT_DISP_CTL);
> +
> +       return ctrl;
> +}
> +
> +static void hibmc_crtc_mode_set_nofb(struct drm_crtc *crtc)
> +{
> +       unsigned int val;
> +       struct drm_display_mode *mode = &crtc->state->mode;
> +       struct drm_device *dev = crtc->dev;
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +       int width = mode->hsync_end - mode->hsync_start;
> +       int height = mode->vsync_end - mode->vsync_start;
> +
> +       writel(format_pll_reg(), priv->mmio + HIBMC_CRT_PLL_CTRL);
> +       writel(HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_TOTAL, mode->htotal - 1) |
> +              HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_DISP_END, mode->hdisplay - 1),
> +              priv->mmio + HIBMC_CRT_HORZ_TOTAL);
> +
> +       writel(HIBMC_FIELD(HIBMC_CRT_HORZ_SYNC_WIDTH, width) |
> +              HIBMC_FIELD(HIBMC_CRT_HORZ_SYNC_START, mode->hsync_start - 1),
> +              priv->mmio + HIBMC_CRT_HORZ_SYNC);
> +
> +       writel(HIBMC_FIELD(HIBMC_CRT_VERT_TOTAL_TOTAL, mode->vtotal - 1) |
> +              HIBMC_FIELD(HIBMC_CRT_VERT_TOTAL_DISP_END, mode->vdisplay - 1),
> +              priv->mmio + HIBMC_CRT_VERT_TOTAL);
> +
> +       writel(HIBMC_FIELD(HIBMC_CRT_VERT_SYNC_HEIGHT, height) |
> +              HIBMC_FIELD(HIBMC_CRT_VERT_SYNC_START, mode->vsync_start - 1),
> +              priv->mmio + HIBMC_CRT_VERT_SYNC);
> +
> +       val = HIBMC_FIELD(HIBMC_CRT_DISP_CTL_VSYNC_PHASE, 0);
> +       val |= HIBMC_FIELD(HIBMC_CRT_DISP_CTL_HSYNC_PHASE, 0);
> +       val |= HIBMC_CRT_DISP_CTL_TIMING(1);
> +       val |= HIBMC_CRT_DISP_CTL_PLANE(1);
> +
> +       display_ctrl_adjust(dev, mode, val);
> +}
> +
> +static void hibmc_crtc_atomic_begin(struct drm_crtc *crtc,
> +                                   struct drm_crtc_state *old_state)
> +{
> +       unsigned int reg;
> +       struct drm_device *dev = crtc->dev;
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +
> +       hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg |= HIBMC_CURR_GATE_DISPLAY(1);
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(1);
> +       hibmc_set_current_gate(priv, reg);
> +
> +       /* We can add more initialization as needed. */
> +}
> +
> +static void hibmc_crtc_atomic_flush(struct drm_crtc *crtc,
> +                                   struct drm_crtc_state *old_state)
> +
> +{
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&crtc->dev->event_lock, flags);
> +       if (crtc->state->event)
> +               drm_crtc_send_vblank_event(crtc, crtc->state->event);
> +       crtc->state->event = NULL;
> +       spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
> +}
> +
> +static const struct drm_crtc_funcs hibmc_crtc_funcs = {
> +       .page_flip = drm_atomic_helper_page_flip,
> +       .set_config = drm_atomic_helper_set_config,
> +       .destroy = drm_crtc_cleanup,
> +       .reset = drm_atomic_helper_crtc_reset,
> +       .atomic_duplicate_state =  drm_atomic_helper_crtc_duplicate_state,
> +       .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
> +};
> +
> +static const struct drm_crtc_helper_funcs hibmc_crtc_helper_funcs = {
> +       .enable         = hibmc_crtc_enable,
> +       .disable        = hibmc_crtc_disable,
> +       .mode_set_nofb  = hibmc_crtc_mode_set_nofb,
> +       .atomic_begin   = hibmc_crtc_atomic_begin,
> +       .atomic_flush   = hibmc_crtc_atomic_flush,
> +};
> +
> +int hibmc_de_init(struct hibmc_drm_private *priv)
> +{
> +       struct drm_device *dev = priv->dev;
> +       struct drm_crtc *crtc;
> +       struct drm_plane *plane;
> +       int ret;
> +
> +       plane = hibmc_plane_init(priv);
> +       if (IS_ERR(plane)) {
> +               DRM_ERROR("failed to create plane: %ld\n", PTR_ERR(plane));
> +               return PTR_ERR(plane);
> +       }
> +
> +       crtc = devm_kzalloc(dev->dev, sizeof(*crtc), GFP_KERNEL);
> +       if (!crtc) {
> +               DRM_ERROR("failed to alloc memory when init crtc\n");
> +               return -ENOMEM;
> +       }
> +
> +       ret = drm_crtc_init_with_planes(dev, crtc, plane,
> +                                       NULL, &hibmc_crtc_funcs, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to init crtc: %d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = drm_mode_crtc_set_gamma_size(crtc, 256);
> +       if (ret) {
> +               DRM_ERROR("failed to set gamma size: %d\n", ret);
> +               return ret;
> +       }
> +       drm_crtc_helper_add(crtc, &hibmc_crtc_helper_funcs);
> +
> +       return 0;
> +}
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index 4b52b29..9de3564 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -19,6 +19,9 @@
>  #include <linux/console.h>
>  #include <linux/module.h>
>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +
>  #include "hibmc_drm_drv.h"
>  #include "hibmc_drm_regs.h"
>
> @@ -44,7 +47,8 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>  }
>
>  static struct drm_driver hibmc_driver = {
> -       .driver_features        = DRIVER_GEM,
> +       .driver_features        = DRIVER_GEM | DRIVER_MODESET |
> +                                 DRIVER_ATOMIC,
>         .fops                   = &hibmc_fops,
>         .name                   = "hibmc",
>         .date                   = "20160828",
> @@ -62,11 +66,31 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>
>  static int hibmc_pm_suspend(struct device *dev)
>  {
> +       struct pci_dev *pdev = to_pci_dev(dev);
> +       struct drm_device *drm_dev = pci_get_drvdata(pdev);
> +       struct hibmc_drm_private *priv = drm_dev->dev_private;
> +
> +       drm_kms_helper_poll_disable(drm_dev);
> +       priv->suspend_state = drm_atomic_helper_suspend(drm_dev);
> +       if (IS_ERR(priv->suspend_state)) {
> +               DRM_ERROR("drm_atomic_helper_suspend failed: %ld\n",
> +                         PTR_ERR(priv->suspend_state));
> +               drm_kms_helper_poll_enable(drm_dev);
> +               return PTR_ERR(priv->suspend_state);
> +       }
> +
>         return 0;
>  }
>
>  static int hibmc_pm_resume(struct device *dev)
>  {
> +       struct pci_dev *pdev = to_pci_dev(dev);
> +       struct drm_device *drm_dev = pci_get_drvdata(pdev);
> +       struct hibmc_drm_private *priv = drm_dev->dev_private;
> +
> +       drm_atomic_helper_resume(drm_dev, priv->suspend_state);
> +       drm_kms_helper_poll_enable(drm_dev);
> +
>         return 0;
>  }
>
> @@ -75,6 +99,41 @@ static int hibmc_pm_resume(struct device *dev)
>                                 hibmc_pm_resume)
>  };
>
> +static int hibmc_kms_init(struct hibmc_drm_private *priv)
> +{
> +       int ret;
> +
> +       drm_mode_config_init(priv->dev);
> +       priv->mode_config_initialized = true;
> +
> +       priv->dev->mode_config.min_width = 0;
> +       priv->dev->mode_config.min_height = 0;
> +       priv->dev->mode_config.max_width = 1920;
> +       priv->dev->mode_config.max_height = 1440;
> +
> +       priv->dev->mode_config.fb_base = priv->fb_base;
> +       priv->dev->mode_config.preferred_depth = 24;
> +       priv->dev->mode_config.prefer_shadow = 0;
> +
> +       priv->dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
> +
> +       ret = hibmc_de_init(priv);
> +       if (ret) {
> +               DRM_ERROR("failed to init de: %d\n", ret);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static void hibmc_kms_fini(struct hibmc_drm_private *priv)
> +{
> +       if (priv->mode_config_initialized) {
> +               drm_mode_config_cleanup(priv->dev);
> +               priv->mode_config_initialized = false;
> +       }
> +}
> +
>  /*
>   * It can operate in one of three modes: 0, 1 or Sleep.
>   */
> @@ -203,6 +262,7 @@ static int hibmc_unload(struct drm_device *dev)
>         struct hibmc_drm_private *priv = dev->dev_private;
>
>         hibmc_fbdev_fini(priv);
> +       hibmc_kms_fini(priv);
>         hibmc_mm_fini(priv);
>         dev->dev_private = NULL;
>         return 0;
> @@ -229,6 +289,13 @@ static int hibmc_load(struct drm_device *dev)
>         if (ret)
>                 goto err;
>
> +       ret = hibmc_kms_init(priv);
> +       if (ret)
> +               goto err;
> +
> +       /* reset all the states of crtc/plane/encoder/connector */
> +       drm_mode_config_reset(dev);
> +
>         ret = hibmc_fbdev_init(priv);
>         if (ret) {
>                 DRM_ERROR("failed to initialize fbdev: %d\n", ret);
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index d283d66..87af1eb 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -20,6 +20,7 @@
>  #define HIBMC_DRM_DRV_H
>
>  #include <drm/drmP.h>
> +#include <drm/drm_atomic.h>
>  #include <drm/drm_fb_helper.h>
>  #include <drm/drm_gem.h>
>  #include <drm/ttm/ttm_bo_driver.h>
> @@ -44,6 +45,8 @@ struct hibmc_drm_private {
>
>         /* drm */
>         struct drm_device  *dev;
> +       bool mode_config_initialized;
> +       struct drm_atomic_state *suspend_state;
>
>         /* ttm */
>         struct drm_global_reference mem_global_ref;
> @@ -82,6 +85,7 @@ void hibmc_set_power_mode(struct hibmc_drm_private *priv,
>  void hibmc_set_current_gate(struct hibmc_drm_private *priv,
>                             unsigned int gate);
>
> +int hibmc_de_init(struct hibmc_drm_private *priv);
>  int hibmc_fbdev_init(struct hibmc_drm_private *priv);
>  void hibmc_fbdev_fini(struct hibmc_drm_private *priv);
>
> @@ -103,4 +107,6 @@ int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
>                            u32 handle, u64 *offset);
>  int hibmc_mmap(struct file *filp, struct vm_area_struct *vma);
>
> +extern const struct drm_mode_config_funcs hibmc_mode_funcs;
> +
>  #endif
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> index 3ff65f4..e76abf6 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> @@ -550,3 +550,9 @@ struct hibmc_framebuffer *
>         }
>         return &hibmc_fb->fb;
>  }
> +
> +const struct drm_mode_config_funcs hibmc_mode_funcs = {
> +       .atomic_check = drm_atomic_helper_check,
> +       .atomic_commit = drm_atomic_helper_commit,
> +       .fb_create = hibmc_user_framebuffer_create,
> +};
> --
> 1.9.1
>

^ permalink raw reply

* [PATCH 2/2] ahci: qoriq: report warning when ecc register is missing
From: Mathieu Poirier @ 2016-11-16 15:56 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1479265879-48840-2-git-send-email-yuantian.tang@nxp.com>

On Wed, Nov 16, 2016 at 11:11:19AM +0800, yuantian.tang at nxp.com wrote:
> From: Tang Yuantian <Yuantian.Tang@nxp.com>
> 
> For ls1021a and ls1046a socs, sata ecc must be disabled.
> If ecc register is not found in sata node in dts, report
> a warning.

Hi Yuantian,

What happens if sata ecc is _not_ disaled on those socs?  Can the driver still
work?  If not then it is probably a better idea to return an error code that can
prevent the driver from initialising.

Thanks,
Mathieu

> 
> Signed-off-by: Tang Yuantian <yuantian.tang@nxp.com>
> ---
>  drivers/ata/ahci_qoriq.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c
> index 45c88de..66eb4b5 100644
> --- a/drivers/ata/ahci_qoriq.c
> +++ b/drivers/ata/ahci_qoriq.c
> @@ -158,6 +158,7 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
>  
>  	switch (qpriv->type) {
>  	case AHCI_LS1021A:
> +		WARN_ON(!qpriv->ecc_addr);
>  		writel(SATA_ECC_DISABLE, qpriv->ecc_addr);
>  		writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
>  		writel(LS1021A_PORT_PHY2, reg_base + PORT_PHY2);
> @@ -185,6 +186,7 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
>  		break;
>  
>  	case AHCI_LS1046A:
> +		WARN_ON(!qpriv->ecc_addr);
>  		writel(LS1046A_SATA_ECC_DIS, qpriv->ecc_addr);
>  		writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
>  		writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
> -- 
> 2.1.0.27.g96db324
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ 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