Message ID | 2afd45902d7e1e849d0aa7a0c4268c424cabe778.1554988934.git-series.maxime.ripard@bootlin.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | drm/vc4: Allow for more boot-time configuration | expand |
On Thu, Apr 11, 2019 at 03:22:41PM +0200, Maxime Ripard wrote: > Rotations and reflections setup are needed in some scenarios to initialise > properly the initial framebuffer. Some drivers already had a bunch of > quirks to deal with this, such as either a private kernel command line > parameter (omapdss) or on the device tree (various panels). > > In order to accomodate this, let's create a video mode parameter to deal > with the rotation and reflexion. > > Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> > --- > drivers/gpu/drm/drm_fb_helper.c | 4 +- > drivers/gpu/drm/drm_modes.c | 110 +++++++++++++++++++++++++++------ > include/drm/drm_connector.h | 1 +- > 3 files changed, 95 insertions(+), 20 deletions(-) > > diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c > index b3a5d79436ae..8781897559b2 100644 > --- a/drivers/gpu/drm/drm_fb_helper.c > +++ b/drivers/gpu/drm/drm_fb_helper.c > @@ -2521,6 +2521,7 @@ static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper, > struct drm_connector *connector) > { > struct drm_plane *plane = fb_crtc->mode_set.crtc->primary; > + struct drm_cmdline_mode *mode = &connector->cmdline_mode; > uint64_t valid_mask = 0; > int i, rotation; > > @@ -2540,6 +2541,9 @@ static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper, > rotation = DRM_MODE_ROTATE_0; > } > > + if (mode->rotation != DRM_MODE_ROTATE_0) > + fb_crtc->rotation = mode->rotation; Hm, kinda awkward that we have to tie all this to the fbdev helpers. But that's already the case with the old stuff, so mea culpa I guess. > + > /* > * TODO: support 90 / 270 degree hardware rotation, > * depending on the hardware this may require the framebuffer > diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c > index 9613c1a28487..ac8d70b92b62 100644 > --- a/drivers/gpu/drm/drm_modes.c > +++ b/drivers/gpu/drm/drm_modes.c > @@ -1531,6 +1531,71 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length, > return 0; > } > > +static int drm_mode_parse_cmdline_options(char *str, size_t len, > + struct drm_connector *connector, > + struct drm_cmdline_mode *mode) > +{ > + unsigned int rotation = 0; > + char *sep = str; > + > + while ((sep = strchr(sep, ','))) { > + char *delim, *option; > + > + option = sep + 1; > + delim = strchr(option, '='); > + if (!delim) { > + delim = strchr(option, ','); > + > + if (!delim) > + delim = str + len; > + } > + > + if (!strncmp(option, "rotate", delim - option)) { > + const char *value = delim + 1; > + unsigned int deg; > + > + deg = simple_strtol(value, &sep, 10); > + > + /* Make sure we have parsed something */ > + if (sep == value) > + return -EINVAL; > + > + switch (deg) { > + case 0: > + rotation |= DRM_MODE_ROTATE_0; > + break; > + > + case 90: > + rotation |= DRM_MODE_ROTATE_90; > + break; > + > + case 180: > + rotation |= DRM_MODE_ROTATE_180; > + break; > + > + case 270: > + rotation |= DRM_MODE_ROTATE_270; > + break; > + > + default: > + return -EINVAL; > + } > + } else if (!strncmp(option, "reflect_x", delim - option)) { > + rotation |= DRM_MODE_REFLECT_X; > + sep = delim; > + } else if (!strncmp(option, "reflect_y", delim - option)) { > + rotation |= DRM_MODE_REFLECT_Y; > + sep = delim; > + } else { > + return -EINVAL; > + } > + } > + > + mode->rotation = rotation; > + > + return 0; > +} > + > /** > * drm_mode_parse_command_line_for_connector - parse command line modeline for connector > * @mode_option: optional per connector mode option > @@ -1558,9 +1623,10 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, > { > const char *name; > bool named_mode = false, parse_extras = false; > - unsigned int bpp_off = 0, refresh_off = 0; > + unsigned int bpp_off = 0, refresh_off = 0, options_off = 0; > unsigned int mode_end = 0; > char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL; > + char *options_ptr = NULL; > char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL; > int ret; > > @@ -1601,13 +1667,18 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, > mode->refresh_specified = true; > } > > + /* Locate the start of named options */ > + options_ptr = strchr(name, ','); > + if (options_ptr) > + options_off = options_ptr - name; > + > /* 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) { > + if (bpp_ptr) { > mode_end = bpp_off; > } else if (refresh_ptr) { > mode_end = refresh_off; > + } else if (options_ptr) { > + mode_end = options_off; > } else { > mode_end = strlen(name); > parse_extras = true; > @@ -1649,24 +1720,23 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, > else if (refresh_ptr) > extra_ptr = refresh_end_ptr; > > - if (extra_ptr) { > - if (!named_mode) { > - int len = strlen(name) - (extra_ptr - name); > + if (extra_ptr && > + extra_ptr != options_ptr) { > + int len = strlen(name) - (extra_ptr - name); > > - ret = drm_mode_parse_cmdline_extra(extra_ptr, len, > - connector, mode); > - if (ret) > - return false; > - } else { > - int remaining = strlen(name) - (extra_ptr - name); > + ret = drm_mode_parse_cmdline_extra(extra_ptr, len, > + connector, mode); > + if (ret) > + return false; > + } > > - /* > - * We still have characters to process, while > - * we shouldn't have any > - */ > - if (remaining > 0) > - return false; > - } > + if (options_ptr) { > + int len = strlen(name) - (options_ptr - name); > + > + ret = drm_mode_parse_cmdline_options(options_ptr, len, > + connector, mode); > + if (ret) > + return false; > } > > return true; > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h > index 06aa3b9cb920..dfe7f2304b35 100644 > --- a/include/drm/drm_connector.h > +++ b/include/drm/drm_connector.h > @@ -907,6 +907,7 @@ struct drm_cmdline_mode { > bool interlace; > bool cvt; > bool margins; > + unsigned int rotation; > enum drm_connector_force force; Kerneldoc for this would be neat. -Daniel > }; > > -- > git-series 0.9.1 > _______________________________________________ > dri-devel mailing list > dri-devel@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/dri-devel
Den 11.04.2019 15.22, skrev Maxime Ripard: > Rotations and reflections setup are needed in some scenarios to initialise > properly the initial framebuffer. Some drivers already had a bunch of > quirks to deal with this, such as either a private kernel command line > parameter (omapdss) or on the device tree (various panels). > > In order to accomodate this, let's create a video mode parameter to deal > with the rotation and reflexion. > > Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> > --- > drivers/gpu/drm/drm_fb_helper.c | 4 +- > drivers/gpu/drm/drm_modes.c | 110 +++++++++++++++++++++++++++------ > include/drm/drm_connector.h | 1 +- > 3 files changed, 95 insertions(+), 20 deletions(-) > > diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c > index b3a5d79436ae..8781897559b2 100644 > --- a/drivers/gpu/drm/drm_fb_helper.c > +++ b/drivers/gpu/drm/drm_fb_helper.c > @@ -2521,6 +2521,7 @@ static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper, > struct drm_connector *connector) > { > struct drm_plane *plane = fb_crtc->mode_set.crtc->primary; > + struct drm_cmdline_mode *mode = &connector->cmdline_mode; > uint64_t valid_mask = 0; > int i, rotation; > > @@ -2540,6 +2541,9 @@ static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper, > rotation = DRM_MODE_ROTATE_0; > } > > + if (mode->rotation != DRM_MODE_ROTATE_0) > + fb_crtc->rotation = mode->rotation; > + We already have a property to describe initial display/panel rotation. If we can set connector->display_info.panel_orientation from the video= parameter, then there's no need to modify drm_fb_helper, it will just work. In that case, maybe 'orientation' is a better argument name with values mapped to the enum. And further, should we add the property (drm_connector_init_panel_orientation_property()) so DRM userspace can know about it to? Some pointers: - 8d70f395e6cb ("drm: Add support for a panel-orientation connector property") - 8f0cb418393b ("drm/fb-helper: Apply panel orientation connector prop to the primary plane") - drivers/gpu/drm/drm_panel_orientation_quirks.c Noralf. > /* > * TODO: support 90 / 270 degree hardware rotation, > * depending on the hardware this may require the framebuffer > diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c > index 9613c1a28487..ac8d70b92b62 100644 > --- a/drivers/gpu/drm/drm_modes.c > +++ b/drivers/gpu/drm/drm_modes.c > @@ -1531,6 +1531,71 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length, > return 0; > } > > +static int drm_mode_parse_cmdline_options(char *str, size_t len, > + struct drm_connector *connector, > + struct drm_cmdline_mode *mode) > +{ > + unsigned int rotation = 0; > + char *sep = str; > + > + while ((sep = strchr(sep, ','))) { > + char *delim, *option; > + > + option = sep + 1; > + delim = strchr(option, '='); > + if (!delim) { > + delim = strchr(option, ','); > + > + if (!delim) > + delim = str + len; > + } > + > + if (!strncmp(option, "rotate", delim - option)) { > + const char *value = delim + 1; > + unsigned int deg; > + > + deg = simple_strtol(value, &sep, 10); > + > + /* Make sure we have parsed something */ > + if (sep == value) > + return -EINVAL; > + > + switch (deg) { > + case 0: > + rotation |= DRM_MODE_ROTATE_0; > + break; > + > + case 90: > + rotation |= DRM_MODE_ROTATE_90; > + break; > + > + case 180: > + rotation |= DRM_MODE_ROTATE_180; > + break; > + > + case 270: > + rotation |= DRM_MODE_ROTATE_270; > + break; > + > + default: > + return -EINVAL; > + } > + } else if (!strncmp(option, "reflect_x", delim - option)) { > + rotation |= DRM_MODE_REFLECT_X; > + sep = delim; > + } else if (!strncmp(option, "reflect_y", delim - option)) { > + rotation |= DRM_MODE_REFLECT_Y; > + sep = delim; > + } else { > + return -EINVAL; > + } > + } > + > + mode->rotation = rotation; > + > + return 0; > +} > + > /** > * drm_mode_parse_command_line_for_connector - parse command line modeline for connector > * @mode_option: optional per connector mode option > @@ -1558,9 +1623,10 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, > { > const char *name; > bool named_mode = false, parse_extras = false; > - unsigned int bpp_off = 0, refresh_off = 0; > + unsigned int bpp_off = 0, refresh_off = 0, options_off = 0; > unsigned int mode_end = 0; > char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL; > + char *options_ptr = NULL; > char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL; > int ret; > > @@ -1601,13 +1667,18 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, > mode->refresh_specified = true; > } > > + /* Locate the start of named options */ > + options_ptr = strchr(name, ','); > + if (options_ptr) > + options_off = options_ptr - name; > + > /* 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) { > + if (bpp_ptr) { > mode_end = bpp_off; > } else if (refresh_ptr) { > mode_end = refresh_off; > + } else if (options_ptr) { > + mode_end = options_off; > } else { > mode_end = strlen(name); > parse_extras = true; > @@ -1649,24 +1720,23 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, > else if (refresh_ptr) > extra_ptr = refresh_end_ptr; > > - if (extra_ptr) { > - if (!named_mode) { > - int len = strlen(name) - (extra_ptr - name); > + if (extra_ptr && > + extra_ptr != options_ptr) { > + int len = strlen(name) - (extra_ptr - name); > > - ret = drm_mode_parse_cmdline_extra(extra_ptr, len, > - connector, mode); > - if (ret) > - return false; > - } else { > - int remaining = strlen(name) - (extra_ptr - name); > + ret = drm_mode_parse_cmdline_extra(extra_ptr, len, > + connector, mode); > + if (ret) > + return false; > + } > > - /* > - * We still have characters to process, while > - * we shouldn't have any > - */ > - if (remaining > 0) > - return false; > - } > + if (options_ptr) { > + int len = strlen(name) - (options_ptr - name); > + > + ret = drm_mode_parse_cmdline_options(options_ptr, len, > + connector, mode); > + if (ret) > + return false; > } > > return true; > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h > index 06aa3b9cb920..dfe7f2304b35 100644 > --- a/include/drm/drm_connector.h > +++ b/include/drm/drm_connector.h > @@ -907,6 +907,7 @@ struct drm_cmdline_mode { > bool interlace; > bool cvt; > bool margins; > + unsigned int rotation; > enum drm_connector_force force; > }; > >
Hi Noralf, On Tue, Apr 16, 2019 at 04:50:00PM +0200, Noralf Trønnes wrote: > Den 11.04.2019 15.22, skrev Maxime Ripard: > > Rotations and reflections setup are needed in some scenarios to initialise > > properly the initial framebuffer. Some drivers already had a bunch of > > quirks to deal with this, such as either a private kernel command line > > parameter (omapdss) or on the device tree (various panels). > > > > In order to accomodate this, let's create a video mode parameter to deal > > with the rotation and reflexion. > > > > Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> > > --- > > drivers/gpu/drm/drm_fb_helper.c | 4 +- > > drivers/gpu/drm/drm_modes.c | 110 +++++++++++++++++++++++++++------ > > include/drm/drm_connector.h | 1 +- > > 3 files changed, 95 insertions(+), 20 deletions(-) > > > > diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c > > index b3a5d79436ae..8781897559b2 100644 > > --- a/drivers/gpu/drm/drm_fb_helper.c > > +++ b/drivers/gpu/drm/drm_fb_helper.c > > @@ -2521,6 +2521,7 @@ static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper, > > struct drm_connector *connector) > > { > > struct drm_plane *plane = fb_crtc->mode_set.crtc->primary; > > + struct drm_cmdline_mode *mode = &connector->cmdline_mode; > > uint64_t valid_mask = 0; > > int i, rotation; > > > > @@ -2540,6 +2541,9 @@ static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper, > > rotation = DRM_MODE_ROTATE_0; > > } > > > > + if (mode->rotation != DRM_MODE_ROTATE_0) > > + fb_crtc->rotation = mode->rotation; > > + > > We already have a property to describe initial display/panel rotation. > If we can set connector->display_info.panel_orientation from the video= > parameter, then there's no need to modify drm_fb_helper, it will just work. > > In that case, maybe 'orientation' is a better argument name with values > mapped to the enum. I wouldn't put it at the same level though. As far as I understand it, the orientation is a hardware constraint: the hardware has been designed that way, and should honor that orientation to make it look with the top, well, on top. However, the rotation is more of a user choice, and you could definitely envision having a combination of a rotation and an orientation constraint. Maxime -- Maxime Ripard, Bootlin Embedded Linux and Kernel engineering https://bootlin.com
Den 17.04.2019 16.30, skrev Maxime Ripard: > Hi Noralf, > > On Tue, Apr 16, 2019 at 04:50:00PM +0200, Noralf Trønnes wrote: >> Den 11.04.2019 15.22, skrev Maxime Ripard: >>> Rotations and reflections setup are needed in some scenarios to initialise >>> properly the initial framebuffer. Some drivers already had a bunch of >>> quirks to deal with this, such as either a private kernel command line >>> parameter (omapdss) or on the device tree (various panels). >>> >>> In order to accomodate this, let's create a video mode parameter to deal >>> with the rotation and reflexion. >>> >>> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> >>> --- >>> drivers/gpu/drm/drm_fb_helper.c | 4 +- >>> drivers/gpu/drm/drm_modes.c | 110 +++++++++++++++++++++++++++------ >>> include/drm/drm_connector.h | 1 +- >>> 3 files changed, 95 insertions(+), 20 deletions(-) >>> >>> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c >>> index b3a5d79436ae..8781897559b2 100644 >>> --- a/drivers/gpu/drm/drm_fb_helper.c >>> +++ b/drivers/gpu/drm/drm_fb_helper.c >>> @@ -2521,6 +2521,7 @@ static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper, >>> struct drm_connector *connector) >>> { >>> struct drm_plane *plane = fb_crtc->mode_set.crtc->primary; >>> + struct drm_cmdline_mode *mode = &connector->cmdline_mode; >>> uint64_t valid_mask = 0; >>> int i, rotation; >>> >>> @@ -2540,6 +2541,9 @@ static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper, >>> rotation = DRM_MODE_ROTATE_0; >>> } >>> >>> + if (mode->rotation != DRM_MODE_ROTATE_0) >>> + fb_crtc->rotation = mode->rotation; >>> + >> >> We already have a property to describe initial display/panel rotation. >> If we can set connector->display_info.panel_orientation from the video= >> parameter, then there's no need to modify drm_fb_helper, it will just work. >> >> In that case, maybe 'orientation' is a better argument name with values >> mapped to the enum. > > I wouldn't put it at the same level though. As far as I understand it, > the orientation is a hardware constraint: the hardware has been > designed that way, and should honor that orientation to make it look > with the top, well, on top. > > However, the rotation is more of a user choice, and you could > definitely envision having a combination of a rotation and an > orientation constraint. > Does this rotation only apply to the fbdev emulation and should not propogate to DRM userspace? I actually don't understand how the DRM plane rotation works for 90/270 rotation. Should the framebuffer width/height be swapped when attaching to a rotated plane? Btw drm_setup_crtc_rotation() doesn't support 90/270 plane rotation even if the hw supports it. It will instead sw rotate fbcon, but fbdev userspace remains unrotated. Noralf. > Maxime > > -- > Maxime Ripard, Bootlin > Embedded Linux and Kernel engineering > https://bootlin.com >
On Wed, Apr 17, 2019 at 04:58:07PM +0200, Noralf Trønnes wrote: > Den 17.04.2019 16.30, skrev Maxime Ripard: > > On Tue, Apr 16, 2019 at 04:50:00PM +0200, Noralf Trønnes wrote: > >> Den 11.04.2019 15.22, skrev Maxime Ripard: > >>> Rotations and reflections setup are needed in some scenarios to initialise > >>> properly the initial framebuffer. Some drivers already had a bunch of > >>> quirks to deal with this, such as either a private kernel command line > >>> parameter (omapdss) or on the device tree (various panels). > >>> > >>> In order to accomodate this, let's create a video mode parameter to deal > >>> with the rotation and reflexion. > >>> > >>> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> > >>> --- > >>> drivers/gpu/drm/drm_fb_helper.c | 4 +- > >>> drivers/gpu/drm/drm_modes.c | 110 +++++++++++++++++++++++++++------ > >>> include/drm/drm_connector.h | 1 +- > >>> 3 files changed, 95 insertions(+), 20 deletions(-) > >>> > >>> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c > >>> index b3a5d79436ae..8781897559b2 100644 > >>> --- a/drivers/gpu/drm/drm_fb_helper.c > >>> +++ b/drivers/gpu/drm/drm_fb_helper.c > >>> @@ -2521,6 +2521,7 @@ static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper, > >>> struct drm_connector *connector) > >>> { > >>> struct drm_plane *plane = fb_crtc->mode_set.crtc->primary; > >>> + struct drm_cmdline_mode *mode = &connector->cmdline_mode; > >>> uint64_t valid_mask = 0; > >>> int i, rotation; > >>> > >>> @@ -2540,6 +2541,9 @@ static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper, > >>> rotation = DRM_MODE_ROTATE_0; > >>> } > >>> > >>> + if (mode->rotation != DRM_MODE_ROTATE_0) > >>> + fb_crtc->rotation = mode->rotation; > >>> + > >> > >> We already have a property to describe initial display/panel rotation. > >> If we can set connector->display_info.panel_orientation from the video= > >> parameter, then there's no need to modify drm_fb_helper, it will just work. > >> > >> In that case, maybe 'orientation' is a better argument name with values > >> mapped to the enum. > > > > I wouldn't put it at the same level though. As far as I understand it, > > the orientation is a hardware constraint: the hardware has been > > designed that way, and should honor that orientation to make it look > > with the top, well, on top. > > > > However, the rotation is more of a user choice, and you could > > definitely envision having a combination of a rotation and an > > orientation constraint. > > > > Does this rotation only apply to the fbdev emulation and should not > propogate to DRM userspace? I guess it definitely should be propagated to the DRM userspace. > I actually don't understand how the DRM plane rotation works for 90/270 > rotation. Should the framebuffer width/height be swapped when attaching > to a rotated plane? I'm not sure either, especially since the stride might be a bit different too. However, since (as you pointed out) it would be much harder to support, I left it out of that patch series for the moment. > Btw drm_setup_crtc_rotation() doesn't support 90/270 plane rotation even > if the hw supports it. It will instead sw rotate fbcon, but fbdev > userspace remains unrotated. That would need to be addressed eventually yep. Maxime -- Maxime Ripard, Bootlin Embedded Linux and Kernel engineering https://bootlin.com
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index b3a5d79436ae..8781897559b2 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -2521,6 +2521,7 @@ static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper, struct drm_connector *connector) { struct drm_plane *plane = fb_crtc->mode_set.crtc->primary; + struct drm_cmdline_mode *mode = &connector->cmdline_mode; uint64_t valid_mask = 0; int i, rotation; @@ -2540,6 +2541,9 @@ static void drm_setup_crtc_rotation(struct drm_fb_helper *fb_helper, rotation = DRM_MODE_ROTATE_0; } + if (mode->rotation != DRM_MODE_ROTATE_0) + fb_crtc->rotation = mode->rotation; + /* * TODO: support 90 / 270 degree hardware rotation, * depending on the hardware this may require the framebuffer diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 9613c1a28487..ac8d70b92b62 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1531,6 +1531,71 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length, return 0; } +static int drm_mode_parse_cmdline_options(char *str, size_t len, + struct drm_connector *connector, + struct drm_cmdline_mode *mode) +{ + unsigned int rotation = 0; + char *sep = str; + + while ((sep = strchr(sep, ','))) { + char *delim, *option; + + option = sep + 1; + delim = strchr(option, '='); + if (!delim) { + delim = strchr(option, ','); + + if (!delim) + delim = str + len; + } + + if (!strncmp(option, "rotate", delim - option)) { + const char *value = delim + 1; + unsigned int deg; + + deg = simple_strtol(value, &sep, 10); + + /* Make sure we have parsed something */ + if (sep == value) + return -EINVAL; + + switch (deg) { + case 0: + rotation |= DRM_MODE_ROTATE_0; + break; + + case 90: + rotation |= DRM_MODE_ROTATE_90; + break; + + case 180: + rotation |= DRM_MODE_ROTATE_180; + break; + + case 270: + rotation |= DRM_MODE_ROTATE_270; + break; + + default: + return -EINVAL; + } + } else if (!strncmp(option, "reflect_x", delim - option)) { + rotation |= DRM_MODE_REFLECT_X; + sep = delim; + } else if (!strncmp(option, "reflect_y", delim - option)) { + rotation |= DRM_MODE_REFLECT_Y; + sep = delim; + } else { + return -EINVAL; + } + } + + mode->rotation = rotation; + + return 0; +} + /** * drm_mode_parse_command_line_for_connector - parse command line modeline for connector * @mode_option: optional per connector mode option @@ -1558,9 +1623,10 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, { const char *name; bool named_mode = false, parse_extras = false; - unsigned int bpp_off = 0, refresh_off = 0; + unsigned int bpp_off = 0, refresh_off = 0, options_off = 0; unsigned int mode_end = 0; char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL; + char *options_ptr = NULL; char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL; int ret; @@ -1601,13 +1667,18 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, mode->refresh_specified = true; } + /* Locate the start of named options */ + options_ptr = strchr(name, ','); + if (options_ptr) + options_off = options_ptr - name; + /* 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) { + if (bpp_ptr) { mode_end = bpp_off; } else if (refresh_ptr) { mode_end = refresh_off; + } else if (options_ptr) { + mode_end = options_off; } else { mode_end = strlen(name); parse_extras = true; @@ -1649,24 +1720,23 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, else if (refresh_ptr) extra_ptr = refresh_end_ptr; - if (extra_ptr) { - if (!named_mode) { - int len = strlen(name) - (extra_ptr - name); + if (extra_ptr && + extra_ptr != options_ptr) { + int len = strlen(name) - (extra_ptr - name); - ret = drm_mode_parse_cmdline_extra(extra_ptr, len, - connector, mode); - if (ret) - return false; - } else { - int remaining = strlen(name) - (extra_ptr - name); + ret = drm_mode_parse_cmdline_extra(extra_ptr, len, + connector, mode); + if (ret) + return false; + } - /* - * We still have characters to process, while - * we shouldn't have any - */ - if (remaining > 0) - return false; - } + if (options_ptr) { + int len = strlen(name) - (options_ptr - name); + + ret = drm_mode_parse_cmdline_options(options_ptr, len, + connector, mode); + if (ret) + return false; } return true; diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 06aa3b9cb920..dfe7f2304b35 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -907,6 +907,7 @@ struct drm_cmdline_mode { bool interlace; bool cvt; bool margins; + unsigned int rotation; enum drm_connector_force force; };
Rotations and reflections setup are needed in some scenarios to initialise properly the initial framebuffer. Some drivers already had a bunch of quirks to deal with this, such as either a private kernel command line parameter (omapdss) or on the device tree (various panels). In order to accomodate this, let's create a video mode parameter to deal with the rotation and reflexion. Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> --- drivers/gpu/drm/drm_fb_helper.c | 4 +- drivers/gpu/drm/drm_modes.c | 110 +++++++++++++++++++++++++++------ include/drm/drm_connector.h | 1 +- 3 files changed, 95 insertions(+), 20 deletions(-)