All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers
@ 2019-10-14 14:04 ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

(was: DRM driver for fbdev devices)

This is version 2 of the fbdev conversion helpers. It's more or less a
rewrite of the original patchset.

The fbdev subsystem is considered legacy and will probably be removed at
some point. This would mean the loss of a signifanct number of drivers.
Some of the affected hardware is not in use any longer, but some hardware
is still around and provides good(-enough) framebuffers.

The fbconv helpers allow for running the current DRM stack on top of fbdev
drivers. It's a set of functions that convert between fbdev interfaces and
DRM interfaces. Based on SHMEM and simple KMS helpers, it only offers the
basic functionality of a framebuffer, but should be compatible with most
existing fbdev drivers.

A DRM driver using fbconv helpers consists of

  * DRM stub code that calls into fbconv helpers, and
  * the original fbdev driver code.

The fbdev driver code has to be modified to register itself with the
stub driver instead of the fbdev core framework. A tutorial on how to use
the helpers is part of this patchset. The resulting driver hybrid can be
refactored into a first-class DRM driver. The fbconv helpers contain a
number of comments, labeled 'DRM porting note', which explain the required
steps.

I tested the current patchset with the following drivers: atyfb, aty128fb,
matroxfb, pm2fb, pm3fb, rivafb, s3fb, savagefb, sisfb, tdfxfb and tridentfb.
With each, I was able to successfully start with fbcon enabled, run weston and
X11. The drivers are available at [1]. For reference, the patchset includes
the Matrox stub driver.

v2:
	* rename to fbconv helpers
	* rewrite as helper library
	* switch over to simple KMS helpers
	* switch over to SHMEM
	* add documentation

[1] https://gitlab.freedesktop.org/tzimmermann/linux/commits/fbconv-plus-drivers

Thomas Zimmermann (15):
  fbdev: Export fb_check_foreignness()
  fbdev: Export FBPIXMAPSIZE
  drm/simple-kms-helper: Add mode_fixup() to simple display pipe
  drm: Add fbconv helper module
  drm/fbconv: Add DRM <-> fbdev pixel-format conversion
  drm/fbconv: Add mode conversion DRM <-> fbdev
  drm/fbconv: Add modesetting infrastructure
  drm/fbconv: Add plane-state check and update
  drm/fbconv: Mode-setting pipeline enable / disable
  drm/fbconv: Reimplement several fbdev interfaces
  drm/fbconv: Add helpers for init and cleanup of fb_info structures
  drm/fbconv: Add helper documentation
  staging: Add mgakms driver
  staging/mgakms: Import matroxfb driver source code
  staging/mgakms: Update matroxfb driver code for DRM

 Documentation/gpu/drm-kms-helpers.rst     |   12 +
 Documentation/gpu/todo.rst                |   15 +
 drivers/gpu/drm/Kconfig                   |   11 +
 drivers/gpu/drm/Makefile                  |    1 +
 drivers/gpu/drm/drm_fbconv_helper.c       | 2126 +++++++++++++++++
 drivers/gpu/drm/drm_simple_kms_helper.c   |   15 +
 drivers/staging/Kconfig                   |    2 +
 drivers/staging/Makefile                  |    1 +
 drivers/staging/mgakms/Kconfig            |   18 +
 drivers/staging/mgakms/Makefile           |   17 +
 drivers/staging/mgakms/g450_pll.c         |  539 +++++
 drivers/staging/mgakms/g450_pll.h         |   13 +
 drivers/staging/mgakms/i2c-matroxfb.c     |  238 ++
 drivers/staging/mgakms/matroxfb_DAC1064.c | 1082 +++++++++
 drivers/staging/mgakms/matroxfb_DAC1064.h |  174 ++
 drivers/staging/mgakms/matroxfb_Ti3026.c  |  746 ++++++
 drivers/staging/mgakms/matroxfb_Ti3026.h  |   10 +
 drivers/staging/mgakms/matroxfb_accel.c   |  519 +++++
 drivers/staging/mgakms/matroxfb_accel.h   |    9 +
 drivers/staging/mgakms/matroxfb_base.c    | 2592 +++++++++++++++++++++
 drivers/staging/mgakms/matroxfb_base.h    |  700 ++++++
 drivers/staging/mgakms/matroxfb_crtc2.h   |   35 +
 drivers/staging/mgakms/matroxfb_g450.c    |  640 +++++
 drivers/staging/mgakms/matroxfb_g450.h    |   10 +
 drivers/staging/mgakms/matroxfb_maven.h   |   21 +
 drivers/staging/mgakms/matroxfb_misc.c    |  815 +++++++
 drivers/staging/mgakms/matroxfb_misc.h    |   22 +
 drivers/staging/mgakms/mga_device.c       |   68 +
 drivers/staging/mgakms/mga_device.h       |   30 +
 drivers/staging/mgakms/mga_drv.c          |  129 +
 drivers/staging/mgakms/mga_drv.h          |   14 +
 drivers/video/fbdev/core/fbmem.c          |    5 +-
 include/drm/drm_fbconv_helper.h           |  150 ++
 include/drm/drm_simple_kms_helper.h       |   43 +
 include/linux/fb.h                        |    3 +
 35 files changed, 10822 insertions(+), 3 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_fbconv_helper.c
 create mode 100644 drivers/staging/mgakms/Kconfig
 create mode 100644 drivers/staging/mgakms/Makefile
 create mode 100644 drivers/staging/mgakms/g450_pll.c
 create mode 100644 drivers/staging/mgakms/g450_pll.h
 create mode 100644 drivers/staging/mgakms/i2c-matroxfb.c
 create mode 100644 drivers/staging/mgakms/matroxfb_DAC1064.c
 create mode 100644 drivers/staging/mgakms/matroxfb_DAC1064.h
 create mode 100644 drivers/staging/mgakms/matroxfb_Ti3026.c
 create mode 100644 drivers/staging/mgakms/matroxfb_Ti3026.h
 create mode 100644 drivers/staging/mgakms/matroxfb_accel.c
 create mode 100644 drivers/staging/mgakms/matroxfb_accel.h
 create mode 100644 drivers/staging/mgakms/matroxfb_base.c
 create mode 100644 drivers/staging/mgakms/matroxfb_base.h
 create mode 100644 drivers/staging/mgakms/matroxfb_crtc2.h
 create mode 100644 drivers/staging/mgakms/matroxfb_g450.c
 create mode 100644 drivers/staging/mgakms/matroxfb_g450.h
 create mode 100644 drivers/staging/mgakms/matroxfb_maven.h
 create mode 100644 drivers/staging/mgakms/matroxfb_misc.c
 create mode 100644 drivers/staging/mgakms/matroxfb_misc.h
 create mode 100644 drivers/staging/mgakms/mga_device.c
 create mode 100644 drivers/staging/mgakms/mga_device.h
 create mode 100644 drivers/staging/mgakms/mga_drv.c
 create mode 100644 drivers/staging/mgakms/mga_drv.h
 create mode 100644 include/drm/drm_fbconv_helper.h

--
2.23.0

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

* [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers
@ 2019-10-14 14:04 ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

(was: DRM driver for fbdev devices)

This is version 2 of the fbdev conversion helpers. It's more or less a
rewrite of the original patchset.

The fbdev subsystem is considered legacy and will probably be removed at
some point. This would mean the loss of a signifanct number of drivers.
Some of the affected hardware is not in use any longer, but some hardware
is still around and provides good(-enough) framebuffers.

The fbconv helpers allow for running the current DRM stack on top of fbdev
drivers. It's a set of functions that convert between fbdev interfaces and
DRM interfaces. Based on SHMEM and simple KMS helpers, it only offers the
basic functionality of a framebuffer, but should be compatible with most
existing fbdev drivers.

A DRM driver using fbconv helpers consists of

  * DRM stub code that calls into fbconv helpers, and
  * the original fbdev driver code.

The fbdev driver code has to be modified to register itself with the
stub driver instead of the fbdev core framework. A tutorial on how to use
the helpers is part of this patchset. The resulting driver hybrid can be
refactored into a first-class DRM driver. The fbconv helpers contain a
number of comments, labeled 'DRM porting note', which explain the required
steps.

I tested the current patchset with the following drivers: atyfb, aty128fb,
matroxfb, pm2fb, pm3fb, rivafb, s3fb, savagefb, sisfb, tdfxfb and tridentfb.
With each, I was able to successfully start with fbcon enabled, run weston and
X11. The drivers are available at [1]. For reference, the patchset includes
the Matrox stub driver.

v2:
	* rename to fbconv helpers
	* rewrite as helper library
	* switch over to simple KMS helpers
	* switch over to SHMEM
	* add documentation

[1] https://gitlab.freedesktop.org/tzimmermann/linux/commits/fbconv-plus-drivers

Thomas Zimmermann (15):
  fbdev: Export fb_check_foreignness()
  fbdev: Export FBPIXMAPSIZE
  drm/simple-kms-helper: Add mode_fixup() to simple display pipe
  drm: Add fbconv helper module
  drm/fbconv: Add DRM <-> fbdev pixel-format conversion
  drm/fbconv: Add mode conversion DRM <-> fbdev
  drm/fbconv: Add modesetting infrastructure
  drm/fbconv: Add plane-state check and update
  drm/fbconv: Mode-setting pipeline enable / disable
  drm/fbconv: Reimplement several fbdev interfaces
  drm/fbconv: Add helpers for init and cleanup of fb_info structures
  drm/fbconv: Add helper documentation
  staging: Add mgakms driver
  staging/mgakms: Import matroxfb driver source code
  staging/mgakms: Update matroxfb driver code for DRM

 Documentation/gpu/drm-kms-helpers.rst     |   12 +
 Documentation/gpu/todo.rst                |   15 +
 drivers/gpu/drm/Kconfig                   |   11 +
 drivers/gpu/drm/Makefile                  |    1 +
 drivers/gpu/drm/drm_fbconv_helper.c       | 2126 +++++++++++++++++
 drivers/gpu/drm/drm_simple_kms_helper.c   |   15 +
 drivers/staging/Kconfig                   |    2 +
 drivers/staging/Makefile                  |    1 +
 drivers/staging/mgakms/Kconfig            |   18 +
 drivers/staging/mgakms/Makefile           |   17 +
 drivers/staging/mgakms/g450_pll.c         |  539 +++++
 drivers/staging/mgakms/g450_pll.h         |   13 +
 drivers/staging/mgakms/i2c-matroxfb.c     |  238 ++
 drivers/staging/mgakms/matroxfb_DAC1064.c | 1082 +++++++++
 drivers/staging/mgakms/matroxfb_DAC1064.h |  174 ++
 drivers/staging/mgakms/matroxfb_Ti3026.c  |  746 ++++++
 drivers/staging/mgakms/matroxfb_Ti3026.h  |   10 +
 drivers/staging/mgakms/matroxfb_accel.c   |  519 +++++
 drivers/staging/mgakms/matroxfb_accel.h   |    9 +
 drivers/staging/mgakms/matroxfb_base.c    | 2592 +++++++++++++++++++++
 drivers/staging/mgakms/matroxfb_base.h    |  700 ++++++
 drivers/staging/mgakms/matroxfb_crtc2.h   |   35 +
 drivers/staging/mgakms/matroxfb_g450.c    |  640 +++++
 drivers/staging/mgakms/matroxfb_g450.h    |   10 +
 drivers/staging/mgakms/matroxfb_maven.h   |   21 +
 drivers/staging/mgakms/matroxfb_misc.c    |  815 +++++++
 drivers/staging/mgakms/matroxfb_misc.h    |   22 +
 drivers/staging/mgakms/mga_device.c       |   68 +
 drivers/staging/mgakms/mga_device.h       |   30 +
 drivers/staging/mgakms/mga_drv.c          |  129 +
 drivers/staging/mgakms/mga_drv.h          |   14 +
 drivers/video/fbdev/core/fbmem.c          |    5 +-
 include/drm/drm_fbconv_helper.h           |  150 ++
 include/drm/drm_simple_kms_helper.h       |   43 +
 include/linux/fb.h                        |    3 +
 35 files changed, 10822 insertions(+), 3 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_fbconv_helper.c
 create mode 100644 drivers/staging/mgakms/Kconfig
 create mode 100644 drivers/staging/mgakms/Makefile
 create mode 100644 drivers/staging/mgakms/g450_pll.c
 create mode 100644 drivers/staging/mgakms/g450_pll.h
 create mode 100644 drivers/staging/mgakms/i2c-matroxfb.c
 create mode 100644 drivers/staging/mgakms/matroxfb_DAC1064.c
 create mode 100644 drivers/staging/mgakms/matroxfb_DAC1064.h
 create mode 100644 drivers/staging/mgakms/matroxfb_Ti3026.c
 create mode 100644 drivers/staging/mgakms/matroxfb_Ti3026.h
 create mode 100644 drivers/staging/mgakms/matroxfb_accel.c
 create mode 100644 drivers/staging/mgakms/matroxfb_accel.h
 create mode 100644 drivers/staging/mgakms/matroxfb_base.c
 create mode 100644 drivers/staging/mgakms/matroxfb_base.h
 create mode 100644 drivers/staging/mgakms/matroxfb_crtc2.h
 create mode 100644 drivers/staging/mgakms/matroxfb_g450.c
 create mode 100644 drivers/staging/mgakms/matroxfb_g450.h
 create mode 100644 drivers/staging/mgakms/matroxfb_maven.h
 create mode 100644 drivers/staging/mgakms/matroxfb_misc.c
 create mode 100644 drivers/staging/mgakms/matroxfb_misc.h
 create mode 100644 drivers/staging/mgakms/mga_device.c
 create mode 100644 drivers/staging/mgakms/mga_device.h
 create mode 100644 drivers/staging/mgakms/mga_drv.c
 create mode 100644 drivers/staging/mgakms/mga_drv.h
 create mode 100644 include/drm/drm_fbconv_helper.h

--
2.23.0

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

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

* [PATCH v2 01/15] fbdev: Export fb_check_foreignness()
  2019-10-14 14:04 ` Thomas Zimmermann
@ 2019-10-14 14:04   ` Thomas Zimmermann
  -1 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

This function is required by DRM's fbdev conversion helpers. Export it
from the module.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/video/fbdev/core/fbmem.c | 3 ++-
 include/linux/fb.h               | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 95c32952fa8a..e828fcccce40 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1481,7 +1481,7 @@ static const struct file_operations fb_fops = {
 struct class *fb_class;
 EXPORT_SYMBOL(fb_class);
 
-static int fb_check_foreignness(struct fb_info *fi)
+int fb_check_foreignness(struct fb_info *fi)
 {
 	const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN;
 
@@ -1505,6 +1505,7 @@ static int fb_check_foreignness(struct fb_info *fi)
 
 	return 0;
 }
+EXPORT_SYMBOL(fb_check_foreignness);
 
 static bool apertures_overlap(struct aperture *gen, struct aperture *hw)
 {
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 41e0069eca0a..372f1f6ae42e 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -622,6 +622,7 @@ extern int fb_get_color_depth(struct fb_var_screeninfo *var,
 			      struct fb_fix_screeninfo *fix);
 extern int fb_get_options(const char *name, char **option);
 extern int fb_new_modelist(struct fb_info *info);
+extern int fb_check_foreignness(struct fb_info *fi);
 
 extern struct fb_info *registered_fb[FB_MAX];
 extern int num_registered_fb;
-- 
2.23.0

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

* [PATCH v2 01/15] fbdev: Export fb_check_foreignness()
@ 2019-10-14 14:04   ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

This function is required by DRM's fbdev conversion helpers. Export it
from the module.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/video/fbdev/core/fbmem.c | 3 ++-
 include/linux/fb.h               | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 95c32952fa8a..e828fcccce40 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1481,7 +1481,7 @@ static const struct file_operations fb_fops = {
 struct class *fb_class;
 EXPORT_SYMBOL(fb_class);
 
-static int fb_check_foreignness(struct fb_info *fi)
+int fb_check_foreignness(struct fb_info *fi)
 {
 	const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN;
 
@@ -1505,6 +1505,7 @@ static int fb_check_foreignness(struct fb_info *fi)
 
 	return 0;
 }
+EXPORT_SYMBOL(fb_check_foreignness);
 
 static bool apertures_overlap(struct aperture *gen, struct aperture *hw)
 {
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 41e0069eca0a..372f1f6ae42e 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -622,6 +622,7 @@ extern int fb_get_color_depth(struct fb_var_screeninfo *var,
 			      struct fb_fix_screeninfo *fix);
 extern int fb_get_options(const char *name, char **option);
 extern int fb_new_modelist(struct fb_info *info);
+extern int fb_check_foreignness(struct fb_info *fi);
 
 extern struct fb_info *registered_fb[FB_MAX];
 extern int num_registered_fb;
-- 
2.23.0

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

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

* [PATCH v2 02/15] fbdev: Export FBPIXMAPSIZE
  2019-10-14 14:04 ` Thomas Zimmermann
@ 2019-10-14 14:04   ` Thomas Zimmermann
  -1 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

This constant is required by DRM's fbdev conversion helpers. Define it in
fbdev's public header file.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/video/fbdev/core/fbmem.c | 2 --
 include/linux/fb.h               | 2 ++
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index e828fcccce40..f02377e959dc 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -43,8 +43,6 @@
      *  Frame buffer device initialization and setup routines
      */
 
-#define FBPIXMAPSIZE	(1024 * 8)
-
 static DEFINE_MUTEX(registration_lock);
 
 struct fb_info *registered_fb[FB_MAX] __read_mostly;
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 372f1f6ae42e..e17d3e1d86ad 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -199,6 +199,8 @@ struct fb_pixmap {
 	void (*readio) (struct fb_info *info, void *dst, void __iomem *src, unsigned int size);
 };
 
+#define FBPIXMAPSIZE	(1024 * 8)
+
 #ifdef CONFIG_FB_DEFERRED_IO
 struct fb_deferred_io {
 	/* delay between mkwrite and deferred handler */
-- 
2.23.0

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

* [PATCH v2 02/15] fbdev: Export FBPIXMAPSIZE
@ 2019-10-14 14:04   ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

This constant is required by DRM's fbdev conversion helpers. Define it in
fbdev's public header file.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/video/fbdev/core/fbmem.c | 2 --
 include/linux/fb.h               | 2 ++
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index e828fcccce40..f02377e959dc 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -43,8 +43,6 @@
      *  Frame buffer device initialization and setup routines
      */
 
-#define FBPIXMAPSIZE	(1024 * 8)
-
 static DEFINE_MUTEX(registration_lock);
 
 struct fb_info *registered_fb[FB_MAX] __read_mostly;
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 372f1f6ae42e..e17d3e1d86ad 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -199,6 +199,8 @@ struct fb_pixmap {
 	void (*readio) (struct fb_info *info, void *dst, void __iomem *src, unsigned int size);
 };
 
+#define FBPIXMAPSIZE	(1024 * 8)
+
 #ifdef CONFIG_FB_DEFERRED_IO
 struct fb_deferred_io {
 	/* delay between mkwrite and deferred handler */
-- 
2.23.0

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

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

* [PATCH v2 03/15] drm/simple-kms-helper: Add mode_fixup() to simple display pipe
  2019-10-14 14:04 ` Thomas Zimmermann
@ 2019-10-14 14:04   ` Thomas Zimmermann
  -1 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

The mode fix-up function for simple display helpers is equivalent to the
regular pipeline's CRTC mode fix-up function. It's called to adjust the
CRTC's display mode for the encoder. Add this function for DRM fbconv
helpers.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/drm_simple_kms_helper.c | 15 +++++++++
 include/drm/drm_simple_kms_helper.h     | 43 +++++++++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
index 046055719245..acd9b79bf92a 100644
--- a/drivers/gpu/drm/drm_simple_kms_helper.c
+++ b/drivers/gpu/drm/drm_simple_kms_helper.c
@@ -46,6 +46,20 @@ drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc,
 	return pipe->funcs->mode_valid(crtc, mode);
 }
 
+static bool
+drm_simple_kms_crtc_mode_fixup(struct drm_crtc *crtc,
+			       const struct drm_display_mode *mode,
+			       struct drm_display_mode *adjusted_mode)
+{
+	struct drm_simple_display_pipe *pipe;
+
+	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
+	if (!pipe->funcs || !pipe->funcs->mode_fixup)
+		return true;
+
+	return pipe->funcs->mode_fixup(crtc, mode, adjusted_mode);
+}
+
 static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
 				     struct drm_crtc_state *state)
 {
@@ -87,6 +101,7 @@ static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc,
 
 static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
 	.mode_valid = drm_simple_kms_crtc_mode_valid,
+	.mode_fixup = drm_simple_kms_crtc_mode_fixup,
 	.atomic_check = drm_simple_kms_crtc_check,
 	.atomic_enable = drm_simple_kms_crtc_enable,
 	.atomic_disable = drm_simple_kms_crtc_disable,
diff --git a/include/drm/drm_simple_kms_helper.h b/include/drm/drm_simple_kms_helper.h
index 4d89cd0a60db..1b975ab67144 100644
--- a/include/drm/drm_simple_kms_helper.h
+++ b/include/drm/drm_simple_kms_helper.h
@@ -52,6 +52,49 @@ struct drm_simple_display_pipe_funcs {
 	enum drm_mode_status (*mode_valid)(struct drm_crtc *crtc,
 					   const struct drm_display_mode *mode);
 
+	/**
+	 * @mode_fixup:
+	 *
+	 * This callback is used to validate a mode. The parameter mode is the
+	 * display mode that userspace requested, adjusted_mode is the mode the
+	 * encoders need to be fed with. Note that this is the inverse semantics
+	 * of the meaning for the &drm_encoder and &drm_bridge_funcs.mode_fixup
+	 * vfunc. If the CRTC of the simple display pipe cannot support the
+	 * requested conversion from mode to adjusted_mode it should reject the
+	 * modeset.
+	 *
+	 * This function is optional.
+	 *
+	 * NOTE:
+	 *
+	 * This function is called in the check phase of atomic modesets, which
+	 * can be aborted for any reason (including on userspace's request to
+	 * just check whether a configuration would be possible). Atomic drivers
+	 * MUST NOT touch any persistent state (hardware or software) or data
+	 * structures except the passed in adjusted_mode parameter.
+	 *
+	 * Atomic drivers which need to inspect and adjust more state should
+	 * instead use the @atomic_check callback, but note that they're not
+	 * perfectly equivalent: @mode_valid is called from
+	 * drm_atomic_helper_check_modeset(), but @atomic_check is called from
+	 * drm_atomic_helper_check_planes(), because originally it was meant for
+	 * plane update checks only.
+	 *
+	 * Also beware that userspace can request its own custom modes, neither
+	 * core nor helpers filter modes to the list of probe modes reported by
+	 * the GETCONNECTOR IOCTL and stored in &drm_connector.modes. To ensure
+	 * that modes are filtered consistently put any CRTC constraints and
+	 * limits checks into @mode_valid.
+	 *
+	 * RETURNS:
+	 *
+	 * True if an acceptable configuration is possible, false if the modeset
+	 * operation should be rejected.
+	 */
+	bool (*mode_fixup)(struct drm_crtc *crtc,
+			   const struct drm_display_mode *mode,
+			   struct drm_display_mode *adjusted_mode);
+
 	/**
 	 * @enable:
 	 *
-- 
2.23.0

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

* [PATCH v2 03/15] drm/simple-kms-helper: Add mode_fixup() to simple display pipe
@ 2019-10-14 14:04   ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

The mode fix-up function for simple display helpers is equivalent to the
regular pipeline's CRTC mode fix-up function. It's called to adjust the
CRTC's display mode for the encoder. Add this function for DRM fbconv
helpers.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/drm_simple_kms_helper.c | 15 +++++++++
 include/drm/drm_simple_kms_helper.h     | 43 +++++++++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
index 046055719245..acd9b79bf92a 100644
--- a/drivers/gpu/drm/drm_simple_kms_helper.c
+++ b/drivers/gpu/drm/drm_simple_kms_helper.c
@@ -46,6 +46,20 @@ drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc,
 	return pipe->funcs->mode_valid(crtc, mode);
 }
 
+static bool
+drm_simple_kms_crtc_mode_fixup(struct drm_crtc *crtc,
+			       const struct drm_display_mode *mode,
+			       struct drm_display_mode *adjusted_mode)
+{
+	struct drm_simple_display_pipe *pipe;
+
+	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
+	if (!pipe->funcs || !pipe->funcs->mode_fixup)
+		return true;
+
+	return pipe->funcs->mode_fixup(crtc, mode, adjusted_mode);
+}
+
 static int drm_simple_kms_crtc_check(struct drm_crtc *crtc,
 				     struct drm_crtc_state *state)
 {
@@ -87,6 +101,7 @@ static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc,
 
 static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
 	.mode_valid = drm_simple_kms_crtc_mode_valid,
+	.mode_fixup = drm_simple_kms_crtc_mode_fixup,
 	.atomic_check = drm_simple_kms_crtc_check,
 	.atomic_enable = drm_simple_kms_crtc_enable,
 	.atomic_disable = drm_simple_kms_crtc_disable,
diff --git a/include/drm/drm_simple_kms_helper.h b/include/drm/drm_simple_kms_helper.h
index 4d89cd0a60db..1b975ab67144 100644
--- a/include/drm/drm_simple_kms_helper.h
+++ b/include/drm/drm_simple_kms_helper.h
@@ -52,6 +52,49 @@ struct drm_simple_display_pipe_funcs {
 	enum drm_mode_status (*mode_valid)(struct drm_crtc *crtc,
 					   const struct drm_display_mode *mode);
 
+	/**
+	 * @mode_fixup:
+	 *
+	 * This callback is used to validate a mode. The parameter mode is the
+	 * display mode that userspace requested, adjusted_mode is the mode the
+	 * encoders need to be fed with. Note that this is the inverse semantics
+	 * of the meaning for the &drm_encoder and &drm_bridge_funcs.mode_fixup
+	 * vfunc. If the CRTC of the simple display pipe cannot support the
+	 * requested conversion from mode to adjusted_mode it should reject the
+	 * modeset.
+	 *
+	 * This function is optional.
+	 *
+	 * NOTE:
+	 *
+	 * This function is called in the check phase of atomic modesets, which
+	 * can be aborted for any reason (including on userspace's request to
+	 * just check whether a configuration would be possible). Atomic drivers
+	 * MUST NOT touch any persistent state (hardware or software) or data
+	 * structures except the passed in adjusted_mode parameter.
+	 *
+	 * Atomic drivers which need to inspect and adjust more state should
+	 * instead use the @atomic_check callback, but note that they're not
+	 * perfectly equivalent: @mode_valid is called from
+	 * drm_atomic_helper_check_modeset(), but @atomic_check is called from
+	 * drm_atomic_helper_check_planes(), because originally it was meant for
+	 * plane update checks only.
+	 *
+	 * Also beware that userspace can request its own custom modes, neither
+	 * core nor helpers filter modes to the list of probe modes reported by
+	 * the GETCONNECTOR IOCTL and stored in &drm_connector.modes. To ensure
+	 * that modes are filtered consistently put any CRTC constraints and
+	 * limits checks into @mode_valid.
+	 *
+	 * RETURNS:
+	 *
+	 * True if an acceptable configuration is possible, false if the modeset
+	 * operation should be rejected.
+	 */
+	bool (*mode_fixup)(struct drm_crtc *crtc,
+			   const struct drm_display_mode *mode,
+			   struct drm_display_mode *adjusted_mode);
+
 	/**
 	 * @enable:
 	 *
-- 
2.23.0

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

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

* [PATCH v2 04/15] drm: Add fbconv helper module
  2019-10-14 14:04 ` Thomas Zimmermann
@ 2019-10-14 14:04   ` Thomas Zimmermann
  -1 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

This adds fbconv helpers for DRM to the build infrastructure. The
configuration symbol is DRM_FBCONV_HELPERS. Drivers should select
it if they wish to use fbconv.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/Kconfig             | 10 ++++++++++
 drivers/gpu/drm/Makefile            |  1 +
 drivers/gpu/drm/drm_fbconv_helper.c |  1 +
 3 files changed, 12 insertions(+)
 create mode 100644 drivers/gpu/drm/drm_fbconv_helper.c

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 9591bd720e56..ed689201ec81 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -157,6 +157,16 @@ config DRM_DP_CEC
 	  Note: not all adapters support this feature, and even for those
 	  that do support this they often do not hook up the CEC pin.
 
+config DRM_FBCONV_HELPER
+	tristate "Enable fbdev conversion helpers"
+	depends on DRM
+	help
+	  Provides helpers for running DRM on top of fbdev drivers. Choose
+	  this option if you're converting an fbdev driver to DRM. The
+	  helpers provide conversion functions for fbdev data structures
+	  and allow to build a basic DRM driver on top of the fbdev
+	  interfaces.
+
 config DRM_TTM
 	tristate
 	depends on DRM && MMU
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 9f1c7c486f88..a7178245d938 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -52,6 +52,7 @@ drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
 drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o
 drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o
 drm_kms_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o
+drm_kms_helper-$(CONFIG_DRM_FBCONV_HELPER) += drm_fbconv_helper.o
 
 obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
 obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/
diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
new file mode 100644
index 000000000000..0cb46d2c98c3
--- /dev/null
+++ b/drivers/gpu/drm/drm_fbconv_helper.c
@@ -0,0 +1 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
-- 
2.23.0

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

* [PATCH v2 04/15] drm: Add fbconv helper module
@ 2019-10-14 14:04   ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

This adds fbconv helpers for DRM to the build infrastructure. The
configuration symbol is DRM_FBCONV_HELPERS. Drivers should select
it if they wish to use fbconv.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/Kconfig             | 10 ++++++++++
 drivers/gpu/drm/Makefile            |  1 +
 drivers/gpu/drm/drm_fbconv_helper.c |  1 +
 3 files changed, 12 insertions(+)
 create mode 100644 drivers/gpu/drm/drm_fbconv_helper.c

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 9591bd720e56..ed689201ec81 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -157,6 +157,16 @@ config DRM_DP_CEC
 	  Note: not all adapters support this feature, and even for those
 	  that do support this they often do not hook up the CEC pin.
 
+config DRM_FBCONV_HELPER
+	tristate "Enable fbdev conversion helpers"
+	depends on DRM
+	help
+	  Provides helpers for running DRM on top of fbdev drivers. Choose
+	  this option if you're converting an fbdev driver to DRM. The
+	  helpers provide conversion functions for fbdev data structures
+	  and allow to build a basic DRM driver on top of the fbdev
+	  interfaces.
+
 config DRM_TTM
 	tristate
 	depends on DRM && MMU
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 9f1c7c486f88..a7178245d938 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -52,6 +52,7 @@ drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
 drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o
 drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o
 drm_kms_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o
+drm_kms_helper-$(CONFIG_DRM_FBCONV_HELPER) += drm_fbconv_helper.o
 
 obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
 obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/
diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
new file mode 100644
index 000000000000..0cb46d2c98c3
--- /dev/null
+++ b/drivers/gpu/drm/drm_fbconv_helper.c
@@ -0,0 +1 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
-- 
2.23.0

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

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

* [PATCH v2 05/15] drm/fbconv: Add DRM <-> fbdev pixel-format conversion
  2019-10-14 14:04 ` Thomas Zimmermann
@ 2019-10-14 14:04   ` Thomas Zimmermann
  -1 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

DRM uses FOURCC constants to describe pixel formats, fbdev uses a
per-component bitfield structure. The functions in this patch convert
between the two.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/drm_fbconv_helper.c | 435 ++++++++++++++++++++++++++++
 include/drm/drm_fbconv_helper.h     |  23 ++
 2 files changed, 458 insertions(+)
 create mode 100644 include/drm/drm_fbconv_helper.h

diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
index 0cb46d2c98c3..af45358a156a 100644
--- a/drivers/gpu/drm/drm_fbconv_helper.c
+++ b/drivers/gpu/drm/drm_fbconv_helper.c
@@ -1 +1,436 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <asm/byteorder.h>
+
+#include <linux/fb.h>
+
+#include <drm/drm_fbconv_helper.h>
+
+/*
+ * Format conversion helpers
+ */
+
+static bool is_c8(const struct fb_var_screeninfo *fb_var)
+{
+	return fb_var->bits_per_pixel = 8;
+}
+
+static bool is_rgb565(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel = 16) &&
+	       (fb_var->red.offset = 11) &&
+	       (fb_var->red.length = 5) &&
+	       (fb_var->green.offset = 5) &&
+	       (fb_var->green.length = 6) &&
+	       (fb_var->blue.offset = 0) &&
+	       (fb_var->blue.length = 5);
+}
+
+static bool is_bgr565(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel = 16) &&
+	       (fb_var->red.offset = 0) &&
+	       (fb_var->red.length = 5) &&
+	       (fb_var->green.offset = 5) &&
+	       (fb_var->green.length = 6) &&
+	       (fb_var->blue.offset = 11) &&
+	       (fb_var->blue.length = 5);
+}
+
+static bool is_rgb888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel = 24) &&
+	       (fb_var->red.offset = 16) &&
+	       (fb_var->red.length = 8) &&
+	       (fb_var->green.offset = 8) &&
+	       (fb_var->green.length = 8) &&
+	       (fb_var->blue.offset = 0) &&
+	       (fb_var->blue.length = 8);
+}
+
+static bool is_bgr888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel = 24) &&
+	       (fb_var->red.offset = 0) &&
+	       (fb_var->red.length = 8) &&
+	       (fb_var->green.offset = 8) &&
+	       (fb_var->green.length = 8) &&
+	       (fb_var->blue.offset = 16) &&
+	       (fb_var->blue.length = 8);
+}
+
+static bool is_xrgb8888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel = 32) &&
+	       (fb_var->red.offset = 16) &&
+	       (fb_var->red.length = 8) &&
+	       (fb_var->green.offset = 8) &&
+	       (fb_var->green.length = 8) &&
+	       (fb_var->blue.offset = 0) &&
+	       (fb_var->blue.length = 8) &&
+	       (fb_var->transp.length = 0);
+}
+
+static bool is_xbgr8888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel = 32) &&
+	       (fb_var->red.offset = 0) &&
+	       (fb_var->red.length = 8) &&
+	       (fb_var->green.offset = 8) &&
+	       (fb_var->green.length = 8) &&
+	       (fb_var->blue.offset = 16) &&
+	       (fb_var->blue.length = 8) &&
+	       (fb_var->transp.length = 0);
+}
+
+static bool is_rgbx8888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel = 32) &&
+	       (fb_var->red.offset = 24) &&
+	       (fb_var->red.length = 8) &&
+	       (fb_var->green.offset = 16) &&
+	       (fb_var->green.length = 8) &&
+	       (fb_var->blue.offset = 8) &&
+	       (fb_var->blue.length = 8) &&
+	       (fb_var->transp.length = 0);
+}
+
+static bool is_bgrx8888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel = 32) &&
+	       (fb_var->red.offset = 8) &&
+	       (fb_var->red.length = 8) &&
+	       (fb_var->green.offset = 16) &&
+	       (fb_var->green.length = 8) &&
+	       (fb_var->blue.offset = 24) &&
+	       (fb_var->blue.length = 8) &&
+	       (fb_var->transp.length = 0);
+}
+
+static bool is_argb8888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel = 32) &&
+	       (fb_var->red.offset = 16) &&
+	       (fb_var->red.length = 8) &&
+	       (fb_var->green.offset = 8) &&
+	       (fb_var->green.length = 8) &&
+	       (fb_var->blue.offset = 0) &&
+	       (fb_var->blue.length = 8) &&
+	       (fb_var->transp.offset = 24) &&
+	       (fb_var->transp.length = 8);
+}
+
+static bool is_abgr8888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel = 32) &&
+	       (fb_var->red.offset = 0) &&
+	       (fb_var->red.length = 8) &&
+	       (fb_var->green.offset = 8) &&
+	       (fb_var->green.length = 8) &&
+	       (fb_var->blue.offset = 16) &&
+	       (fb_var->blue.length = 8) &&
+	       (fb_var->transp.offset = 24) &&
+	       (fb_var->transp.length = 8);
+}
+
+static bool is_rgba8888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel = 32) &&
+	       (fb_var->red.offset = 24) &&
+	       (fb_var->red.length = 8) &&
+	       (fb_var->green.offset = 16) &&
+	       (fb_var->green.length = 8) &&
+	       (fb_var->blue.offset = 8) &&
+	       (fb_var->blue.length = 8) &&
+	       (fb_var->transp.offset = 0) &&
+	       (fb_var->transp.length = 8);
+}
+
+static bool is_bgra8888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel = 32) &&
+	       (fb_var->red.offset = 8) &&
+	       (fb_var->red.length = 8) &&
+	       (fb_var->green.offset = 16) &&
+	       (fb_var->green.length = 8) &&
+	       (fb_var->blue.offset = 24) &&
+	       (fb_var->blue.length = 8) &&
+	       (fb_var->transp.offset = 0) &&
+	       (fb_var->transp.length = 8);
+}
+
+struct format_map {
+	bool (*is_format)(const struct fb_var_screeninfo *fb_var);
+	uint32_t format;
+};
+
+/**
+ * drm_fbconv_format_of_fb_var_screeninfo - Returns a DRM_FORMAT constant
+ *	from an fb_var_screeninfo structure
+ * @fb_info:	the fb_var_screeninfo structure
+ * Returns:
+ *	A DRM_FORMAT constant on success, or
+ *	DRM_FORMAT_INVALID otherwise.
+ */
+uint32_t
+drm_fbconv_format_of_fb_var_screeninfo(const struct fb_var_screeninfo *fb_var)
+{
+	static const struct format_map map[] = {
+		{ is_c8,       DRM_FORMAT_C8 }, /* 256-color palette */
+		{ is_rgb565,   DRM_FORMAT_RGB565 },
+		{ is_bgr565,   DRM_FORMAT_BGR565 },
+		{ is_rgb888,   DRM_FORMAT_RGB888 },
+		{ is_bgr888,   DRM_FORMAT_BGR888 },
+		{ is_xrgb8888, DRM_FORMAT_XRGB8888 },
+		{ is_xbgr8888, DRM_FORMAT_XBGR8888 },
+		{ is_rgbx8888, DRM_FORMAT_RGBX8888 },
+		{ is_bgrx8888, DRM_FORMAT_BGRX8888 },
+		{ is_argb8888, DRM_FORMAT_ARGB8888 },
+		{ is_abgr8888, DRM_FORMAT_ABGR8888 },
+		{ is_rgba8888, DRM_FORMAT_RGBA8888 },
+		{ is_bgra8888, DRM_FORMAT_BGRA8888 }
+	};
+
+	size_t i;
+
+	if (fb_var->bits_per_pixel < 8)
+		goto err; /* at least 8-bit color required */
+	if (fb_var->grayscale = 1)
+		goto err; /* grayscale output is not supported */
+
+	for (i = 0; i < ARRAY_SIZE(map); ++i) {
+		if (map[i].is_format(fb_var))
+			return map[i].format;
+	}
+
+err:
+	return DRM_FORMAT_INVALID;
+}
+EXPORT_SYMBOL(drm_fbconv_format_of_fb_var_screeninfo);
+
+/**
+ * drm_fbconv_format_of_fb_info - Returns a DRM_FORMAT constant from
+ *	an fb_info structure
+ * @fb_info:	the fb_info structure
+ * Returns:
+ *	A DRM_FORMAT constant on success, or
+ *	DRM_FORMAT_INVALID otherwise.
+ */
+uint32_t drm_fbconv_format_of_fb_info(const struct fb_info *fb_info)
+{
+	if (fb_info->fix.type != FB_TYPE_PACKED_PIXELS)
+		return DRM_FORMAT_INVALID; /* no multi-plane formats */
+
+	return drm_fbconv_format_of_fb_var_screeninfo(&fb_info->var);
+}
+EXPORT_SYMBOL(drm_fbconv_format_of_fb_info);
+
+static void set_fb_bitfield(struct fb_bitfield *bits, __u32 offset,
+			    __u32 length)
+{
+	bits->offset = offset;
+	bits->length = length;
+	bits->msb_right = 0;
+}
+
+static void set_c8(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 8;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    0, 8);
+	set_fb_bitfield(&fb_var->green,  0, 8);
+	set_fb_bitfield(&fb_var->blue,   0, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_rgb565(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 16;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,   11, 5);
+	set_fb_bitfield(&fb_var->green,  5, 6);
+	set_fb_bitfield(&fb_var->blue,   0, 5);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_bgr565(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 16;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    0, 5);
+	set_fb_bitfield(&fb_var->green,  5, 6);
+	set_fb_bitfield(&fb_var->blue,  11, 5);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_rgb888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 24;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,   16, 8);
+	set_fb_bitfield(&fb_var->green,  8, 8);
+	set_fb_bitfield(&fb_var->blue,   0, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_bgr888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 24;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    0, 8);
+	set_fb_bitfield(&fb_var->green,  8, 8);
+	set_fb_bitfield(&fb_var->blue,  16, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_xrgb8888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    16, 8);
+	set_fb_bitfield(&fb_var->green,   8, 8);
+	set_fb_bitfield(&fb_var->blue,    0, 8);
+	set_fb_bitfield(&fb_var->transp, 24, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_xbgr8888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,     0, 8);
+	set_fb_bitfield(&fb_var->green,   8, 8);
+	set_fb_bitfield(&fb_var->blue,   16, 8);
+	set_fb_bitfield(&fb_var->transp, 24, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_rgbx8888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,   24, 8);
+	set_fb_bitfield(&fb_var->green, 16, 8);
+	set_fb_bitfield(&fb_var->blue,   8, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_bgrx8888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    8, 8);
+	set_fb_bitfield(&fb_var->green, 16, 8);
+	set_fb_bitfield(&fb_var->blue,  24, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_argb8888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    16, 8);
+	set_fb_bitfield(&fb_var->green,   8, 8);
+	set_fb_bitfield(&fb_var->blue,    0, 8);
+	set_fb_bitfield(&fb_var->transp, 24, 8);
+	fb_var->nonstd = 0;
+}
+
+static void set_abgr8888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,     0, 8);
+	set_fb_bitfield(&fb_var->green,   8, 8);
+	set_fb_bitfield(&fb_var->blue,   16, 8);
+	set_fb_bitfield(&fb_var->transp, 24, 8);
+	fb_var->nonstd = 0;
+}
+
+static void set_rgba8888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,   24, 8);
+	set_fb_bitfield(&fb_var->green, 16, 8);
+	set_fb_bitfield(&fb_var->blue,   8, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 8);
+	fb_var->nonstd = 0;
+}
+
+static void set_bgra8888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    8, 8);
+	set_fb_bitfield(&fb_var->green, 16, 8);
+	set_fb_bitfield(&fb_var->blue,  24, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 8);
+	fb_var->nonstd = 0;
+}
+
+/**
+ * drm_fbconv_update_fb_var_screen_info_from_format - sets the pixel format
+ *	of a fb_var_screeninfo structure from a DRM_FORMAT constant
+ * @fb_var:	the fb_var_screeninfo structure to update
+ * @format:	a DRM_FORMAT constant
+ * Returns:
+ *	0 on success, or
+ *	a negative error code otherwise.
+ */
+int drm_fbconv_update_fb_var_screeninfo_from_format(
+	struct fb_var_screeninfo *fb_var, uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_C8:
+		set_c8(fb_var);
+		break;
+	case DRM_FORMAT_RGB565:
+		set_rgb565(fb_var);
+		break;
+	case DRM_FORMAT_BGR565:
+		set_bgr565(fb_var);
+		break;
+	case DRM_FORMAT_RGB888:
+		set_rgb888(fb_var);
+		break;
+	case DRM_FORMAT_BGR888:
+		set_bgr888(fb_var);
+		break;
+	case DRM_FORMAT_XRGB8888:
+		set_xrgb8888(fb_var);
+		break;
+	case DRM_FORMAT_XBGR8888:
+		set_xbgr8888(fb_var);
+		break;
+	case DRM_FORMAT_RGBX8888:
+		set_rgbx8888(fb_var);
+		break;
+	case DRM_FORMAT_BGRX8888:
+		set_bgrx8888(fb_var);
+		break;
+	case DRM_FORMAT_ARGB8888:
+		set_argb8888(fb_var);
+		break;
+	case DRM_FORMAT_ABGR8888:
+		set_abgr8888(fb_var);
+		break;
+	case DRM_FORMAT_RGBA8888:
+		set_rgba8888(fb_var);
+		break;
+	case DRM_FORMAT_BGRA8888:
+		set_bgra8888(fb_var);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(drm_fbconv_update_fb_var_screeninfo_from_format);
diff --git a/include/drm/drm_fbconv_helper.h b/include/drm/drm_fbconv_helper.h
new file mode 100644
index 000000000000..6b2ed12b579a
--- /dev/null
+++ b/include/drm/drm_fbconv_helper.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef DRM_FBCONV_HELPER_H
+#define DRM_FBCONV_HELPER_H
+
+#include <drm/drm_fourcc.h>
+
+struct fb_info;
+struct fb_var_screeninfo;
+
+/*
+ * Format conversion helpers
+ */
+
+uint32_t
+drm_fbconv_format_of_fb_var_screeninfo(const struct fb_var_screeninfo *fb_var);
+
+uint32_t drm_fbconv_format_of_fb_info(const struct fb_info *fb_info);
+
+int drm_fbconv_update_fb_var_screeninfo_from_format(
+	struct fb_var_screeninfo *fb_var, uint32_t format);
+
+#endif
-- 
2.23.0

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

* [PATCH v2 05/15] drm/fbconv: Add DRM <-> fbdev pixel-format conversion
@ 2019-10-14 14:04   ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

DRM uses FOURCC constants to describe pixel formats, fbdev uses a
per-component bitfield structure. The functions in this patch convert
between the two.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/drm_fbconv_helper.c | 435 ++++++++++++++++++++++++++++
 include/drm/drm_fbconv_helper.h     |  23 ++
 2 files changed, 458 insertions(+)
 create mode 100644 include/drm/drm_fbconv_helper.h

diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
index 0cb46d2c98c3..af45358a156a 100644
--- a/drivers/gpu/drm/drm_fbconv_helper.c
+++ b/drivers/gpu/drm/drm_fbconv_helper.c
@@ -1 +1,436 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <asm/byteorder.h>
+
+#include <linux/fb.h>
+
+#include <drm/drm_fbconv_helper.h>
+
+/*
+ * Format conversion helpers
+ */
+
+static bool is_c8(const struct fb_var_screeninfo *fb_var)
+{
+	return fb_var->bits_per_pixel == 8;
+}
+
+static bool is_rgb565(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel == 16) &&
+	       (fb_var->red.offset == 11) &&
+	       (fb_var->red.length == 5) &&
+	       (fb_var->green.offset == 5) &&
+	       (fb_var->green.length == 6) &&
+	       (fb_var->blue.offset == 0) &&
+	       (fb_var->blue.length == 5);
+}
+
+static bool is_bgr565(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel == 16) &&
+	       (fb_var->red.offset == 0) &&
+	       (fb_var->red.length == 5) &&
+	       (fb_var->green.offset == 5) &&
+	       (fb_var->green.length == 6) &&
+	       (fb_var->blue.offset == 11) &&
+	       (fb_var->blue.length == 5);
+}
+
+static bool is_rgb888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel == 24) &&
+	       (fb_var->red.offset == 16) &&
+	       (fb_var->red.length == 8) &&
+	       (fb_var->green.offset == 8) &&
+	       (fb_var->green.length == 8) &&
+	       (fb_var->blue.offset == 0) &&
+	       (fb_var->blue.length == 8);
+}
+
+static bool is_bgr888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel == 24) &&
+	       (fb_var->red.offset == 0) &&
+	       (fb_var->red.length == 8) &&
+	       (fb_var->green.offset == 8) &&
+	       (fb_var->green.length == 8) &&
+	       (fb_var->blue.offset == 16) &&
+	       (fb_var->blue.length == 8);
+}
+
+static bool is_xrgb8888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel == 32) &&
+	       (fb_var->red.offset == 16) &&
+	       (fb_var->red.length == 8) &&
+	       (fb_var->green.offset == 8) &&
+	       (fb_var->green.length == 8) &&
+	       (fb_var->blue.offset == 0) &&
+	       (fb_var->blue.length == 8) &&
+	       (fb_var->transp.length == 0);
+}
+
+static bool is_xbgr8888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel == 32) &&
+	       (fb_var->red.offset == 0) &&
+	       (fb_var->red.length == 8) &&
+	       (fb_var->green.offset == 8) &&
+	       (fb_var->green.length == 8) &&
+	       (fb_var->blue.offset == 16) &&
+	       (fb_var->blue.length == 8) &&
+	       (fb_var->transp.length == 0);
+}
+
+static bool is_rgbx8888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel == 32) &&
+	       (fb_var->red.offset == 24) &&
+	       (fb_var->red.length == 8) &&
+	       (fb_var->green.offset == 16) &&
+	       (fb_var->green.length == 8) &&
+	       (fb_var->blue.offset == 8) &&
+	       (fb_var->blue.length == 8) &&
+	       (fb_var->transp.length == 0);
+}
+
+static bool is_bgrx8888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel == 32) &&
+	       (fb_var->red.offset == 8) &&
+	       (fb_var->red.length == 8) &&
+	       (fb_var->green.offset == 16) &&
+	       (fb_var->green.length == 8) &&
+	       (fb_var->blue.offset == 24) &&
+	       (fb_var->blue.length == 8) &&
+	       (fb_var->transp.length == 0);
+}
+
+static bool is_argb8888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel == 32) &&
+	       (fb_var->red.offset == 16) &&
+	       (fb_var->red.length == 8) &&
+	       (fb_var->green.offset == 8) &&
+	       (fb_var->green.length == 8) &&
+	       (fb_var->blue.offset == 0) &&
+	       (fb_var->blue.length == 8) &&
+	       (fb_var->transp.offset == 24) &&
+	       (fb_var->transp.length == 8);
+}
+
+static bool is_abgr8888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel == 32) &&
+	       (fb_var->red.offset == 0) &&
+	       (fb_var->red.length == 8) &&
+	       (fb_var->green.offset == 8) &&
+	       (fb_var->green.length == 8) &&
+	       (fb_var->blue.offset == 16) &&
+	       (fb_var->blue.length == 8) &&
+	       (fb_var->transp.offset == 24) &&
+	       (fb_var->transp.length == 8);
+}
+
+static bool is_rgba8888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel == 32) &&
+	       (fb_var->red.offset == 24) &&
+	       (fb_var->red.length == 8) &&
+	       (fb_var->green.offset == 16) &&
+	       (fb_var->green.length == 8) &&
+	       (fb_var->blue.offset == 8) &&
+	       (fb_var->blue.length == 8) &&
+	       (fb_var->transp.offset == 0) &&
+	       (fb_var->transp.length == 8);
+}
+
+static bool is_bgra8888(const struct fb_var_screeninfo *fb_var)
+{
+	return (fb_var->bits_per_pixel == 32) &&
+	       (fb_var->red.offset == 8) &&
+	       (fb_var->red.length == 8) &&
+	       (fb_var->green.offset == 16) &&
+	       (fb_var->green.length == 8) &&
+	       (fb_var->blue.offset == 24) &&
+	       (fb_var->blue.length == 8) &&
+	       (fb_var->transp.offset == 0) &&
+	       (fb_var->transp.length == 8);
+}
+
+struct format_map {
+	bool (*is_format)(const struct fb_var_screeninfo *fb_var);
+	uint32_t format;
+};
+
+/**
+ * drm_fbconv_format_of_fb_var_screeninfo - Returns a DRM_FORMAT constant
+ *	from an fb_var_screeninfo structure
+ * @fb_info:	the fb_var_screeninfo structure
+ * Returns:
+ *	A DRM_FORMAT constant on success, or
+ *	DRM_FORMAT_INVALID otherwise.
+ */
+uint32_t
+drm_fbconv_format_of_fb_var_screeninfo(const struct fb_var_screeninfo *fb_var)
+{
+	static const struct format_map map[] = {
+		{ is_c8,       DRM_FORMAT_C8 }, /* 256-color palette */
+		{ is_rgb565,   DRM_FORMAT_RGB565 },
+		{ is_bgr565,   DRM_FORMAT_BGR565 },
+		{ is_rgb888,   DRM_FORMAT_RGB888 },
+		{ is_bgr888,   DRM_FORMAT_BGR888 },
+		{ is_xrgb8888, DRM_FORMAT_XRGB8888 },
+		{ is_xbgr8888, DRM_FORMAT_XBGR8888 },
+		{ is_rgbx8888, DRM_FORMAT_RGBX8888 },
+		{ is_bgrx8888, DRM_FORMAT_BGRX8888 },
+		{ is_argb8888, DRM_FORMAT_ARGB8888 },
+		{ is_abgr8888, DRM_FORMAT_ABGR8888 },
+		{ is_rgba8888, DRM_FORMAT_RGBA8888 },
+		{ is_bgra8888, DRM_FORMAT_BGRA8888 }
+	};
+
+	size_t i;
+
+	if (fb_var->bits_per_pixel < 8)
+		goto err; /* at least 8-bit color required */
+	if (fb_var->grayscale == 1)
+		goto err; /* grayscale output is not supported */
+
+	for (i = 0; i < ARRAY_SIZE(map); ++i) {
+		if (map[i].is_format(fb_var))
+			return map[i].format;
+	}
+
+err:
+	return DRM_FORMAT_INVALID;
+}
+EXPORT_SYMBOL(drm_fbconv_format_of_fb_var_screeninfo);
+
+/**
+ * drm_fbconv_format_of_fb_info - Returns a DRM_FORMAT constant from
+ *	an fb_info structure
+ * @fb_info:	the fb_info structure
+ * Returns:
+ *	A DRM_FORMAT constant on success, or
+ *	DRM_FORMAT_INVALID otherwise.
+ */
+uint32_t drm_fbconv_format_of_fb_info(const struct fb_info *fb_info)
+{
+	if (fb_info->fix.type != FB_TYPE_PACKED_PIXELS)
+		return DRM_FORMAT_INVALID; /* no multi-plane formats */
+
+	return drm_fbconv_format_of_fb_var_screeninfo(&fb_info->var);
+}
+EXPORT_SYMBOL(drm_fbconv_format_of_fb_info);
+
+static void set_fb_bitfield(struct fb_bitfield *bits, __u32 offset,
+			    __u32 length)
+{
+	bits->offset = offset;
+	bits->length = length;
+	bits->msb_right = 0;
+}
+
+static void set_c8(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 8;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    0, 8);
+	set_fb_bitfield(&fb_var->green,  0, 8);
+	set_fb_bitfield(&fb_var->blue,   0, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_rgb565(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 16;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,   11, 5);
+	set_fb_bitfield(&fb_var->green,  5, 6);
+	set_fb_bitfield(&fb_var->blue,   0, 5);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_bgr565(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 16;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    0, 5);
+	set_fb_bitfield(&fb_var->green,  5, 6);
+	set_fb_bitfield(&fb_var->blue,  11, 5);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_rgb888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 24;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,   16, 8);
+	set_fb_bitfield(&fb_var->green,  8, 8);
+	set_fb_bitfield(&fb_var->blue,   0, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_bgr888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 24;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    0, 8);
+	set_fb_bitfield(&fb_var->green,  8, 8);
+	set_fb_bitfield(&fb_var->blue,  16, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_xrgb8888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    16, 8);
+	set_fb_bitfield(&fb_var->green,   8, 8);
+	set_fb_bitfield(&fb_var->blue,    0, 8);
+	set_fb_bitfield(&fb_var->transp, 24, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_xbgr8888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,     0, 8);
+	set_fb_bitfield(&fb_var->green,   8, 8);
+	set_fb_bitfield(&fb_var->blue,   16, 8);
+	set_fb_bitfield(&fb_var->transp, 24, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_rgbx8888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,   24, 8);
+	set_fb_bitfield(&fb_var->green, 16, 8);
+	set_fb_bitfield(&fb_var->blue,   8, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_bgrx8888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    8, 8);
+	set_fb_bitfield(&fb_var->green, 16, 8);
+	set_fb_bitfield(&fb_var->blue,  24, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 0);
+	fb_var->nonstd = 0;
+}
+
+static void set_argb8888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    16, 8);
+	set_fb_bitfield(&fb_var->green,   8, 8);
+	set_fb_bitfield(&fb_var->blue,    0, 8);
+	set_fb_bitfield(&fb_var->transp, 24, 8);
+	fb_var->nonstd = 0;
+}
+
+static void set_abgr8888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,     0, 8);
+	set_fb_bitfield(&fb_var->green,   8, 8);
+	set_fb_bitfield(&fb_var->blue,   16, 8);
+	set_fb_bitfield(&fb_var->transp, 24, 8);
+	fb_var->nonstd = 0;
+}
+
+static void set_rgba8888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,   24, 8);
+	set_fb_bitfield(&fb_var->green, 16, 8);
+	set_fb_bitfield(&fb_var->blue,   8, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 8);
+	fb_var->nonstd = 0;
+}
+
+static void set_bgra8888(struct fb_var_screeninfo *fb_var)
+{
+	fb_var->bits_per_pixel = 32;
+	fb_var->grayscale = 0;
+	set_fb_bitfield(&fb_var->red,    8, 8);
+	set_fb_bitfield(&fb_var->green, 16, 8);
+	set_fb_bitfield(&fb_var->blue,  24, 8);
+	set_fb_bitfield(&fb_var->transp, 0, 8);
+	fb_var->nonstd = 0;
+}
+
+/**
+ * drm_fbconv_update_fb_var_screen_info_from_format - sets the pixel format
+ *	of a fb_var_screeninfo structure from a DRM_FORMAT constant
+ * @fb_var:	the fb_var_screeninfo structure to update
+ * @format:	a DRM_FORMAT constant
+ * Returns:
+ *	0 on success, or
+ *	a negative error code otherwise.
+ */
+int drm_fbconv_update_fb_var_screeninfo_from_format(
+	struct fb_var_screeninfo *fb_var, uint32_t format)
+{
+	switch (format) {
+	case DRM_FORMAT_C8:
+		set_c8(fb_var);
+		break;
+	case DRM_FORMAT_RGB565:
+		set_rgb565(fb_var);
+		break;
+	case DRM_FORMAT_BGR565:
+		set_bgr565(fb_var);
+		break;
+	case DRM_FORMAT_RGB888:
+		set_rgb888(fb_var);
+		break;
+	case DRM_FORMAT_BGR888:
+		set_bgr888(fb_var);
+		break;
+	case DRM_FORMAT_XRGB8888:
+		set_xrgb8888(fb_var);
+		break;
+	case DRM_FORMAT_XBGR8888:
+		set_xbgr8888(fb_var);
+		break;
+	case DRM_FORMAT_RGBX8888:
+		set_rgbx8888(fb_var);
+		break;
+	case DRM_FORMAT_BGRX8888:
+		set_bgrx8888(fb_var);
+		break;
+	case DRM_FORMAT_ARGB8888:
+		set_argb8888(fb_var);
+		break;
+	case DRM_FORMAT_ABGR8888:
+		set_abgr8888(fb_var);
+		break;
+	case DRM_FORMAT_RGBA8888:
+		set_rgba8888(fb_var);
+		break;
+	case DRM_FORMAT_BGRA8888:
+		set_bgra8888(fb_var);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(drm_fbconv_update_fb_var_screeninfo_from_format);
diff --git a/include/drm/drm_fbconv_helper.h b/include/drm/drm_fbconv_helper.h
new file mode 100644
index 000000000000..6b2ed12b579a
--- /dev/null
+++ b/include/drm/drm_fbconv_helper.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef DRM_FBCONV_HELPER_H
+#define DRM_FBCONV_HELPER_H
+
+#include <drm/drm_fourcc.h>
+
+struct fb_info;
+struct fb_var_screeninfo;
+
+/*
+ * Format conversion helpers
+ */
+
+uint32_t
+drm_fbconv_format_of_fb_var_screeninfo(const struct fb_var_screeninfo *fb_var);
+
+uint32_t drm_fbconv_format_of_fb_info(const struct fb_info *fb_info);
+
+int drm_fbconv_update_fb_var_screeninfo_from_format(
+	struct fb_var_screeninfo *fb_var, uint32_t format);
+
+#endif
-- 
2.23.0

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

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

* [PATCH v2 06/15] drm/fbconv: Add mode conversion DRM <-> fbdev
  2019-10-14 14:04 ` Thomas Zimmermann
@ 2019-10-14 14:04   ` Thomas Zimmermann
  -1 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

DRM uses struct drm_display_mode to describe a display mode. The
conversion functions fill it from fbdev data strucutures, and vice
versa.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/drm_fbconv_helper.c | 201 ++++++++++++++++++++++++++++
 include/drm/drm_fbconv_helper.h     |  31 +++++
 2 files changed, 232 insertions(+)

diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
index af45358a156a..e5a58a361ae9 100644
--- a/drivers/gpu/drm/drm_fbconv_helper.c
+++ b/drivers/gpu/drm/drm_fbconv_helper.c
@@ -5,6 +5,7 @@
 #include <linux/fb.h>
 
 #include <drm/drm_fbconv_helper.h>
+#include <drm/drm_modes.h>
 
 /*
  * Format conversion helpers
@@ -434,3 +435,203 @@ int drm_fbconv_update_fb_var_screeninfo_from_format(
 	return 0;
 }
 EXPORT_SYMBOL(drm_fbconv_update_fb_var_screeninfo_from_format);
+
+/*
+ * Mode conversion helpers
+ */
+
+/**
+ * drm_mode_update_from_fb_videomode - Sets a drm_display mode struecture
+ *	from an fb_videomode structure
+ * @mode:	the DRM display mode structure to update
+ * @fb_mode:	an fb_videomode structure
+ */
+void drm_mode_update_from_fb_videomode(struct drm_display_mode *mode,
+				       const struct fb_videomode *fb_mode)
+{
+	mode->type = DRM_MODE_TYPE_DRIVER;
+
+	mode->clock = PICOS2KHZ(fb_mode->pixclock);
+
+	mode->hdisplay = fb_mode->xres;
+	mode->hsync_start = mode->hdisplay + fb_mode->right_margin;
+	mode->hsync_end = mode->hsync_start + fb_mode->hsync_len;
+	mode->htotal = mode->hsync_end + fb_mode->left_margin;
+	mode->hskew = 0;
+
+	mode->vdisplay = fb_mode->yres;
+	mode->vsync_start = mode->vdisplay + fb_mode->lower_margin;
+	mode->vsync_end = mode->vsync_start + fb_mode->vsync_len;
+	mode->vtotal = mode->vsync_end + fb_mode->upper_margin;
+	mode->vscan = 0;
+
+	mode->flags = 0;
+
+	if (fb_mode->sync & FB_SYNC_HOR_HIGH_ACT)
+		mode->flags |= DRM_MODE_FLAG_PHSYNC;
+	else
+		mode->flags |= DRM_MODE_FLAG_NHSYNC;
+
+	if (fb_mode->sync & FB_SYNC_VERT_HIGH_ACT)
+		mode->flags |= DRM_MODE_FLAG_PVSYNC;
+	else
+		mode->flags |= DRM_MODE_FLAG_NVSYNC;
+
+	if (fb_mode->sync & FB_SYNC_COMP_HIGH_ACT)
+		mode->flags |= DRM_MODE_FLAG_CSYNC | DRM_MODE_FLAG_PCSYNC;
+
+	if (fb_mode->vmode & FB_VMODE_INTERLACED)
+		mode->flags |= DRM_MODE_FLAG_INTERLACE;
+
+	if (fb_mode->vmode & FB_VMODE_DOUBLE)
+		mode->flags |= DRM_MODE_FLAG_DBLSCAN;
+
+	mode->width_mm = 0;
+	mode->height_mm = 0;
+
+	mode->vrefresh = fb_mode->refresh;
+	mode->hsync = mode->clock / mode->vtotal;
+
+	/* final step; depends on previous setup */
+	if (fb_mode->name) {
+		strncpy(mode->name, fb_mode->name, sizeof(mode->name) - 1);
+		mode->name[sizeof(mode->name) - 1] = '\0';
+	} else {
+		drm_mode_set_name(mode);
+	}
+}
+EXPORT_SYMBOL(drm_mode_update_from_fb_videomode);
+
+/**
+ * drm_mode_update_from_fb_var_screeninfo - Sets a drm_display mode structure
+ *	from an fb_var_screenmode structure
+ * @mode:	the DRM display mode structure to update
+ * @fb_var:	an fb_var_screeninfo structure
+ */
+void drm_mode_update_from_fb_var_screeninfo(
+	struct drm_display_mode *mode, const struct fb_var_screeninfo *fb_var)
+{
+	struct fb_videomode fb_mode;
+
+	fb_var_to_videomode(&fb_mode, fb_var);
+	drm_mode_update_from_fb_videomode(mode, &fb_mode);
+}
+EXPORT_SYMBOL(drm_mode_update_from_fb_var_screeninfo);
+
+/**
+ * drm_mode_create_from_fb_videomode - Creates a drm_display mode structure
+ *	from an fb_videomode structure
+ * @dev:	the new mode's DRM device
+ * @fb_mode:	an fb_videomode structure
+ * Returns:
+ *	A newly allocated DRM display mode structure on success, or
+ *	NULL otherwise
+ */
+struct drm_display_mode * drm_mode_create_from_fb_videomode(
+	struct drm_device *dev, const struct fb_videomode *fb_mode)
+{
+	/* cleared to '0' */
+	struct drm_display_mode *mode;
+
+	mode = drm_mode_create(dev);
+	if (!mode)
+		return NULL;
+
+	drm_mode_update_from_fb_videomode(mode, fb_mode);
+
+	return mode;
+}
+EXPORT_SYMBOL(drm_mode_create_from_fb_videomode);
+
+/**
+ * drm_fbconv_update_fb_videomode_from_mode - updates an fb_videomode
+ *	structure from a DRM display mode
+ * @fb_mode:	the fb_videomode structure to update
+ * @mode:	a DRM display mode
+ */
+void
+drm_fbconv_update_fb_videomode_from_mode(struct fb_videomode *fb_mode,
+					 const struct drm_display_mode *mode)
+{
+	fb_mode->name = NULL;
+	fb_mode->refresh = mode->vrefresh;
+	fb_mode->xres = mode->hdisplay;
+	fb_mode->yres = mode->vdisplay;
+	fb_mode->pixclock = KHZ2PICOS(mode->clock);
+	fb_mode->left_margin = mode->htotal - mode->hsync_end;
+	fb_mode->right_margin = mode->hsync_start - mode->hdisplay;
+	fb_mode->upper_margin = mode->vtotal - mode->vsync_end;
+	fb_mode->lower_margin = mode->vsync_start - mode->vdisplay;
+	fb_mode->hsync_len = mode->hsync_end - mode->hsync_start;
+	fb_mode->vsync_len = mode->vsync_end - mode->vsync_start;
+
+	fb_mode->sync = 0;
+	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+		fb_mode->sync |= FB_SYNC_HOR_HIGH_ACT;
+	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+		fb_mode->sync |= FB_SYNC_VERT_HIGH_ACT;
+	if (mode->flags & (DRM_MODE_FLAG_CSYNC | DRM_MODE_FLAG_PCSYNC))
+		fb_mode->sync |= FB_SYNC_COMP_HIGH_ACT;
+
+	fb_mode->vmode = 0;
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		fb_mode->vmode |= FB_VMODE_INTERLACED;
+	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		fb_mode->vmode |= FB_VMODE_DOUBLE;
+
+	fb_mode->flag = 0;
+}
+EXPORT_SYMBOL(drm_fbconv_update_fb_videomode_from_mode);
+
+/**
+ * drm_fbconv_init_fb_videomode_from_mode - initializes an fb_videomode
+ *	structure from a DRM display mode
+ * @fb_mode:	the fb_videomode structure to update
+ * @mode:	a DRM display mode
+ *
+ * This is the same as drm_fbconv_update_fb_videomode_from_mode(), but
+ * first clears the fb_screeninfo structure to 0.
+ */
+void drm_fbconv_init_fb_videomode_from_mode(
+	struct fb_videomode *fb_mode, const struct drm_display_mode *mode)
+{
+	memset(fb_mode, 0, sizeof(*fb_mode));
+	drm_fbconv_update_fb_videomode_from_mode(fb_mode, mode);
+}
+EXPORT_SYMBOL(drm_fbconv_init_fb_videomode_from_mode);
+
+/**
+ * drm_fbconv_update_fb_var_screeninfo_from_mode - updates an
+ *	fb_var_screeninfo structure from a DRM display mode
+ * @fb_var:	the fb_var_screeninfo structure to update
+ * @mode:	a DRM display mode
+ */
+void drm_fbconv_update_fb_var_screeninfo_from_mode(
+	struct fb_var_screeninfo *fb_var, const struct drm_display_mode *mode)
+{
+	struct fb_videomode fb_mode;
+
+	drm_fbconv_init_fb_videomode_from_mode(&fb_mode, mode);
+	fb_videomode_to_var(fb_var, &fb_mode);
+
+	fb_var->height = mode->height_mm;
+	fb_var->width = mode->width_mm;
+}
+EXPORT_SYMBOL(drm_fbconv_update_fb_var_screeninfo_from_mode);
+
+/**
+ * drm_fbconv_init_fb_var_screeninfo_from_mode - initialize an
+ *	fb_var_screeninfo structure from a DRM display mode
+ * @fb_var:	the fb_var_screeninfo structure to update
+ * @mode:	a DRM display mode
+ *
+ * This is the same as drm_fbconv_update_fb_var_screeninfo_from_mode(), but
+ * first clears the fb_screeninfo structure to 0.
+ */
+void drm_fbconv_init_fb_var_screeninfo_from_mode(
+	struct fb_var_screeninfo *fb_var, const struct drm_display_mode *mode)
+{
+	memset(fb_var, 0, sizeof(*fb_var));
+	drm_fbconv_update_fb_var_screeninfo_from_mode(fb_var, mode);
+}
+EXPORT_SYMBOL(drm_fbconv_init_fb_var_screeninfo_from_mode);
diff --git a/include/drm/drm_fbconv_helper.h b/include/drm/drm_fbconv_helper.h
index 6b2ed12b579a..cbb13228c76c 100644
--- a/include/drm/drm_fbconv_helper.h
+++ b/include/drm/drm_fbconv_helper.h
@@ -5,8 +5,12 @@
 
 #include <drm/drm_fourcc.h>
 
+struct drm_device;
+struct drm_display_mode;
 struct fb_info;
 struct fb_var_screeninfo;
+struct fb_var_screeninfo;
+struct fb_videomode;
 
 /*
  * Format conversion helpers
@@ -20,4 +24,31 @@ uint32_t drm_fbconv_format_of_fb_info(const struct fb_info *fb_info);
 int drm_fbconv_update_fb_var_screeninfo_from_format(
 	struct fb_var_screeninfo *fb_var, uint32_t format);
 
+/*
+ * Mode conversion helpers
+ */
+
+void drm_mode_update_from_fb_videomode(struct drm_display_mode *mode,
+				       const struct fb_videomode *fb_mode);
+
+void drm_mode_update_from_fb_var_screeninfo(
+	struct drm_display_mode *mode, const struct fb_var_screeninfo *fb_var);
+
+struct drm_display_mode * drm_mode_create_from_fb_videomode(
+	struct drm_device *dev, const struct fb_videomode *fb_mode);
+
+void
+drm_fbconv_update_fb_videomode_from_mode(struct fb_videomode *fb_mode,
+					 const struct drm_display_mode *mode);
+
+void
+drm_fbconv_init_fb_videomode_from_mode(struct fb_videomode *fb_mode,
+				       const struct drm_display_mode *mode);
+
+void drm_fbconv_update_fb_var_screeninfo_from_mode(
+	struct fb_var_screeninfo *var, const struct drm_display_mode *mode);
+
+void drm_fbconv_init_fb_var_screeninfo_from_mode(
+	struct fb_var_screeninfo *var, const struct drm_display_mode *mode);
+
 #endif
-- 
2.23.0

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

* [PATCH v2 06/15] drm/fbconv: Add mode conversion DRM <-> fbdev
@ 2019-10-14 14:04   ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

DRM uses struct drm_display_mode to describe a display mode. The
conversion functions fill it from fbdev data strucutures, and vice
versa.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/drm_fbconv_helper.c | 201 ++++++++++++++++++++++++++++
 include/drm/drm_fbconv_helper.h     |  31 +++++
 2 files changed, 232 insertions(+)

diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
index af45358a156a..e5a58a361ae9 100644
--- a/drivers/gpu/drm/drm_fbconv_helper.c
+++ b/drivers/gpu/drm/drm_fbconv_helper.c
@@ -5,6 +5,7 @@
 #include <linux/fb.h>
 
 #include <drm/drm_fbconv_helper.h>
+#include <drm/drm_modes.h>
 
 /*
  * Format conversion helpers
@@ -434,3 +435,203 @@ int drm_fbconv_update_fb_var_screeninfo_from_format(
 	return 0;
 }
 EXPORT_SYMBOL(drm_fbconv_update_fb_var_screeninfo_from_format);
+
+/*
+ * Mode conversion helpers
+ */
+
+/**
+ * drm_mode_update_from_fb_videomode - Sets a drm_display mode struecture
+ *	from an fb_videomode structure
+ * @mode:	the DRM display mode structure to update
+ * @fb_mode:	an fb_videomode structure
+ */
+void drm_mode_update_from_fb_videomode(struct drm_display_mode *mode,
+				       const struct fb_videomode *fb_mode)
+{
+	mode->type = DRM_MODE_TYPE_DRIVER;
+
+	mode->clock = PICOS2KHZ(fb_mode->pixclock);
+
+	mode->hdisplay = fb_mode->xres;
+	mode->hsync_start = mode->hdisplay + fb_mode->right_margin;
+	mode->hsync_end = mode->hsync_start + fb_mode->hsync_len;
+	mode->htotal = mode->hsync_end + fb_mode->left_margin;
+	mode->hskew = 0;
+
+	mode->vdisplay = fb_mode->yres;
+	mode->vsync_start = mode->vdisplay + fb_mode->lower_margin;
+	mode->vsync_end = mode->vsync_start + fb_mode->vsync_len;
+	mode->vtotal = mode->vsync_end + fb_mode->upper_margin;
+	mode->vscan = 0;
+
+	mode->flags = 0;
+
+	if (fb_mode->sync & FB_SYNC_HOR_HIGH_ACT)
+		mode->flags |= DRM_MODE_FLAG_PHSYNC;
+	else
+		mode->flags |= DRM_MODE_FLAG_NHSYNC;
+
+	if (fb_mode->sync & FB_SYNC_VERT_HIGH_ACT)
+		mode->flags |= DRM_MODE_FLAG_PVSYNC;
+	else
+		mode->flags |= DRM_MODE_FLAG_NVSYNC;
+
+	if (fb_mode->sync & FB_SYNC_COMP_HIGH_ACT)
+		mode->flags |= DRM_MODE_FLAG_CSYNC | DRM_MODE_FLAG_PCSYNC;
+
+	if (fb_mode->vmode & FB_VMODE_INTERLACED)
+		mode->flags |= DRM_MODE_FLAG_INTERLACE;
+
+	if (fb_mode->vmode & FB_VMODE_DOUBLE)
+		mode->flags |= DRM_MODE_FLAG_DBLSCAN;
+
+	mode->width_mm = 0;
+	mode->height_mm = 0;
+
+	mode->vrefresh = fb_mode->refresh;
+	mode->hsync = mode->clock / mode->vtotal;
+
+	/* final step; depends on previous setup */
+	if (fb_mode->name) {
+		strncpy(mode->name, fb_mode->name, sizeof(mode->name) - 1);
+		mode->name[sizeof(mode->name) - 1] = '\0';
+	} else {
+		drm_mode_set_name(mode);
+	}
+}
+EXPORT_SYMBOL(drm_mode_update_from_fb_videomode);
+
+/**
+ * drm_mode_update_from_fb_var_screeninfo - Sets a drm_display mode structure
+ *	from an fb_var_screenmode structure
+ * @mode:	the DRM display mode structure to update
+ * @fb_var:	an fb_var_screeninfo structure
+ */
+void drm_mode_update_from_fb_var_screeninfo(
+	struct drm_display_mode *mode, const struct fb_var_screeninfo *fb_var)
+{
+	struct fb_videomode fb_mode;
+
+	fb_var_to_videomode(&fb_mode, fb_var);
+	drm_mode_update_from_fb_videomode(mode, &fb_mode);
+}
+EXPORT_SYMBOL(drm_mode_update_from_fb_var_screeninfo);
+
+/**
+ * drm_mode_create_from_fb_videomode - Creates a drm_display mode structure
+ *	from an fb_videomode structure
+ * @dev:	the new mode's DRM device
+ * @fb_mode:	an fb_videomode structure
+ * Returns:
+ *	A newly allocated DRM display mode structure on success, or
+ *	NULL otherwise
+ */
+struct drm_display_mode * drm_mode_create_from_fb_videomode(
+	struct drm_device *dev, const struct fb_videomode *fb_mode)
+{
+	/* cleared to '0' */
+	struct drm_display_mode *mode;
+
+	mode = drm_mode_create(dev);
+	if (!mode)
+		return NULL;
+
+	drm_mode_update_from_fb_videomode(mode, fb_mode);
+
+	return mode;
+}
+EXPORT_SYMBOL(drm_mode_create_from_fb_videomode);
+
+/**
+ * drm_fbconv_update_fb_videomode_from_mode - updates an fb_videomode
+ *	structure from a DRM display mode
+ * @fb_mode:	the fb_videomode structure to update
+ * @mode:	a DRM display mode
+ */
+void
+drm_fbconv_update_fb_videomode_from_mode(struct fb_videomode *fb_mode,
+					 const struct drm_display_mode *mode)
+{
+	fb_mode->name = NULL;
+	fb_mode->refresh = mode->vrefresh;
+	fb_mode->xres = mode->hdisplay;
+	fb_mode->yres = mode->vdisplay;
+	fb_mode->pixclock = KHZ2PICOS(mode->clock);
+	fb_mode->left_margin = mode->htotal - mode->hsync_end;
+	fb_mode->right_margin = mode->hsync_start - mode->hdisplay;
+	fb_mode->upper_margin = mode->vtotal - mode->vsync_end;
+	fb_mode->lower_margin = mode->vsync_start - mode->vdisplay;
+	fb_mode->hsync_len = mode->hsync_end - mode->hsync_start;
+	fb_mode->vsync_len = mode->vsync_end - mode->vsync_start;
+
+	fb_mode->sync = 0;
+	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+		fb_mode->sync |= FB_SYNC_HOR_HIGH_ACT;
+	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+		fb_mode->sync |= FB_SYNC_VERT_HIGH_ACT;
+	if (mode->flags & (DRM_MODE_FLAG_CSYNC | DRM_MODE_FLAG_PCSYNC))
+		fb_mode->sync |= FB_SYNC_COMP_HIGH_ACT;
+
+	fb_mode->vmode = 0;
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		fb_mode->vmode |= FB_VMODE_INTERLACED;
+	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+		fb_mode->vmode |= FB_VMODE_DOUBLE;
+
+	fb_mode->flag = 0;
+}
+EXPORT_SYMBOL(drm_fbconv_update_fb_videomode_from_mode);
+
+/**
+ * drm_fbconv_init_fb_videomode_from_mode - initializes an fb_videomode
+ *	structure from a DRM display mode
+ * @fb_mode:	the fb_videomode structure to update
+ * @mode:	a DRM display mode
+ *
+ * This is the same as drm_fbconv_update_fb_videomode_from_mode(), but
+ * first clears the fb_screeninfo structure to 0.
+ */
+void drm_fbconv_init_fb_videomode_from_mode(
+	struct fb_videomode *fb_mode, const struct drm_display_mode *mode)
+{
+	memset(fb_mode, 0, sizeof(*fb_mode));
+	drm_fbconv_update_fb_videomode_from_mode(fb_mode, mode);
+}
+EXPORT_SYMBOL(drm_fbconv_init_fb_videomode_from_mode);
+
+/**
+ * drm_fbconv_update_fb_var_screeninfo_from_mode - updates an
+ *	fb_var_screeninfo structure from a DRM display mode
+ * @fb_var:	the fb_var_screeninfo structure to update
+ * @mode:	a DRM display mode
+ */
+void drm_fbconv_update_fb_var_screeninfo_from_mode(
+	struct fb_var_screeninfo *fb_var, const struct drm_display_mode *mode)
+{
+	struct fb_videomode fb_mode;
+
+	drm_fbconv_init_fb_videomode_from_mode(&fb_mode, mode);
+	fb_videomode_to_var(fb_var, &fb_mode);
+
+	fb_var->height = mode->height_mm;
+	fb_var->width = mode->width_mm;
+}
+EXPORT_SYMBOL(drm_fbconv_update_fb_var_screeninfo_from_mode);
+
+/**
+ * drm_fbconv_init_fb_var_screeninfo_from_mode - initialize an
+ *	fb_var_screeninfo structure from a DRM display mode
+ * @fb_var:	the fb_var_screeninfo structure to update
+ * @mode:	a DRM display mode
+ *
+ * This is the same as drm_fbconv_update_fb_var_screeninfo_from_mode(), but
+ * first clears the fb_screeninfo structure to 0.
+ */
+void drm_fbconv_init_fb_var_screeninfo_from_mode(
+	struct fb_var_screeninfo *fb_var, const struct drm_display_mode *mode)
+{
+	memset(fb_var, 0, sizeof(*fb_var));
+	drm_fbconv_update_fb_var_screeninfo_from_mode(fb_var, mode);
+}
+EXPORT_SYMBOL(drm_fbconv_init_fb_var_screeninfo_from_mode);
diff --git a/include/drm/drm_fbconv_helper.h b/include/drm/drm_fbconv_helper.h
index 6b2ed12b579a..cbb13228c76c 100644
--- a/include/drm/drm_fbconv_helper.h
+++ b/include/drm/drm_fbconv_helper.h
@@ -5,8 +5,12 @@
 
 #include <drm/drm_fourcc.h>
 
+struct drm_device;
+struct drm_display_mode;
 struct fb_info;
 struct fb_var_screeninfo;
+struct fb_var_screeninfo;
+struct fb_videomode;
 
 /*
  * Format conversion helpers
@@ -20,4 +24,31 @@ uint32_t drm_fbconv_format_of_fb_info(const struct fb_info *fb_info);
 int drm_fbconv_update_fb_var_screeninfo_from_format(
 	struct fb_var_screeninfo *fb_var, uint32_t format);
 
+/*
+ * Mode conversion helpers
+ */
+
+void drm_mode_update_from_fb_videomode(struct drm_display_mode *mode,
+				       const struct fb_videomode *fb_mode);
+
+void drm_mode_update_from_fb_var_screeninfo(
+	struct drm_display_mode *mode, const struct fb_var_screeninfo *fb_var);
+
+struct drm_display_mode * drm_mode_create_from_fb_videomode(
+	struct drm_device *dev, const struct fb_videomode *fb_mode);
+
+void
+drm_fbconv_update_fb_videomode_from_mode(struct fb_videomode *fb_mode,
+					 const struct drm_display_mode *mode);
+
+void
+drm_fbconv_init_fb_videomode_from_mode(struct fb_videomode *fb_mode,
+				       const struct drm_display_mode *mode);
+
+void drm_fbconv_update_fb_var_screeninfo_from_mode(
+	struct fb_var_screeninfo *var, const struct drm_display_mode *mode);
+
+void drm_fbconv_init_fb_var_screeninfo_from_mode(
+	struct fb_var_screeninfo *var, const struct drm_display_mode *mode);
+
 #endif
-- 
2.23.0

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

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

* [PATCH v2 07/15] drm/fbconv: Add modesetting infrastructure
  2019-10-14 14:04 ` Thomas Zimmermann
@ 2019-10-14 14:04   ` Thomas Zimmermann
  -1 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

Modesetting for fbconv supports a single display pipeline with CRTC,
primary plane, encoder and connector. It's implementation is based on
struct drm_simple_display_pipe, which fits this use case nicely.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/drm_fbconv_helper.c | 382 ++++++++++++++++++++++++++++
 include/drm/drm_fbconv_helper.h     |  78 ++++++
 2 files changed, 460 insertions(+)

diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
index e5a58a361ae9..4cda1f15e072 100644
--- a/drivers/gpu/drm/drm_fbconv_helper.c
+++ b/drivers/gpu/drm/drm_fbconv_helper.c
@@ -4,8 +4,13 @@
 
 #include <linux/fb.h>
 
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_fbconv_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_modes.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_probe_helper.h>
 
 /*
  * Format conversion helpers
@@ -635,3 +640,380 @@ void drm_fbconv_init_fb_var_screeninfo_from_mode(
 	drm_fbconv_update_fb_var_screeninfo_from_mode(fb_var, mode);
 }
 EXPORT_SYMBOL(drm_fbconv_init_fb_var_screeninfo_from_mode);
+
+/*
+ * Connector
+ */
+
+static int connector_helper_get_modes(struct drm_connector *connector)
+{
+	return 0;
+}
+
+static int connector_helper_detect_ctx(struct drm_connector *connector,
+				       struct drm_modeset_acquire_ctx *ctx,
+				       bool force)
+{
+	return connector_status_connected;
+}
+
+static enum drm_mode_status connector_helper_mode_valid(
+	struct drm_connector *connector, struct drm_display_mode *mode)
+{
+	return MODE_OK;
+}
+
+static int connector_helper_atomic_check(struct drm_connector *connector,
+					 struct drm_atomic_state *state)
+{
+	return 0;
+}
+
+static void connector_helper_atomic_commit(struct drm_connector *connector,
+					   struct drm_connector_state *state)
+{ }
+
+static const struct drm_connector_helper_funcs connector_helper_funcs = {
+	.get_modes = connector_helper_get_modes,
+	.detect_ctx = connector_helper_detect_ctx,
+	.mode_valid = connector_helper_mode_valid,
+	.best_encoder = NULL, /* use default */
+	.atomic_best_encoder = NULL, /* use best_encoder instead */
+	.atomic_check = connector_helper_atomic_check,
+	.atomic_commit = connector_helper_atomic_commit
+};
+
+static enum drm_connector_status connector_detect(
+	struct drm_connector *connector, bool force)
+{
+	return connector_status_connected;
+}
+
+static void connector_force(struct drm_connector *connector)
+{ }
+
+static void connector_destroy(struct drm_connector *connector)
+{ }
+
+static int connector_atomic_set_property(struct drm_connector *connector,
+					 struct drm_connector_state *state,
+					 struct drm_property *property,
+					 uint64_t val)
+{
+	return -EINVAL;
+}
+
+static int connector_atomic_get_property(
+	struct drm_connector *connector,
+	const struct drm_connector_state *state, struct drm_property *property,
+	uint64_t *val)
+{
+	return -EINVAL;
+}
+
+static const struct drm_connector_funcs connector_funcs = {
+	.dpms = NULL, /* not used by atomic drivers */
+	.reset = drm_atomic_helper_connector_reset,
+	.detect = connector_detect,
+	.force = connector_force,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.set_property = NULL,
+	.late_register = NULL,
+	.early_unregister = NULL,
+	.destroy = connector_destroy,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+	.atomic_set_property = connector_atomic_set_property,
+	.atomic_get_property = connector_atomic_get_property,
+	.atomic_print_state = NULL
+};
+
+/*
+ * Simple display pipe
+ */
+
+/**
+ * drm_fbconv_simple_display_pipe_mode_valid - default implementation for
+ *	struct drm_simple_display_pipe_funcs.mode_valid
+ * @crtc:	the DRM CRTC structure
+ * @mode:	the display mode to validate
+ * Returns:
+ *	MODE_OK on success, or
+ *	a MODE constant otherwise
+ */
+enum drm_mode_status
+drm_fbconv_simple_display_pipe_mode_valid(struct drm_crtc *crtc,
+					  const struct drm_display_mode *mode)
+{
+	return MODE_OK;
+}
+EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_mode_valid);
+
+/**
+ * drm_fbconv_simple_display_pipe_mode_fixup - default implementation for
+ *	struct drm_simple_display_pipe_funcs.mode_fixup
+ * @crtc:		the DRM CRTC structure
+ * @mode:		the display mode
+ * @adjusted_mode:	the adjusted display mode
+ * Returns:
+ *	true on success, or
+ *	false otherwise
+ */
+bool drm_fbconv_simple_display_pipe_mode_fixup(
+	struct drm_crtc *crtc, const struct drm_display_mode *mode,
+	struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_mode_fixup);
+
+/**
+ * drm_fbconv_simple_display_pipe_enable - default implementation for
+ *	struct drm_simple_display_pipe_funcs.enable
+ * @pipe:		the display pipe structure
+ * @crtc_state:		the new CRTC state
+ * @plane_state:	the new plane state
+ */
+void
+drm_fbconv_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
+				      struct drm_crtc_state *crtc_state,
+				      struct drm_plane_state *plane_state)
+{ }
+EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_enable);
+
+/**
+ * drm_fbconv_simple_display_pipe_disable - default implementation for
+ *	struct drm_simple_display_pipe_funcs.disable
+ * @pipe:		the display pipe structure
+ */
+void
+drm_fbconv_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
+{ }
+EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_disable);
+
+/**
+ * drm_fbconv_simple_display_pipe_check - default implementation for
+ *	struct drm_simple_display_pipe_funcs.check
+ * @pipe:		the display pipe structure
+ * @plane_state:	the new plane state
+ * @crtc_state:		the new CRTC state
+ */
+int
+drm_fbconv_simple_display_pipe_check(struct drm_simple_display_pipe *pipe,
+				     struct drm_plane_state *plane_state,
+				     struct drm_crtc_state *crtc_state)
+{
+	return 0;
+}
+EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_check);
+
+/**
+ * drm_fbconv_simple_display_pipe_mode_update - default implementation for
+ *	struct drm_simple_display_pipe_funcs.update
+ * @pipe:		the display pipe structure
+ * @old_plane_state:	the old plane state
+ */
+void
+drm_fbconv_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
+				      struct drm_plane_state *old_plane_state)
+{ }
+EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_update);
+
+/**
+ * drm_fbconv_simple_display_pipe_prepare_fb - default implementation for
+ *	struct drm_simple_display_pipe_funcs.prepare_fb
+ * @pipe:		the display pipe structure
+ * @plane_state:	the new plane state
+ * Returns:
+ *	0 on success, or
+ *	a negative error code otherwise.
+ *
+ * The implementation of struct drm_simple_display_pipe_funcs.prepare_fb
+ * maps the framebuffer's buffer object and the fbdev's screen memory, if
+ * necessary. After converting the fbdev driver to DRM, only the buffer-object
+ * mapping should remaing. See drm_fbconv_simple_display_pipe_cleanup_fb() for
+ * the corresponding clean-up helper.
+ */
+int
+drm_fbconv_simple_display_pipe_prepare_fb(struct drm_simple_display_pipe *pipe,
+					  struct drm_plane_state *plane_state)
+{ }
+EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_prepare_fb);
+
+/**
+ * drm_fbconv_simple_display_pipe_cleanup_fb - default implementation for
+ *	struct drm_simple_display_pipe_funcs.cleanup_fb
+ * @pipe:		the display pipe structure
+ * @plane_state:	the old plane state
+ *
+ * This function cleans up the framebuffer state after a plane update. See
+ * drm_fbconv_simple_display_pipe_prepare_fb() for the corresponding prepare
+ * helper.
+ */
+void
+drm_fbconv_simple_display_pipe_cleanup_fb(struct drm_simple_display_pipe *pipe,
+					  struct drm_plane_state *plane_state)
+{ }
+
+static const struct drm_simple_display_pipe_funcs simple_display_pipe_funcs = {
+	.mode_valid = drm_fbconv_simple_display_pipe_mode_valid,
+	.mode_fixup = drm_fbconv_simple_display_pipe_mode_fixup,
+	.enable	    = drm_fbconv_simple_display_pipe_enable,
+	.disable    = drm_fbconv_simple_display_pipe_disable,
+	.check	    = drm_fbconv_simple_display_pipe_check,
+	.update	    = drm_fbconv_simple_display_pipe_update,
+	.prepare_fb = drm_fbconv_simple_display_pipe_prepare_fb,
+	.cleanup_fb = drm_fbconv_simple_display_pipe_cleanup_fb,
+};
+
+/*
+ * Mode config
+ */
+
+static enum drm_mode_status mode_config_mode_valid(
+	struct drm_device *dev, const struct drm_display_mode *mode)
+{
+	return MODE_OK;
+}
+
+static const struct drm_mode_config_funcs mode_config_funcs = {
+	.fb_create = drm_gem_fb_create_with_dirty,
+	.get_format_info = NULL,
+	/* DRM porting notes: the output_poll_changed callback is used by
+	 * fb helpers to implement fbdev emulation. If you're porting an
+	 * fbdev driver to DRM and enable fbdev emulation, this callback
+	 * will become useful.
+	 */
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
+	.mode_valid = mode_config_mode_valid,
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+	.atomic_state_alloc = NULL,
+	.atomic_state_clear = NULL,
+	.atomic_state_free = NULL
+};
+
+/**
+ * drm_fbconv_modeset_init - initializes an fbconv modesetting structure
+ * @modeset:		the fbconv modesetting structure to initialize
+ * @dev:		the DRM device
+ * @fb_info:		the fbdev driver's fb_info structure
+ * @max_width:		the maximum display width that is supported by
+ *                      the device
+ * @max_height:		the maximum display height that is supported by
+ *                      the device
+ * @preferred_depth:	the device's preferred color depth
+ * Returns:
+ *	0 on success, or
+ *	a negative error code otherwise
+ *
+ * This function initializes an instance of struct drm_fbconv_modeset. The
+ * supplied values for max_width, max_height, and max_depth should match the
+ * devices capabilities and be supported by the fbdev driver. DRM helpers
+ * will use these to auto-configure and validate display settings.
+ */
+int drm_fbconv_modeset_init(struct drm_fbconv_modeset *modeset,
+			    struct drm_device *dev, struct fb_info *fb_info,
+			    unsigned int max_width, unsigned int max_height,
+			    unsigned int preferred_depth)
+{
+	struct drm_mode_config *mode_config = &dev->mode_config;
+
+	modeset->dev = dev;
+	modeset->fb_info = fb_info;
+
+	drm_mode_config_init(dev);
+
+	mode_config->max_width = (int)max_width;
+	mode_config->max_height = (int)max_height;
+	mode_config->fb_base = fb_info->fix.smem_start;
+	mode_config->preferred_depth = preferred_depth;
+	mode_config->prefer_shadow_fbdev = true;
+	mode_config->funcs = &mode_config_funcs;
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_fbconv_modeset_init);
+
+/**
+ * drm_fbconv_modeset_cleanup - Cleans up an fbconv modesetting structure
+ * @modeset:	the fbconv modesetting structure to clean up
+ */
+void drm_fbconv_modeset_cleanup(struct drm_fbconv_modeset *modeset)
+{
+	drm_mode_config_cleanup(modeset->dev);
+}
+EXPORT_SYMBOL(drm_fbconv_modeset_cleanup);
+
+/**
+ * drm_fbconv_modeset_setup_pipe - sets up the display pipeline for fbconv
+ * @modeset:		an fbconv modesetting structure
+ * @funcs:		an implementation of
+ *                      struct drm_simple_display_pipe_funcs, or NULL
+ * @formats:		the device's supported display formats
+ * @format_count:	the number of entries in @formats
+ * @format_modifiers:	DRM format modifiers, or NULL
+ * @connector:		the DRM connector, or NULL
+ * Returns:
+ *	0 on success, or
+ *	a negative error code otherwise
+ *
+ * This function sets up the display pipeline for an initialized instance of
+ * struct drm_fbconv_modeset. For maximum compatibility with userspace, the
+ * provided list of formats should contain at least DRM_FORMAT_XRGB8888 and
+ * DRM_FORMAT_RGB565. The necessary conversion to the hardware's actual
+ * configuration can be performed by drm_fbconv_simple_display_pipe_update().
+ *
+ * The values for @funcs, @format_modifiers, and @connector should be NULL
+ * by default. Explicitly settings these parameters will only be helpful for
+ * refactoring an fbdev driver into a DRM driver.
+ */
+int
+drm_fbconv_modeset_setup_pipe(struct drm_fbconv_modeset *modeset,
+			      const struct drm_simple_display_pipe_funcs *funcs,
+			      const uint32_t *formats,
+			      unsigned int format_count,
+			      const uint64_t *format_modifiers,
+			      struct drm_connector *connector)
+{
+	int ret;
+
+	/* DRM porting note: Now let's enable the display pipeline. If
+	 * you're porting a framebuffer driver to DRM, you may want to
+	 * set the correct connector type or replace the simple display
+	 * pipeline with something more sophisticated.
+	 */
+
+	if (!funcs)
+		funcs = &simple_display_pipe_funcs;
+
+	if (!connector) {
+		connector = &modeset->connector;
+
+		ret = drm_connector_init(modeset->dev, connector,
+					 &connector_funcs,
+					 DRM_MODE_CONNECTOR_Unknown);
+		if (ret)
+			return ret;
+		drm_connector_helper_add(connector, &connector_helper_funcs);
+
+		ret = drm_connector_register(connector);
+		if (ret < 0)
+			return ret;
+
+	}
+
+	ret = drm_simple_display_pipe_init(modeset->dev, &modeset->pipe,
+					   funcs, formats, format_count,
+					   format_modifiers, connector);
+	if (ret)
+		return ret;
+
+	/* Final step: resetting the device's mode config creates
+	 * state for all objects in the mode-setting pipeline.
+	 */
+	drm_mode_config_reset(modeset->dev);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_fbconv_modeset_setup_pipe);
diff --git a/include/drm/drm_fbconv_helper.h b/include/drm/drm_fbconv_helper.h
index cbb13228c76c..79716af687c1 100644
--- a/include/drm/drm_fbconv_helper.h
+++ b/include/drm/drm_fbconv_helper.h
@@ -3,7 +3,11 @@
 #ifndef DRM_FBCONV_HELPER_H
 #define DRM_FBCONV_HELPER_H
 
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_encoder.h>
 #include <drm/drm_fourcc.h>
+#include <drm/drm_simple_kms_helper.h>
 
 struct drm_device;
 struct drm_display_mode;
@@ -51,4 +55,78 @@ void drm_fbconv_update_fb_var_screeninfo_from_mode(
 void drm_fbconv_init_fb_var_screeninfo_from_mode(
 	struct fb_var_screeninfo *var, const struct drm_display_mode *mode);
 
+/*
+ * Simple display pipe
+ */
+
+enum drm_mode_status
+drm_fbconv_simple_display_pipe_mode_valid(struct drm_crtc *crtc,
+					  const struct drm_display_mode *mode);
+
+bool drm_fbconv_simple_display_pipe_mode_fixup(
+	struct drm_crtc *crtc, const struct drm_display_mode *mode,
+	struct drm_display_mode *adjusted_mode);
+
+void
+drm_fbconv_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
+				      struct drm_crtc_state *crtc_state,
+				      struct drm_plane_state *plane_state);
+
+void
+drm_fbconv_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe);
+
+int
+drm_fbconv_simple_display_pipe_check(struct drm_simple_display_pipe *pipe,
+				     struct drm_plane_state *plane_state,
+				     struct drm_crtc_state *crtc_state);
+
+void
+drm_fbconv_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
+				      struct drm_plane_state *old_plane_state);
+
+int
+drm_fbconv_simple_display_pipe_prepare_fb(struct drm_simple_display_pipe *pipe,
+					  struct drm_plane_state *plane_state);
+
+void
+drm_fbconv_simple_display_pipe_cleanup_fb(struct drm_simple_display_pipe *pipe,
+					  struct drm_plane_state *plane_state);
+
+/*
+ * Modeset helpers
+ */
+
+/**
+ * struct drm_fbconv_modeset - contains state for fbconv modesetting
+ * @connector:	the DRM connector
+ * @pipe:	the modesetting pipeline
+ * @dev:	the DRM device
+ * @fb_info:	the fbdev driver's fb_info structure
+ */
+struct drm_fbconv_modeset {
+	struct drm_connector connector;
+	struct drm_simple_display_pipe pipe;
+
+	struct drm_device *dev;
+	struct fb_info *fb_info;
+};
+
+static inline struct drm_fbconv_modeset *drm_fbconv_modeset_of_pipe(
+	struct drm_simple_display_pipe *pipe)
+{
+	return container_of(pipe, struct drm_fbconv_modeset, pipe);
+}
+
+int drm_fbconv_modeset_init(struct drm_fbconv_modeset *modeset,
+			    struct drm_device *dev, struct fb_info *fb_info,
+			    unsigned int max_width, unsigned int max_height,
+			    unsigned int preferred_depth);
+void drm_fbconv_modeset_cleanup(struct drm_fbconv_modeset *modeset);
+
+int drm_fbconv_modeset_setup_pipe(
+	struct drm_fbconv_modeset *modeset,
+	const struct drm_simple_display_pipe_funcs *funcs,
+	const uint32_t *formats, unsigned int format_count,
+	const uint64_t *format_modifiers, struct drm_connector *connector);
+
 #endif
-- 
2.23.0

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

* [PATCH v2 07/15] drm/fbconv: Add modesetting infrastructure
@ 2019-10-14 14:04   ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

Modesetting for fbconv supports a single display pipeline with CRTC,
primary plane, encoder and connector. It's implementation is based on
struct drm_simple_display_pipe, which fits this use case nicely.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/drm_fbconv_helper.c | 382 ++++++++++++++++++++++++++++
 include/drm/drm_fbconv_helper.h     |  78 ++++++
 2 files changed, 460 insertions(+)

diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
index e5a58a361ae9..4cda1f15e072 100644
--- a/drivers/gpu/drm/drm_fbconv_helper.c
+++ b/drivers/gpu/drm/drm_fbconv_helper.c
@@ -4,8 +4,13 @@
 
 #include <linux/fb.h>
 
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_fbconv_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_modes.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_probe_helper.h>
 
 /*
  * Format conversion helpers
@@ -635,3 +640,380 @@ void drm_fbconv_init_fb_var_screeninfo_from_mode(
 	drm_fbconv_update_fb_var_screeninfo_from_mode(fb_var, mode);
 }
 EXPORT_SYMBOL(drm_fbconv_init_fb_var_screeninfo_from_mode);
+
+/*
+ * Connector
+ */
+
+static int connector_helper_get_modes(struct drm_connector *connector)
+{
+	return 0;
+}
+
+static int connector_helper_detect_ctx(struct drm_connector *connector,
+				       struct drm_modeset_acquire_ctx *ctx,
+				       bool force)
+{
+	return connector_status_connected;
+}
+
+static enum drm_mode_status connector_helper_mode_valid(
+	struct drm_connector *connector, struct drm_display_mode *mode)
+{
+	return MODE_OK;
+}
+
+static int connector_helper_atomic_check(struct drm_connector *connector,
+					 struct drm_atomic_state *state)
+{
+	return 0;
+}
+
+static void connector_helper_atomic_commit(struct drm_connector *connector,
+					   struct drm_connector_state *state)
+{ }
+
+static const struct drm_connector_helper_funcs connector_helper_funcs = {
+	.get_modes = connector_helper_get_modes,
+	.detect_ctx = connector_helper_detect_ctx,
+	.mode_valid = connector_helper_mode_valid,
+	.best_encoder = NULL, /* use default */
+	.atomic_best_encoder = NULL, /* use best_encoder instead */
+	.atomic_check = connector_helper_atomic_check,
+	.atomic_commit = connector_helper_atomic_commit
+};
+
+static enum drm_connector_status connector_detect(
+	struct drm_connector *connector, bool force)
+{
+	return connector_status_connected;
+}
+
+static void connector_force(struct drm_connector *connector)
+{ }
+
+static void connector_destroy(struct drm_connector *connector)
+{ }
+
+static int connector_atomic_set_property(struct drm_connector *connector,
+					 struct drm_connector_state *state,
+					 struct drm_property *property,
+					 uint64_t val)
+{
+	return -EINVAL;
+}
+
+static int connector_atomic_get_property(
+	struct drm_connector *connector,
+	const struct drm_connector_state *state, struct drm_property *property,
+	uint64_t *val)
+{
+	return -EINVAL;
+}
+
+static const struct drm_connector_funcs connector_funcs = {
+	.dpms = NULL, /* not used by atomic drivers */
+	.reset = drm_atomic_helper_connector_reset,
+	.detect = connector_detect,
+	.force = connector_force,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.set_property = NULL,
+	.late_register = NULL,
+	.early_unregister = NULL,
+	.destroy = connector_destroy,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+	.atomic_set_property = connector_atomic_set_property,
+	.atomic_get_property = connector_atomic_get_property,
+	.atomic_print_state = NULL
+};
+
+/*
+ * Simple display pipe
+ */
+
+/**
+ * drm_fbconv_simple_display_pipe_mode_valid - default implementation for
+ *	struct drm_simple_display_pipe_funcs.mode_valid
+ * @crtc:	the DRM CRTC structure
+ * @mode:	the display mode to validate
+ * Returns:
+ *	MODE_OK on success, or
+ *	a MODE constant otherwise
+ */
+enum drm_mode_status
+drm_fbconv_simple_display_pipe_mode_valid(struct drm_crtc *crtc,
+					  const struct drm_display_mode *mode)
+{
+	return MODE_OK;
+}
+EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_mode_valid);
+
+/**
+ * drm_fbconv_simple_display_pipe_mode_fixup - default implementation for
+ *	struct drm_simple_display_pipe_funcs.mode_fixup
+ * @crtc:		the DRM CRTC structure
+ * @mode:		the display mode
+ * @adjusted_mode:	the adjusted display mode
+ * Returns:
+ *	true on success, or
+ *	false otherwise
+ */
+bool drm_fbconv_simple_display_pipe_mode_fixup(
+	struct drm_crtc *crtc, const struct drm_display_mode *mode,
+	struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_mode_fixup);
+
+/**
+ * drm_fbconv_simple_display_pipe_enable - default implementation for
+ *	struct drm_simple_display_pipe_funcs.enable
+ * @pipe:		the display pipe structure
+ * @crtc_state:		the new CRTC state
+ * @plane_state:	the new plane state
+ */
+void
+drm_fbconv_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
+				      struct drm_crtc_state *crtc_state,
+				      struct drm_plane_state *plane_state)
+{ }
+EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_enable);
+
+/**
+ * drm_fbconv_simple_display_pipe_disable - default implementation for
+ *	struct drm_simple_display_pipe_funcs.disable
+ * @pipe:		the display pipe structure
+ */
+void
+drm_fbconv_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
+{ }
+EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_disable);
+
+/**
+ * drm_fbconv_simple_display_pipe_check - default implementation for
+ *	struct drm_simple_display_pipe_funcs.check
+ * @pipe:		the display pipe structure
+ * @plane_state:	the new plane state
+ * @crtc_state:		the new CRTC state
+ */
+int
+drm_fbconv_simple_display_pipe_check(struct drm_simple_display_pipe *pipe,
+				     struct drm_plane_state *plane_state,
+				     struct drm_crtc_state *crtc_state)
+{
+	return 0;
+}
+EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_check);
+
+/**
+ * drm_fbconv_simple_display_pipe_mode_update - default implementation for
+ *	struct drm_simple_display_pipe_funcs.update
+ * @pipe:		the display pipe structure
+ * @old_plane_state:	the old plane state
+ */
+void
+drm_fbconv_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
+				      struct drm_plane_state *old_plane_state)
+{ }
+EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_update);
+
+/**
+ * drm_fbconv_simple_display_pipe_prepare_fb - default implementation for
+ *	struct drm_simple_display_pipe_funcs.prepare_fb
+ * @pipe:		the display pipe structure
+ * @plane_state:	the new plane state
+ * Returns:
+ *	0 on success, or
+ *	a negative error code otherwise.
+ *
+ * The implementation of struct drm_simple_display_pipe_funcs.prepare_fb
+ * maps the framebuffer's buffer object and the fbdev's screen memory, if
+ * necessary. After converting the fbdev driver to DRM, only the buffer-object
+ * mapping should remaing. See drm_fbconv_simple_display_pipe_cleanup_fb() for
+ * the corresponding clean-up helper.
+ */
+int
+drm_fbconv_simple_display_pipe_prepare_fb(struct drm_simple_display_pipe *pipe,
+					  struct drm_plane_state *plane_state)
+{ }
+EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_prepare_fb);
+
+/**
+ * drm_fbconv_simple_display_pipe_cleanup_fb - default implementation for
+ *	struct drm_simple_display_pipe_funcs.cleanup_fb
+ * @pipe:		the display pipe structure
+ * @plane_state:	the old plane state
+ *
+ * This function cleans up the framebuffer state after a plane update. See
+ * drm_fbconv_simple_display_pipe_prepare_fb() for the corresponding prepare
+ * helper.
+ */
+void
+drm_fbconv_simple_display_pipe_cleanup_fb(struct drm_simple_display_pipe *pipe,
+					  struct drm_plane_state *plane_state)
+{ }
+
+static const struct drm_simple_display_pipe_funcs simple_display_pipe_funcs = {
+	.mode_valid = drm_fbconv_simple_display_pipe_mode_valid,
+	.mode_fixup = drm_fbconv_simple_display_pipe_mode_fixup,
+	.enable	    = drm_fbconv_simple_display_pipe_enable,
+	.disable    = drm_fbconv_simple_display_pipe_disable,
+	.check	    = drm_fbconv_simple_display_pipe_check,
+	.update	    = drm_fbconv_simple_display_pipe_update,
+	.prepare_fb = drm_fbconv_simple_display_pipe_prepare_fb,
+	.cleanup_fb = drm_fbconv_simple_display_pipe_cleanup_fb,
+};
+
+/*
+ * Mode config
+ */
+
+static enum drm_mode_status mode_config_mode_valid(
+	struct drm_device *dev, const struct drm_display_mode *mode)
+{
+	return MODE_OK;
+}
+
+static const struct drm_mode_config_funcs mode_config_funcs = {
+	.fb_create = drm_gem_fb_create_with_dirty,
+	.get_format_info = NULL,
+	/* DRM porting notes: the output_poll_changed callback is used by
+	 * fb helpers to implement fbdev emulation. If you're porting an
+	 * fbdev driver to DRM and enable fbdev emulation, this callback
+	 * will become useful.
+	 */
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
+	.mode_valid = mode_config_mode_valid,
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+	.atomic_state_alloc = NULL,
+	.atomic_state_clear = NULL,
+	.atomic_state_free = NULL
+};
+
+/**
+ * drm_fbconv_modeset_init - initializes an fbconv modesetting structure
+ * @modeset:		the fbconv modesetting structure to initialize
+ * @dev:		the DRM device
+ * @fb_info:		the fbdev driver's fb_info structure
+ * @max_width:		the maximum display width that is supported by
+ *                      the device
+ * @max_height:		the maximum display height that is supported by
+ *                      the device
+ * @preferred_depth:	the device's preferred color depth
+ * Returns:
+ *	0 on success, or
+ *	a negative error code otherwise
+ *
+ * This function initializes an instance of struct drm_fbconv_modeset. The
+ * supplied values for max_width, max_height, and max_depth should match the
+ * devices capabilities and be supported by the fbdev driver. DRM helpers
+ * will use these to auto-configure and validate display settings.
+ */
+int drm_fbconv_modeset_init(struct drm_fbconv_modeset *modeset,
+			    struct drm_device *dev, struct fb_info *fb_info,
+			    unsigned int max_width, unsigned int max_height,
+			    unsigned int preferred_depth)
+{
+	struct drm_mode_config *mode_config = &dev->mode_config;
+
+	modeset->dev = dev;
+	modeset->fb_info = fb_info;
+
+	drm_mode_config_init(dev);
+
+	mode_config->max_width = (int)max_width;
+	mode_config->max_height = (int)max_height;
+	mode_config->fb_base = fb_info->fix.smem_start;
+	mode_config->preferred_depth = preferred_depth;
+	mode_config->prefer_shadow_fbdev = true;
+	mode_config->funcs = &mode_config_funcs;
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_fbconv_modeset_init);
+
+/**
+ * drm_fbconv_modeset_cleanup - Cleans up an fbconv modesetting structure
+ * @modeset:	the fbconv modesetting structure to clean up
+ */
+void drm_fbconv_modeset_cleanup(struct drm_fbconv_modeset *modeset)
+{
+	drm_mode_config_cleanup(modeset->dev);
+}
+EXPORT_SYMBOL(drm_fbconv_modeset_cleanup);
+
+/**
+ * drm_fbconv_modeset_setup_pipe - sets up the display pipeline for fbconv
+ * @modeset:		an fbconv modesetting structure
+ * @funcs:		an implementation of
+ *                      struct drm_simple_display_pipe_funcs, or NULL
+ * @formats:		the device's supported display formats
+ * @format_count:	the number of entries in @formats
+ * @format_modifiers:	DRM format modifiers, or NULL
+ * @connector:		the DRM connector, or NULL
+ * Returns:
+ *	0 on success, or
+ *	a negative error code otherwise
+ *
+ * This function sets up the display pipeline for an initialized instance of
+ * struct drm_fbconv_modeset. For maximum compatibility with userspace, the
+ * provided list of formats should contain at least DRM_FORMAT_XRGB8888 and
+ * DRM_FORMAT_RGB565. The necessary conversion to the hardware's actual
+ * configuration can be performed by drm_fbconv_simple_display_pipe_update().
+ *
+ * The values for @funcs, @format_modifiers, and @connector should be NULL
+ * by default. Explicitly settings these parameters will only be helpful for
+ * refactoring an fbdev driver into a DRM driver.
+ */
+int
+drm_fbconv_modeset_setup_pipe(struct drm_fbconv_modeset *modeset,
+			      const struct drm_simple_display_pipe_funcs *funcs,
+			      const uint32_t *formats,
+			      unsigned int format_count,
+			      const uint64_t *format_modifiers,
+			      struct drm_connector *connector)
+{
+	int ret;
+
+	/* DRM porting note: Now let's enable the display pipeline. If
+	 * you're porting a framebuffer driver to DRM, you may want to
+	 * set the correct connector type or replace the simple display
+	 * pipeline with something more sophisticated.
+	 */
+
+	if (!funcs)
+		funcs = &simple_display_pipe_funcs;
+
+	if (!connector) {
+		connector = &modeset->connector;
+
+		ret = drm_connector_init(modeset->dev, connector,
+					 &connector_funcs,
+					 DRM_MODE_CONNECTOR_Unknown);
+		if (ret)
+			return ret;
+		drm_connector_helper_add(connector, &connector_helper_funcs);
+
+		ret = drm_connector_register(connector);
+		if (ret < 0)
+			return ret;
+
+	}
+
+	ret = drm_simple_display_pipe_init(modeset->dev, &modeset->pipe,
+					   funcs, formats, format_count,
+					   format_modifiers, connector);
+	if (ret)
+		return ret;
+
+	/* Final step: resetting the device's mode config creates
+	 * state for all objects in the mode-setting pipeline.
+	 */
+	drm_mode_config_reset(modeset->dev);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_fbconv_modeset_setup_pipe);
diff --git a/include/drm/drm_fbconv_helper.h b/include/drm/drm_fbconv_helper.h
index cbb13228c76c..79716af687c1 100644
--- a/include/drm/drm_fbconv_helper.h
+++ b/include/drm/drm_fbconv_helper.h
@@ -3,7 +3,11 @@
 #ifndef DRM_FBCONV_HELPER_H
 #define DRM_FBCONV_HELPER_H
 
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_encoder.h>
 #include <drm/drm_fourcc.h>
+#include <drm/drm_simple_kms_helper.h>
 
 struct drm_device;
 struct drm_display_mode;
@@ -51,4 +55,78 @@ void drm_fbconv_update_fb_var_screeninfo_from_mode(
 void drm_fbconv_init_fb_var_screeninfo_from_mode(
 	struct fb_var_screeninfo *var, const struct drm_display_mode *mode);
 
+/*
+ * Simple display pipe
+ */
+
+enum drm_mode_status
+drm_fbconv_simple_display_pipe_mode_valid(struct drm_crtc *crtc,
+					  const struct drm_display_mode *mode);
+
+bool drm_fbconv_simple_display_pipe_mode_fixup(
+	struct drm_crtc *crtc, const struct drm_display_mode *mode,
+	struct drm_display_mode *adjusted_mode);
+
+void
+drm_fbconv_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
+				      struct drm_crtc_state *crtc_state,
+				      struct drm_plane_state *plane_state);
+
+void
+drm_fbconv_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe);
+
+int
+drm_fbconv_simple_display_pipe_check(struct drm_simple_display_pipe *pipe,
+				     struct drm_plane_state *plane_state,
+				     struct drm_crtc_state *crtc_state);
+
+void
+drm_fbconv_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
+				      struct drm_plane_state *old_plane_state);
+
+int
+drm_fbconv_simple_display_pipe_prepare_fb(struct drm_simple_display_pipe *pipe,
+					  struct drm_plane_state *plane_state);
+
+void
+drm_fbconv_simple_display_pipe_cleanup_fb(struct drm_simple_display_pipe *pipe,
+					  struct drm_plane_state *plane_state);
+
+/*
+ * Modeset helpers
+ */
+
+/**
+ * struct drm_fbconv_modeset - contains state for fbconv modesetting
+ * @connector:	the DRM connector
+ * @pipe:	the modesetting pipeline
+ * @dev:	the DRM device
+ * @fb_info:	the fbdev driver's fb_info structure
+ */
+struct drm_fbconv_modeset {
+	struct drm_connector connector;
+	struct drm_simple_display_pipe pipe;
+
+	struct drm_device *dev;
+	struct fb_info *fb_info;
+};
+
+static inline struct drm_fbconv_modeset *drm_fbconv_modeset_of_pipe(
+	struct drm_simple_display_pipe *pipe)
+{
+	return container_of(pipe, struct drm_fbconv_modeset, pipe);
+}
+
+int drm_fbconv_modeset_init(struct drm_fbconv_modeset *modeset,
+			    struct drm_device *dev, struct fb_info *fb_info,
+			    unsigned int max_width, unsigned int max_height,
+			    unsigned int preferred_depth);
+void drm_fbconv_modeset_cleanup(struct drm_fbconv_modeset *modeset);
+
+int drm_fbconv_modeset_setup_pipe(
+	struct drm_fbconv_modeset *modeset,
+	const struct drm_simple_display_pipe_funcs *funcs,
+	const uint32_t *formats, unsigned int format_count,
+	const uint64_t *format_modifiers, struct drm_connector *connector);
+
 #endif
-- 
2.23.0

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

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

* [PATCH v2 08/15] drm/fbconv: Add plane-state check and update
  2019-10-14 14:04 ` Thomas Zimmermann
@ 2019-10-14 14:04   ` Thomas Zimmermann
  -1 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

For the update of the primary plane, we copy the content of a SHMEM buffer
object to the hardware's on-screen buffer; doing a format conversion if
necessary. This is able to support all combinations of framebuffers and
hardware, and should work with any fbdev driver.

Occasionally, fbdev drivers require an update of the hardware's gamma
tables to not show distorted colors. We also do this during the plane
update.

There's no support for horizontal panning, as fbdev drivers vary widely
in their capability to do this. Vertical panning is supported to the
extend allowed by available video ram. However, this whole functionality
is more interesting for porting drivers and not directly required by
fbconv itself.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/Kconfig             |   1 +
 drivers/gpu/drm/drm_fbconv_helper.c | 500 +++++++++++++++++++++++++++-
 include/drm/drm_fbconv_helper.h     |   9 +
 3 files changed, 507 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index ed689201ec81..2ce7749c3157 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -160,6 +160,7 @@ config DRM_DP_CEC
 config DRM_FBCONV_HELPER
 	tristate "Enable fbdev conversion helpers"
 	depends on DRM
+	select DRM_GEM_SHMEM_HELPER
 	help
 	  Provides helpers for running DRM on top of fbdev drivers. Choose
 	  this option if you're converting an fbdev driver to DRM. The
diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
index 4cda1f15e072..cf218016ac05 100644
--- a/drivers/gpu/drm/drm_fbconv_helper.c
+++ b/drivers/gpu/drm/drm_fbconv_helper.c
@@ -5,12 +5,17 @@
 #include <linux/fb.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_damage_helper.h>
 #include <drm/drm_fbconv_helper.h>
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_format_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
 #include <drm/drm_modes.h>
 #include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
 
 /*
  * Format conversion helpers
@@ -728,10 +733,192 @@ static const struct drm_connector_funcs connector_funcs = {
 	.atomic_print_state = NULL
 };
 
+/*
+ * Colormap updates
+ */
+
+/* provides a default colormap for palette modes */
+static int create_palette_cmap(struct fb_cmap *cmap,
+			       const struct fb_var_screeninfo *fb_var)
+{
+	__u32 len;
+	const struct fb_cmap *default_cmap;
+	int ret;
+
+	len = max3(fb_var->red.length,
+		   fb_var->green.length,
+		   fb_var->blue.length);
+	if (!len || (len > 31)) {
+		DRM_ERROR("fbconv: Gamma LUT has invalid bit count of %u\n",
+			  (unsigned int)len);
+		return -EINVAL;
+	}
+
+	default_cmap = fb_default_cmap(1ul << len);
+	if (!default_cmap) {
+		DRM_ERROR("fbconv: fb_default_cmap() failed\n");
+		return -EINVAL;
+	}
+
+	ret = fb_alloc_cmap(cmap, default_cmap->len, 0);
+	if (ret) {
+		DRM_ERROR("fbconv: fb_alloc_cmap() failed: %d\n", ret);
+		return ret;
+	}
+	ret = fb_copy_cmap(default_cmap, cmap);
+	if (ret) {
+		DRM_ERROR("fbconv: fb_copy_cmap() failed: %d\n", ret);
+		goto err_fb_dealloc_cmap;
+	}
+
+	return 0;
+
+err_fb_dealloc_cmap:
+	fb_dealloc_cmap(cmap);
+	return ret;
+}
+
+/* provides a linear color ramp for RGB modes */
+static int create_linear_cmap(struct fb_cmap *cmap,
+			      const struct fb_var_screeninfo *fb_var)
+{
+	int ret;
+	size_t i;
+	unsigned int j;
+	u16 *lut;
+	u16 incr;
+	u16 *gamma_lut[3];
+	__u32 len;
+	const __u32 gamma_len[3] = {
+		fb_var->red.length,
+		fb_var->green.length,
+		fb_var->blue.length
+	};
+
+	len = max3(gamma_len[0], gamma_len[1], gamma_len[2]);
+	if (!len || (len > 8)) {
+		DRM_ERROR("fbconv: gamma LUT has invalid bit count of %u\n",
+			  (unsigned int)len);
+		return -EINVAL;
+	}
+
+	ret = fb_alloc_cmap(cmap, 1ul << len, 0);
+	if (ret) {
+		DRM_ERROR("fbconv: fb_alloc_cmap() failed: %d\n", ret);
+		return ret;
+	}
+
+	gamma_lut[0] = cmap->red;
+	gamma_lut[1] = cmap->green;
+	gamma_lut[2] = cmap->blue;
+
+	for (i = 0; i < ARRAY_SIZE(gamma_lut); ++i) {
+		lut = gamma_lut[i];
+		len = 1ul << gamma_len[i];
+		incr = 0x10000u >> gamma_len[i];
+		for (j = 0; j < len; ++j, ++lut)
+			*lut = incr * j;
+
+		/* In order to have no intensity at index 0 and full
+		 * intensity at the final index of the LUT, we fix-up the
+		 * table's final entries. The fix-up makes intensity grow
+		 * faster near the final entries of the gamma LUT. The human
+		 * eye is more sensitive to changes to the lower intensities,
+		 * so this is probably not directly perceivable.
+		 */
+		for (lut -= gamma_len[i], j = gamma_len[i]; j > 0; ++lut) {
+			--j;
+			/* subtract 1 to not overflow the LUT's final entry */
+			*lut += (incr >> j) - 1;
+		}
+	}
+
+	return 0;
+}
+
+static int set_cmap(struct fb_info *fb_info)
+{
+	struct fb_cmap cmap;
+	int ret;
+
+	memset(&cmap, 0, sizeof(cmap));
+
+	switch (fb_info->fix.visual) {
+	case FB_VISUAL_PSEUDOCOLOR:
+		ret = create_palette_cmap(&cmap, &fb_info->var);
+		break;
+	case FB_VISUAL_DIRECTCOLOR:
+		ret = create_linear_cmap(&cmap, &fb_info->var);
+		break;
+	default:
+		return 0;
+	}
+	if (ret)
+		return ret;
+
+	ret = fb_set_cmap(&cmap, fb_info);
+	if (ret) {
+		DRM_ERROR("fbconv: fb_set_cmap() failed: %d\n", ret);
+		goto err_fb_dealloc_cmap;
+	}
+	fb_dealloc_cmap(&cmap);
+
+	return 0;
+
+err_fb_dealloc_cmap:
+	fb_dealloc_cmap(&cmap);
+	return ret;
+}
+
 /*
  * Simple display pipe
  */
 
+static void drm_fbconv_update_fb_var_screeninfo_from_crtc_state(
+	struct fb_var_screeninfo *fb_var, struct drm_crtc_state *crtc_state)
+{
+	drm_fbconv_update_fb_var_screeninfo_from_mode(
+		fb_var, &crtc_state->adjusted_mode);
+}
+
+static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
+	struct fb_var_screeninfo *fb_var, struct drm_framebuffer *fb,
+	size_t vram_size)
+{
+	unsigned int width, pitch;
+	uint64_t cpp, lines;
+	int ret;
+
+	/* Our virtual screen covers all the graphics memory (sans some
+	 * trailing bytes). This allows for setting the scanout buffer's
+	 * address with fb_pan_display().
+	 */
+
+	width = fb->pitches[0];
+	cpp = fb->format[0].cpp[0];
+	do_div(width, cpp);
+
+	if (width > (__u32)-1)
+		return -EINVAL; /* would overflow fb_var->xres_virtual */
+
+	pitch = fb->pitches[0];
+	lines = vram_size;
+	do_div(lines, pitch);
+
+	if (lines > (__u32)-1)
+		return -EINVAL; /* would overflow fb_var->yres_virtual */
+
+	fb_var->xres_virtual = width;
+	fb_var->yres_virtual = lines;
+
+	ret = drm_fbconv_update_fb_var_screeninfo_from_format(
+		fb_var, fb->format[0].format);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 /**
  * drm_fbconv_simple_display_pipe_mode_valid - default implementation for
  *	struct drm_simple_display_pipe_funcs.mode_valid
@@ -767,6 +954,52 @@ bool drm_fbconv_simple_display_pipe_mode_fixup(
 }
 EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_mode_fixup);
 
+/**
+ * drm_fbconv_blit_rect - copy an area of pixel data from a framebuffer
+ *	to the hardware buffer
+ * @dst:	the on-screen hardware buffer
+ * @vaddr:	the source buffer in kernel address space
+ * @fb:		the framebuffer of the source buffer
+ * @rect:	the area to copy
+ * Returns:
+ *	0 on success, or
+ *	a negative error code otherwise.
+ *
+ * This function copies the pixel data from a DRM framebuffer to a hardware
+ * buffer; doing necessary format conversion in the process. Not all
+ * combinations of source and destination formats are currently supported.
+ */
+int drm_fbconv_blit_rect(void *dst, void *vaddr, struct drm_framebuffer *fb,
+			 struct drm_rect *rect)
+{
+	struct drm_device *dev = fb->dev;
+
+	if (!vaddr)
+		return 0; /* no framebuffer set for plane; no error */
+
+	if (dev->mode_config.preferred_depth = (fb->format->cpp[0] * 8))
+		drm_fb_memcpy_dstclip(dst, vaddr, fb, rect);
+
+	else if (fb->format->cpp[0] = 4 &&
+		 dev->mode_config.preferred_depth = 16)
+		drm_fb_xrgb8888_to_rgb565_dstclip(dst, fb->pitches[0],
+						  vaddr, fb, rect, false);
+
+	else if (fb->format->cpp[0] = 4 &&
+		 dev->mode_config.preferred_depth = 24)
+		drm_fb_xrgb8888_to_rgb888_dstclip(dst, fb->pitches[0],
+						  vaddr, fb, rect);
+
+	else {
+		/* TODO: add the missing conversion */
+		DRM_ERROR("fbconv: mismatching pixel formats\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_fbconv_blit_rect);
+
 /**
  * drm_fbconv_simple_display_pipe_enable - default implementation for
  *	struct drm_simple_display_pipe_funcs.enable
@@ -803,6 +1036,100 @@ drm_fbconv_simple_display_pipe_check(struct drm_simple_display_pipe *pipe,
 				     struct drm_plane_state *plane_state,
 				     struct drm_crtc_state *crtc_state)
 {
+	struct drm_fbconv_modeset *modeset;
+	struct fb_videomode fb_mode, fb_var_mode;
+	int ret;
+	struct fb_var_screeninfo fb_var;
+
+	/*
+	 * CRTC check
+	 */
+
+	modeset = drm_fbconv_modeset_of_pipe(pipe);
+
+	/* DRM porting notes: when fbcon takes over the console, it regularly
+	 * changes the display mode. Where's apparently no way to detect this
+	 * directly from fbcon itself. DRM's mode information might therefore
+	 * be out of data, after it takes over the display at a later time.
+	 * Here, we test the CRTC's current mode with the fbdev state. If they
+	 * do not match, we request a mode change from DRM. If you port an
+	 * fbdev driver to DRM, you can remove this code section, DRM will
+	 * be in full control of the display device and doesn't have to react
+	 * to changes from external sources.
+	 */
+
+	if (!crtc_state->mode_changed && crtc_state->adjusted_mode.clock) {
+		drm_fbconv_init_fb_videomode_from_mode(
+			&fb_mode, &crtc_state->adjusted_mode);
+		fb_var_to_videomode(&fb_var_mode, &modeset->fb_info->var);
+		if (!fb_mode_is_equal(&fb_mode, &fb_var_mode))
+			crtc_state->mode_changed = true;
+	}
+
+	/* TODO: The vblank interrupt is currently not supported. We set
+	 * the corresponding flag as a workaround. Some fbdev drivers
+	 * support FBIO_WAITFORVSYNC, which we might use for querying
+	 * vblanks.
+	 *
+	 * DRM porting notes: if you're porting an fbdev driver to DRM,
+	 * remove this line and instead signal a vblank event from the
+	 * interrupt handler.
+	 */
+	crtc_state->no_vblank = true;
+
+	/*
+	 * Plane check
+	 */
+
+	if (!plane_state->crtc)
+		return 0;
+
+	ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
+						  1 << 16, 1 << 16,
+						  false, true);
+	if (ret < 0)
+		return ret;
+
+	if (!plane_state->visible || !plane_state->fb)
+		return 0;
+
+	/* Virtual screen sizes are not supported.
+	 */
+
+	if (drm_rect_width(&plane_state->dst) != plane_state->fb->width ||
+	    drm_rect_height(&plane_state->dst) != plane_state->fb->height) {
+		DRM_ERROR("fbconv: virtual screen sizes not supported\n");
+		return -EINVAL;
+	}
+	if (plane_state->dst.x1 || plane_state->dst.y1) {
+		DRM_ERROR("fbconv: virtual screen offset not supported\n");
+		return -EINVAL;
+	}
+
+	/* Pixel formats have to be compatible with fbdev. This is
+	 * usually some variation of XRGB.
+	 */
+
+	if (!pipe->plane.state ||
+	    !pipe->plane.state->fb ||
+	    pipe->plane.state->fb->format[0].format !+		plane_state->fb->format[0].format) {
+
+		if (modeset->fb_info->fbops->fb_check_var) {
+			memcpy(&fb_var, &modeset->fb_info->var,
+			       sizeof(fb_var));
+			drm_fbconv_update_fb_var_screeninfo_from_crtc_state(
+				&fb_var, crtc_state);
+			drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
+				&fb_var, plane_state->fb,
+				modeset->fb_info->fix.smem_len);
+			ret = modeset->fb_info->fbops->fb_check_var(
+				&fb_var, modeset->fb_info);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_check);
@@ -816,7 +1143,119 @@ EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_check);
 void
 drm_fbconv_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
 				      struct drm_plane_state *old_plane_state)
-{ }
+{
+	struct drm_fbconv_modeset *modeset;
+	uint32_t format;
+	struct fb_var_screeninfo fb_var;
+	int ret;
+	bool do_blit;
+	struct drm_rect rect;
+	struct drm_crtc *crtc = &pipe->crtc;
+
+	/*
+	 * Plane update
+	 */
+
+	modeset = drm_fbconv_modeset_of_pipe(pipe);
+
+	format = drm_fbconv_format_of_fb_info(modeset->fb_info);
+
+	/* DRM porting notes: Some fbdev drivers report alpha channels for
+	 * their framebuffer, even though they don't support transparent
+	 * primary planes. For the format test below, we ignore the alpha
+	 * channel and use the non-transparent equivalent of the pixel format.
+	 * If you're porting an fbdev driver to DRM, remove this switch
+	 * statement and report the correct format instead.
+	 */
+	switch (format) {
+	case DRM_FORMAT_ARGB8888:
+		format = DRM_FORMAT_XRGB8888;
+		break;
+	case DRM_FORMAT_ABGR8888:
+		format = DRM_FORMAT_XBGR8888;
+		break;
+	case DRM_FORMAT_RGBA8888:
+		format = DRM_FORMAT_RGBX8888;
+		break;
+	case DRM_FORMAT_BGRA8888:
+		format = DRM_FORMAT_BGRX8888;
+		break;
+	default:
+		break;
+	}
+
+	if (!pipe->plane.state->fb) {
+		/* No framebuffer installed; blank display. */
+		fb_blank(modeset->fb_info, FB_BLANK_NORMAL);
+		return;
+	}
+
+	if ((format != pipe->plane.state->fb->format[0].format) ||
+	    (modeset->fb_info->var.xres_virtual !+	    pipe->plane.state->fb->width)) {
+
+		/* Pixel format changed, update fb_info accordingly
+		 */
+
+		memcpy(&fb_var, &modeset->fb_info->var, sizeof(fb_var));
+		ret = drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
+			&fb_var, pipe->plane.state->fb,
+			modeset->fb_info->fix.smem_len);
+		if (ret)
+			return;
+
+		fb_var.activate = FB_ACTIVATE_NOW;
+
+		ret = fb_set_var(modeset->fb_info, &fb_var);
+		if (ret) {
+			DRM_ERROR("fbconv: fb_set_var() failed: %d\n", ret);
+			return;
+		}
+	}
+
+	if (!old_plane_state->fb || /* first-time update */
+	    (format != pipe->plane.state->fb->format[0].format)) {
+
+		/* DRM porting notes: Below we set the LUTs for palette and
+		 * gamma correction. This is required by some fbdev drivers,
+		 * such as nvidiafb and atyfb, which don't initialize the
+		 * table to pass-through the framebuffer values unchanged. This
+		 * is actually CRTC state, but the respective function
+		 * crtc_helper_mode_set_nofb() is only called when a CRTC
+		 * property changes, changes in color formats are not handled
+		 * there. When you're porting a fbdev driver to DRM, remove
+		 * the call. Gamma LUTs are CRTC properties and should be
+		 * handled there. Either remove gamma correction or set up
+		 * the respective CRTC properties for userspace.
+		 */
+		set_cmap(modeset->fb_info);
+	}
+
+	memcpy(&fb_var, &modeset->fb_info->var, sizeof(fb_var));
+	fb_var.xoffset = 0;
+	fb_var.yoffset = 0;
+
+	ret = fb_pan_display(modeset->fb_info, &fb_var);
+	if (ret) {
+		DRM_ERROR("fbconv: fb_pan_display() failed: %d\n", ret);
+		return;
+	}
+
+	do_blit = drm_atomic_helper_damage_merged(old_plane_state,
+						  pipe->plane.state,
+						  &rect);
+	if (do_blit)
+		drm_fbconv_blit_rect(modeset->blit.screen_base,
+				     modeset->blit.vmap, pipe->plane.state->fb,
+				     &rect);
+
+	if (crtc->state->event) {
+		spin_lock_irq(&crtc->dev->event_lock);
+		drm_crtc_send_vblank_event(crtc, crtc->state->event);
+		crtc->state->event = NULL;
+		spin_unlock_irq(&crtc->dev->event_lock);
+	}
+}
 EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_update);
 
 /**
@@ -837,7 +1276,48 @@ EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_update);
 int
 drm_fbconv_simple_display_pipe_prepare_fb(struct drm_simple_display_pipe *pipe,
 					  struct drm_plane_state *plane_state)
-{ }
+{
+	struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
+	struct fb_info *fb_info = modeset->fb_info;
+	struct drm_framebuffer *fb = plane_state->fb;
+	bool unmap_screen_base = false;
+	void *screen_base;
+	void *vmap;
+	int ret;
+
+	if (!fb)
+		return 0;
+
+	screen_base = fb_info->screen_base;
+
+	if (!screen_base) {
+		screen_base = ioremap(fb_info->fix.smem_start,
+				      fb_info->fix.smem_len);
+		if (!screen_base) {
+			DRM_ERROR("fbconv: ioremap() failed\n");
+			return -ENOMEM;
+		}
+		unmap_screen_base = true;
+	}
+
+	vmap = drm_gem_shmem_vmap(fb->obj[0]);
+	if (!vmap) {
+		DRM_ERROR("fbconv: drm_gem_shmem_vmap() failed\n");
+		ret = -ENOMEM;
+		goto err_iounmap;
+	}
+
+	modeset->blit.vmap = vmap;
+	modeset->blit.screen_base = screen_base;
+	modeset->blit.unmap_screen_base = unmap_screen_base;
+
+	return 0;
+
+err_iounmap:
+	if (unmap_screen_base)
+		iounmap(screen_base);
+	return ret;
+}
 EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_prepare_fb);
 
 /**
@@ -853,7 +1333,21 @@ EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_prepare_fb);
 void
 drm_fbconv_simple_display_pipe_cleanup_fb(struct drm_simple_display_pipe *pipe,
 					  struct drm_plane_state *plane_state)
-{ }
+{
+	struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
+	struct drm_framebuffer *fb = plane_state->fb;
+
+	if (!fb)
+		return;
+
+	drm_gem_shmem_vunmap(fb->obj[0], modeset->blit.vmap);
+
+	if (modeset->blit.unmap_screen_base)
+		iounmap(modeset->blit.screen_base);
+
+	memset(&modeset->blit, 0, sizeof(modeset->blit));
+}
+EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_cleanup_fb);
 
 static const struct drm_simple_display_pipe_funcs simple_display_pipe_funcs = {
 	.mode_valid = drm_fbconv_simple_display_pipe_mode_valid,
diff --git a/include/drm/drm_fbconv_helper.h b/include/drm/drm_fbconv_helper.h
index 79716af687c1..3e62b5e80af6 100644
--- a/include/drm/drm_fbconv_helper.h
+++ b/include/drm/drm_fbconv_helper.h
@@ -92,6 +92,9 @@ void
 drm_fbconv_simple_display_pipe_cleanup_fb(struct drm_simple_display_pipe *pipe,
 					  struct drm_plane_state *plane_state);
 
+int drm_fbconv_blit_rect(void *dst, void *vaddr, struct drm_framebuffer *fb,
+			 struct drm_rect *rect);
+
 /*
  * Modeset helpers
  */
@@ -107,6 +110,12 @@ struct drm_fbconv_modeset {
 	struct drm_connector connector;
 	struct drm_simple_display_pipe pipe;
 
+	struct {
+		void *vmap;
+		void *screen_base;
+		bool unmap_screen_base;
+	} blit;
+
 	struct drm_device *dev;
 	struct fb_info *fb_info;
 };
-- 
2.23.0

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

* [PATCH v2 08/15] drm/fbconv: Add plane-state check and update
@ 2019-10-14 14:04   ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

For the update of the primary plane, we copy the content of a SHMEM buffer
object to the hardware's on-screen buffer; doing a format conversion if
necessary. This is able to support all combinations of framebuffers and
hardware, and should work with any fbdev driver.

Occasionally, fbdev drivers require an update of the hardware's gamma
tables to not show distorted colors. We also do this during the plane
update.

There's no support for horizontal panning, as fbdev drivers vary widely
in their capability to do this. Vertical panning is supported to the
extend allowed by available video ram. However, this whole functionality
is more interesting for porting drivers and not directly required by
fbconv itself.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/Kconfig             |   1 +
 drivers/gpu/drm/drm_fbconv_helper.c | 500 +++++++++++++++++++++++++++-
 include/drm/drm_fbconv_helper.h     |   9 +
 3 files changed, 507 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index ed689201ec81..2ce7749c3157 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -160,6 +160,7 @@ config DRM_DP_CEC
 config DRM_FBCONV_HELPER
 	tristate "Enable fbdev conversion helpers"
 	depends on DRM
+	select DRM_GEM_SHMEM_HELPER
 	help
 	  Provides helpers for running DRM on top of fbdev drivers. Choose
 	  this option if you're converting an fbdev driver to DRM. The
diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
index 4cda1f15e072..cf218016ac05 100644
--- a/drivers/gpu/drm/drm_fbconv_helper.c
+++ b/drivers/gpu/drm/drm_fbconv_helper.c
@@ -5,12 +5,17 @@
 #include <linux/fb.h>
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_damage_helper.h>
 #include <drm/drm_fbconv_helper.h>
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_format_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_shmem_helper.h>
 #include <drm/drm_modes.h>
 #include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
 
 /*
  * Format conversion helpers
@@ -728,10 +733,192 @@ static const struct drm_connector_funcs connector_funcs = {
 	.atomic_print_state = NULL
 };
 
+/*
+ * Colormap updates
+ */
+
+/* provides a default colormap for palette modes */
+static int create_palette_cmap(struct fb_cmap *cmap,
+			       const struct fb_var_screeninfo *fb_var)
+{
+	__u32 len;
+	const struct fb_cmap *default_cmap;
+	int ret;
+
+	len = max3(fb_var->red.length,
+		   fb_var->green.length,
+		   fb_var->blue.length);
+	if (!len || (len > 31)) {
+		DRM_ERROR("fbconv: Gamma LUT has invalid bit count of %u\n",
+			  (unsigned int)len);
+		return -EINVAL;
+	}
+
+	default_cmap = fb_default_cmap(1ul << len);
+	if (!default_cmap) {
+		DRM_ERROR("fbconv: fb_default_cmap() failed\n");
+		return -EINVAL;
+	}
+
+	ret = fb_alloc_cmap(cmap, default_cmap->len, 0);
+	if (ret) {
+		DRM_ERROR("fbconv: fb_alloc_cmap() failed: %d\n", ret);
+		return ret;
+	}
+	ret = fb_copy_cmap(default_cmap, cmap);
+	if (ret) {
+		DRM_ERROR("fbconv: fb_copy_cmap() failed: %d\n", ret);
+		goto err_fb_dealloc_cmap;
+	}
+
+	return 0;
+
+err_fb_dealloc_cmap:
+	fb_dealloc_cmap(cmap);
+	return ret;
+}
+
+/* provides a linear color ramp for RGB modes */
+static int create_linear_cmap(struct fb_cmap *cmap,
+			      const struct fb_var_screeninfo *fb_var)
+{
+	int ret;
+	size_t i;
+	unsigned int j;
+	u16 *lut;
+	u16 incr;
+	u16 *gamma_lut[3];
+	__u32 len;
+	const __u32 gamma_len[3] = {
+		fb_var->red.length,
+		fb_var->green.length,
+		fb_var->blue.length
+	};
+
+	len = max3(gamma_len[0], gamma_len[1], gamma_len[2]);
+	if (!len || (len > 8)) {
+		DRM_ERROR("fbconv: gamma LUT has invalid bit count of %u\n",
+			  (unsigned int)len);
+		return -EINVAL;
+	}
+
+	ret = fb_alloc_cmap(cmap, 1ul << len, 0);
+	if (ret) {
+		DRM_ERROR("fbconv: fb_alloc_cmap() failed: %d\n", ret);
+		return ret;
+	}
+
+	gamma_lut[0] = cmap->red;
+	gamma_lut[1] = cmap->green;
+	gamma_lut[2] = cmap->blue;
+
+	for (i = 0; i < ARRAY_SIZE(gamma_lut); ++i) {
+		lut = gamma_lut[i];
+		len = 1ul << gamma_len[i];
+		incr = 0x10000u >> gamma_len[i];
+		for (j = 0; j < len; ++j, ++lut)
+			*lut = incr * j;
+
+		/* In order to have no intensity at index 0 and full
+		 * intensity at the final index of the LUT, we fix-up the
+		 * table's final entries. The fix-up makes intensity grow
+		 * faster near the final entries of the gamma LUT. The human
+		 * eye is more sensitive to changes to the lower intensities,
+		 * so this is probably not directly perceivable.
+		 */
+		for (lut -= gamma_len[i], j = gamma_len[i]; j > 0; ++lut) {
+			--j;
+			/* subtract 1 to not overflow the LUT's final entry */
+			*lut += (incr >> j) - 1;
+		}
+	}
+
+	return 0;
+}
+
+static int set_cmap(struct fb_info *fb_info)
+{
+	struct fb_cmap cmap;
+	int ret;
+
+	memset(&cmap, 0, sizeof(cmap));
+
+	switch (fb_info->fix.visual) {
+	case FB_VISUAL_PSEUDOCOLOR:
+		ret = create_palette_cmap(&cmap, &fb_info->var);
+		break;
+	case FB_VISUAL_DIRECTCOLOR:
+		ret = create_linear_cmap(&cmap, &fb_info->var);
+		break;
+	default:
+		return 0;
+	}
+	if (ret)
+		return ret;
+
+	ret = fb_set_cmap(&cmap, fb_info);
+	if (ret) {
+		DRM_ERROR("fbconv: fb_set_cmap() failed: %d\n", ret);
+		goto err_fb_dealloc_cmap;
+	}
+	fb_dealloc_cmap(&cmap);
+
+	return 0;
+
+err_fb_dealloc_cmap:
+	fb_dealloc_cmap(&cmap);
+	return ret;
+}
+
 /*
  * Simple display pipe
  */
 
+static void drm_fbconv_update_fb_var_screeninfo_from_crtc_state(
+	struct fb_var_screeninfo *fb_var, struct drm_crtc_state *crtc_state)
+{
+	drm_fbconv_update_fb_var_screeninfo_from_mode(
+		fb_var, &crtc_state->adjusted_mode);
+}
+
+static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
+	struct fb_var_screeninfo *fb_var, struct drm_framebuffer *fb,
+	size_t vram_size)
+{
+	unsigned int width, pitch;
+	uint64_t cpp, lines;
+	int ret;
+
+	/* Our virtual screen covers all the graphics memory (sans some
+	 * trailing bytes). This allows for setting the scanout buffer's
+	 * address with fb_pan_display().
+	 */
+
+	width = fb->pitches[0];
+	cpp = fb->format[0].cpp[0];
+	do_div(width, cpp);
+
+	if (width > (__u32)-1)
+		return -EINVAL; /* would overflow fb_var->xres_virtual */
+
+	pitch = fb->pitches[0];
+	lines = vram_size;
+	do_div(lines, pitch);
+
+	if (lines > (__u32)-1)
+		return -EINVAL; /* would overflow fb_var->yres_virtual */
+
+	fb_var->xres_virtual = width;
+	fb_var->yres_virtual = lines;
+
+	ret = drm_fbconv_update_fb_var_screeninfo_from_format(
+		fb_var, fb->format[0].format);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 /**
  * drm_fbconv_simple_display_pipe_mode_valid - default implementation for
  *	struct drm_simple_display_pipe_funcs.mode_valid
@@ -767,6 +954,52 @@ bool drm_fbconv_simple_display_pipe_mode_fixup(
 }
 EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_mode_fixup);
 
+/**
+ * drm_fbconv_blit_rect - copy an area of pixel data from a framebuffer
+ *	to the hardware buffer
+ * @dst:	the on-screen hardware buffer
+ * @vaddr:	the source buffer in kernel address space
+ * @fb:		the framebuffer of the source buffer
+ * @rect:	the area to copy
+ * Returns:
+ *	0 on success, or
+ *	a negative error code otherwise.
+ *
+ * This function copies the pixel data from a DRM framebuffer to a hardware
+ * buffer; doing necessary format conversion in the process. Not all
+ * combinations of source and destination formats are currently supported.
+ */
+int drm_fbconv_blit_rect(void *dst, void *vaddr, struct drm_framebuffer *fb,
+			 struct drm_rect *rect)
+{
+	struct drm_device *dev = fb->dev;
+
+	if (!vaddr)
+		return 0; /* no framebuffer set for plane; no error */
+
+	if (dev->mode_config.preferred_depth == (fb->format->cpp[0] * 8))
+		drm_fb_memcpy_dstclip(dst, vaddr, fb, rect);
+
+	else if (fb->format->cpp[0] == 4 &&
+		 dev->mode_config.preferred_depth == 16)
+		drm_fb_xrgb8888_to_rgb565_dstclip(dst, fb->pitches[0],
+						  vaddr, fb, rect, false);
+
+	else if (fb->format->cpp[0] == 4 &&
+		 dev->mode_config.preferred_depth == 24)
+		drm_fb_xrgb8888_to_rgb888_dstclip(dst, fb->pitches[0],
+						  vaddr, fb, rect);
+
+	else {
+		/* TODO: add the missing conversion */
+		DRM_ERROR("fbconv: mismatching pixel formats\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_fbconv_blit_rect);
+
 /**
  * drm_fbconv_simple_display_pipe_enable - default implementation for
  *	struct drm_simple_display_pipe_funcs.enable
@@ -803,6 +1036,100 @@ drm_fbconv_simple_display_pipe_check(struct drm_simple_display_pipe *pipe,
 				     struct drm_plane_state *plane_state,
 				     struct drm_crtc_state *crtc_state)
 {
+	struct drm_fbconv_modeset *modeset;
+	struct fb_videomode fb_mode, fb_var_mode;
+	int ret;
+	struct fb_var_screeninfo fb_var;
+
+	/*
+	 * CRTC check
+	 */
+
+	modeset = drm_fbconv_modeset_of_pipe(pipe);
+
+	/* DRM porting notes: when fbcon takes over the console, it regularly
+	 * changes the display mode. Where's apparently no way to detect this
+	 * directly from fbcon itself. DRM's mode information might therefore
+	 * be out of data, after it takes over the display at a later time.
+	 * Here, we test the CRTC's current mode with the fbdev state. If they
+	 * do not match, we request a mode change from DRM. If you port an
+	 * fbdev driver to DRM, you can remove this code section, DRM will
+	 * be in full control of the display device and doesn't have to react
+	 * to changes from external sources.
+	 */
+
+	if (!crtc_state->mode_changed && crtc_state->adjusted_mode.clock) {
+		drm_fbconv_init_fb_videomode_from_mode(
+			&fb_mode, &crtc_state->adjusted_mode);
+		fb_var_to_videomode(&fb_var_mode, &modeset->fb_info->var);
+		if (!fb_mode_is_equal(&fb_mode, &fb_var_mode))
+			crtc_state->mode_changed = true;
+	}
+
+	/* TODO: The vblank interrupt is currently not supported. We set
+	 * the corresponding flag as a workaround. Some fbdev drivers
+	 * support FBIO_WAITFORVSYNC, which we might use for querying
+	 * vblanks.
+	 *
+	 * DRM porting notes: if you're porting an fbdev driver to DRM,
+	 * remove this line and instead signal a vblank event from the
+	 * interrupt handler.
+	 */
+	crtc_state->no_vblank = true;
+
+	/*
+	 * Plane check
+	 */
+
+	if (!plane_state->crtc)
+		return 0;
+
+	ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
+						  1 << 16, 1 << 16,
+						  false, true);
+	if (ret < 0)
+		return ret;
+
+	if (!plane_state->visible || !plane_state->fb)
+		return 0;
+
+	/* Virtual screen sizes are not supported.
+	 */
+
+	if (drm_rect_width(&plane_state->dst) != plane_state->fb->width ||
+	    drm_rect_height(&plane_state->dst) != plane_state->fb->height) {
+		DRM_ERROR("fbconv: virtual screen sizes not supported\n");
+		return -EINVAL;
+	}
+	if (plane_state->dst.x1 || plane_state->dst.y1) {
+		DRM_ERROR("fbconv: virtual screen offset not supported\n");
+		return -EINVAL;
+	}
+
+	/* Pixel formats have to be compatible with fbdev. This is
+	 * usually some variation of XRGB.
+	 */
+
+	if (!pipe->plane.state ||
+	    !pipe->plane.state->fb ||
+	    pipe->plane.state->fb->format[0].format !=
+		plane_state->fb->format[0].format) {
+
+		if (modeset->fb_info->fbops->fb_check_var) {
+			memcpy(&fb_var, &modeset->fb_info->var,
+			       sizeof(fb_var));
+			drm_fbconv_update_fb_var_screeninfo_from_crtc_state(
+				&fb_var, crtc_state);
+			drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
+				&fb_var, plane_state->fb,
+				modeset->fb_info->fix.smem_len);
+			ret = modeset->fb_info->fbops->fb_check_var(
+				&fb_var, modeset->fb_info);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_check);
@@ -816,7 +1143,119 @@ EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_check);
 void
 drm_fbconv_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
 				      struct drm_plane_state *old_plane_state)
-{ }
+{
+	struct drm_fbconv_modeset *modeset;
+	uint32_t format;
+	struct fb_var_screeninfo fb_var;
+	int ret;
+	bool do_blit;
+	struct drm_rect rect;
+	struct drm_crtc *crtc = &pipe->crtc;
+
+	/*
+	 * Plane update
+	 */
+
+	modeset = drm_fbconv_modeset_of_pipe(pipe);
+
+	format = drm_fbconv_format_of_fb_info(modeset->fb_info);
+
+	/* DRM porting notes: Some fbdev drivers report alpha channels for
+	 * their framebuffer, even though they don't support transparent
+	 * primary planes. For the format test below, we ignore the alpha
+	 * channel and use the non-transparent equivalent of the pixel format.
+	 * If you're porting an fbdev driver to DRM, remove this switch
+	 * statement and report the correct format instead.
+	 */
+	switch (format) {
+	case DRM_FORMAT_ARGB8888:
+		format = DRM_FORMAT_XRGB8888;
+		break;
+	case DRM_FORMAT_ABGR8888:
+		format = DRM_FORMAT_XBGR8888;
+		break;
+	case DRM_FORMAT_RGBA8888:
+		format = DRM_FORMAT_RGBX8888;
+		break;
+	case DRM_FORMAT_BGRA8888:
+		format = DRM_FORMAT_BGRX8888;
+		break;
+	default:
+		break;
+	}
+
+	if (!pipe->plane.state->fb) {
+		/* No framebuffer installed; blank display. */
+		fb_blank(modeset->fb_info, FB_BLANK_NORMAL);
+		return;
+	}
+
+	if ((format != pipe->plane.state->fb->format[0].format) ||
+	    (modeset->fb_info->var.xres_virtual !=
+	    pipe->plane.state->fb->width)) {
+
+		/* Pixel format changed, update fb_info accordingly
+		 */
+
+		memcpy(&fb_var, &modeset->fb_info->var, sizeof(fb_var));
+		ret = drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
+			&fb_var, pipe->plane.state->fb,
+			modeset->fb_info->fix.smem_len);
+		if (ret)
+			return;
+
+		fb_var.activate = FB_ACTIVATE_NOW;
+
+		ret = fb_set_var(modeset->fb_info, &fb_var);
+		if (ret) {
+			DRM_ERROR("fbconv: fb_set_var() failed: %d\n", ret);
+			return;
+		}
+	}
+
+	if (!old_plane_state->fb || /* first-time update */
+	    (format != pipe->plane.state->fb->format[0].format)) {
+
+		/* DRM porting notes: Below we set the LUTs for palette and
+		 * gamma correction. This is required by some fbdev drivers,
+		 * such as nvidiafb and atyfb, which don't initialize the
+		 * table to pass-through the framebuffer values unchanged. This
+		 * is actually CRTC state, but the respective function
+		 * crtc_helper_mode_set_nofb() is only called when a CRTC
+		 * property changes, changes in color formats are not handled
+		 * there. When you're porting a fbdev driver to DRM, remove
+		 * the call. Gamma LUTs are CRTC properties and should be
+		 * handled there. Either remove gamma correction or set up
+		 * the respective CRTC properties for userspace.
+		 */
+		set_cmap(modeset->fb_info);
+	}
+
+	memcpy(&fb_var, &modeset->fb_info->var, sizeof(fb_var));
+	fb_var.xoffset = 0;
+	fb_var.yoffset = 0;
+
+	ret = fb_pan_display(modeset->fb_info, &fb_var);
+	if (ret) {
+		DRM_ERROR("fbconv: fb_pan_display() failed: %d\n", ret);
+		return;
+	}
+
+	do_blit = drm_atomic_helper_damage_merged(old_plane_state,
+						  pipe->plane.state,
+						  &rect);
+	if (do_blit)
+		drm_fbconv_blit_rect(modeset->blit.screen_base,
+				     modeset->blit.vmap, pipe->plane.state->fb,
+				     &rect);
+
+	if (crtc->state->event) {
+		spin_lock_irq(&crtc->dev->event_lock);
+		drm_crtc_send_vblank_event(crtc, crtc->state->event);
+		crtc->state->event = NULL;
+		spin_unlock_irq(&crtc->dev->event_lock);
+	}
+}
 EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_update);
 
 /**
@@ -837,7 +1276,48 @@ EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_update);
 int
 drm_fbconv_simple_display_pipe_prepare_fb(struct drm_simple_display_pipe *pipe,
 					  struct drm_plane_state *plane_state)
-{ }
+{
+	struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
+	struct fb_info *fb_info = modeset->fb_info;
+	struct drm_framebuffer *fb = plane_state->fb;
+	bool unmap_screen_base = false;
+	void *screen_base;
+	void *vmap;
+	int ret;
+
+	if (!fb)
+		return 0;
+
+	screen_base = fb_info->screen_base;
+
+	if (!screen_base) {
+		screen_base = ioremap(fb_info->fix.smem_start,
+				      fb_info->fix.smem_len);
+		if (!screen_base) {
+			DRM_ERROR("fbconv: ioremap() failed\n");
+			return -ENOMEM;
+		}
+		unmap_screen_base = true;
+	}
+
+	vmap = drm_gem_shmem_vmap(fb->obj[0]);
+	if (!vmap) {
+		DRM_ERROR("fbconv: drm_gem_shmem_vmap() failed\n");
+		ret = -ENOMEM;
+		goto err_iounmap;
+	}
+
+	modeset->blit.vmap = vmap;
+	modeset->blit.screen_base = screen_base;
+	modeset->blit.unmap_screen_base = unmap_screen_base;
+
+	return 0;
+
+err_iounmap:
+	if (unmap_screen_base)
+		iounmap(screen_base);
+	return ret;
+}
 EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_prepare_fb);
 
 /**
@@ -853,7 +1333,21 @@ EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_prepare_fb);
 void
 drm_fbconv_simple_display_pipe_cleanup_fb(struct drm_simple_display_pipe *pipe,
 					  struct drm_plane_state *plane_state)
-{ }
+{
+	struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
+	struct drm_framebuffer *fb = plane_state->fb;
+
+	if (!fb)
+		return;
+
+	drm_gem_shmem_vunmap(fb->obj[0], modeset->blit.vmap);
+
+	if (modeset->blit.unmap_screen_base)
+		iounmap(modeset->blit.screen_base);
+
+	memset(&modeset->blit, 0, sizeof(modeset->blit));
+}
+EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_cleanup_fb);
 
 static const struct drm_simple_display_pipe_funcs simple_display_pipe_funcs = {
 	.mode_valid = drm_fbconv_simple_display_pipe_mode_valid,
diff --git a/include/drm/drm_fbconv_helper.h b/include/drm/drm_fbconv_helper.h
index 79716af687c1..3e62b5e80af6 100644
--- a/include/drm/drm_fbconv_helper.h
+++ b/include/drm/drm_fbconv_helper.h
@@ -92,6 +92,9 @@ void
 drm_fbconv_simple_display_pipe_cleanup_fb(struct drm_simple_display_pipe *pipe,
 					  struct drm_plane_state *plane_state);
 
+int drm_fbconv_blit_rect(void *dst, void *vaddr, struct drm_framebuffer *fb,
+			 struct drm_rect *rect);
+
 /*
  * Modeset helpers
  */
@@ -107,6 +110,12 @@ struct drm_fbconv_modeset {
 	struct drm_connector connector;
 	struct drm_simple_display_pipe pipe;
 
+	struct {
+		void *vmap;
+		void *screen_base;
+		bool unmap_screen_base;
+	} blit;
+
 	struct drm_device *dev;
 	struct fb_info *fb_info;
 };
-- 
2.23.0

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

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

* [PATCH v2 09/15] drm/fbconv: Mode-setting pipeline enable / disable
  2019-10-14 14:04 ` Thomas Zimmermann
@ 2019-10-14 14:04   ` Thomas Zimmermann
  -1 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

The display mode is set by converting the DRM display mode to an
fb_info state and handling it to the fbdev driver's fb_setvar()
function. This also requires a color depth, which we take from the
value of struct drm_mode_config.preferred_depth

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/drm_fbconv_helper.c | 113 +++++++++++++++++++++++++++-
 include/drm/drm_fbconv_helper.h     |   2 +
 2 files changed, 113 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
index cf218016ac05..ca8b43c91266 100644
--- a/drivers/gpu/drm/drm_fbconv_helper.c
+++ b/drivers/gpu/drm/drm_fbconv_helper.c
@@ -919,6 +919,24 @@ static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
 	return 0;
 }
 
+static int drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
+	struct fb_var_screeninfo *fb_var, struct drm_simple_display_pipe *pipe)
+{
+	struct drm_plane *primary = pipe->crtc.primary;
+	struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
+
+	if (primary && primary->state && primary->state->fb)
+		return drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
+			fb_var, primary->state->fb,
+			modeset->fb_info->fix.smem_len);
+
+	fb_var->xres_virtual = fb_var->xres;
+	fb_var->yres_virtual = fb_var->yres;
+	fb_var->bits_per_pixel = modeset->dev->mode_config.preferred_depth;
+
+	return 0;
+}
+
 /**
  * drm_fbconv_simple_display_pipe_mode_valid - default implementation for
  *	struct drm_simple_display_pipe_funcs.mode_valid
@@ -950,6 +968,28 @@ bool drm_fbconv_simple_display_pipe_mode_fixup(
 	struct drm_crtc *crtc, const struct drm_display_mode *mode,
 	struct drm_display_mode *adjusted_mode)
 {
+	struct drm_simple_display_pipe *pipe +		container_of(crtc, struct drm_simple_display_pipe, crtc);
+	struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
+	struct fb_var_screeninfo fb_var;
+	int ret;
+
+	if (!modeset->fb_info->fbops->fb_check_var)
+		return true;
+
+	drm_fbconv_init_fb_var_screeninfo_from_mode(&fb_var, mode);
+
+	ret = drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
+		&fb_var, &modeset->pipe);
+	if (ret)
+		return true;
+
+	ret = modeset->fb_info->fbops->fb_check_var(&fb_var, modeset->fb_info);
+	if (ret < 0)
+		return false;
+
+	drm_mode_update_from_fb_var_screeninfo(adjusted_mode, &fb_var);
+
 	return true;
 }
 EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_mode_fixup);
@@ -1000,6 +1040,32 @@ int drm_fbconv_blit_rect(void *dst, void *vaddr, struct drm_framebuffer *fb,
 }
 EXPORT_SYMBOL(drm_fbconv_blit_rect);
 
+/**
+ * drm_fbconv_blit_fullscreen - copy all pixel data from a framebuffer
+ *	to the hardware buffer
+ * @dst:	the on-screen hardware buffer
+ * @vaddr:	the source buffer in kernel address space
+ * @fb:		the framebuffer of the source buffer
+ * Returns:
+ *	0 on success, or
+ *	a negative error code otherwise.
+ *
+ * This function is equivalent to drm_fbconv_blit_rect(), but copies the
+ * framebuffer's complete content.
+ */
+int drm_fbconv_blit_fullscreen(void *dst, void *vaddr,
+			       struct drm_framebuffer *fb)
+{
+	struct drm_rect fullscreen = {
+		.x1 = 0,
+		.x2 = fb->width,
+		.y1 = 0,
+		.y2 = fb->height,
+	};
+	return drm_fbconv_blit_rect(dst, vaddr, fb, &fullscreen);
+}
+EXPORT_SYMBOL(drm_fbconv_blit_fullscreen);
+
 /**
  * drm_fbconv_simple_display_pipe_enable - default implementation for
  *	struct drm_simple_display_pipe_funcs.enable
@@ -1011,7 +1077,46 @@ void
 drm_fbconv_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
 				      struct drm_crtc_state *crtc_state,
 				      struct drm_plane_state *plane_state)
-{ }
+{
+	struct drm_fbconv_modeset *modeset;
+	struct fb_var_screeninfo fb_var;
+	int ret;
+
+	/* As this is atomic mode setting, any function call is not
+	 * allowed to fail. If it does, an additional test should be
+	 * added to simple_display_pipe_check().
+	 */
+
+	modeset = drm_fbconv_modeset_of_pipe(pipe);
+
+	drm_fbconv_init_fb_var_screeninfo_from_mode(
+		&fb_var, &crtc_state->adjusted_mode);
+
+	if (plane_state && plane_state->fb) {
+		ret = drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
+			&fb_var, plane_state->fb,
+			modeset->fb_info->fix.smem_len);
+		if (ret)
+			return;
+	} else {
+		fb_var.xres_virtual = fb_var.xres;
+		fb_var.yres_virtual = fb_var.yres;
+	}
+
+	fb_var.activate = FB_ACTIVATE_NOW;
+
+	ret = fb_set_var(modeset->fb_info, &fb_var);
+	if (ret) {
+		DRM_ERROR("fbconv: fb_set_var() failed: %d\n", ret);
+		return;
+	}
+
+	fb_blank(modeset->fb_info, FB_BLANK_UNBLANK);
+
+	drm_fbconv_blit_fullscreen(modeset->blit.screen_base,
+				   modeset->blit.vmap,
+				   plane_state->fb);
+}
 EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_enable);
 
 /**
@@ -1021,7 +1126,11 @@ EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_enable);
  */
 void
 drm_fbconv_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
-{ }
+{
+	struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
+
+	fb_blank(modeset->fb_info, FB_BLANK_POWERDOWN);
+}
 EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_disable);
 
 /**
diff --git a/include/drm/drm_fbconv_helper.h b/include/drm/drm_fbconv_helper.h
index 3e62b5e80af6..c7d211f40462 100644
--- a/include/drm/drm_fbconv_helper.h
+++ b/include/drm/drm_fbconv_helper.h
@@ -94,6 +94,8 @@ drm_fbconv_simple_display_pipe_cleanup_fb(struct drm_simple_display_pipe *pipe,
 
 int drm_fbconv_blit_rect(void *dst, void *vaddr, struct drm_framebuffer *fb,
 			 struct drm_rect *rect);
+int drm_fbconv_blit_fullscreen(void *dst, void *vaddr,
+			       struct drm_framebuffer *fb);
 
 /*
  * Modeset helpers
-- 
2.23.0

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

* [PATCH v2 09/15] drm/fbconv: Mode-setting pipeline enable / disable
@ 2019-10-14 14:04   ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

The display mode is set by converting the DRM display mode to an
fb_info state and handling it to the fbdev driver's fb_setvar()
function. This also requires a color depth, which we take from the
value of struct drm_mode_config.preferred_depth

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/drm_fbconv_helper.c | 113 +++++++++++++++++++++++++++-
 include/drm/drm_fbconv_helper.h     |   2 +
 2 files changed, 113 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
index cf218016ac05..ca8b43c91266 100644
--- a/drivers/gpu/drm/drm_fbconv_helper.c
+++ b/drivers/gpu/drm/drm_fbconv_helper.c
@@ -919,6 +919,24 @@ static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
 	return 0;
 }
 
+static int drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
+	struct fb_var_screeninfo *fb_var, struct drm_simple_display_pipe *pipe)
+{
+	struct drm_plane *primary = pipe->crtc.primary;
+	struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
+
+	if (primary && primary->state && primary->state->fb)
+		return drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
+			fb_var, primary->state->fb,
+			modeset->fb_info->fix.smem_len);
+
+	fb_var->xres_virtual = fb_var->xres;
+	fb_var->yres_virtual = fb_var->yres;
+	fb_var->bits_per_pixel = modeset->dev->mode_config.preferred_depth;
+
+	return 0;
+}
+
 /**
  * drm_fbconv_simple_display_pipe_mode_valid - default implementation for
  *	struct drm_simple_display_pipe_funcs.mode_valid
@@ -950,6 +968,28 @@ bool drm_fbconv_simple_display_pipe_mode_fixup(
 	struct drm_crtc *crtc, const struct drm_display_mode *mode,
 	struct drm_display_mode *adjusted_mode)
 {
+	struct drm_simple_display_pipe *pipe =
+		container_of(crtc, struct drm_simple_display_pipe, crtc);
+	struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
+	struct fb_var_screeninfo fb_var;
+	int ret;
+
+	if (!modeset->fb_info->fbops->fb_check_var)
+		return true;
+
+	drm_fbconv_init_fb_var_screeninfo_from_mode(&fb_var, mode);
+
+	ret = drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
+		&fb_var, &modeset->pipe);
+	if (ret)
+		return true;
+
+	ret = modeset->fb_info->fbops->fb_check_var(&fb_var, modeset->fb_info);
+	if (ret < 0)
+		return false;
+
+	drm_mode_update_from_fb_var_screeninfo(adjusted_mode, &fb_var);
+
 	return true;
 }
 EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_mode_fixup);
@@ -1000,6 +1040,32 @@ int drm_fbconv_blit_rect(void *dst, void *vaddr, struct drm_framebuffer *fb,
 }
 EXPORT_SYMBOL(drm_fbconv_blit_rect);
 
+/**
+ * drm_fbconv_blit_fullscreen - copy all pixel data from a framebuffer
+ *	to the hardware buffer
+ * @dst:	the on-screen hardware buffer
+ * @vaddr:	the source buffer in kernel address space
+ * @fb:		the framebuffer of the source buffer
+ * Returns:
+ *	0 on success, or
+ *	a negative error code otherwise.
+ *
+ * This function is equivalent to drm_fbconv_blit_rect(), but copies the
+ * framebuffer's complete content.
+ */
+int drm_fbconv_blit_fullscreen(void *dst, void *vaddr,
+			       struct drm_framebuffer *fb)
+{
+	struct drm_rect fullscreen = {
+		.x1 = 0,
+		.x2 = fb->width,
+		.y1 = 0,
+		.y2 = fb->height,
+	};
+	return drm_fbconv_blit_rect(dst, vaddr, fb, &fullscreen);
+}
+EXPORT_SYMBOL(drm_fbconv_blit_fullscreen);
+
 /**
  * drm_fbconv_simple_display_pipe_enable - default implementation for
  *	struct drm_simple_display_pipe_funcs.enable
@@ -1011,7 +1077,46 @@ void
 drm_fbconv_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
 				      struct drm_crtc_state *crtc_state,
 				      struct drm_plane_state *plane_state)
-{ }
+{
+	struct drm_fbconv_modeset *modeset;
+	struct fb_var_screeninfo fb_var;
+	int ret;
+
+	/* As this is atomic mode setting, any function call is not
+	 * allowed to fail. If it does, an additional test should be
+	 * added to simple_display_pipe_check().
+	 */
+
+	modeset = drm_fbconv_modeset_of_pipe(pipe);
+
+	drm_fbconv_init_fb_var_screeninfo_from_mode(
+		&fb_var, &crtc_state->adjusted_mode);
+
+	if (plane_state && plane_state->fb) {
+		ret = drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
+			&fb_var, plane_state->fb,
+			modeset->fb_info->fix.smem_len);
+		if (ret)
+			return;
+	} else {
+		fb_var.xres_virtual = fb_var.xres;
+		fb_var.yres_virtual = fb_var.yres;
+	}
+
+	fb_var.activate = FB_ACTIVATE_NOW;
+
+	ret = fb_set_var(modeset->fb_info, &fb_var);
+	if (ret) {
+		DRM_ERROR("fbconv: fb_set_var() failed: %d\n", ret);
+		return;
+	}
+
+	fb_blank(modeset->fb_info, FB_BLANK_UNBLANK);
+
+	drm_fbconv_blit_fullscreen(modeset->blit.screen_base,
+				   modeset->blit.vmap,
+				   plane_state->fb);
+}
 EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_enable);
 
 /**
@@ -1021,7 +1126,11 @@ EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_enable);
  */
 void
 drm_fbconv_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
-{ }
+{
+	struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
+
+	fb_blank(modeset->fb_info, FB_BLANK_POWERDOWN);
+}
 EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_disable);
 
 /**
diff --git a/include/drm/drm_fbconv_helper.h b/include/drm/drm_fbconv_helper.h
index 3e62b5e80af6..c7d211f40462 100644
--- a/include/drm/drm_fbconv_helper.h
+++ b/include/drm/drm_fbconv_helper.h
@@ -94,6 +94,8 @@ drm_fbconv_simple_display_pipe_cleanup_fb(struct drm_simple_display_pipe *pipe,
 
 int drm_fbconv_blit_rect(void *dst, void *vaddr, struct drm_framebuffer *fb,
 			 struct drm_rect *rect);
+int drm_fbconv_blit_fullscreen(void *dst, void *vaddr,
+			       struct drm_framebuffer *fb);
 
 /*
  * Modeset helpers
-- 
2.23.0

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

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

* [PATCH v2 10/15] drm/fbconv: Reimplement several fbdev interfaces
  2019-10-14 14:04 ` Thomas Zimmermann
@ 2019-10-14 14:04   ` Thomas Zimmermann
  -1 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

This patch reimplements fb_blank(), fb_pan_display(), fb_set_cmap() and
fb_set_var() for fbconv helpers. The goal is to have all calls to driver
callback functions located within fbconv and to reduce the amount of
contained work to a minimum.

Some noteable differences to fbdev include:

  * Code related to fbcon has been left out. Console support is
    emulated by DRM and the drivers don't interact directly with
    it.

  * No events are sent out. As the fbconv helpers are not part of
    the fbdev framework, there are no event listeners anyway.

  * Code related to ioctl and user-space has been left out as
    well. User-space interfaces are provided by DRM.

  * Error messages have been added.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/drm_fbconv_helper.c | 240 +++++++++++++++++++++++++---
 1 file changed, 220 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
index ca8b43c91266..f7f247e30a3d 100644
--- a/drivers/gpu/drm/drm_fbconv_helper.c
+++ b/drivers/gpu/drm/drm_fbconv_helper.c
@@ -737,6 +737,55 @@ static const struct drm_connector_funcs connector_funcs = {
  * Colormap updates
  */
 
+static int drm_fbconv_set_cmap(struct fb_cmap *cmap, struct fb_info *fb_info)
+{
+	int i, start, res;
+	u16 *red, *green, *blue, *transp;
+	u_int hred, hgreen, hblue, htransp = 0xffff;
+
+	red = cmap->red;
+	green = cmap->green;
+	blue = cmap->blue;
+	transp = cmap->transp;
+	start = cmap->start;
+
+	if (start < 0 || (!fb_info->fbops->fb_setcolreg &&
+			  !fb_info->fbops->fb_setcmap)) {
+		DRM_ERROR("fbconv: Palette not supported.\n");
+		return -EINVAL;
+	}
+
+	if (fb_info->fbops->fb_setcmap) {
+		res = fb_info->fbops->fb_setcmap(cmap, fb_info);
+		if (res) {
+			DRM_ERROR("fbconv: fbops->fb_setcmap() failed: %d\n",
+				  res);
+			return res;
+		}
+	} else {
+		for (i = 0; i < cmap->len; i++) {
+			hred = *red++;
+			hgreen = *green++;
+			hblue = *blue++;
+			if (transp)
+				htransp = *transp++;
+			res = fb_info->fbops->fb_setcolreg(start++,
+							   hred, hgreen, hblue,
+							   htransp, fb_info);
+			if (res) {
+				DRM_ERROR("fbconv: fbops->fb_setcolreg() failed: %d\n",
+					  res);
+				/* cmap handling is a mess; don't err here */
+				break;
+			}
+		}
+	}
+
+	fb_copy_cmap(cmap, &fb_info->cmap);
+
+	return 0;
+}
+
 /* provides a default colormap for palette modes */
 static int create_palette_cmap(struct fb_cmap *cmap,
 			       const struct fb_var_screeninfo *fb_var)
@@ -856,11 +905,9 @@ static int set_cmap(struct fb_info *fb_info)
 	if (ret)
 		return ret;
 
-	ret = fb_set_cmap(&cmap, fb_info);
-	if (ret) {
-		DRM_ERROR("fbconv: fb_set_cmap() failed: %d\n", ret);
+	ret = drm_fbconv_set_cmap(&cmap, fb_info);
+	if (ret)
 		goto err_fb_dealloc_cmap;
-	}
 	fb_dealloc_cmap(&cmap);
 
 	return 0;
@@ -891,7 +938,7 @@ static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
 
 	/* Our virtual screen covers all the graphics memory (sans some
 	 * trailing bytes). This allows for setting the scanout buffer's
-	 * address with fb_pan_display().
+	 * address with drm_fbconv_pan_display().
 	 */
 
 	width = fb->pitches[0];
@@ -937,6 +984,165 @@ static int drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
 	return 0;
 }
 
+static int drm_fbconv_blank(struct fb_info *fb_info, int blank)
+{
+	int ret = -EINVAL;
+
+	if (fb_info->fbops->fb_blank) {
+		ret = fb_info->fbops->fb_blank(blank, fb_info);
+		if (ret) {
+			DRM_ERROR("fbconv: fbops->fb_blank() failed: %d\n",
+				  ret);
+		}
+	}
+	return ret;
+}
+
+static int drm_fbconv_pan_display(struct fb_info *fb_info,
+				  struct fb_var_screeninfo *var)
+{
+	struct fb_fix_screeninfo *fix = &fb_info->fix;
+	unsigned int yres = fb_info->var.yres;
+	int err;
+
+	if (var->yoffset > 0) {
+		if (var->vmode & FB_VMODE_YWRAP) {
+			if (!fix->ywrapstep ||
+			    (var->yoffset % fix->ywrapstep)) {
+				DRM_ERROR("fbconv: Invalid fix->ywrapstep: %d\n",
+					  fix->ywrapstep);
+				return -EINVAL;
+			}
+			yres = 0;
+		} else if (!fix->ypanstep || (var->yoffset % fix->ypanstep)) {
+			DRM_ERROR("fbconv: Invalid fix->ypanstep: %d\n",
+				  fix->ypanstep);
+			return -EINVAL;
+		}
+	}
+
+	if (var->xoffset > 0) {
+		if (!fix->xpanstep || (var->xoffset % fix->xpanstep)) {
+			DRM_ERROR("fbconv: Invalid fix->xpanstep: %d\n",
+				  fix->xpanstep);
+			return -EINVAL;
+		}
+	}
+
+	if (!fb_info->fbops->fb_pan_display ||
+	    var->yoffset > fb_info->var.yres_virtual - yres ||
+	    var->xoffset > fb_info->var.xres_virtual - fb_info->var.xres) {
+		DRM_ERROR("fbconv: Display panning unsupported\n");
+		return -EINVAL;
+	}
+
+	err = fb_info->fbops->fb_pan_display(var, fb_info);
+	if (err) {
+		DRM_ERROR("fbconv: fbops->pan_display() failed: %d", err);
+		return err;
+	}
+
+	fb_info->var.xoffset = var->xoffset;
+	fb_info->var.yoffset = var->yoffset;
+
+	if (var->vmode & FB_VMODE_YWRAP)
+		fb_info->var.vmode |= FB_VMODE_YWRAP;
+	else
+		fb_info->var.vmode &= ~FB_VMODE_YWRAP;
+
+	return 0;
+}
+
+static int drm_fbconv_set_var(struct fb_info *fb_info,
+			      struct fb_var_screeninfo *var)
+{
+	int ret = 0;
+	u32 activate;
+	struct fb_var_screeninfo old_var;
+	struct fb_videomode mode;
+
+	if (var->activate & FB_ACTIVATE_INV_MODE) {
+		struct fb_videomode mode1, mode2;
+
+		fb_var_to_videomode(&mode1, var);
+		fb_var_to_videomode(&mode2, &fb_info->var);
+		/* make sure we don't delete the videomode of current var */
+		ret = fb_mode_is_equal(&mode1, &mode2);
+		if (ret) {
+			DRM_ERROR("fbconv: fb_mode_is_equal() failed: %d\n",
+				  ret);
+			return -EINVAL;
+		}
+
+		fb_delete_videomode(&mode1, &fb_info->modelist);
+
+		return 0;
+	}
+
+	if (!(var->activate & FB_ACTIVATE_FORCE) &&
+	    !memcmp(&fb_info->var, var, sizeof(*var)))
+		return 0;
+
+	activate = var->activate;
+
+	/* When using FOURCC mode, make sure the red, green, blue and
+	 * transp fields are set to 0.
+	 */
+	if ((fb_info->fix.capabilities & FB_CAP_FOURCC) && var->grayscale > 1) {
+		if (var->red.offset     || var->green.offset    ||
+		    var->blue.offset    || var->transp.offset   ||
+		    var->red.length     || var->green.length    ||
+		    var->blue.length    || var->transp.length   ||
+		    var->red.msb_right  || var->green.msb_right ||
+		    var->blue.msb_right || var->transp.msb_right) {
+			DRM_ERROR("fbconv: Invalid color offsets in FOURCC mode\n");
+			return -EINVAL;
+		}
+	}
+
+	if (!fb_info->fbops->fb_check_var) {
+		*var = fb_info->var;
+		return 0;
+	}
+
+	ret = fb_info->fbops->fb_check_var(var, fb_info);
+	if (ret) {
+		DRM_ERROR("fbconv: fbops->fb_check_var() failed: %d\n", ret);
+		return ret;
+	}
+
+	if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
+		return 0;
+
+	old_var = fb_info->var;
+	fb_info->var = *var;
+
+	if (fb_info->fbops->fb_set_par) {
+		ret = fb_info->fbops->fb_set_par(fb_info);
+		if (ret) {
+			fb_info->var = old_var;
+			DRM_ERROR("fbconv: fbops->fb_set_par() failed: %d\n",
+				  ret);
+			return ret;
+		}
+	}
+
+	drm_fbconv_pan_display(fb_info, &fb_info->var);
+	drm_fbconv_set_cmap(&fb_info->cmap, fb_info);
+	fb_var_to_videomode(&mode, &fb_info->var);
+
+	if (fb_info->modelist.prev && fb_info->modelist.next &&
+	    !list_empty(&fb_info->modelist))
+		ret = fb_add_videomode(&mode, &fb_info->modelist);
+
+	if (ret) {
+		DRM_ERROR("fbconv: fb_add_videomode() failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 /**
  * drm_fbconv_simple_display_pipe_mode_valid - default implementation for
  *	struct drm_simple_display_pipe_funcs.mode_valid
@@ -1105,13 +1311,11 @@ drm_fbconv_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
 
 	fb_var.activate = FB_ACTIVATE_NOW;
 
-	ret = fb_set_var(modeset->fb_info, &fb_var);
-	if (ret) {
-		DRM_ERROR("fbconv: fb_set_var() failed: %d\n", ret);
+	ret = drm_fbconv_set_var(modeset->fb_info, &fb_var);
+	if (ret)
 		return;
-	}
 
-	fb_blank(modeset->fb_info, FB_BLANK_UNBLANK);
+	drm_fbconv_blank(modeset->fb_info, FB_BLANK_UNBLANK);
 
 	drm_fbconv_blit_fullscreen(modeset->blit.screen_base,
 				   modeset->blit.vmap,
@@ -1129,7 +1333,7 @@ drm_fbconv_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
 {
 	struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
 
-	fb_blank(modeset->fb_info, FB_BLANK_POWERDOWN);
+	drm_fbconv_blank(modeset->fb_info, FB_BLANK_POWERDOWN);
 }
 EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_disable);
 
@@ -1295,7 +1499,7 @@ drm_fbconv_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
 
 	if (!pipe->plane.state->fb) {
 		/* No framebuffer installed; blank display. */
-		fb_blank(modeset->fb_info, FB_BLANK_NORMAL);
+		drm_fbconv_blank(modeset->fb_info, FB_BLANK_NORMAL);
 		return;
 	}
 
@@ -1315,11 +1519,9 @@ drm_fbconv_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
 
 		fb_var.activate = FB_ACTIVATE_NOW;
 
-		ret = fb_set_var(modeset->fb_info, &fb_var);
-		if (ret) {
-			DRM_ERROR("fbconv: fb_set_var() failed: %d\n", ret);
+		ret = drm_fbconv_set_var(modeset->fb_info, &fb_var);
+		if (ret)
 			return;
-		}
 	}
 
 	if (!old_plane_state->fb || /* first-time update */
@@ -1344,11 +1546,9 @@ drm_fbconv_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
 	fb_var.xoffset = 0;
 	fb_var.yoffset = 0;
 
-	ret = fb_pan_display(modeset->fb_info, &fb_var);
-	if (ret) {
-		DRM_ERROR("fbconv: fb_pan_display() failed: %d\n", ret);
+	ret = drm_fbconv_pan_display(modeset->fb_info, &fb_var);
+	if (ret)
 		return;
-	}
 
 	do_blit = drm_atomic_helper_damage_merged(old_plane_state,
 						  pipe->plane.state,
-- 
2.23.0

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

* [PATCH v2 10/15] drm/fbconv: Reimplement several fbdev interfaces
@ 2019-10-14 14:04   ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

This patch reimplements fb_blank(), fb_pan_display(), fb_set_cmap() and
fb_set_var() for fbconv helpers. The goal is to have all calls to driver
callback functions located within fbconv and to reduce the amount of
contained work to a minimum.

Some noteable differences to fbdev include:

  * Code related to fbcon has been left out. Console support is
    emulated by DRM and the drivers don't interact directly with
    it.

  * No events are sent out. As the fbconv helpers are not part of
    the fbdev framework, there are no event listeners anyway.

  * Code related to ioctl and user-space has been left out as
    well. User-space interfaces are provided by DRM.

  * Error messages have been added.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/drm_fbconv_helper.c | 240 +++++++++++++++++++++++++---
 1 file changed, 220 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
index ca8b43c91266..f7f247e30a3d 100644
--- a/drivers/gpu/drm/drm_fbconv_helper.c
+++ b/drivers/gpu/drm/drm_fbconv_helper.c
@@ -737,6 +737,55 @@ static const struct drm_connector_funcs connector_funcs = {
  * Colormap updates
  */
 
+static int drm_fbconv_set_cmap(struct fb_cmap *cmap, struct fb_info *fb_info)
+{
+	int i, start, res;
+	u16 *red, *green, *blue, *transp;
+	u_int hred, hgreen, hblue, htransp = 0xffff;
+
+	red = cmap->red;
+	green = cmap->green;
+	blue = cmap->blue;
+	transp = cmap->transp;
+	start = cmap->start;
+
+	if (start < 0 || (!fb_info->fbops->fb_setcolreg &&
+			  !fb_info->fbops->fb_setcmap)) {
+		DRM_ERROR("fbconv: Palette not supported.\n");
+		return -EINVAL;
+	}
+
+	if (fb_info->fbops->fb_setcmap) {
+		res = fb_info->fbops->fb_setcmap(cmap, fb_info);
+		if (res) {
+			DRM_ERROR("fbconv: fbops->fb_setcmap() failed: %d\n",
+				  res);
+			return res;
+		}
+	} else {
+		for (i = 0; i < cmap->len; i++) {
+			hred = *red++;
+			hgreen = *green++;
+			hblue = *blue++;
+			if (transp)
+				htransp = *transp++;
+			res = fb_info->fbops->fb_setcolreg(start++,
+							   hred, hgreen, hblue,
+							   htransp, fb_info);
+			if (res) {
+				DRM_ERROR("fbconv: fbops->fb_setcolreg() failed: %d\n",
+					  res);
+				/* cmap handling is a mess; don't err here */
+				break;
+			}
+		}
+	}
+
+	fb_copy_cmap(cmap, &fb_info->cmap);
+
+	return 0;
+}
+
 /* provides a default colormap for palette modes */
 static int create_palette_cmap(struct fb_cmap *cmap,
 			       const struct fb_var_screeninfo *fb_var)
@@ -856,11 +905,9 @@ static int set_cmap(struct fb_info *fb_info)
 	if (ret)
 		return ret;
 
-	ret = fb_set_cmap(&cmap, fb_info);
-	if (ret) {
-		DRM_ERROR("fbconv: fb_set_cmap() failed: %d\n", ret);
+	ret = drm_fbconv_set_cmap(&cmap, fb_info);
+	if (ret)
 		goto err_fb_dealloc_cmap;
-	}
 	fb_dealloc_cmap(&cmap);
 
 	return 0;
@@ -891,7 +938,7 @@ static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
 
 	/* Our virtual screen covers all the graphics memory (sans some
 	 * trailing bytes). This allows for setting the scanout buffer's
-	 * address with fb_pan_display().
+	 * address with drm_fbconv_pan_display().
 	 */
 
 	width = fb->pitches[0];
@@ -937,6 +984,165 @@ static int drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
 	return 0;
 }
 
+static int drm_fbconv_blank(struct fb_info *fb_info, int blank)
+{
+	int ret = -EINVAL;
+
+	if (fb_info->fbops->fb_blank) {
+		ret = fb_info->fbops->fb_blank(blank, fb_info);
+		if (ret) {
+			DRM_ERROR("fbconv: fbops->fb_blank() failed: %d\n",
+				  ret);
+		}
+	}
+	return ret;
+}
+
+static int drm_fbconv_pan_display(struct fb_info *fb_info,
+				  struct fb_var_screeninfo *var)
+{
+	struct fb_fix_screeninfo *fix = &fb_info->fix;
+	unsigned int yres = fb_info->var.yres;
+	int err;
+
+	if (var->yoffset > 0) {
+		if (var->vmode & FB_VMODE_YWRAP) {
+			if (!fix->ywrapstep ||
+			    (var->yoffset % fix->ywrapstep)) {
+				DRM_ERROR("fbconv: Invalid fix->ywrapstep: %d\n",
+					  fix->ywrapstep);
+				return -EINVAL;
+			}
+			yres = 0;
+		} else if (!fix->ypanstep || (var->yoffset % fix->ypanstep)) {
+			DRM_ERROR("fbconv: Invalid fix->ypanstep: %d\n",
+				  fix->ypanstep);
+			return -EINVAL;
+		}
+	}
+
+	if (var->xoffset > 0) {
+		if (!fix->xpanstep || (var->xoffset % fix->xpanstep)) {
+			DRM_ERROR("fbconv: Invalid fix->xpanstep: %d\n",
+				  fix->xpanstep);
+			return -EINVAL;
+		}
+	}
+
+	if (!fb_info->fbops->fb_pan_display ||
+	    var->yoffset > fb_info->var.yres_virtual - yres ||
+	    var->xoffset > fb_info->var.xres_virtual - fb_info->var.xres) {
+		DRM_ERROR("fbconv: Display panning unsupported\n");
+		return -EINVAL;
+	}
+
+	err = fb_info->fbops->fb_pan_display(var, fb_info);
+	if (err) {
+		DRM_ERROR("fbconv: fbops->pan_display() failed: %d", err);
+		return err;
+	}
+
+	fb_info->var.xoffset = var->xoffset;
+	fb_info->var.yoffset = var->yoffset;
+
+	if (var->vmode & FB_VMODE_YWRAP)
+		fb_info->var.vmode |= FB_VMODE_YWRAP;
+	else
+		fb_info->var.vmode &= ~FB_VMODE_YWRAP;
+
+	return 0;
+}
+
+static int drm_fbconv_set_var(struct fb_info *fb_info,
+			      struct fb_var_screeninfo *var)
+{
+	int ret = 0;
+	u32 activate;
+	struct fb_var_screeninfo old_var;
+	struct fb_videomode mode;
+
+	if (var->activate & FB_ACTIVATE_INV_MODE) {
+		struct fb_videomode mode1, mode2;
+
+		fb_var_to_videomode(&mode1, var);
+		fb_var_to_videomode(&mode2, &fb_info->var);
+		/* make sure we don't delete the videomode of current var */
+		ret = fb_mode_is_equal(&mode1, &mode2);
+		if (ret) {
+			DRM_ERROR("fbconv: fb_mode_is_equal() failed: %d\n",
+				  ret);
+			return -EINVAL;
+		}
+
+		fb_delete_videomode(&mode1, &fb_info->modelist);
+
+		return 0;
+	}
+
+	if (!(var->activate & FB_ACTIVATE_FORCE) &&
+	    !memcmp(&fb_info->var, var, sizeof(*var)))
+		return 0;
+
+	activate = var->activate;
+
+	/* When using FOURCC mode, make sure the red, green, blue and
+	 * transp fields are set to 0.
+	 */
+	if ((fb_info->fix.capabilities & FB_CAP_FOURCC) && var->grayscale > 1) {
+		if (var->red.offset     || var->green.offset    ||
+		    var->blue.offset    || var->transp.offset   ||
+		    var->red.length     || var->green.length    ||
+		    var->blue.length    || var->transp.length   ||
+		    var->red.msb_right  || var->green.msb_right ||
+		    var->blue.msb_right || var->transp.msb_right) {
+			DRM_ERROR("fbconv: Invalid color offsets in FOURCC mode\n");
+			return -EINVAL;
+		}
+	}
+
+	if (!fb_info->fbops->fb_check_var) {
+		*var = fb_info->var;
+		return 0;
+	}
+
+	ret = fb_info->fbops->fb_check_var(var, fb_info);
+	if (ret) {
+		DRM_ERROR("fbconv: fbops->fb_check_var() failed: %d\n", ret);
+		return ret;
+	}
+
+	if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
+		return 0;
+
+	old_var = fb_info->var;
+	fb_info->var = *var;
+
+	if (fb_info->fbops->fb_set_par) {
+		ret = fb_info->fbops->fb_set_par(fb_info);
+		if (ret) {
+			fb_info->var = old_var;
+			DRM_ERROR("fbconv: fbops->fb_set_par() failed: %d\n",
+				  ret);
+			return ret;
+		}
+	}
+
+	drm_fbconv_pan_display(fb_info, &fb_info->var);
+	drm_fbconv_set_cmap(&fb_info->cmap, fb_info);
+	fb_var_to_videomode(&mode, &fb_info->var);
+
+	if (fb_info->modelist.prev && fb_info->modelist.next &&
+	    !list_empty(&fb_info->modelist))
+		ret = fb_add_videomode(&mode, &fb_info->modelist);
+
+	if (ret) {
+		DRM_ERROR("fbconv: fb_add_videomode() failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 /**
  * drm_fbconv_simple_display_pipe_mode_valid - default implementation for
  *	struct drm_simple_display_pipe_funcs.mode_valid
@@ -1105,13 +1311,11 @@ drm_fbconv_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
 
 	fb_var.activate = FB_ACTIVATE_NOW;
 
-	ret = fb_set_var(modeset->fb_info, &fb_var);
-	if (ret) {
-		DRM_ERROR("fbconv: fb_set_var() failed: %d\n", ret);
+	ret = drm_fbconv_set_var(modeset->fb_info, &fb_var);
+	if (ret)
 		return;
-	}
 
-	fb_blank(modeset->fb_info, FB_BLANK_UNBLANK);
+	drm_fbconv_blank(modeset->fb_info, FB_BLANK_UNBLANK);
 
 	drm_fbconv_blit_fullscreen(modeset->blit.screen_base,
 				   modeset->blit.vmap,
@@ -1129,7 +1333,7 @@ drm_fbconv_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
 {
 	struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
 
-	fb_blank(modeset->fb_info, FB_BLANK_POWERDOWN);
+	drm_fbconv_blank(modeset->fb_info, FB_BLANK_POWERDOWN);
 }
 EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_disable);
 
@@ -1295,7 +1499,7 @@ drm_fbconv_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
 
 	if (!pipe->plane.state->fb) {
 		/* No framebuffer installed; blank display. */
-		fb_blank(modeset->fb_info, FB_BLANK_NORMAL);
+		drm_fbconv_blank(modeset->fb_info, FB_BLANK_NORMAL);
 		return;
 	}
 
@@ -1315,11 +1519,9 @@ drm_fbconv_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
 
 		fb_var.activate = FB_ACTIVATE_NOW;
 
-		ret = fb_set_var(modeset->fb_info, &fb_var);
-		if (ret) {
-			DRM_ERROR("fbconv: fb_set_var() failed: %d\n", ret);
+		ret = drm_fbconv_set_var(modeset->fb_info, &fb_var);
+		if (ret)
 			return;
-		}
 	}
 
 	if (!old_plane_state->fb || /* first-time update */
@@ -1344,11 +1546,9 @@ drm_fbconv_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
 	fb_var.xoffset = 0;
 	fb_var.yoffset = 0;
 
-	ret = fb_pan_display(modeset->fb_info, &fb_var);
-	if (ret) {
-		DRM_ERROR("fbconv: fb_pan_display() failed: %d\n", ret);
+	ret = drm_fbconv_pan_display(modeset->fb_info, &fb_var);
+	if (ret)
 		return;
-	}
 
 	do_blit = drm_atomic_helper_damage_merged(old_plane_state,
 						  pipe->plane.state,
-- 
2.23.0

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

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

* [PATCH v2 11/15] drm/fbconv: Add helpers for init and cleanup of fb_info structures
  2019-10-14 14:04 ` Thomas Zimmermann
@ 2019-10-14 14:04   ` Thomas Zimmermann
  -1 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

The implementation of drm_fbconv_fill_fb_info() sets up an fbdev driver's
fb_info structure for use. It's similar to register_framebuffer(), but does
not create device files, register the driver with the fbdev code or create
a console. drm_fbconv_cleanup_fb_info() does the inverse.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/drm_fbconv_helper.c | 123 ++++++++++++++++++++++++++++
 include/drm/drm_fbconv_helper.h     |   7 ++
 2 files changed, 130 insertions(+)

diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
index f7f247e30a3d..7d7e4da2a29e 100644
--- a/drivers/gpu/drm/drm_fbconv_helper.c
+++ b/drivers/gpu/drm/drm_fbconv_helper.c
@@ -3,6 +3,7 @@
 #include <asm/byteorder.h>
 
 #include <linux/fb.h>
+#include <linux/major.h>
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_damage_helper.h>
@@ -1722,6 +1723,9 @@ int drm_fbconv_modeset_init(struct drm_fbconv_modeset *modeset,
 {
 	struct drm_mode_config *mode_config = &dev->mode_config;
 
+	if (WARN_ON(fb_info->node != FB_MAX))
+		return -EINVAL; /* forgot to run drm_fbconv_fill_fb_info()? */
+
 	modeset->dev = dev;
 	modeset->fb_info = fb_info;
 
@@ -1820,3 +1824,122 @@ drm_fbconv_modeset_setup_pipe(struct drm_fbconv_modeset *modeset,
 	return 0;
 }
 EXPORT_SYMBOL(drm_fbconv_modeset_setup_pipe);
+
+/*
+ * Helpers for struct fb_info
+ *
+ * This is the setup and cleanup code for struct fb_info. It has been
+ * adapted from the fbdev core modules.
+ *
+ * The original implementation in fbdev also handles device files, console,
+ * and framebuffer events. As DRM drivers use DRM's framebuffer emulation,
+ * the respective code has been removed here.
+ *
+ * In contrast to the fbdev core, we don't need locking here. These don't
+ * interact with fbdev's internal state.
+ */
+
+static bool is_matroxfb(const struct fb_info *fb_info)
+{
+	return !!(fb_info->fix.accel & (FB_ACCEL_MATROX_MGA2064W |
+					FB_ACCEL_MATROX_MGA1064SG |
+					FB_ACCEL_MATROX_MGA2164W |
+					FB_ACCEL_MATROX_MGA2164W_AGP |
+					FB_ACCEL_MATROX_MGAG100 |
+					FB_ACCEL_MATROX_MGAG200 |
+					FB_ACCEL_MATROX_MGAG400));
+}
+
+/**
+ * drm_fbconv_fill_fb_info - prepares an fbdev driver's fb_info structure
+ *	for use
+ * @fb_info:	the fb_info structure to set up
+ * Returns:
+ *	0 on success, or
+ *	a negative error code otherwise.
+ *
+ * The fbdev driver provides fbconv helpers with an fb_info structure. Before
+ * use, the structure has to be set up correctly. In fbdev core,
+ * register_framebuffer() does this; here it's provided by
+ * drm_fbconv_fill_fb_info().
+ *
+ * Call drm_fbconv_cleanup_fb_info() during shutdown to clean up the fb_info
+ * structure.
+ */
+int drm_fbconv_fill_fb_info(struct fb_info *fb_info)
+{
+	struct fb_videomode mode;
+
+	/* Returing -ENOSYS on error is technically wrong, but it's
+	 * what the fbdev core code would do. So we do the same.
+	 */
+	if (fb_check_foreignness(fb_info))
+		return -ENOSYS;
+
+	fb_info->node = FB_MAX; /* not registered; filled by fbconv helpers */
+	atomic_set(&fb_info->count, 1);
+	mutex_init(&fb_info->lock);
+	mutex_init(&fb_info->mm_lock);
+
+	fb_info->dev = NULL; /* device file not needed for fbconv. */
+
+	if (fb_info->pixmap.addr = NULL) {
+		fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
+		if (fb_info->pixmap.addr) {
+			fb_info->pixmap.size = FBPIXMAPSIZE;
+			fb_info->pixmap.buf_align = 1;
+			fb_info->pixmap.scan_align = 1;
+			fb_info->pixmap.access_align = 32;
+			fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
+		}
+	}
+	fb_info->pixmap.offset = 0;
+
+	if (!fb_info->pixmap.blit_x)
+		fb_info->pixmap.blit_x = ~(u32)0;
+
+	if (!fb_info->pixmap.blit_y)
+		fb_info->pixmap.blit_y = ~(u32)0;
+
+	if (!fb_info->modelist.prev || !fb_info->modelist.next)
+		INIT_LIST_HEAD(&fb_info->modelist);
+
+	fb_var_to_videomode(&mode, &fb_info->var);
+	fb_add_videomode(&mode, &fb_info->modelist);
+
+	/* matroxfb: Requries a call to fb_set_par() to initialize
+	 * fbinfo->fix.{smem_start,smem_len}. Otherwise, we won't be
+	 * able to initialize framebuffer memory management.
+	 */
+	if (is_matroxfb(fb_info)) {
+		if (fb_info->fbops->fb_set_par)
+			fb_info->fbops->fb_set_par(fb_info);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_fbconv_fill_fb_info);
+
+/**
+ * drm_fbconv_cleanup_fb_info - cleans up an fbdev driver's fb_info structure
+ *	after use
+ * @fb_info:	the fb_info structure to clean up
+ */
+void drm_fbconv_cleanup_fb_info(struct fb_info *fb_info)
+{
+	if (fb_info->node != FB_MAX)
+		return;
+
+	if (fb_info->pixmap.addr &&
+	    (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
+		kfree(fb_info->pixmap.addr);
+
+	fb_destroy_modelist(&fb_info->modelist);
+
+	if (!atomic_dec_and_test(&fb_info->count))
+		return;
+
+	if (fb_info->fbops->fb_destroy)
+		fb_info->fbops->fb_destroy(fb_info);
+}
+EXPORT_SYMBOL(drm_fbconv_cleanup_fb_info);
diff --git a/include/drm/drm_fbconv_helper.h b/include/drm/drm_fbconv_helper.h
index c7d211f40462..23d17ad14b81 100644
--- a/include/drm/drm_fbconv_helper.h
+++ b/include/drm/drm_fbconv_helper.h
@@ -140,4 +140,11 @@ int drm_fbconv_modeset_setup_pipe(
 	const uint32_t *formats, unsigned int format_count,
 	const uint64_t *format_modifiers, struct drm_connector *connector);
 
+/*
+ * Helpers for struct fb_info
+ */
+
+int drm_fbconv_fill_fb_info(struct fb_info *fb_info);
+void drm_fbconv_cleanup_fb_info(struct fb_info *fb_info);
+
 #endif
-- 
2.23.0

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

* [PATCH v2 11/15] drm/fbconv: Add helpers for init and cleanup of fb_info structures
@ 2019-10-14 14:04   ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

The implementation of drm_fbconv_fill_fb_info() sets up an fbdev driver's
fb_info structure for use. It's similar to register_framebuffer(), but does
not create device files, register the driver with the fbdev code or create
a console. drm_fbconv_cleanup_fb_info() does the inverse.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/drm_fbconv_helper.c | 123 ++++++++++++++++++++++++++++
 include/drm/drm_fbconv_helper.h     |   7 ++
 2 files changed, 130 insertions(+)

diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
index f7f247e30a3d..7d7e4da2a29e 100644
--- a/drivers/gpu/drm/drm_fbconv_helper.c
+++ b/drivers/gpu/drm/drm_fbconv_helper.c
@@ -3,6 +3,7 @@
 #include <asm/byteorder.h>
 
 #include <linux/fb.h>
+#include <linux/major.h>
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_damage_helper.h>
@@ -1722,6 +1723,9 @@ int drm_fbconv_modeset_init(struct drm_fbconv_modeset *modeset,
 {
 	struct drm_mode_config *mode_config = &dev->mode_config;
 
+	if (WARN_ON(fb_info->node != FB_MAX))
+		return -EINVAL; /* forgot to run drm_fbconv_fill_fb_info()? */
+
 	modeset->dev = dev;
 	modeset->fb_info = fb_info;
 
@@ -1820,3 +1824,122 @@ drm_fbconv_modeset_setup_pipe(struct drm_fbconv_modeset *modeset,
 	return 0;
 }
 EXPORT_SYMBOL(drm_fbconv_modeset_setup_pipe);
+
+/*
+ * Helpers for struct fb_info
+ *
+ * This is the setup and cleanup code for struct fb_info. It has been
+ * adapted from the fbdev core modules.
+ *
+ * The original implementation in fbdev also handles device files, console,
+ * and framebuffer events. As DRM drivers use DRM's framebuffer emulation,
+ * the respective code has been removed here.
+ *
+ * In contrast to the fbdev core, we don't need locking here. These don't
+ * interact with fbdev's internal state.
+ */
+
+static bool is_matroxfb(const struct fb_info *fb_info)
+{
+	return !!(fb_info->fix.accel & (FB_ACCEL_MATROX_MGA2064W |
+					FB_ACCEL_MATROX_MGA1064SG |
+					FB_ACCEL_MATROX_MGA2164W |
+					FB_ACCEL_MATROX_MGA2164W_AGP |
+					FB_ACCEL_MATROX_MGAG100 |
+					FB_ACCEL_MATROX_MGAG200 |
+					FB_ACCEL_MATROX_MGAG400));
+}
+
+/**
+ * drm_fbconv_fill_fb_info - prepares an fbdev driver's fb_info structure
+ *	for use
+ * @fb_info:	the fb_info structure to set up
+ * Returns:
+ *	0 on success, or
+ *	a negative error code otherwise.
+ *
+ * The fbdev driver provides fbconv helpers with an fb_info structure. Before
+ * use, the structure has to be set up correctly. In fbdev core,
+ * register_framebuffer() does this; here it's provided by
+ * drm_fbconv_fill_fb_info().
+ *
+ * Call drm_fbconv_cleanup_fb_info() during shutdown to clean up the fb_info
+ * structure.
+ */
+int drm_fbconv_fill_fb_info(struct fb_info *fb_info)
+{
+	struct fb_videomode mode;
+
+	/* Returing -ENOSYS on error is technically wrong, but it's
+	 * what the fbdev core code would do. So we do the same.
+	 */
+	if (fb_check_foreignness(fb_info))
+		return -ENOSYS;
+
+	fb_info->node = FB_MAX; /* not registered; filled by fbconv helpers */
+	atomic_set(&fb_info->count, 1);
+	mutex_init(&fb_info->lock);
+	mutex_init(&fb_info->mm_lock);
+
+	fb_info->dev = NULL; /* device file not needed for fbconv. */
+
+	if (fb_info->pixmap.addr == NULL) {
+		fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
+		if (fb_info->pixmap.addr) {
+			fb_info->pixmap.size = FBPIXMAPSIZE;
+			fb_info->pixmap.buf_align = 1;
+			fb_info->pixmap.scan_align = 1;
+			fb_info->pixmap.access_align = 32;
+			fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
+		}
+	}
+	fb_info->pixmap.offset = 0;
+
+	if (!fb_info->pixmap.blit_x)
+		fb_info->pixmap.blit_x = ~(u32)0;
+
+	if (!fb_info->pixmap.blit_y)
+		fb_info->pixmap.blit_y = ~(u32)0;
+
+	if (!fb_info->modelist.prev || !fb_info->modelist.next)
+		INIT_LIST_HEAD(&fb_info->modelist);
+
+	fb_var_to_videomode(&mode, &fb_info->var);
+	fb_add_videomode(&mode, &fb_info->modelist);
+
+	/* matroxfb: Requries a call to fb_set_par() to initialize
+	 * fbinfo->fix.{smem_start,smem_len}. Otherwise, we won't be
+	 * able to initialize framebuffer memory management.
+	 */
+	if (is_matroxfb(fb_info)) {
+		if (fb_info->fbops->fb_set_par)
+			fb_info->fbops->fb_set_par(fb_info);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_fbconv_fill_fb_info);
+
+/**
+ * drm_fbconv_cleanup_fb_info - cleans up an fbdev driver's fb_info structure
+ *	after use
+ * @fb_info:	the fb_info structure to clean up
+ */
+void drm_fbconv_cleanup_fb_info(struct fb_info *fb_info)
+{
+	if (fb_info->node != FB_MAX)
+		return;
+
+	if (fb_info->pixmap.addr &&
+	    (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
+		kfree(fb_info->pixmap.addr);
+
+	fb_destroy_modelist(&fb_info->modelist);
+
+	if (!atomic_dec_and_test(&fb_info->count))
+		return;
+
+	if (fb_info->fbops->fb_destroy)
+		fb_info->fbops->fb_destroy(fb_info);
+}
+EXPORT_SYMBOL(drm_fbconv_cleanup_fb_info);
diff --git a/include/drm/drm_fbconv_helper.h b/include/drm/drm_fbconv_helper.h
index c7d211f40462..23d17ad14b81 100644
--- a/include/drm/drm_fbconv_helper.h
+++ b/include/drm/drm_fbconv_helper.h
@@ -140,4 +140,11 @@ int drm_fbconv_modeset_setup_pipe(
 	const uint32_t *formats, unsigned int format_count,
 	const uint64_t *format_modifiers, struct drm_connector *connector);
 
+/*
+ * Helpers for struct fb_info
+ */
+
+int drm_fbconv_fill_fb_info(struct fb_info *fb_info);
+void drm_fbconv_cleanup_fb_info(struct fb_info *fb_info);
+
 #endif
-- 
2.23.0

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

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

* [PATCH v2 12/15] drm/fbconv: Add helper documentation
  2019-10-14 14:04 ` Thomas Zimmermann
@ 2019-10-14 14:04   ` Thomas Zimmermann
  -1 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

There's now a tutorial on how to create a DRM driver on top of fbconv
helpers. The DRM TODO list contains an entry for converting fbdev
drivers over to DRM.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 Documentation/gpu/drm-kms-helpers.rst |  12 ++
 Documentation/gpu/todo.rst            |  15 +++
 drivers/gpu/drm/drm_fbconv_helper.c   | 181 ++++++++++++++++++++++++++
 3 files changed, 208 insertions(+)

diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst
index 9668a7fe2408..1232a3ef24ff 100644
--- a/Documentation/gpu/drm-kms-helpers.rst
+++ b/Documentation/gpu/drm-kms-helpers.rst
@@ -411,3 +411,15 @@ SHMEM GEM Helper Reference
 
 .. kernel-doc:: drivers/gpu/drm/drm_gem_shmem_helper.c
    :export:
+
+fbdev Conversion Helper Reference
+================+
+.. kernel-doc:: drivers/gpu/drm/drm_fbconv_helper.c
+   :doc: fbconv helpers
+
+.. kernel-doc:: include/drm/drm_fbconv_helper.h
+   :internal:
+
+.. kernel-doc:: drivers/gpu/drm/drm_fbconv_helper.c
+   :export:
diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst
index 79785559d711..1be44a17f3e8 100644
--- a/Documentation/gpu/todo.rst
+++ b/Documentation/gpu/todo.rst
@@ -462,3 +462,18 @@ Contact: Sam Ravnborg
 
 Outside DRM
 =====+
+Convert fbdev drivers to DRM
+----------------------------
+
+There are plenty of fbdev drivers for old hardware. With fbconv helpers, we
+have a simple and clean way of transitioning fbdev drivers to DRM. Set up a
+simple DRM driver that builds onto the fbconv helpers, copy over the fbdev
+driver and connect both. This should result in a basic DRM driver that can
+run X11 and Weston.  There's a tutorial for this process with example source
+code in the fbconv documentation.
+
+From there, refactor the driver source code into a clean DRM driver that
+requires neither fbdev nor fbconv helpers.
+
+Contact: Thomas Zimmermann
diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
index 7d7e4da2a29e..1fa240a4789f 100644
--- a/drivers/gpu/drm/drm_fbconv_helper.c
+++ b/drivers/gpu/drm/drm_fbconv_helper.c
@@ -18,6 +18,187 @@
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_vblank.h>
 
+/**
+ * DOC: fbconv helpers
+ *
+ * The Linux kernel's fbdev subsystem provides a wide range of drivers for
+ * older graphics hardware. Except for these existng drivers, fbdev is
+ * deprecated and expected to be removed at some point in the future. All new
+ * development happens in DRM. Some of the fbdev drivers are worth carrying
+ * forward. The fbconv helper functions provide a framework for porting fbdev
+ * drivers to DRM.
+ *
+ * When porting over fbdev drivers to DRM, the most significant problem is the
+ * difference in how the internal driver interfaces work. Fbdev has a single
+ * function, struct fb_ops.fb_set_par(), to set video mode and framebuffer
+ * format. DRM use a much more fine-grained interface. In fbdev, framebuffer
+ * memory is managed by a single client, while in DRM multiple clients can
+ * hold buffers with framebuffer data.
+ *
+ * The fbconv helper library provides a set of data structures and functions
+ * that connect DRM and fbdev. The resulting DRM driver maps DRM operations
+ * to fbdev interfaces and uses an fbdev driver for its hardware operations.
+ * Such a driver is not intended to be merged into DRM as-is. It does,
+ * however, provide a starting point for refactoring the fbdev driver's
+ * implementation into first-class DRM code.
+ *
+ * As an example, we create a DRM driver from vesafb, fbdev's generic
+ * vesa driver. We begin by creating a DRM stub driver vesadrm. Please keep
+ * in mind that the provided code is for illustrative purposes and requires
+ * error handling.
+ *
+ * .. code-block:: c
+ *
+ *	DEFINE_DRM_GEM_SHMEM_FOPS(vesadrm_file_operations);
+ *
+ *	static struct drm_driver vesadrm_driver = {
+ *		.major = 1,
+ *		.minor = 0,
+ *		.patchlevel = 0,
+ *		.name = "vesadrm",
+ *		.desc = "DRM VESA driver",
+ *		.date = "01/01/1970",
+ *		.driver_features = DRIVER_ATOMIC |
+ *				   DRIVER_GEM |
+ *				   DRIVER_MODESET,
+ *		.fops = &vesadrm_file_operations,
+ *		DRM_GEM_SHMEM_DRIVER_OPS,
+ *	};
+ *
+ * Fbconv uses SHMEM, so we set up the structures accordingly.
+ *
+ * The fbdev code usually calls register_framebuffer() and
+ * unregister_framebuffer() to connect and disconnect itself to the fbdev
+ * core code. In our case, we replace these calls with
+ * vesadrm_register_framebuffer() and vesadrm_unregister_framebuffer(), which
+ * serve as entry points for vesafb.
+ *
+ * .. code-block:: c
+ *
+ *	#include <drm/drm/fbconv_helper.h>
+ *
+ *	struct vesadrm_device {
+ *		struct drm_device dev;
+ *		struct fb_info *fb_info;
+ *
+ *		struct drm_fbconv_modeset modeset;
+ *	};
+ *
+ *	struct vesadrm_device* vesadrm_register_framebuffer(struct fb_info *fb_info)
+ *	{
+ *		struct vesadrm *vdev;
+ *
+ *		drm_fbconv_fill_fb_info(fb_info);
+ *
+ *		vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+ *		vesadrm_device_init(vdev, &vesadrm_driver, fb_info)
+ *
+ *		drm_dev_register(&vdev->dev, 0);
+ *
+ *		return vdev;
+ *	}
+ *
+ * Here, we have the first references to fbconf helpers. The instance
+ * of struct drm_fbconv_modeset is the central data structure for fbconv.
+ * Built upon struct drm_simple_display_pipe, it stores most state for the
+ * DRM driver.
+ *
+ * The function vesadrm_register_framebuffer() will later be called by
+ * vesafb code with the fbdev driver's fb_info structure. In core fbdev,
+ * register_framebuffer() would fill fb_info with general state and complete
+ * registration. With fbconv helpers, drm_fbconv_fill_fb_info() does this.
+ * It's a simplified version of the fbdev setup process, without device file
+ * creation, registration, or events. No console is created either.
+ * Finally vesadrm_register_framebuffer() initializes the vesadrm device and
+ * registers the DRM device. At this point, vesadrm is completely initialized.
+ *
+ * For completeness, here's the implementation of
+ * vesadrm_unregister_framebuffer(), which shuts the device down.
+ *
+ * .. code-block:: c
+ *
+ *	void vesadrm_unregister_framebuffer(struct vesadrm_device *vdev)
+ *	{
+ *		struct fb_info *fb_info = vdev->fb_info;
+ *
+ *		vesadrm_device_cleanup(vdev);
+ *		kfree(vdev);
+ *		drm_fbconv_cleanup_fb_info(fb_info);
+ *	}
+ *
+ * Next we need an implementation of vesadrm_device_init() and
+ * vesadrm_device_cleanup(). These functions handle the details of
+ * device configuration and console setup. As all this functionality
+ * is provided by helpers, the actual implementation is fairly small.
+ *
+ * .. code-block:: c
+ *
+ *	static int vesadrm_device_init(struct vesadrm_device *vdev,
+ *				       struct drm_driver *drv,
+ *				       struct fb_info *fb_info)
+ *	{
+ *		static const uint32_t formats[] = {
+ *			DRM_FORMAT_XRGB8888,
+ *			DRM_FORMAT_RGB565
+ *		};
+ *		static unsigned int max_width = 1600;
+ *		static unsigned int max_height = 1200;
+ *		static unsigned int preferred_depth = 32;
+ *
+ *		drm_dev_init(&vdev->dev, drv, fb_info->device);
+ *
+ *		vdev->dev.dev_private = vdev;
+ *		vdev->dev.pdev = container_of(fb_info->device, struct pci_dev, dev);
+ *		vdev->fb_info = fb_info;
+ *
+ *		drm_fbconv_modeset_init(&vdev->modeset, &vdev->dev, fb_info,
+ *					max_width, max_height, preferred_depth);
+ *
+ *		drm_fbconv_modeset_setup_pipe(&vdev->modeset, NULL, formats,
+ *					      ARRAY_SIZE(formats), NULL, NULL);
+ *
+ *		drm_fbdev_generic_setup(&vdev->dev, 0);
+ *
+ *		return 0;
+ *	}
+ *
+ *	static void vesadrm_device_cleanup(struct vesadrm_device *vdev)
+ *	{
+ *		struct drm_device *dev = &vdev->dev;
+ *
+ *		drm_fbconv_modeset_cleanup(&vdev->modeset);
+ *
+ *		drm_dev_fini(dev);
+ *		dev->dev_private = NULL;
+ *	}
+ *
+ * In vesadrm_device_init(), several device-specific constants are declared.
+ * Depending on the hardware, drivers should set them accordingly.
+ * The call to drm_fbconv_modeset_init() initializes fbconv modesetting
+ * helpers with these device constants.
+ *
+ * The drm_fbconv_modeset_setup_pipe() creates the simple display pipe with
+ * the specified color formats. By default, everything is set up
+ * automatically. But the function also accepts format modifiers, a DRM
+ * connector, and call-back functions for struct drm_simple_display_pipe.
+ * So each of these can be refactored individually later on.
+ *
+ * After setting up the fbconv helpers, there's is a call to
+ * drm_fbdev_generic_setup(), which set an initial mode and creates a
+ * framebuffer console.
+ *
+ * The implementation of vesadrm_device_cleanup() is the inverse of the
+ * init function. It cleans up the fbconv modesetting helper and releases
+ * the DRM device.
+ *
+ * What is left is connecting vesafb to vesadrm. As a first step, we need a
+ * copy the vesafb source files into the vesadrm driver and make them compile.
+ * Once this is done, we have to replace the call to register_framebuffer()
+ * with a call to vesadrm_register_framebuffer(), and unregister_framebuffer()
+ * with vesadrm_unregister_framebuffer(). We have now disconnected vesafb from
+ * the fbdev core and run it as part of DRM.
+ */
+
 /*
  * Format conversion helpers
  */
-- 
2.23.0

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

* [PATCH v2 12/15] drm/fbconv: Add helper documentation
@ 2019-10-14 14:04   ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

There's now a tutorial on how to create a DRM driver on top of fbconv
helpers. The DRM TODO list contains an entry for converting fbdev
drivers over to DRM.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 Documentation/gpu/drm-kms-helpers.rst |  12 ++
 Documentation/gpu/todo.rst            |  15 +++
 drivers/gpu/drm/drm_fbconv_helper.c   | 181 ++++++++++++++++++++++++++
 3 files changed, 208 insertions(+)

diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst
index 9668a7fe2408..1232a3ef24ff 100644
--- a/Documentation/gpu/drm-kms-helpers.rst
+++ b/Documentation/gpu/drm-kms-helpers.rst
@@ -411,3 +411,15 @@ SHMEM GEM Helper Reference
 
 .. kernel-doc:: drivers/gpu/drm/drm_gem_shmem_helper.c
    :export:
+
+fbdev Conversion Helper Reference
+=================================
+
+.. kernel-doc:: drivers/gpu/drm/drm_fbconv_helper.c
+   :doc: fbconv helpers
+
+.. kernel-doc:: include/drm/drm_fbconv_helper.h
+   :internal:
+
+.. kernel-doc:: drivers/gpu/drm/drm_fbconv_helper.c
+   :export:
diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst
index 79785559d711..1be44a17f3e8 100644
--- a/Documentation/gpu/todo.rst
+++ b/Documentation/gpu/todo.rst
@@ -462,3 +462,18 @@ Contact: Sam Ravnborg
 
 Outside DRM
 ===========
+
+Convert fbdev drivers to DRM
+----------------------------
+
+There are plenty of fbdev drivers for old hardware. With fbconv helpers, we
+have a simple and clean way of transitioning fbdev drivers to DRM. Set up a
+simple DRM driver that builds onto the fbconv helpers, copy over the fbdev
+driver and connect both. This should result in a basic DRM driver that can
+run X11 and Weston.  There's a tutorial for this process with example source
+code in the fbconv documentation.
+
+From there, refactor the driver source code into a clean DRM driver that
+requires neither fbdev nor fbconv helpers.
+
+Contact: Thomas Zimmermann
diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
index 7d7e4da2a29e..1fa240a4789f 100644
--- a/drivers/gpu/drm/drm_fbconv_helper.c
+++ b/drivers/gpu/drm/drm_fbconv_helper.c
@@ -18,6 +18,187 @@
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_vblank.h>
 
+/**
+ * DOC: fbconv helpers
+ *
+ * The Linux kernel's fbdev subsystem provides a wide range of drivers for
+ * older graphics hardware. Except for these existng drivers, fbdev is
+ * deprecated and expected to be removed at some point in the future. All new
+ * development happens in DRM. Some of the fbdev drivers are worth carrying
+ * forward. The fbconv helper functions provide a framework for porting fbdev
+ * drivers to DRM.
+ *
+ * When porting over fbdev drivers to DRM, the most significant problem is the
+ * difference in how the internal driver interfaces work. Fbdev has a single
+ * function, struct fb_ops.fb_set_par(), to set video mode and framebuffer
+ * format. DRM use a much more fine-grained interface. In fbdev, framebuffer
+ * memory is managed by a single client, while in DRM multiple clients can
+ * hold buffers with framebuffer data.
+ *
+ * The fbconv helper library provides a set of data structures and functions
+ * that connect DRM and fbdev. The resulting DRM driver maps DRM operations
+ * to fbdev interfaces and uses an fbdev driver for its hardware operations.
+ * Such a driver is not intended to be merged into DRM as-is. It does,
+ * however, provide a starting point for refactoring the fbdev driver's
+ * implementation into first-class DRM code.
+ *
+ * As an example, we create a DRM driver from vesafb, fbdev's generic
+ * vesa driver. We begin by creating a DRM stub driver vesadrm. Please keep
+ * in mind that the provided code is for illustrative purposes and requires
+ * error handling.
+ *
+ * .. code-block:: c
+ *
+ *	DEFINE_DRM_GEM_SHMEM_FOPS(vesadrm_file_operations);
+ *
+ *	static struct drm_driver vesadrm_driver = {
+ *		.major = 1,
+ *		.minor = 0,
+ *		.patchlevel = 0,
+ *		.name = "vesadrm",
+ *		.desc = "DRM VESA driver",
+ *		.date = "01/01/1970",
+ *		.driver_features = DRIVER_ATOMIC |
+ *				   DRIVER_GEM |
+ *				   DRIVER_MODESET,
+ *		.fops = &vesadrm_file_operations,
+ *		DRM_GEM_SHMEM_DRIVER_OPS,
+ *	};
+ *
+ * Fbconv uses SHMEM, so we set up the structures accordingly.
+ *
+ * The fbdev code usually calls register_framebuffer() and
+ * unregister_framebuffer() to connect and disconnect itself to the fbdev
+ * core code. In our case, we replace these calls with
+ * vesadrm_register_framebuffer() and vesadrm_unregister_framebuffer(), which
+ * serve as entry points for vesafb.
+ *
+ * .. code-block:: c
+ *
+ *	#include <drm/drm/fbconv_helper.h>
+ *
+ *	struct vesadrm_device {
+ *		struct drm_device dev;
+ *		struct fb_info *fb_info;
+ *
+ *		struct drm_fbconv_modeset modeset;
+ *	};
+ *
+ *	struct vesadrm_device* vesadrm_register_framebuffer(struct fb_info *fb_info)
+ *	{
+ *		struct vesadrm *vdev;
+ *
+ *		drm_fbconv_fill_fb_info(fb_info);
+ *
+ *		vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+ *		vesadrm_device_init(vdev, &vesadrm_driver, fb_info)
+ *
+ *		drm_dev_register(&vdev->dev, 0);
+ *
+ *		return vdev;
+ *	}
+ *
+ * Here, we have the first references to fbconf helpers. The instance
+ * of struct drm_fbconv_modeset is the central data structure for fbconv.
+ * Built upon struct drm_simple_display_pipe, it stores most state for the
+ * DRM driver.
+ *
+ * The function vesadrm_register_framebuffer() will later be called by
+ * vesafb code with the fbdev driver's fb_info structure. In core fbdev,
+ * register_framebuffer() would fill fb_info with general state and complete
+ * registration. With fbconv helpers, drm_fbconv_fill_fb_info() does this.
+ * It's a simplified version of the fbdev setup process, without device file
+ * creation, registration, or events. No console is created either.
+ * Finally vesadrm_register_framebuffer() initializes the vesadrm device and
+ * registers the DRM device. At this point, vesadrm is completely initialized.
+ *
+ * For completeness, here's the implementation of
+ * vesadrm_unregister_framebuffer(), which shuts the device down.
+ *
+ * .. code-block:: c
+ *
+ *	void vesadrm_unregister_framebuffer(struct vesadrm_device *vdev)
+ *	{
+ *		struct fb_info *fb_info = vdev->fb_info;
+ *
+ *		vesadrm_device_cleanup(vdev);
+ *		kfree(vdev);
+ *		drm_fbconv_cleanup_fb_info(fb_info);
+ *	}
+ *
+ * Next we need an implementation of vesadrm_device_init() and
+ * vesadrm_device_cleanup(). These functions handle the details of
+ * device configuration and console setup. As all this functionality
+ * is provided by helpers, the actual implementation is fairly small.
+ *
+ * .. code-block:: c
+ *
+ *	static int vesadrm_device_init(struct vesadrm_device *vdev,
+ *				       struct drm_driver *drv,
+ *				       struct fb_info *fb_info)
+ *	{
+ *		static const uint32_t formats[] = {
+ *			DRM_FORMAT_XRGB8888,
+ *			DRM_FORMAT_RGB565
+ *		};
+ *		static unsigned int max_width = 1600;
+ *		static unsigned int max_height = 1200;
+ *		static unsigned int preferred_depth = 32;
+ *
+ *		drm_dev_init(&vdev->dev, drv, fb_info->device);
+ *
+ *		vdev->dev.dev_private = vdev;
+ *		vdev->dev.pdev = container_of(fb_info->device, struct pci_dev, dev);
+ *		vdev->fb_info = fb_info;
+ *
+ *		drm_fbconv_modeset_init(&vdev->modeset, &vdev->dev, fb_info,
+ *					max_width, max_height, preferred_depth);
+ *
+ *		drm_fbconv_modeset_setup_pipe(&vdev->modeset, NULL, formats,
+ *					      ARRAY_SIZE(formats), NULL, NULL);
+ *
+ *		drm_fbdev_generic_setup(&vdev->dev, 0);
+ *
+ *		return 0;
+ *	}
+ *
+ *	static void vesadrm_device_cleanup(struct vesadrm_device *vdev)
+ *	{
+ *		struct drm_device *dev = &vdev->dev;
+ *
+ *		drm_fbconv_modeset_cleanup(&vdev->modeset);
+ *
+ *		drm_dev_fini(dev);
+ *		dev->dev_private = NULL;
+ *	}
+ *
+ * In vesadrm_device_init(), several device-specific constants are declared.
+ * Depending on the hardware, drivers should set them accordingly.
+ * The call to drm_fbconv_modeset_init() initializes fbconv modesetting
+ * helpers with these device constants.
+ *
+ * The drm_fbconv_modeset_setup_pipe() creates the simple display pipe with
+ * the specified color formats. By default, everything is set up
+ * automatically. But the function also accepts format modifiers, a DRM
+ * connector, and call-back functions for struct drm_simple_display_pipe.
+ * So each of these can be refactored individually later on.
+ *
+ * After setting up the fbconv helpers, there's is a call to
+ * drm_fbdev_generic_setup(), which set an initial mode and creates a
+ * framebuffer console.
+ *
+ * The implementation of vesadrm_device_cleanup() is the inverse of the
+ * init function. It cleans up the fbconv modesetting helper and releases
+ * the DRM device.
+ *
+ * What is left is connecting vesafb to vesadrm. As a first step, we need a
+ * copy the vesafb source files into the vesadrm driver and make them compile.
+ * Once this is done, we have to replace the call to register_framebuffer()
+ * with a call to vesadrm_register_framebuffer(), and unregister_framebuffer()
+ * with vesadrm_unregister_framebuffer(). We have now disconnected vesafb from
+ * the fbdev core and run it as part of DRM.
+ */
+
 /*
  * Format conversion helpers
  */
-- 
2.23.0

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

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

* [PATCH v2 13/15] staging: Add mgakms driver
  2019-10-14 14:04 ` Thomas Zimmermann
@ 2019-10-14 14:04   ` Thomas Zimmermann
  -1 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

The mgakms driver uses DRM's fbconv helpers to provide a DRM driver
for Matrox chipsets. This will allow matroxfb to be refactored into
a first-class DRM driver.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/staging/Kconfig             |   2 +
 drivers/staging/Makefile            |   1 +
 drivers/staging/mgakms/Kconfig      |  13 +++
 drivers/staging/mgakms/Makefile     |   6 ++
 drivers/staging/mgakms/mga_device.c |  68 +++++++++++++++
 drivers/staging/mgakms/mga_device.h |  30 +++++++
 drivers/staging/mgakms/mga_drv.c    | 129 ++++++++++++++++++++++++++++
 drivers/staging/mgakms/mga_drv.h    |  14 +++
 8 files changed, 263 insertions(+)
 create mode 100644 drivers/staging/mgakms/Kconfig
 create mode 100644 drivers/staging/mgakms/Makefile
 create mode 100644 drivers/staging/mgakms/mga_device.c
 create mode 100644 drivers/staging/mgakms/mga_device.h
 create mode 100644 drivers/staging/mgakms/mga_drv.c
 create mode 100644 drivers/staging/mgakms/mga_drv.h

diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 6f1fa4c849a1..fd25596813c5 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -125,4 +125,6 @@ source "drivers/staging/exfat/Kconfig"
 
 source "drivers/staging/qlge/Kconfig"
 
+source "drivers/staging/mgakms/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index a90f9b308c8d..4c98b028ee99 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -53,3 +53,4 @@ obj-$(CONFIG_UWB)		+= uwb/
 obj-$(CONFIG_USB_WUSB)		+= wusbcore/
 obj-$(CONFIG_EXFAT_FS)		+= exfat/
 obj-$(CONFIG_QLGE)		+= qlge/
+obj-$(CONFIG_DRM_MGAKMS)	+= mgakms/
diff --git a/drivers/staging/mgakms/Kconfig b/drivers/staging/mgakms/Kconfig
new file mode 100644
index 000000000000..de23e76317bd
--- /dev/null
+++ b/drivers/staging/mgakms/Kconfig
@@ -0,0 +1,13 @@
+config DRM_MGAKMS
+	tristate "Matrox g200/g400"
+	depends on DRM && PCI
+	select DRM_FBCONV_HELPER
+	select DRM_GEM_SHMEM_HELPER
+	select DRM_KMS_HELPER
+	help
+	  Choose this option if you have a Matrox Millennium,
+	  Matrox Millennium II, Matrox Mystique, Matrox Mystique 220,
+	  Matrox Productiva G100, Matrox Mystique G200,
+	  Matrox Millennium G200, Matrox Marvel G200 video, Matrox G400,
+	  G450 or G550 card. If M is selected, the module will be called mga.
+	  AGP support is required for this driver to work.
diff --git a/drivers/staging/mgakms/Makefile b/drivers/staging/mgakms/Makefile
new file mode 100644
index 000000000000..65695f04eb7f
--- /dev/null
+++ b/drivers/staging/mgakms/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+
+mgakms-y	:= mga_device.o \
+		   mga_drv.o
+
+obj-$(CONFIG_DRM_MGAKMS)	+= mgakms.o
diff --git a/drivers/staging/mgakms/mga_device.c b/drivers/staging/mgakms/mga_device.c
new file mode 100644
index 000000000000..34b3bb1ed8a5
--- /dev/null
+++ b/drivers/staging/mgakms/mga_device.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/fb.h>
+#include <linux/pci.h>
+
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_modeset_helper.h>
+
+#include "mga_device.h"
+
+/*
+ * struct mga_device
+ */
+
+int mga_device_init(struct mga_device *mdev, struct drm_driver *drv,
+		    struct fb_info *fb_info)
+{
+	static const uint32_t formats[] = {
+		DRM_FORMAT_XRGB8888,
+		DRM_FORMAT_RGB565
+	};
+	static unsigned int max_width = 2048;
+	static unsigned int max_height = 2048;
+	static unsigned int preferred_depth = 32;
+
+	int ret;
+
+	ret = drm_dev_init(&mdev->dev, drv, fb_info->device);
+	if (ret)
+		return ret;
+	mdev->dev.dev_private = mdev;
+	mdev->dev.pdev = container_of(fb_info->device, struct pci_dev, dev);
+	mdev->fb_info = fb_info;
+
+	ret = drm_fbconv_modeset_init(&mdev->modeset, &mdev->dev, fb_info,
+				      max_width, max_height, preferred_depth);
+	if (ret)
+		goto err_drm_dev_fini;
+
+	ret = drm_fbconv_modeset_setup_pipe(&mdev->modeset, NULL, formats,
+					    ARRAY_SIZE(formats), NULL, NULL);
+	if (ret)
+		goto err_drm_fbconv_modeset_cleanup;
+
+	ret = drm_fbdev_generic_setup(&mdev->dev, 0);
+	if (ret)
+		goto err_drm_fbconv_modeset_cleanup;
+
+	return 0;
+
+err_drm_fbconv_modeset_cleanup:
+	/* cleans up all mode-setting structures */
+	drm_fbconv_modeset_cleanup(&mdev->modeset);
+err_drm_dev_fini:
+	drm_dev_fini(&mdev->dev);
+	return ret;
+}
+
+void mga_device_cleanup(struct mga_device *mdev)
+{
+	struct drm_device *dev = &mdev->dev;
+
+	drm_fbconv_modeset_cleanup(&mdev->modeset);
+
+	drm_dev_fini(dev);
+	dev->dev_private = NULL;
+}
diff --git a/drivers/staging/mgakms/mga_device.h b/drivers/staging/mgakms/mga_device.h
new file mode 100644
index 000000000000..442effbf37bc
--- /dev/null
+++ b/drivers/staging/mgakms/mga_device.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef MGA_DEVICE_H
+#define MGA_DEVICE_H
+
+#include <linux/kernel.h>
+
+#include <drm/drm_device.h>
+#include <drm/drm_fbconv_helper.h>
+
+struct drm_driver;
+struct fb_info;
+
+struct mga_device {
+	struct drm_device dev;
+	struct fb_info *fb_info;
+
+	struct drm_fbconv_modeset modeset;
+};
+
+static inline struct mga_device *mga_device_of_dev(struct drm_device *dev)
+{
+	return container_of(dev, struct mga_device, dev);
+}
+
+int mga_device_init(struct mga_device *mdev, struct drm_driver *drv,
+		    struct fb_info *fb_info);
+void mga_device_cleanup(struct mga_device *mdev);
+
+#endif
diff --git a/drivers/staging/mgakms/mga_drv.c b/drivers/staging/mgakms/mga_drv.c
new file mode 100644
index 000000000000..75e26d3046f3
--- /dev/null
+++ b/drivers/staging/mgakms/mga_drv.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/fb.h>
+#include <linux/pci.h>
+
+#include <drm/drm_drv.h>
+#include <drm/drm_fbconv_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_file.h>
+#include <drm/drm_gem_shmem_helper.h>
+#include <drm/drm_ioctl.h>
+
+#include "mga_device.h"
+#include "mga_drv.h"
+
+#define DRIVER_AUTHOR		"Thomas Zimmermann <tzimmermann@suse.de>"
+#define DRIVER_NAME		"mgakms"
+#define DRIVER_DESCRIPTION	"DRM driver for Matrox graphics chipsets"
+#define DRIVER_LICENSE		"GPL"
+#define DRIVER_DATE		"20190301"
+#define DRIVER_MAJOR		0
+#define DRIVER_MINOR		0
+#define DRIVER_PATCHLEVEL	1
+
+/*
+ * DRM driver
+ */
+
+DEFINE_DRM_GEM_SHMEM_FOPS(mga_file_operations);
+
+static struct drm_driver mga_driver = {
+	.major = DRIVER_MAJOR,
+	.minor = DRIVER_MINOR,
+	.patchlevel = DRIVER_PATCHLEVEL,
+	.name = DRIVER_NAME,
+	.desc = DRIVER_DESCRIPTION,
+	.date = DRIVER_DATE,
+	.driver_features = DRIVER_ATOMIC |
+			   DRIVER_GEM |
+			   DRIVER_MODESET,
+	.fops = &mga_file_operations,
+	DRM_GEM_SHMEM_DRIVER_OPS,
+};
+
+static void mga_remove_conflicting_framebuffers(struct pci_dev *pdev)
+{
+	struct apertures_struct *ap;
+	bool primary = false;
+
+	ap = alloc_apertures(1);
+	if (!ap)
+		return;
+
+	ap->ranges[0].base = pci_resource_start(pdev, 1);
+	ap->ranges[0].size = pci_resource_len(pdev, 1);
+
+#ifdef CONFIG_X86
+	primary = pdev->resource[PCI_ROM_RESOURCE].flags &
+		IORESOURCE_ROM_SHADOW;
+#endif
+	drm_fb_helper_remove_conflicting_framebuffers(ap, DRIVER_NAME,
+						      primary);
+	kfree(ap);
+}
+
+static struct mga_device *mga_create_device(struct fb_info *fb_info)
+{
+	struct mga_device *mdev;
+	int ret;
+
+	mdev = devm_kzalloc(fb_info->device, sizeof(*mdev), GFP_KERNEL);
+	if (!mdev)
+		return ERR_PTR(-ENOMEM);
+	ret = mga_device_init(mdev, &mga_driver, fb_info);
+	if (ret)
+		goto err_devm_kfree;
+	return mdev;
+
+err_devm_kfree:
+	devm_kfree(fb_info->device, mdev);
+	return ERR_PTR(ret);
+}
+
+static void mga_destroy_device(struct mga_device *mdev)
+{
+	struct device *dev = mdev->fb_info->device;
+
+	mga_device_cleanup(mdev);
+	devm_kfree(dev, mdev);
+}
+
+struct mga_device *mga_register_framebuffer(struct fb_info *fb_info,
+					    struct pci_dev *pdev)
+{
+	int ret;
+	struct mga_device *mdev;
+
+	mga_remove_conflicting_framebuffers(pdev);
+
+	ret = drm_fbconv_fill_fb_info(fb_info);
+	if (ret)
+		return ERR_PTR(ret);
+
+	mdev = mga_create_device(fb_info);
+	if (IS_ERR(mdev)) {
+		ret = PTR_ERR(mdev);
+		goto err_drm_fbconv_cleanup_fb_info;
+	}
+
+	ret = drm_dev_register(&mdev->dev, 0);
+	if (ret)
+		goto err_mga_destroy_device;
+
+	return mdev;
+
+err_mga_destroy_device:
+	mga_destroy_device(mdev);
+err_drm_fbconv_cleanup_fb_info:
+	drm_fbconv_cleanup_fb_info(fb_info);
+	return ERR_PTR(ret);
+}
+
+void mga_unregister_framebuffer(struct mga_device *mdev)
+{
+	struct fb_info *fb_info = mdev->fb_info;
+
+	mga_destroy_device(mdev);
+	drm_fbconv_cleanup_fb_info(fb_info);
+}
diff --git a/drivers/staging/mgakms/mga_drv.h b/drivers/staging/mgakms/mga_drv.h
new file mode 100644
index 000000000000..d214719516c0
--- /dev/null
+++ b/drivers/staging/mgakms/mga_drv.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef MGA_DRV_H
+#define MGA_DRV_H
+
+struct fb_info;
+struct mga_device;
+struct pci_dev;
+
+struct mga_device *mga_register_framebuffer(struct fb_info *fb_info,
+					    struct pci_dev *pdev);
+void mga_unregister_framebuffer(struct mga_device *mdev);
+
+#endif
-- 
2.23.0

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

* [PATCH v2 13/15] staging: Add mgakms driver
@ 2019-10-14 14:04   ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

The mgakms driver uses DRM's fbconv helpers to provide a DRM driver
for Matrox chipsets. This will allow matroxfb to be refactored into
a first-class DRM driver.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/staging/Kconfig             |   2 +
 drivers/staging/Makefile            |   1 +
 drivers/staging/mgakms/Kconfig      |  13 +++
 drivers/staging/mgakms/Makefile     |   6 ++
 drivers/staging/mgakms/mga_device.c |  68 +++++++++++++++
 drivers/staging/mgakms/mga_device.h |  30 +++++++
 drivers/staging/mgakms/mga_drv.c    | 129 ++++++++++++++++++++++++++++
 drivers/staging/mgakms/mga_drv.h    |  14 +++
 8 files changed, 263 insertions(+)
 create mode 100644 drivers/staging/mgakms/Kconfig
 create mode 100644 drivers/staging/mgakms/Makefile
 create mode 100644 drivers/staging/mgakms/mga_device.c
 create mode 100644 drivers/staging/mgakms/mga_device.h
 create mode 100644 drivers/staging/mgakms/mga_drv.c
 create mode 100644 drivers/staging/mgakms/mga_drv.h

diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 6f1fa4c849a1..fd25596813c5 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -125,4 +125,6 @@ source "drivers/staging/exfat/Kconfig"
 
 source "drivers/staging/qlge/Kconfig"
 
+source "drivers/staging/mgakms/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index a90f9b308c8d..4c98b028ee99 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -53,3 +53,4 @@ obj-$(CONFIG_UWB)		+= uwb/
 obj-$(CONFIG_USB_WUSB)		+= wusbcore/
 obj-$(CONFIG_EXFAT_FS)		+= exfat/
 obj-$(CONFIG_QLGE)		+= qlge/
+obj-$(CONFIG_DRM_MGAKMS)	+= mgakms/
diff --git a/drivers/staging/mgakms/Kconfig b/drivers/staging/mgakms/Kconfig
new file mode 100644
index 000000000000..de23e76317bd
--- /dev/null
+++ b/drivers/staging/mgakms/Kconfig
@@ -0,0 +1,13 @@
+config DRM_MGAKMS
+	tristate "Matrox g200/g400"
+	depends on DRM && PCI
+	select DRM_FBCONV_HELPER
+	select DRM_GEM_SHMEM_HELPER
+	select DRM_KMS_HELPER
+	help
+	  Choose this option if you have a Matrox Millennium,
+	  Matrox Millennium II, Matrox Mystique, Matrox Mystique 220,
+	  Matrox Productiva G100, Matrox Mystique G200,
+	  Matrox Millennium G200, Matrox Marvel G200 video, Matrox G400,
+	  G450 or G550 card. If M is selected, the module will be called mga.
+	  AGP support is required for this driver to work.
diff --git a/drivers/staging/mgakms/Makefile b/drivers/staging/mgakms/Makefile
new file mode 100644
index 000000000000..65695f04eb7f
--- /dev/null
+++ b/drivers/staging/mgakms/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+
+mgakms-y	:= mga_device.o \
+		   mga_drv.o
+
+obj-$(CONFIG_DRM_MGAKMS)	+= mgakms.o
diff --git a/drivers/staging/mgakms/mga_device.c b/drivers/staging/mgakms/mga_device.c
new file mode 100644
index 000000000000..34b3bb1ed8a5
--- /dev/null
+++ b/drivers/staging/mgakms/mga_device.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/fb.h>
+#include <linux/pci.h>
+
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_modeset_helper.h>
+
+#include "mga_device.h"
+
+/*
+ * struct mga_device
+ */
+
+int mga_device_init(struct mga_device *mdev, struct drm_driver *drv,
+		    struct fb_info *fb_info)
+{
+	static const uint32_t formats[] = {
+		DRM_FORMAT_XRGB8888,
+		DRM_FORMAT_RGB565
+	};
+	static unsigned int max_width = 2048;
+	static unsigned int max_height = 2048;
+	static unsigned int preferred_depth = 32;
+
+	int ret;
+
+	ret = drm_dev_init(&mdev->dev, drv, fb_info->device);
+	if (ret)
+		return ret;
+	mdev->dev.dev_private = mdev;
+	mdev->dev.pdev = container_of(fb_info->device, struct pci_dev, dev);
+	mdev->fb_info = fb_info;
+
+	ret = drm_fbconv_modeset_init(&mdev->modeset, &mdev->dev, fb_info,
+				      max_width, max_height, preferred_depth);
+	if (ret)
+		goto err_drm_dev_fini;
+
+	ret = drm_fbconv_modeset_setup_pipe(&mdev->modeset, NULL, formats,
+					    ARRAY_SIZE(formats), NULL, NULL);
+	if (ret)
+		goto err_drm_fbconv_modeset_cleanup;
+
+	ret = drm_fbdev_generic_setup(&mdev->dev, 0);
+	if (ret)
+		goto err_drm_fbconv_modeset_cleanup;
+
+	return 0;
+
+err_drm_fbconv_modeset_cleanup:
+	/* cleans up all mode-setting structures */
+	drm_fbconv_modeset_cleanup(&mdev->modeset);
+err_drm_dev_fini:
+	drm_dev_fini(&mdev->dev);
+	return ret;
+}
+
+void mga_device_cleanup(struct mga_device *mdev)
+{
+	struct drm_device *dev = &mdev->dev;
+
+	drm_fbconv_modeset_cleanup(&mdev->modeset);
+
+	drm_dev_fini(dev);
+	dev->dev_private = NULL;
+}
diff --git a/drivers/staging/mgakms/mga_device.h b/drivers/staging/mgakms/mga_device.h
new file mode 100644
index 000000000000..442effbf37bc
--- /dev/null
+++ b/drivers/staging/mgakms/mga_device.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef MGA_DEVICE_H
+#define MGA_DEVICE_H
+
+#include <linux/kernel.h>
+
+#include <drm/drm_device.h>
+#include <drm/drm_fbconv_helper.h>
+
+struct drm_driver;
+struct fb_info;
+
+struct mga_device {
+	struct drm_device dev;
+	struct fb_info *fb_info;
+
+	struct drm_fbconv_modeset modeset;
+};
+
+static inline struct mga_device *mga_device_of_dev(struct drm_device *dev)
+{
+	return container_of(dev, struct mga_device, dev);
+}
+
+int mga_device_init(struct mga_device *mdev, struct drm_driver *drv,
+		    struct fb_info *fb_info);
+void mga_device_cleanup(struct mga_device *mdev);
+
+#endif
diff --git a/drivers/staging/mgakms/mga_drv.c b/drivers/staging/mgakms/mga_drv.c
new file mode 100644
index 000000000000..75e26d3046f3
--- /dev/null
+++ b/drivers/staging/mgakms/mga_drv.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/fb.h>
+#include <linux/pci.h>
+
+#include <drm/drm_drv.h>
+#include <drm/drm_fbconv_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_file.h>
+#include <drm/drm_gem_shmem_helper.h>
+#include <drm/drm_ioctl.h>
+
+#include "mga_device.h"
+#include "mga_drv.h"
+
+#define DRIVER_AUTHOR		"Thomas Zimmermann <tzimmermann@suse.de>"
+#define DRIVER_NAME		"mgakms"
+#define DRIVER_DESCRIPTION	"DRM driver for Matrox graphics chipsets"
+#define DRIVER_LICENSE		"GPL"
+#define DRIVER_DATE		"20190301"
+#define DRIVER_MAJOR		0
+#define DRIVER_MINOR		0
+#define DRIVER_PATCHLEVEL	1
+
+/*
+ * DRM driver
+ */
+
+DEFINE_DRM_GEM_SHMEM_FOPS(mga_file_operations);
+
+static struct drm_driver mga_driver = {
+	.major = DRIVER_MAJOR,
+	.minor = DRIVER_MINOR,
+	.patchlevel = DRIVER_PATCHLEVEL,
+	.name = DRIVER_NAME,
+	.desc = DRIVER_DESCRIPTION,
+	.date = DRIVER_DATE,
+	.driver_features = DRIVER_ATOMIC |
+			   DRIVER_GEM |
+			   DRIVER_MODESET,
+	.fops = &mga_file_operations,
+	DRM_GEM_SHMEM_DRIVER_OPS,
+};
+
+static void mga_remove_conflicting_framebuffers(struct pci_dev *pdev)
+{
+	struct apertures_struct *ap;
+	bool primary = false;
+
+	ap = alloc_apertures(1);
+	if (!ap)
+		return;
+
+	ap->ranges[0].base = pci_resource_start(pdev, 1);
+	ap->ranges[0].size = pci_resource_len(pdev, 1);
+
+#ifdef CONFIG_X86
+	primary = pdev->resource[PCI_ROM_RESOURCE].flags &
+		IORESOURCE_ROM_SHADOW;
+#endif
+	drm_fb_helper_remove_conflicting_framebuffers(ap, DRIVER_NAME,
+						      primary);
+	kfree(ap);
+}
+
+static struct mga_device *mga_create_device(struct fb_info *fb_info)
+{
+	struct mga_device *mdev;
+	int ret;
+
+	mdev = devm_kzalloc(fb_info->device, sizeof(*mdev), GFP_KERNEL);
+	if (!mdev)
+		return ERR_PTR(-ENOMEM);
+	ret = mga_device_init(mdev, &mga_driver, fb_info);
+	if (ret)
+		goto err_devm_kfree;
+	return mdev;
+
+err_devm_kfree:
+	devm_kfree(fb_info->device, mdev);
+	return ERR_PTR(ret);
+}
+
+static void mga_destroy_device(struct mga_device *mdev)
+{
+	struct device *dev = mdev->fb_info->device;
+
+	mga_device_cleanup(mdev);
+	devm_kfree(dev, mdev);
+}
+
+struct mga_device *mga_register_framebuffer(struct fb_info *fb_info,
+					    struct pci_dev *pdev)
+{
+	int ret;
+	struct mga_device *mdev;
+
+	mga_remove_conflicting_framebuffers(pdev);
+
+	ret = drm_fbconv_fill_fb_info(fb_info);
+	if (ret)
+		return ERR_PTR(ret);
+
+	mdev = mga_create_device(fb_info);
+	if (IS_ERR(mdev)) {
+		ret = PTR_ERR(mdev);
+		goto err_drm_fbconv_cleanup_fb_info;
+	}
+
+	ret = drm_dev_register(&mdev->dev, 0);
+	if (ret)
+		goto err_mga_destroy_device;
+
+	return mdev;
+
+err_mga_destroy_device:
+	mga_destroy_device(mdev);
+err_drm_fbconv_cleanup_fb_info:
+	drm_fbconv_cleanup_fb_info(fb_info);
+	return ERR_PTR(ret);
+}
+
+void mga_unregister_framebuffer(struct mga_device *mdev)
+{
+	struct fb_info *fb_info = mdev->fb_info;
+
+	mga_destroy_device(mdev);
+	drm_fbconv_cleanup_fb_info(fb_info);
+}
diff --git a/drivers/staging/mgakms/mga_drv.h b/drivers/staging/mgakms/mga_drv.h
new file mode 100644
index 000000000000..d214719516c0
--- /dev/null
+++ b/drivers/staging/mgakms/mga_drv.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef MGA_DRV_H
+#define MGA_DRV_H
+
+struct fb_info;
+struct mga_device;
+struct pci_dev;
+
+struct mga_device *mga_register_framebuffer(struct fb_info *fb_info,
+					    struct pci_dev *pdev);
+void mga_unregister_framebuffer(struct mga_device *mdev);
+
+#endif
-- 
2.23.0

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

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

* [PATCH v2 14/15] staging/mgakms: Import matroxfb driver source code
  2019-10-14 14:04 ` Thomas Zimmermann
                   ` (13 preceding siblings ...)
  (?)
@ 2019-10-14 14:04 ` Thomas Zimmermann
  2019-10-15 11:48     ` Ville Syrjälä
  -1 siblings, 1 reply; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

Only code is being copied, no functional changes are made.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/staging/mgakms/g450_pll.c         |  539 +++++
 drivers/staging/mgakms/g450_pll.h         |   13 +
 drivers/staging/mgakms/i2c-matroxfb.c     |  238 ++
 drivers/staging/mgakms/matroxfb_DAC1064.c | 1113 +++++++++
 drivers/staging/mgakms/matroxfb_DAC1064.h |  180 ++
 drivers/staging/mgakms/matroxfb_Ti3026.c  |  748 ++++++
 drivers/staging/mgakms/matroxfb_Ti3026.h  |   12 +
 drivers/staging/mgakms/matroxfb_accel.c   |  519 ++++
 drivers/staging/mgakms/matroxfb_accel.h   |    9 +
 drivers/staging/mgakms/matroxfb_base.c    | 2607 +++++++++++++++++++++
 drivers/staging/mgakms/matroxfb_base.h    |  710 ++++++
 drivers/staging/mgakms/matroxfb_crtc2.h   |   35 +
 drivers/staging/mgakms/matroxfb_g450.c    |  640 +++++
 drivers/staging/mgakms/matroxfb_g450.h    |   15 +
 drivers/staging/mgakms/matroxfb_maven.h   |   21 +
 drivers/staging/mgakms/matroxfb_misc.c    |  815 +++++++
 drivers/staging/mgakms/matroxfb_misc.h    |   22 +
 17 files changed, 8236 insertions(+)
 create mode 100644 drivers/staging/mgakms/g450_pll.c
 create mode 100644 drivers/staging/mgakms/g450_pll.h
 create mode 100644 drivers/staging/mgakms/i2c-matroxfb.c
 create mode 100644 drivers/staging/mgakms/matroxfb_DAC1064.c
 create mode 100644 drivers/staging/mgakms/matroxfb_DAC1064.h
 create mode 100644 drivers/staging/mgakms/matroxfb_Ti3026.c
 create mode 100644 drivers/staging/mgakms/matroxfb_Ti3026.h
 create mode 100644 drivers/staging/mgakms/matroxfb_accel.c
 create mode 100644 drivers/staging/mgakms/matroxfb_accel.h
 create mode 100644 drivers/staging/mgakms/matroxfb_base.c
 create mode 100644 drivers/staging/mgakms/matroxfb_base.h
 create mode 100644 drivers/staging/mgakms/matroxfb_crtc2.h
 create mode 100644 drivers/staging/mgakms/matroxfb_g450.c
 create mode 100644 drivers/staging/mgakms/matroxfb_g450.h
 create mode 100644 drivers/staging/mgakms/matroxfb_maven.h
 create mode 100644 drivers/staging/mgakms/matroxfb_misc.c
 create mode 100644 drivers/staging/mgakms/matroxfb_misc.h

diff --git a/drivers/staging/mgakms/g450_pll.c b/drivers/staging/mgakms/g450_pll.c
new file mode 100644
index 000000000000..c15f8a57498e
--- /dev/null
+++ b/drivers/staging/mgakms/g450_pll.c
@@ -0,0 +1,539 @@
+/*
+ *
+ * Hardware accelerated Matrox PCI cards - G450/G550 PLL control.
+ *
+ * (c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Portions Copyright (c) 2001 Matrox Graphics Inc.
+ *
+ * Version: 1.64 2002/06/10
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ */
+
+#include "g450_pll.h"
+#include "matroxfb_DAC1064.h"
+
+static inline unsigned int g450_vco2f(unsigned char p, unsigned int fvco) {
+	return (p & 0x40) ? fvco : fvco >> ((p & 3) + 1);
+}
+
+static inline unsigned int g450_f2vco(unsigned char p, unsigned int fin) {
+	return (p & 0x40) ? fin : fin << ((p & 3) + 1);
+}
+
+static unsigned int g450_mnp2vco(const struct matrox_fb_info *minfo,
+				 unsigned int mnp)
+{
+	unsigned int m, n;
+
+	m = ((mnp >> 16) & 0x0FF) + 1;
+	n = ((mnp >>  7) & 0x1FE) + 4;
+	return (minfo->features.pll.ref_freq * n + (m >> 1)) / m;
+}
+
+unsigned int g450_mnp2f(const struct matrox_fb_info *minfo, unsigned int mnp)
+{
+	return g450_vco2f(mnp, g450_mnp2vco(minfo, mnp));
+}
+
+static inline unsigned int pll_freq_delta(unsigned int f1, unsigned int f2) {
+	if (f2 < f1) {
+    		f2 = f1 - f2;
+	} else {
+		f2 = f2 - f1;
+	}
+	return f2;
+}
+
+#define NO_MORE_MNP	0x01FFFFFF
+#define G450_MNP_FREQBITS	(0xFFFFFF43)	/* do not mask high byte so we'll catch NO_MORE_MNP */
+
+static unsigned int g450_nextpll(const struct matrox_fb_info *minfo,
+				 const struct matrox_pll_limits *pi,
+				 unsigned int *fvco, unsigned int mnp)
+{
+	unsigned int m, n, p;
+	unsigned int tvco = *fvco;
+
+	m = (mnp >> 16) & 0xFF;
+	p = mnp & 0xFF;
+
+	do {
+		if (m == 0 || m == 0xFF) {
+			if (m == 0) {
+				if (p & 0x40) {
+					return NO_MORE_MNP;
+				}
+			        if (p & 3) {
+					p--;
+				} else {
+					p = 0x40;
+				}
+				tvco >>= 1;
+				if (tvco < pi->vcomin) {
+					return NO_MORE_MNP;
+				}
+				*fvco = tvco;
+			}
+
+			p &= 0x43;
+			if (tvco < 550000) {
+/*				p |= 0x00; */
+			} else if (tvco < 700000) {
+				p |= 0x08;
+			} else if (tvco < 1000000) {
+				p |= 0x10;
+			} else if (tvco < 1150000) {
+				p |= 0x18;
+			} else {
+				p |= 0x20;
+			}
+			m = 9;
+		} else {
+			m--;
+		}
+		n = ((tvco * (m+1) + minfo->features.pll.ref_freq) / (minfo->features.pll.ref_freq * 2)) - 2;
+	} while (n < 0x03 || n > 0x7A);
+	return (m << 16) | (n << 8) | p;
+}
+
+static unsigned int g450_firstpll(const struct matrox_fb_info *minfo,
+				  const struct matrox_pll_limits *pi,
+				  unsigned int *vco, unsigned int fout)
+{
+	unsigned int p;
+	unsigned int vcomax;
+
+	vcomax = pi->vcomax;
+	if (fout > (vcomax / 2)) {
+		if (fout > vcomax) {
+			*vco = vcomax;
+		} else {
+			*vco = fout;
+		}
+		p = 0x40;
+	} else {
+		unsigned int tvco;
+
+		p = 3;
+		tvco = g450_f2vco(p, fout);
+		while (p && (tvco > vcomax)) {
+			p--;
+			tvco >>= 1;
+		}
+		if (tvco < pi->vcomin) {
+			tvco = pi->vcomin;
+		}
+		*vco = tvco;
+	}
+	return g450_nextpll(minfo, pi, vco, 0xFF0000 | p);
+}
+
+static inline unsigned int g450_setpll(const struct matrox_fb_info *minfo,
+				       unsigned int mnp, unsigned int pll)
+{
+	switch (pll) {
+		case M_PIXEL_PLL_A:
+			matroxfb_DAC_out(minfo, M1064_XPIXPLLAM, mnp >> 16);
+			matroxfb_DAC_out(minfo, M1064_XPIXPLLAN, mnp >> 8);
+			matroxfb_DAC_out(minfo, M1064_XPIXPLLAP, mnp);
+			return M1064_XPIXPLLSTAT;
+
+		case M_PIXEL_PLL_B:
+			matroxfb_DAC_out(minfo, M1064_XPIXPLLBM, mnp >> 16);
+			matroxfb_DAC_out(minfo, M1064_XPIXPLLBN, mnp >> 8);
+			matroxfb_DAC_out(minfo, M1064_XPIXPLLBP, mnp);
+			return M1064_XPIXPLLSTAT;
+
+		case M_PIXEL_PLL_C:
+			matroxfb_DAC_out(minfo, M1064_XPIXPLLCM, mnp >> 16);
+			matroxfb_DAC_out(minfo, M1064_XPIXPLLCN, mnp >> 8);
+			matroxfb_DAC_out(minfo, M1064_XPIXPLLCP, mnp);
+			return M1064_XPIXPLLSTAT;
+
+		case M_SYSTEM_PLL:
+			matroxfb_DAC_out(minfo, DAC1064_XSYSPLLM, mnp >> 16);
+			matroxfb_DAC_out(minfo, DAC1064_XSYSPLLN, mnp >> 8);
+			matroxfb_DAC_out(minfo, DAC1064_XSYSPLLP, mnp);
+			return DAC1064_XSYSPLLSTAT;
+
+		case M_VIDEO_PLL:
+			matroxfb_DAC_out(minfo, M1064_XVIDPLLM, mnp >> 16);
+			matroxfb_DAC_out(minfo, M1064_XVIDPLLN, mnp >> 8);
+			matroxfb_DAC_out(minfo, M1064_XVIDPLLP, mnp);
+			return M1064_XVIDPLLSTAT;
+	}
+	return 0;
+}
+
+static inline unsigned int g450_cmppll(const struct matrox_fb_info *minfo,
+				       unsigned int mnp, unsigned int pll)
+{
+	unsigned char m = mnp >> 16;
+	unsigned char n = mnp >> 8;
+	unsigned char p = mnp;
+
+	switch (pll) {
+		case M_PIXEL_PLL_A:
+			return (matroxfb_DAC_in(minfo, M1064_XPIXPLLAM) != m ||
+				matroxfb_DAC_in(minfo, M1064_XPIXPLLAN) != n ||
+				matroxfb_DAC_in(minfo, M1064_XPIXPLLAP) != p);
+
+		case M_PIXEL_PLL_B:
+			return (matroxfb_DAC_in(minfo, M1064_XPIXPLLBM) != m ||
+				matroxfb_DAC_in(minfo, M1064_XPIXPLLBN) != n ||
+				matroxfb_DAC_in(minfo, M1064_XPIXPLLBP) != p);
+
+		case M_PIXEL_PLL_C:
+			return (matroxfb_DAC_in(minfo, M1064_XPIXPLLCM) != m ||
+				matroxfb_DAC_in(minfo, M1064_XPIXPLLCN) != n ||
+				matroxfb_DAC_in(minfo, M1064_XPIXPLLCP) != p);
+
+		case M_SYSTEM_PLL:
+			return (matroxfb_DAC_in(minfo, DAC1064_XSYSPLLM) != m ||
+				matroxfb_DAC_in(minfo, DAC1064_XSYSPLLN) != n ||
+				matroxfb_DAC_in(minfo, DAC1064_XSYSPLLP) != p);
+
+		case M_VIDEO_PLL:
+			return (matroxfb_DAC_in(minfo, M1064_XVIDPLLM) != m ||
+				matroxfb_DAC_in(minfo, M1064_XVIDPLLN) != n ||
+				matroxfb_DAC_in(minfo, M1064_XVIDPLLP) != p);
+	}
+	return 1;
+}
+
+static inline int g450_isplllocked(const struct matrox_fb_info *minfo,
+				   unsigned int regidx)
+{
+	unsigned int j;
+
+	for (j = 0; j < 1000; j++) {
+		if (matroxfb_DAC_in(minfo, regidx) & 0x40) {
+			unsigned int r = 0;
+			int i;
+
+			for (i = 0; i < 100; i++) {
+				r += matroxfb_DAC_in(minfo, regidx) & 0x40;
+			}
+			return r >= (90 * 0x40);
+		}
+		/* udelay(1)... but DAC_in is much slower... */
+	}
+	return 0;
+}
+
+static int g450_testpll(const struct matrox_fb_info *minfo, unsigned int mnp,
+			unsigned int pll)
+{
+	return g450_isplllocked(minfo, g450_setpll(minfo, mnp, pll));
+}
+
+static void updatehwstate_clk(struct matrox_hw_state* hw, unsigned int mnp, unsigned int pll) {
+	switch (pll) {
+		case M_SYSTEM_PLL:
+			hw->DACclk[3] = mnp >> 16;
+			hw->DACclk[4] = mnp >> 8;
+			hw->DACclk[5] = mnp;
+			break;
+	}
+}
+
+void matroxfb_g450_setpll_cond(struct matrox_fb_info *minfo, unsigned int mnp,
+			       unsigned int pll)
+{
+	if (g450_cmppll(minfo, mnp, pll)) {
+		g450_setpll(minfo, mnp, pll);
+	}
+}
+
+static inline unsigned int g450_findworkingpll(struct matrox_fb_info *minfo,
+					       unsigned int pll,
+					       unsigned int *mnparray,
+					       unsigned int mnpcount)
+{
+	unsigned int found = 0;
+	unsigned int idx;
+	unsigned int mnpfound = mnparray[0];
+		
+	for (idx = 0; idx < mnpcount; idx++) {
+		unsigned int sarray[3];
+		unsigned int *sptr;
+		{
+			unsigned int mnp;
+		
+			sptr = sarray;
+			mnp = mnparray[idx];
+			if (mnp & 0x38) {
+				*sptr++ = mnp - 8;
+			}
+			if ((mnp & 0x38) != 0x38) {
+				*sptr++ = mnp + 8;
+			}
+			*sptr = mnp;
+		}
+		while (sptr >= sarray) {
+			unsigned int mnp = *sptr--;
+		
+			if (g450_testpll(minfo, mnp - 0x0300, pll) &&
+			    g450_testpll(minfo, mnp + 0x0300, pll) &&
+			    g450_testpll(minfo, mnp - 0x0200, pll) &&
+			    g450_testpll(minfo, mnp + 0x0200, pll) &&
+			    g450_testpll(minfo, mnp - 0x0100, pll) &&
+			    g450_testpll(minfo, mnp + 0x0100, pll)) {
+				if (g450_testpll(minfo, mnp, pll)) {
+					return mnp;
+				}
+			} else if (!found && g450_testpll(minfo, mnp, pll)) {
+				mnpfound = mnp;
+				found = 1;
+			}
+		}
+	}
+	g450_setpll(minfo, mnpfound, pll);
+	return mnpfound;
+}
+
+static void g450_addcache(struct matrox_pll_cache* ci, unsigned int mnp_key, unsigned int mnp_value) {
+	if (++ci->valid > ARRAY_SIZE(ci->data)) {
+		ci->valid = ARRAY_SIZE(ci->data);
+	}
+	memmove(ci->data + 1, ci->data, (ci->valid - 1) * sizeof(*ci->data));
+	ci->data[0].mnp_key = mnp_key & G450_MNP_FREQBITS;
+	ci->data[0].mnp_value = mnp_value;
+}
+
+static int g450_checkcache(struct matrox_fb_info *minfo,
+			   struct matrox_pll_cache *ci, unsigned int mnp_key)
+{
+	unsigned int i;
+	
+	mnp_key &= G450_MNP_FREQBITS;
+	for (i = 0; i < ci->valid; i++) {
+		if (ci->data[i].mnp_key == mnp_key) {
+			unsigned int mnp;
+			
+			mnp = ci->data[i].mnp_value;
+			if (i) {
+				memmove(ci->data + 1, ci->data, i * sizeof(*ci->data));
+				ci->data[0].mnp_key = mnp_key;
+				ci->data[0].mnp_value = mnp;
+			}
+			return mnp;
+		}
+	}
+	return NO_MORE_MNP;
+}
+
+static int __g450_setclk(struct matrox_fb_info *minfo, unsigned int fout,
+			 unsigned int pll, unsigned int *mnparray,
+			 unsigned int *deltaarray)
+{
+	unsigned int mnpcount;
+	unsigned int pixel_vco;
+	const struct matrox_pll_limits* pi;
+	struct matrox_pll_cache* ci;
+
+	pixel_vco = 0;
+	switch (pll) {
+		case M_PIXEL_PLL_A:
+		case M_PIXEL_PLL_B:
+		case M_PIXEL_PLL_C:
+			{
+				u_int8_t tmp, xpwrctrl;
+				unsigned long flags;
+				
+				matroxfb_DAC_lock_irqsave(flags);
+
+				xpwrctrl = matroxfb_DAC_in(minfo, M1064_XPWRCTRL);
+				matroxfb_DAC_out(minfo, M1064_XPWRCTRL, xpwrctrl & ~M1064_XPWRCTRL_PANELPDN);
+				mga_outb(M_SEQ_INDEX, M_SEQ1);
+				mga_outb(M_SEQ_DATA, mga_inb(M_SEQ_DATA) | M_SEQ1_SCROFF);
+				tmp = matroxfb_DAC_in(minfo, M1064_XPIXCLKCTRL);
+				tmp |= M1064_XPIXCLKCTRL_DIS;
+				if (!(tmp & M1064_XPIXCLKCTRL_PLL_UP)) {
+					tmp |= M1064_XPIXCLKCTRL_PLL_UP;
+				}
+				matroxfb_DAC_out(minfo, M1064_XPIXCLKCTRL, tmp);
+				/* DVI PLL preferred for frequencies up to
+				   panel link max, standard PLL otherwise */
+				if (fout >= minfo->max_pixel_clock_panellink)
+					tmp = 0;
+				else tmp =
+					M1064_XDVICLKCTRL_DVIDATAPATHSEL |
+					M1064_XDVICLKCTRL_C1DVICLKSEL |
+					M1064_XDVICLKCTRL_C1DVICLKEN |
+					M1064_XDVICLKCTRL_DVILOOPCTL |
+					M1064_XDVICLKCTRL_P1LOOPBWDTCTL;
+                                /* Setting this breaks PC systems so don't do it */
+				/* matroxfb_DAC_out(minfo, M1064_XDVICLKCTRL, tmp); */
+				matroxfb_DAC_out(minfo, M1064_XPWRCTRL,
+						 xpwrctrl);
+
+				matroxfb_DAC_unlock_irqrestore(flags);
+			}
+			{
+				u_int8_t misc;
+		
+				misc = mga_inb(M_MISC_REG_READ) & ~0x0C;
+				switch (pll) {
+					case M_PIXEL_PLL_A:
+						break;
+					case M_PIXEL_PLL_B:
+						misc |=  0x04;
+						break;
+					default:
+						misc |=  0x0C;
+						break;
+				}
+				mga_outb(M_MISC_REG, misc);
+			}
+			pi = &minfo->limits.pixel;
+			ci = &minfo->cache.pixel;
+			break;
+		case M_SYSTEM_PLL:
+			{
+				u_int32_t opt;
+
+				pci_read_config_dword(minfo->pcidev, PCI_OPTION_REG, &opt);
+				if (!(opt & 0x20)) {
+					pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, opt | 0x20);
+				}
+			}
+			pi = &minfo->limits.system;
+			ci = &minfo->cache.system;
+			break;
+		case M_VIDEO_PLL:
+			{
+				u_int8_t tmp;
+				unsigned int mnp;
+				unsigned long flags;
+				
+				matroxfb_DAC_lock_irqsave(flags);
+				tmp = matroxfb_DAC_in(minfo, M1064_XPWRCTRL);
+				if (!(tmp & 2)) {
+					matroxfb_DAC_out(minfo, M1064_XPWRCTRL, tmp | 2);
+				}
+				
+				mnp = matroxfb_DAC_in(minfo, M1064_XPIXPLLCM) << 16;
+				mnp |= matroxfb_DAC_in(minfo, M1064_XPIXPLLCN) << 8;
+				pixel_vco = g450_mnp2vco(minfo, mnp);
+				matroxfb_DAC_unlock_irqrestore(flags);
+			}
+			pi = &minfo->limits.video;
+			ci = &minfo->cache.video;
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	mnpcount = 0;
+	{
+		unsigned int mnp;
+		unsigned int xvco;
+
+		for (mnp = g450_firstpll(minfo, pi, &xvco, fout); mnp != NO_MORE_MNP; mnp = g450_nextpll(minfo, pi, &xvco, mnp)) {
+			unsigned int idx;
+			unsigned int vco;
+			unsigned int delta;
+
+			vco = g450_mnp2vco(minfo, mnp);
+#if 0			
+			if (pll == M_VIDEO_PLL) {
+				unsigned int big, small;
+
+				if (vco < pixel_vco) {
+					small = vco;
+					big = pixel_vco;
+				} else {
+					small = pixel_vco;
+					big = vco;
+				}
+				while (big > small) {
+					big >>= 1;
+				}
+				if (big == small) {
+					continue;
+				}
+			}
+#endif			
+			delta = pll_freq_delta(fout, g450_vco2f(mnp, vco));
+			for (idx = mnpcount; idx > 0; idx--) {
+				/* == is important; due to nextpll algorithm we get
+				   sorted equally good frequencies from lower VCO 
+				   frequency to higher - with <= lowest wins, while
+				   with < highest one wins */
+				if (delta <= deltaarray[idx-1]) {
+					/* all else being equal except VCO,
+					 * choose VCO not near (within 1/16th or so) VCOmin
+					 * (freqs near VCOmin aren't as stable)
+					 */
+					if (delta == deltaarray[idx-1]
+					    && vco != g450_mnp2vco(minfo, mnparray[idx-1])
+					    && vco < (pi->vcomin * 17 / 16)) {
+						break;
+					}
+					mnparray[idx] = mnparray[idx-1];
+					deltaarray[idx] = deltaarray[idx-1];
+				} else {
+					break;
+				}
+			}
+			mnparray[idx] = mnp;
+			deltaarray[idx] = delta;
+			mnpcount++;
+		}
+	}
+	/* VideoPLL and PixelPLL matched: do nothing... In all other cases we should get at least one frequency */
+	if (!mnpcount) {
+		return -EBUSY;
+	}
+	{
+		unsigned long flags;
+		unsigned int mnp;
+		
+		matroxfb_DAC_lock_irqsave(flags);
+		mnp = g450_checkcache(minfo, ci, mnparray[0]);
+		if (mnp != NO_MORE_MNP) {
+			matroxfb_g450_setpll_cond(minfo, mnp, pll);
+		} else {
+			mnp = g450_findworkingpll(minfo, pll, mnparray, mnpcount);
+			g450_addcache(ci, mnparray[0], mnp);
+		}
+		updatehwstate_clk(&minfo->hw, mnp, pll);
+		matroxfb_DAC_unlock_irqrestore(flags);
+		return mnp;
+	}
+}
+
+/* It must be greater than number of possible PLL values.
+ * Currently there is 5(p) * 10(m) = 50 possible values. */
+#define MNP_TABLE_SIZE  64
+
+int matroxfb_g450_setclk(struct matrox_fb_info *minfo, unsigned int fout,
+			 unsigned int pll)
+{
+	unsigned int* arr;
+	
+	arr = kmalloc(sizeof(*arr) * MNP_TABLE_SIZE * 2, GFP_KERNEL);
+	if (arr) {
+		int r;
+
+		r = __g450_setclk(minfo, fout, pll, arr, arr + MNP_TABLE_SIZE);
+		kfree(arr);
+		return r;
+	}
+	return -ENOMEM;
+}
+
+EXPORT_SYMBOL(matroxfb_g450_setclk);
+EXPORT_SYMBOL(g450_mnp2f);
+EXPORT_SYMBOL(matroxfb_g450_setpll_cond);
+
+MODULE_AUTHOR("(c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Matrox G450/G550 PLL driver");
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/mgakms/g450_pll.h b/drivers/staging/mgakms/g450_pll.h
new file mode 100644
index 000000000000..5303336c6547
--- /dev/null
+++ b/drivers/staging/mgakms/g450_pll.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __G450_PLL_H__
+#define __G450_PLL_H__
+
+#include "matroxfb_base.h"
+
+int matroxfb_g450_setclk(struct matrox_fb_info *minfo, unsigned int fout,
+			 unsigned int pll);
+unsigned int g450_mnp2f(const struct matrox_fb_info *minfo, unsigned int mnp);
+void matroxfb_g450_setpll_cond(struct matrox_fb_info *minfo, unsigned int mnp,
+			       unsigned int pll);
+
+#endif	/* __G450_PLL_H__ */
diff --git a/drivers/staging/mgakms/i2c-matroxfb.c b/drivers/staging/mgakms/i2c-matroxfb.c
new file mode 100644
index 000000000000..0fb280ead3dc
--- /dev/null
+++ b/drivers/staging/mgakms/i2c-matroxfb.c
@@ -0,0 +1,238 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Version: 1.64 2002/06/10
+ *
+ * See matroxfb_base.c for contributors.
+ *
+ */
+
+#include "matroxfb_base.h"
+#include "matroxfb_maven.h"
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/i2c-algo-bit.h>
+
+/* MGA-TVO I2C for G200, G400 */
+#define MAT_CLK		0x20
+#define MAT_DATA	0x10
+/* primary head DDC for Mystique(?), G100, G200, G400 */
+#define DDC1_CLK	0x08
+#define DDC1_DATA	0x02
+/* primary head DDC for Millennium, Millennium II */
+#define DDC1B_CLK	0x10
+#define DDC1B_DATA	0x04
+/* secondary head DDC for G400 */
+#define DDC2_CLK	0x04
+#define DDC2_DATA	0x01
+
+/******************************************************/
+
+struct matroxfb_dh_maven_info {
+	struct i2c_bit_adapter	maven;
+	struct i2c_bit_adapter	ddc1;
+	struct i2c_bit_adapter	ddc2;
+};
+
+static int matroxfb_read_gpio(struct matrox_fb_info* minfo) {
+	unsigned long flags;
+	int v;
+
+	matroxfb_DAC_lock_irqsave(flags);
+	v = matroxfb_DAC_in(minfo, DAC_XGENIODATA);
+	matroxfb_DAC_unlock_irqrestore(flags);
+	return v;
+}
+
+static void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int val) {
+	unsigned long flags;
+	int v;
+
+	matroxfb_DAC_lock_irqsave(flags);
+	v = (matroxfb_DAC_in(minfo, DAC_XGENIOCTRL) & mask) | val;
+	matroxfb_DAC_out(minfo, DAC_XGENIOCTRL, v);
+	/* We must reset GENIODATA very often... XFree plays with this register */
+	matroxfb_DAC_out(minfo, DAC_XGENIODATA, 0x00);
+	matroxfb_DAC_unlock_irqrestore(flags);
+}
+
+/* software I2C functions */
+static inline void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state) {
+	if (state)
+		state = 0;
+	else
+		state = mask;
+	matroxfb_set_gpio(minfo, ~mask, state);
+}
+
+static void matroxfb_gpio_setsda(void* data, int state) {
+	struct i2c_bit_adapter* b = data;
+	matroxfb_i2c_set(b->minfo, b->mask.data, state);
+}
+
+static void matroxfb_gpio_setscl(void* data, int state) {
+	struct i2c_bit_adapter* b = data;
+	matroxfb_i2c_set(b->minfo, b->mask.clock, state);
+}
+
+static int matroxfb_gpio_getsda(void* data) {
+	struct i2c_bit_adapter* b = data;
+	return (matroxfb_read_gpio(b->minfo) & b->mask.data) ? 1 : 0;
+}
+
+static int matroxfb_gpio_getscl(void* data) {
+	struct i2c_bit_adapter* b = data;
+	return (matroxfb_read_gpio(b->minfo) & b->mask.clock) ? 1 : 0;
+}
+
+static const struct i2c_algo_bit_data matrox_i2c_algo_template =
+{
+	.setsda		= matroxfb_gpio_setsda,
+	.setscl		= matroxfb_gpio_setscl,
+	.getsda		= matroxfb_gpio_getsda,
+	.getscl		= matroxfb_gpio_getscl,
+	.udelay		= 10,
+	.timeout	= 100,
+};
+
+static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo, 
+		unsigned int data, unsigned int clock, const char *name,
+		int class)
+{
+	int err;
+
+	b->minfo = minfo;
+	b->mask.data = data;
+	b->mask.clock = clock;
+	b->adapter.owner = THIS_MODULE;
+	snprintf(b->adapter.name, sizeof(b->adapter.name), name,
+		minfo->fbcon.node);
+	i2c_set_adapdata(&b->adapter, b);
+	b->adapter.class = class;
+	b->adapter.algo_data = &b->bac;
+	b->adapter.dev.parent = &minfo->pcidev->dev;
+	b->bac = matrox_i2c_algo_template;
+	b->bac.data = b;
+	err = i2c_bit_add_bus(&b->adapter);
+	b->initialized = !err;
+	return err;
+}
+
+static void i2c_bit_bus_del(struct i2c_bit_adapter* b) {
+	if (b->initialized) {
+		i2c_del_adapter(&b->adapter);
+		b->initialized = 0;
+	}
+}
+
+static inline void i2c_maven_done(struct matroxfb_dh_maven_info* minfo2) {
+	i2c_bit_bus_del(&minfo2->maven);
+}
+
+static inline void i2c_ddc1_done(struct matroxfb_dh_maven_info* minfo2) {
+	i2c_bit_bus_del(&minfo2->ddc1);
+}
+
+static inline void i2c_ddc2_done(struct matroxfb_dh_maven_info* minfo2) {
+	i2c_bit_bus_del(&minfo2->ddc2);
+}
+
+static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) {
+	int err;
+	unsigned long flags;
+	struct matroxfb_dh_maven_info* m2info;
+
+	m2info = kzalloc(sizeof(*m2info), GFP_KERNEL);
+	if (!m2info)
+		return NULL;
+
+	matroxfb_DAC_lock_irqsave(flags);
+	matroxfb_DAC_out(minfo, DAC_XGENIODATA, 0xFF);
+	matroxfb_DAC_out(minfo, DAC_XGENIOCTRL, 0x00);
+	matroxfb_DAC_unlock_irqrestore(flags);
+
+	switch (minfo->chip) {
+		case MGA_2064:
+		case MGA_2164:
+			err = i2c_bus_reg(&m2info->ddc1, minfo,
+					  DDC1B_DATA, DDC1B_CLK,
+					  "DDC:fb%u #0", I2C_CLASS_DDC);
+			break;
+		default:
+			err = i2c_bus_reg(&m2info->ddc1, minfo,
+					  DDC1_DATA, DDC1_CLK,
+					  "DDC:fb%u #0", I2C_CLASS_DDC);
+			break;
+	}
+	if (err)
+		goto fail_ddc1;
+	if (minfo->devflags.dualhead) {
+		err = i2c_bus_reg(&m2info->ddc2, minfo,
+				  DDC2_DATA, DDC2_CLK,
+				  "DDC:fb%u #1", I2C_CLASS_DDC);
+		if (err == -ENODEV) {
+			printk(KERN_INFO "i2c-matroxfb: VGA->TV plug detected, DDC unavailable.\n");
+		} else if (err)
+			printk(KERN_INFO "i2c-matroxfb: Could not register secondary output i2c bus. Continuing anyway.\n");
+		/* Register maven bus even on G450/G550 */
+		err = i2c_bus_reg(&m2info->maven, minfo,
+				  MAT_DATA, MAT_CLK, "MAVEN:fb%u", 0);
+		if (err)
+			printk(KERN_INFO "i2c-matroxfb: Could not register Maven i2c bus. Continuing anyway.\n");
+		else {
+			struct i2c_board_info maven_info = {
+				I2C_BOARD_INFO("maven", 0x1b),
+			};
+			unsigned short const addr_list[2] = {
+				0x1b, I2C_CLIENT_END
+			};
+
+			i2c_new_probed_device(&m2info->maven.adapter,
+					      &maven_info, addr_list, NULL);
+		}
+	}
+	return m2info;
+fail_ddc1:;
+	kfree(m2info);
+	printk(KERN_ERR "i2c-matroxfb: Could not register primary adapter DDC bus.\n");
+	return NULL;
+}
+
+static void i2c_matroxfb_remove(struct matrox_fb_info* minfo, void* data) {
+	struct matroxfb_dh_maven_info* m2info = data;
+
+	i2c_maven_done(m2info);
+	i2c_ddc2_done(m2info);
+	i2c_ddc1_done(m2info);
+	kfree(m2info);
+}
+
+static struct matroxfb_driver i2c_matroxfb = {
+	.node =		LIST_HEAD_INIT(i2c_matroxfb.node),
+	.name =		"i2c-matroxfb",
+	.probe = 	i2c_matroxfb_probe,
+	.remove =	i2c_matroxfb_remove,
+};
+
+static int __init i2c_matroxfb_init(void) {
+	if (matroxfb_register_driver(&i2c_matroxfb)) {
+		printk(KERN_ERR "i2c-matroxfb: failed to register driver\n");
+		return -ENXIO;
+	}
+	return 0;
+}
+
+static void __exit i2c_matroxfb_exit(void) {
+	matroxfb_unregister_driver(&i2c_matroxfb);
+}
+
+MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Support module providing I2C buses present on Matrox videocards");
+
+module_init(i2c_matroxfb_init);
+module_exit(i2c_matroxfb_exit);
+/* no __setup required */
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/mgakms/matroxfb_DAC1064.c b/drivers/staging/mgakms/matroxfb_DAC1064.c
new file mode 100644
index 000000000000..b380a393cbc3
--- /dev/null
+++ b/drivers/staging/mgakms/matroxfb_DAC1064.c
@@ -0,0 +1,1113 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Portions Copyright (c) 2001 Matrox Graphics Inc.
+ *
+ * Version: 1.65 2002/08/14
+ *
+ * See matroxfb_base.c for contributors.
+ *
+ */
+
+
+#include "matroxfb_DAC1064.h"
+#include "matroxfb_misc.h"
+#include "matroxfb_accel.h"
+#include "g450_pll.h"
+#include <linux/matroxfb.h>
+
+#ifdef NEED_DAC1064
+#define outDAC1064 matroxfb_DAC_out
+#define inDAC1064 matroxfb_DAC_in
+
+#define DAC1064_OPT_SCLK_PCI	0x00
+#define DAC1064_OPT_SCLK_PLL	0x01
+#define DAC1064_OPT_SCLK_EXT	0x02
+#define DAC1064_OPT_SCLK_MASK	0x03
+#define DAC1064_OPT_GDIV1	0x04	/* maybe it is GDIV2 on G100 ?! */
+#define DAC1064_OPT_GDIV3	0x00
+#define DAC1064_OPT_MDIV1	0x08
+#define DAC1064_OPT_MDIV2	0x00
+#define DAC1064_OPT_RESERVED	0x10
+
+static void DAC1064_calcclock(const struct matrox_fb_info *minfo,
+			      unsigned int freq, unsigned int fmax,
+			      unsigned int *in, unsigned int *feed,
+			      unsigned int *post)
+{
+	unsigned int fvco;
+	unsigned int p;
+
+	DBG(__func__)
+	
+	/* only for devices older than G450 */
+
+	fvco = PLL_calcclock(minfo, freq, fmax, in, feed, &p);
+	
+	p = (1 << p) - 1;
+	if (fvco <= 100000)
+		;
+	else if (fvco <= 140000)
+		p |= 0x08;
+	else if (fvco <= 180000)
+		p |= 0x10;
+	else
+		p |= 0x18;
+	*post = p;
+}
+
+/* they must be in POS order */
+static const unsigned char MGA1064_DAC_regs[] = {
+		M1064_XCURADDL, M1064_XCURADDH, M1064_XCURCTRL,
+		M1064_XCURCOL0RED, M1064_XCURCOL0GREEN, M1064_XCURCOL0BLUE,
+		M1064_XCURCOL1RED, M1064_XCURCOL1GREEN, M1064_XCURCOL1BLUE,
+		M1064_XCURCOL2RED, M1064_XCURCOL2GREEN, M1064_XCURCOL2BLUE,
+		DAC1064_XVREFCTRL, M1064_XMULCTRL, M1064_XPIXCLKCTRL, M1064_XGENCTRL,
+		M1064_XMISCCTRL,
+		M1064_XGENIOCTRL, M1064_XGENIODATA, M1064_XZOOMCTRL, M1064_XSENSETEST,
+		M1064_XCRCBITSEL,
+		M1064_XCOLKEYMASKL, M1064_XCOLKEYMASKH, M1064_XCOLKEYL, M1064_XCOLKEYH };
+
+static const unsigned char MGA1064_DAC[] = {
+		0x00, 0x00, M1064_XCURCTRL_DIS,
+		0x00, 0x00, 0x00, 	/* black */
+		0xFF, 0xFF, 0xFF,	/* white */
+		0xFF, 0x00, 0x00,	/* red */
+		0x00, 0,
+		M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL,
+		M1064_XGENCTRL_VS_0 | M1064_XGENCTRL_ALPHA_DIS | M1064_XGENCTRL_BLACK_0IRE | M1064_XGENCTRL_NO_SYNC_ON_GREEN,
+		M1064_XMISCCTRL_DAC_8BIT,
+		0x00, 0x00, M1064_XZOOMCTRL_1, M1064_XSENSETEST_BCOMP | M1064_XSENSETEST_GCOMP | M1064_XSENSETEST_RCOMP | M1064_XSENSETEST_PDOWN,
+		0x00,
+		0x00, 0x00, 0xFF, 0xFF};
+
+static void DAC1064_setpclk(struct matrox_fb_info *minfo, unsigned long fout)
+{
+	unsigned int m, n, p;
+
+	DBG(__func__)
+
+	DAC1064_calcclock(minfo, fout, minfo->max_pixel_clock, &m, &n, &p);
+	minfo->hw.DACclk[0] = m;
+	minfo->hw.DACclk[1] = n;
+	minfo->hw.DACclk[2] = p;
+}
+
+static void DAC1064_setmclk(struct matrox_fb_info *minfo, int oscinfo,
+			    unsigned long fmem)
+{
+	u_int32_t mx;
+	struct matrox_hw_state *hw = &minfo->hw;
+
+	DBG(__func__)
+
+	if (minfo->devflags.noinit) {
+		/* read MCLK and give up... */
+		hw->DACclk[3] = inDAC1064(minfo, DAC1064_XSYSPLLM);
+		hw->DACclk[4] = inDAC1064(minfo, DAC1064_XSYSPLLN);
+		hw->DACclk[5] = inDAC1064(minfo, DAC1064_XSYSPLLP);
+		return;
+	}
+	mx = hw->MXoptionReg | 0x00000004;
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
+	mx &= ~0x000000BB;
+	if (oscinfo & DAC1064_OPT_GDIV1)
+		mx |= 0x00000008;
+	if (oscinfo & DAC1064_OPT_MDIV1)
+		mx |= 0x00000010;
+	if (oscinfo & DAC1064_OPT_RESERVED)
+		mx |= 0x00000080;
+	if ((oscinfo & DAC1064_OPT_SCLK_MASK) == DAC1064_OPT_SCLK_PLL) {
+		/* select PCI clock until we have setup oscilator... */
+		int clk;
+		unsigned int m, n, p;
+
+		/* powerup system PLL, select PCI clock */
+		mx |= 0x00000020;
+		pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
+		mx &= ~0x00000004;
+		pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
+
+		/* !!! you must not access device if MCLK is not running !!!
+		   Doing so cause immediate PCI lockup :-( Maybe they should
+		   generate ABORT or I/O (parity...) error and Linux should
+		   recover from this... (kill driver/process). But world is not
+		   perfect... */
+		/* (bit 2 of PCI_OPTION_REG must be 0... and bits 0,1 must not
+		   select PLL... because of PLL can be stopped at this time) */
+		DAC1064_calcclock(minfo, fmem, minfo->max_pixel_clock, &m, &n, &p);
+		outDAC1064(minfo, DAC1064_XSYSPLLM, hw->DACclk[3] = m);
+		outDAC1064(minfo, DAC1064_XSYSPLLN, hw->DACclk[4] = n);
+		outDAC1064(minfo, DAC1064_XSYSPLLP, hw->DACclk[5] = p);
+		for (clk = 65536; clk; --clk) {
+			if (inDAC1064(minfo, DAC1064_XSYSPLLSTAT) & 0x40)
+				break;
+		}
+		if (!clk)
+			printk(KERN_ERR "matroxfb: aiee, SYSPLL not locked\n");
+		/* select PLL */
+		mx |= 0x00000005;
+	} else {
+		/* select specified system clock source */
+		mx |= oscinfo & DAC1064_OPT_SCLK_MASK;
+	}
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
+	mx &= ~0x00000004;
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mx);
+	hw->MXoptionReg = mx;
+}
+
+#ifdef CONFIG_FB_MATROX_G
+static void g450_set_plls(struct matrox_fb_info *minfo)
+{
+	u_int32_t c2_ctl;
+	unsigned int pxc;
+	struct matrox_hw_state *hw = &minfo->hw;
+	int pixelmnp;
+	int videomnp;
+	
+	c2_ctl = hw->crtc2.ctl & ~0x4007;	/* Clear PLL + enable for CRTC2 */
+	c2_ctl |= 0x0001;			/* Enable CRTC2 */
+	hw->DACreg[POS1064_XPWRCTRL] &= ~0x02;	/* Stop VIDEO PLL */
+	pixelmnp = minfo->crtc1.mnp;
+	videomnp = minfo->crtc2.mnp;
+	if (videomnp < 0) {
+		c2_ctl &= ~0x0001;			/* Disable CRTC2 */
+		hw->DACreg[POS1064_XPWRCTRL] &= ~0x10;	/* Powerdown CRTC2 */
+	} else if (minfo->crtc2.pixclock == minfo->features.pll.ref_freq) {
+		c2_ctl |=  0x4002;	/* Use reference directly */
+	} else if (videomnp == pixelmnp) {
+		c2_ctl |=  0x0004;	/* Use pixel PLL */
+	} else {
+		if (0 == ((videomnp ^ pixelmnp) & 0xFFFFFF00)) {
+			/* PIXEL and VIDEO PLL must not use same frequency. We modify N
+			   of PIXEL PLL in such case because of VIDEO PLL may be source
+			   of TVO clocks, and chroma subcarrier is derived from its
+			   pixel clocks */
+			pixelmnp += 0x000100;
+		}
+		c2_ctl |=  0x0006;	/* Use video PLL */
+		hw->DACreg[POS1064_XPWRCTRL] |= 0x02;
+		
+		outDAC1064(minfo, M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
+		matroxfb_g450_setpll_cond(minfo, videomnp, M_VIDEO_PLL);
+	}
+
+	hw->DACreg[POS1064_XPIXCLKCTRL] &= ~M1064_XPIXCLKCTRL_PLL_UP;
+	if (pixelmnp >= 0) {
+		hw->DACreg[POS1064_XPIXCLKCTRL] |= M1064_XPIXCLKCTRL_PLL_UP;
+		
+		outDAC1064(minfo, M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]);
+		matroxfb_g450_setpll_cond(minfo, pixelmnp, M_PIXEL_PLL_C);
+	}
+	if (c2_ctl != hw->crtc2.ctl) {
+		hw->crtc2.ctl = c2_ctl;
+		mga_outl(0x3C10, c2_ctl);
+	}
+
+	pxc = minfo->crtc1.pixclock;
+	if (pxc == 0 || minfo->outputs[2].src == MATROXFB_SRC_CRTC2) {
+		pxc = minfo->crtc2.pixclock;
+	}
+	if (minfo->chip == MGA_G550) {
+		if (pxc < 45000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x00;	/* 0-50 */
+		} else if (pxc < 55000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x08;	/* 34-62 */
+		} else if (pxc < 70000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x10;	/* 42-78 */
+		} else if (pxc < 85000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x18;	/* 62-92 */
+		} else if (pxc < 100000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x20;	/* 74-108 */
+		} else if (pxc < 115000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x28;	/* 94-122 */
+		} else if (pxc < 125000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x30;	/* 108-132 */
+		} else {
+			hw->DACreg[POS1064_XPANMODE] = 0x38;	/* 120-168 */
+		}
+	} else {
+		/* G450 */
+		if (pxc < 45000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x00;	/* 0-54 */
+		} else if (pxc < 65000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x08;	/* 38-70 */
+		} else if (pxc < 85000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x10;	/* 56-96 */
+		} else if (pxc < 105000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x18;	/* 80-114 */
+		} else if (pxc < 135000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x20;	/* 102-144 */
+		} else if (pxc < 160000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x28;	/* 132-166 */
+		} else if (pxc < 175000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x30;	/* 154-182 */
+		} else {
+			hw->DACreg[POS1064_XPANMODE] = 0x38;	/* 170-204 */
+		}
+	}
+}
+#endif
+
+void DAC1064_global_init(struct matrox_fb_info *minfo)
+{
+	struct matrox_hw_state *hw = &minfo->hw;
+
+	hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK;
+	hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN;
+	hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL;
+#ifdef CONFIG_FB_MATROX_G
+	if (minfo->devflags.g450dac) {
+		hw->DACreg[POS1064_XPWRCTRL] = 0x1F;	/* powerup everything */
+		hw->DACreg[POS1064_XOUTPUTCONN] = 0x00;	/* disable outputs */
+		hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
+		switch (minfo->outputs[0].src) {
+			case MATROXFB_SRC_CRTC1:
+			case MATROXFB_SRC_CRTC2:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x01;	/* enable output; CRTC1/2 selection is in CRTC2 ctl */
+				break;
+			case MATROXFB_SRC_NONE:
+				hw->DACreg[POS1064_XMISCCTRL] &= ~M1064_XMISCCTRL_DAC_EN;
+				break;
+		}
+		switch (minfo->outputs[1].src) {
+			case MATROXFB_SRC_CRTC1:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x04;
+				break;
+			case MATROXFB_SRC_CRTC2:
+				if (minfo->outputs[1].mode == MATROXFB_OUTPUT_MODE_MONITOR) {
+					hw->DACreg[POS1064_XOUTPUTCONN] |= 0x08;
+				} else {
+					hw->DACreg[POS1064_XOUTPUTCONN] |= 0x0C;
+				}
+				break;
+			case MATROXFB_SRC_NONE:
+				hw->DACreg[POS1064_XPWRCTRL] &= ~0x01;		/* Poweroff DAC2 */
+				break;
+		}
+		switch (minfo->outputs[2].src) {
+			case MATROXFB_SRC_CRTC1:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x20;
+				break;
+			case MATROXFB_SRC_CRTC2:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x40;
+				break;
+			case MATROXFB_SRC_NONE:
+#if 0
+				/* HELP! If we boot without DFP connected to DVI, we can
+				   poweroff TMDS. But if we boot with DFP connected,
+				   TMDS generated clocks are used instead of ALL pixclocks
+				   available... If someone knows which register
+				   handles it, please reveal this secret to me... */			
+				hw->DACreg[POS1064_XPWRCTRL] &= ~0x04;		/* Poweroff TMDS */
+#endif				
+				break;
+		}
+		/* Now set timming related variables... */
+		g450_set_plls(minfo);
+	} else
+#endif
+	{
+		if (minfo->outputs[1].src == MATROXFB_SRC_CRTC1) {
+			hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT;
+			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12;
+		} else if (minfo->outputs[1].src == MATROXFB_SRC_CRTC2) {
+			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12;
+		} else if (minfo->outputs[2].src == MATROXFB_SRC_CRTC1)
+			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12;
+		else
+			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS;
+
+		if (minfo->outputs[0].src != MATROXFB_SRC_NONE)
+			hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
+	}
+}
+
+void DAC1064_global_restore(struct matrox_fb_info *minfo)
+{
+	struct matrox_hw_state *hw = &minfo->hw;
+
+	outDAC1064(minfo, M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]);
+	outDAC1064(minfo, M1064_XMISCCTRL, hw->DACreg[POS1064_XMISCCTRL]);
+	if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) {
+		outDAC1064(minfo, 0x20, 0x04);
+		outDAC1064(minfo, 0x1F, minfo->devflags.dfp_type);
+		if (minfo->devflags.g450dac) {
+			outDAC1064(minfo, M1064_XSYNCCTRL, 0xCC);
+			outDAC1064(minfo, M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
+			outDAC1064(minfo, M1064_XPANMODE, hw->DACreg[POS1064_XPANMODE]);
+			outDAC1064(minfo, M1064_XOUTPUTCONN, hw->DACreg[POS1064_XOUTPUTCONN]);
+		}
+	}
+}
+
+static int DAC1064_init_1(struct matrox_fb_info *minfo, struct my_timming *m)
+{
+	struct matrox_hw_state *hw = &minfo->hw;
+
+	DBG(__func__)
+
+	memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs));
+	switch (minfo->fbcon.var.bits_per_pixel) {
+		/* case 4: not supported by MGA1064 DAC */
+		case 8:
+			hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+			break;
+		case 16:
+			if (minfo->fbcon.var.green.length == 5)
+				hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_15BPP_1BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+			else
+				hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_16BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+			break;
+		case 24:
+			hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_24BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+			break;
+		case 32:
+			hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_32BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED;
+			break;
+		default:
+			return 1;	/* unsupported depth */
+	}
+	hw->DACreg[POS1064_XVREFCTRL] = minfo->features.DAC1064.xvrefctrl;
+	hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK;
+	hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN;
+	hw->DACreg[POS1064_XCURADDL] = 0;
+	hw->DACreg[POS1064_XCURADDH] = 0;
+
+	DAC1064_global_init(minfo);
+	return 0;
+}
+
+static int DAC1064_init_2(struct matrox_fb_info *minfo, struct my_timming *m)
+{
+	struct matrox_hw_state *hw = &minfo->hw;
+
+	DBG(__func__)
+
+	if (minfo->fbcon.var.bits_per_pixel > 16) {	/* 256 entries */
+		int i;
+
+		for (i = 0; i < 256; i++) {
+			hw->DACpal[i * 3 + 0] = i;
+			hw->DACpal[i * 3 + 1] = i;
+			hw->DACpal[i * 3 + 2] = i;
+		}
+	} else if (minfo->fbcon.var.bits_per_pixel > 8) {
+		if (minfo->fbcon.var.green.length == 5) {	/* 0..31, 128..159 */
+			int i;
+
+			for (i = 0; i < 32; i++) {
+				/* with p15 == 0 */
+				hw->DACpal[i * 3 + 0] = i << 3;
+				hw->DACpal[i * 3 + 1] = i << 3;
+				hw->DACpal[i * 3 + 2] = i << 3;
+				/* with p15 == 1 */
+				hw->DACpal[(i + 128) * 3 + 0] = i << 3;
+				hw->DACpal[(i + 128) * 3 + 1] = i << 3;
+				hw->DACpal[(i + 128) * 3 + 2] = i << 3;
+			}
+		} else {
+			int i;
+
+			for (i = 0; i < 64; i++) {		/* 0..63 */
+				hw->DACpal[i * 3 + 0] = i << 3;
+				hw->DACpal[i * 3 + 1] = i << 2;
+				hw->DACpal[i * 3 + 2] = i << 3;
+			}
+		}
+	} else {
+		memset(hw->DACpal, 0, 768);
+	}
+	return 0;
+}
+
+static void DAC1064_restore_1(struct matrox_fb_info *minfo)
+{
+	struct matrox_hw_state *hw = &minfo->hw;
+
+	CRITFLAGS
+
+	DBG(__func__)
+
+	CRITBEGIN
+
+	if ((inDAC1064(minfo, DAC1064_XSYSPLLM) != hw->DACclk[3]) ||
+	    (inDAC1064(minfo, DAC1064_XSYSPLLN) != hw->DACclk[4]) ||
+	    (inDAC1064(minfo, DAC1064_XSYSPLLP) != hw->DACclk[5])) {
+		outDAC1064(minfo, DAC1064_XSYSPLLM, hw->DACclk[3]);
+		outDAC1064(minfo, DAC1064_XSYSPLLN, hw->DACclk[4]);
+		outDAC1064(minfo, DAC1064_XSYSPLLP, hw->DACclk[5]);
+	}
+	{
+		unsigned int i;
+
+		for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
+			if ((i != POS1064_XPIXCLKCTRL) && (i != POS1064_XMISCCTRL))
+				outDAC1064(minfo, MGA1064_DAC_regs[i], hw->DACreg[i]);
+		}
+	}
+
+	DAC1064_global_restore(minfo);
+
+	CRITEND
+};
+
+static void DAC1064_restore_2(struct matrox_fb_info *minfo)
+{
+#ifdef DEBUG
+	unsigned int i;
+#endif
+
+	DBG(__func__)
+
+#ifdef DEBUG
+	dprintk(KERN_DEBUG "DAC1064regs ");
+	for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) {
+		dprintk("R%02X=%02X ", MGA1064_DAC_regs[i], minfo->hw.DACreg[i]);
+		if ((i & 0x7) == 0x7) dprintk(KERN_DEBUG "continuing... ");
+	}
+	dprintk(KERN_DEBUG "DAC1064clk ");
+	for (i = 0; i < 6; i++)
+		dprintk("C%02X=%02X ", i, minfo->hw.DACclk[i]);
+	dprintk("\n");
+#endif
+}
+
+static int m1064_compute(void* out, struct my_timming* m) {
+#define minfo ((struct matrox_fb_info*)out)
+	{
+		int i;
+		int tmout;
+		CRITFLAGS
+
+		DAC1064_setpclk(minfo, m->pixclock);
+
+		CRITBEGIN
+
+		for (i = 0; i < 3; i++)
+			outDAC1064(minfo, M1064_XPIXPLLCM + i, minfo->hw.DACclk[i]);
+		for (tmout = 500000; tmout; tmout--) {
+			if (inDAC1064(minfo, M1064_XPIXPLLSTAT) & 0x40)
+				break;
+			udelay(10);
+		}
+
+		CRITEND
+
+		if (!tmout)
+			printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
+	}
+#undef minfo
+	return 0;
+}
+
+static struct matrox_altout m1064 = {
+	.name	 = "Primary output",
+	.compute = m1064_compute,
+};
+
+#ifdef CONFIG_FB_MATROX_G
+static int g450_compute(void* out, struct my_timming* m) {
+#define minfo ((struct matrox_fb_info*)out)
+	if (m->mnp < 0) {
+		m->mnp = matroxfb_g450_setclk(minfo, m->pixclock, (m->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
+		if (m->mnp >= 0) {
+			m->pixclock = g450_mnp2f(minfo, m->mnp);
+		}
+	}
+#undef minfo
+	return 0;
+}
+
+static struct matrox_altout g450out = {
+	.name	 = "Primary output",
+	.compute = g450_compute,
+};
+#endif
+
+#endif /* NEED_DAC1064 */
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static int MGA1064_init(struct matrox_fb_info *minfo, struct my_timming *m)
+{
+	struct matrox_hw_state *hw = &minfo->hw;
+
+	DBG(__func__)
+
+	if (DAC1064_init_1(minfo, m)) return 1;
+	if (matroxfb_vgaHWinit(minfo, m)) return 1;
+
+	hw->MiscOutReg = 0xCB;
+	if (m->sync & FB_SYNC_HOR_HIGH_ACT)
+		hw->MiscOutReg &= ~0x40;
+	if (m->sync & FB_SYNC_VERT_HIGH_ACT)
+		hw->MiscOutReg &= ~0x80;
+	if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
+		hw->CRTCEXT[3] |= 0x40;
+
+	if (DAC1064_init_2(minfo, m)) return 1;
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G
+static int MGAG100_init(struct matrox_fb_info *minfo, struct my_timming *m)
+{
+	struct matrox_hw_state *hw = &minfo->hw;
+
+	DBG(__func__)
+
+	if (DAC1064_init_1(minfo, m)) return 1;
+	hw->MXoptionReg &= ~0x2000;
+	if (matroxfb_vgaHWinit(minfo, m)) return 1;
+
+	hw->MiscOutReg = 0xEF;
+	if (m->sync & FB_SYNC_HOR_HIGH_ACT)
+		hw->MiscOutReg &= ~0x40;
+	if (m->sync & FB_SYNC_VERT_HIGH_ACT)
+		hw->MiscOutReg &= ~0x80;
+	if (m->sync & FB_SYNC_COMP_HIGH_ACT) /* should be only FB_SYNC_COMP */
+		hw->CRTCEXT[3] |= 0x40;
+
+	if (DAC1064_init_2(minfo, m)) return 1;
+	return 0;
+}
+#endif	/* G */
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static void MGA1064_ramdac_init(struct matrox_fb_info *minfo)
+{
+
+	DBG(__func__)
+
+	/* minfo->features.DAC1064.vco_freq_min = 120000; */
+	minfo->features.pll.vco_freq_min = 62000;
+	minfo->features.pll.ref_freq	 = 14318;
+	minfo->features.pll.feed_div_min = 100;
+	minfo->features.pll.feed_div_max = 127;
+	minfo->features.pll.in_div_min	 = 1;
+	minfo->features.pll.in_div_max	 = 31;
+	minfo->features.pll.post_shift_max = 3;
+	minfo->features.DAC1064.xvrefctrl = DAC1064_XVREFCTRL_EXTERNAL;
+	/* maybe cmdline MCLK= ?, doc says gclk=44MHz, mclk=66MHz... it was 55/83 with old values */
+	DAC1064_setmclk(minfo, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G
+/* BIOS environ */
+static int x7AF4 = 0x10;	/* flags, maybe 0x10 = SDRAM, 0x00 = SGRAM??? */
+				/* G100 wants 0x10, G200 SGRAM does not care... */
+#if 0
+static int def50 = 0;	/* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */
+#endif
+
+static void MGAG100_progPixClock(const struct matrox_fb_info *minfo, int flags,
+				 int m, int n, int p)
+{
+	int reg;
+	int selClk;
+	int clk;
+
+	DBG(__func__)
+
+	outDAC1064(minfo, M1064_XPIXCLKCTRL, inDAC1064(minfo, M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS |
+		   M1064_XPIXCLKCTRL_PLL_UP);
+	switch (flags & 3) {
+		case 0:		reg = M1064_XPIXPLLAM; break;
+		case 1:		reg = M1064_XPIXPLLBM; break;
+		default:	reg = M1064_XPIXPLLCM; break;
+	}
+	outDAC1064(minfo, reg++, m);
+	outDAC1064(minfo, reg++, n);
+	outDAC1064(minfo, reg, p);
+	selClk = mga_inb(M_MISC_REG_READ) & ~0xC;
+	/* there should be flags & 0x03 & case 0/1/else */
+	/* and we should first select source and after that we should wait for PLL */
+	/* and we are waiting for PLL with oscilator disabled... Is it right? */
+	switch (flags & 0x03) {
+		case 0x00:	break;
+		case 0x01:	selClk |= 4; break;
+		default:	selClk |= 0x0C; break;
+	}
+	mga_outb(M_MISC_REG, selClk);
+	for (clk = 500000; clk; clk--) {
+		if (inDAC1064(minfo, M1064_XPIXPLLSTAT) & 0x40)
+			break;
+		udelay(10);
+	}
+	if (!clk)
+		printk(KERN_ERR "matroxfb: Pixel PLL%c not locked after usual time\n", (reg-M1064_XPIXPLLAM-2)/4 + 'A');
+	selClk = inDAC1064(minfo, M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_SRC_MASK;
+	switch (flags & 0x0C) {
+		case 0x00:	selClk |= M1064_XPIXCLKCTRL_SRC_PCI; break;
+		case 0x04:	selClk |= M1064_XPIXCLKCTRL_SRC_PLL; break;
+		default:	selClk |= M1064_XPIXCLKCTRL_SRC_EXT; break;
+	}
+	outDAC1064(minfo, M1064_XPIXCLKCTRL, selClk);
+	outDAC1064(minfo, M1064_XPIXCLKCTRL, inDAC1064(minfo, M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS);
+}
+
+static void MGAG100_setPixClock(const struct matrox_fb_info *minfo, int flags,
+				int freq)
+{
+	unsigned int m, n, p;
+
+	DBG(__func__)
+
+	DAC1064_calcclock(minfo, freq, minfo->max_pixel_clock, &m, &n, &p);
+	MGAG100_progPixClock(minfo, flags, m, n, p);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static int MGA1064_preinit(struct matrox_fb_info *minfo)
+{
+	static const int vxres_mystique[] = { 512,        640, 768,  800,  832,  960,
+					     1024, 1152, 1280,      1600, 1664, 1920,
+					     2048,    0};
+	struct matrox_hw_state *hw = &minfo->hw;
+
+	DBG(__func__)
+
+	/* minfo->capable.cfb4 = 0; ... preinitialized by 0 */
+	minfo->capable.text = 1;
+	minfo->capable.vxres = vxres_mystique;
+
+	minfo->outputs[0].output = &m1064;
+	minfo->outputs[0].src = minfo->outputs[0].default_src;
+	minfo->outputs[0].data = minfo;
+	minfo->outputs[0].mode = MATROXFB_OUTPUT_MODE_MONITOR;
+
+	if (minfo->devflags.noinit)
+		return 0;	/* do not modify settings */
+	hw->MXoptionReg &= 0xC0000100;
+	hw->MXoptionReg |= 0x00094E20;
+	if (minfo->devflags.novga)
+		hw->MXoptionReg &= ~0x00000100;
+	if (minfo->devflags.nobios)
+		hw->MXoptionReg &= ~0x40000000;
+	if (minfo->devflags.nopciretry)
+		hw->MXoptionReg |=  0x20000000;
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
+	mga_setr(M_SEQ_INDEX, 0x01, 0x20);
+	mga_outl(M_CTLWTST, 0x00000000);
+	udelay(200);
+	mga_outl(M_MACCESS, 0x00008000);
+	udelay(100);
+	mga_outl(M_MACCESS, 0x0000C000);
+	return 0;
+}
+
+static void MGA1064_reset(struct matrox_fb_info *minfo)
+{
+
+	DBG(__func__);
+
+	MGA1064_ramdac_init(minfo);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G
+static void g450_mclk_init(struct matrox_fb_info *minfo)
+{
+	/* switch all clocks to PCI source */
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg | 4);
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION3_REG, minfo->values.reg.opt3 & ~0x00300C03);
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
+
+	if (((minfo->values.reg.opt3 & 0x000003) == 0x000003) ||
+	    ((minfo->values.reg.opt3 & 0x000C00) == 0x000C00) ||
+	    ((minfo->values.reg.opt3 & 0x300000) == 0x300000)) {
+		matroxfb_g450_setclk(minfo, minfo->values.pll.video, M_VIDEO_PLL);
+	} else {
+		unsigned long flags;
+		unsigned int pwr;
+		
+		matroxfb_DAC_lock_irqsave(flags);
+		pwr = inDAC1064(minfo, M1064_XPWRCTRL) & ~0x02;
+		outDAC1064(minfo, M1064_XPWRCTRL, pwr);
+		matroxfb_DAC_unlock_irqrestore(flags);
+	}
+	matroxfb_g450_setclk(minfo, minfo->values.pll.system, M_SYSTEM_PLL);
+	
+	/* switch clocks to their real PLL source(s) */
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg | 4);
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION3_REG, minfo->values.reg.opt3);
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
+
+}
+
+static void g450_memory_init(struct matrox_fb_info *minfo)
+{
+	/* disable memory refresh */
+	minfo->hw.MXoptionReg &= ~0x001F8000;
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
+	
+	/* set memory interface parameters */
+	minfo->hw.MXoptionReg &= ~0x00207E00;
+	minfo->hw.MXoptionReg |= 0x00207E00 & minfo->values.reg.opt;
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, minfo->values.reg.opt2);
+	
+	mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst);
+	
+	/* first set up memory interface with disabled memory interface clocks */
+	pci_write_config_dword(minfo->pcidev, PCI_MEMMISC_REG, minfo->values.reg.memmisc & ~0x80000000U);
+	mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk);
+	mga_outl(M_MACCESS, minfo->values.reg.maccess);
+	/* start memory clocks */
+	pci_write_config_dword(minfo->pcidev, PCI_MEMMISC_REG, minfo->values.reg.memmisc | 0x80000000U);
+
+	udelay(200);
+	
+	if (minfo->values.memory.ddr && (!minfo->values.memory.emrswen || !minfo->values.memory.dll)) {
+		mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk & ~0x1000);
+	}
+	mga_outl(M_MACCESS, minfo->values.reg.maccess | 0x8000);
+	
+	udelay(200);
+	
+	minfo->hw.MXoptionReg |= 0x001F8000 & minfo->values.reg.opt;
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
+	
+	/* value is written to memory chips only if old != new */
+	mga_outl(M_PLNWT, 0);
+	mga_outl(M_PLNWT, ~0);
+	
+	if (minfo->values.reg.mctlwtst != minfo->values.reg.mctlwtst_core) {
+		mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst_core);
+	}
+	
+}
+
+static void g450_preinit(struct matrox_fb_info *minfo)
+{
+	u_int32_t c2ctl;
+	u_int8_t curctl;
+	u_int8_t c1ctl;
+	
+	/* minfo->hw.MXoptionReg = minfo->values.reg.opt; */
+	minfo->hw.MXoptionReg &= 0xC0000100;
+	minfo->hw.MXoptionReg |= 0x00000020;
+	if (minfo->devflags.novga)
+		minfo->hw.MXoptionReg &= ~0x00000100;
+	if (minfo->devflags.nobios)
+		minfo->hw.MXoptionReg &= ~0x40000000;
+	if (minfo->devflags.nopciretry)
+		minfo->hw.MXoptionReg |=  0x20000000;
+	minfo->hw.MXoptionReg |= minfo->values.reg.opt & 0x03400040;
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
+
+	/* Init system clocks */
+		
+	/* stop crtc2 */
+	c2ctl = mga_inl(M_C2CTL);
+	mga_outl(M_C2CTL, c2ctl & ~1);
+	/* stop cursor */
+	curctl = inDAC1064(minfo, M1064_XCURCTRL);
+	outDAC1064(minfo, M1064_XCURCTRL, 0);
+	/* stop crtc1 */
+	c1ctl = mga_readr(M_SEQ_INDEX, 1);
+	mga_setr(M_SEQ_INDEX, 1, c1ctl | 0x20);
+
+	g450_mclk_init(minfo);
+	g450_memory_init(minfo);
+	
+	/* set legacy VGA clock sources for DOSEmu or VMware... */
+	matroxfb_g450_setclk(minfo, 25175, M_PIXEL_PLL_A);
+	matroxfb_g450_setclk(minfo, 28322, M_PIXEL_PLL_B);
+
+	/* restore crtc1 */
+	mga_setr(M_SEQ_INDEX, 1, c1ctl);
+	
+	/* restore cursor */
+	outDAC1064(minfo, M1064_XCURCTRL, curctl);
+
+	/* restore crtc2 */
+	mga_outl(M_C2CTL, c2ctl);
+	
+	return;
+}
+
+static int MGAG100_preinit(struct matrox_fb_info *minfo)
+{
+	static const int vxres_g100[] = {  512,        640, 768,  800,  832,  960,
+                                          1024, 1152, 1280,      1600, 1664, 1920,
+                                          2048, 0};
+	struct matrox_hw_state *hw = &minfo->hw;
+
+        u_int32_t reg50;
+#if 0
+	u_int32_t q;
+#endif
+
+	DBG(__func__)
+
+	/* there are some instabilities if in_div > 19 && vco < 61000 */
+	if (minfo->devflags.g450dac) {
+		minfo->features.pll.vco_freq_min = 130000;	/* my sample: >118 */
+	} else {
+		minfo->features.pll.vco_freq_min = 62000;
+	}
+	if (!minfo->features.pll.ref_freq) {
+		minfo->features.pll.ref_freq	 = 27000;
+	}
+	minfo->features.pll.feed_div_min = 7;
+	minfo->features.pll.feed_div_max = 127;
+	minfo->features.pll.in_div_min	 = 1;
+	minfo->features.pll.in_div_max	 = 31;
+	minfo->features.pll.post_shift_max = 3;
+	minfo->features.DAC1064.xvrefctrl = DAC1064_XVREFCTRL_G100_DEFAULT;
+	/* minfo->capable.cfb4 = 0; ... preinitialized by 0 */
+	minfo->capable.text = 1;
+	minfo->capable.vxres = vxres_g100;
+	minfo->capable.plnwt = minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG100
+			? minfo->devflags.sgram : 1;
+
+	if (minfo->devflags.g450dac) {
+		minfo->outputs[0].output = &g450out;
+	} else {
+		minfo->outputs[0].output = &m1064;
+	}
+	minfo->outputs[0].src = minfo->outputs[0].default_src;
+	minfo->outputs[0].data = minfo;
+	minfo->outputs[0].mode = MATROXFB_OUTPUT_MODE_MONITOR;
+
+	if (minfo->devflags.g450dac) {
+		/* we must do this always, BIOS does not do it for us
+		   and accelerator dies without it */
+		mga_outl(0x1C0C, 0);
+	}
+	if (minfo->devflags.noinit)
+		return 0;
+	if (minfo->devflags.g450dac) {
+		g450_preinit(minfo);
+		return 0;
+	}
+	hw->MXoptionReg &= 0xC0000100;
+	hw->MXoptionReg |= 0x00000020;
+	if (minfo->devflags.novga)
+		hw->MXoptionReg &= ~0x00000100;
+	if (minfo->devflags.nobios)
+		hw->MXoptionReg &= ~0x40000000;
+	if (minfo->devflags.nopciretry)
+		hw->MXoptionReg |=  0x20000000;
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
+	DAC1064_setmclk(minfo, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PCI, 133333);
+
+	if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG100) {
+		pci_read_config_dword(minfo->pcidev, PCI_OPTION2_REG, &reg50);
+		reg50 &= ~0x3000;
+		pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50);
+
+		hw->MXoptionReg |= 0x1080;
+		pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
+		mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst);
+		udelay(100);
+		mga_outb(0x1C05, 0x00);
+		mga_outb(0x1C05, 0x80);
+		udelay(100);
+		mga_outb(0x1C05, 0x40);
+		mga_outb(0x1C05, 0xC0);
+		udelay(100);
+		reg50 &= ~0xFF;
+		reg50 |=  0x07;
+		pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50);
+		/* it should help with G100 */
+		mga_outb(M_GRAPHICS_INDEX, 6);
+		mga_outb(M_GRAPHICS_DATA, (mga_inb(M_GRAPHICS_DATA) & 3) | 4);
+		mga_setr(M_EXTVGA_INDEX, 0x03, 0x81);
+		mga_setr(M_EXTVGA_INDEX, 0x04, 0x00);
+		mga_writeb(minfo->video.vbase, 0x0000, 0xAA);
+		mga_writeb(minfo->video.vbase, 0x0800, 0x55);
+		mga_writeb(minfo->video.vbase, 0x4000, 0x55);
+#if 0
+		if (mga_readb(minfo->video.vbase, 0x0000) != 0xAA) {
+			hw->MXoptionReg &= ~0x1000;
+		}
+#endif
+		hw->MXoptionReg |= 0x00078020;
+	} else if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG200) {
+		pci_read_config_dword(minfo->pcidev, PCI_OPTION2_REG, &reg50);
+		reg50 &= ~0x3000;
+		pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50);
+
+		if (minfo->devflags.memtype == -1)
+			hw->MXoptionReg |= minfo->values.reg.opt & 0x1C00;
+		else
+			hw->MXoptionReg |= (minfo->devflags.memtype & 7) << 10;
+		if (minfo->devflags.sgram)
+			hw->MXoptionReg |= 0x4000;
+		mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst);
+		mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk);
+		udelay(200);
+		mga_outl(M_MACCESS, 0x00000000);
+		mga_outl(M_MACCESS, 0x00008000);
+		udelay(100);
+		mga_outw(M_MEMRDBK, minfo->values.reg.memrdbk);
+		hw->MXoptionReg |= 0x00078020;
+	} else {
+		pci_read_config_dword(minfo->pcidev, PCI_OPTION2_REG, &reg50);
+		reg50 &= ~0x00000100;
+		reg50 |=  0x00000000;
+		pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, reg50);
+
+		if (minfo->devflags.memtype == -1)
+			hw->MXoptionReg |= minfo->values.reg.opt & 0x1C00;
+		else
+			hw->MXoptionReg |= (minfo->devflags.memtype & 7) << 10;
+		if (minfo->devflags.sgram)
+			hw->MXoptionReg |= 0x4000;
+		mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst);
+		mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk);
+		udelay(200);
+		mga_outl(M_MACCESS, 0x00000000);
+		mga_outl(M_MACCESS, 0x00008000);
+		udelay(100);
+		mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk);
+		hw->MXoptionReg |= 0x00040020;
+	}
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
+	return 0;
+}
+
+static void MGAG100_reset(struct matrox_fb_info *minfo)
+{
+	u_int8_t b;
+	struct matrox_hw_state *hw = &minfo->hw;
+
+	DBG(__func__)
+
+	{
+#ifdef G100_BROKEN_IBM_82351
+		u_int32_t d;
+
+		find 1014/22 (IBM/82351); /* if found and bridging Matrox, do some strange stuff */
+		pci_read_config_byte(ibm, PCI_SECONDARY_BUS, &b);
+		if (b == minfo->pcidev->bus->number) {
+			pci_write_config_byte(ibm, PCI_COMMAND+1, 0);	/* disable back-to-back & SERR */
+			pci_write_config_byte(ibm, 0x41, 0xF4);		/* ??? */
+			pci_write_config_byte(ibm, PCI_IO_BASE, 0xF0);	/* ??? */
+			pci_write_config_byte(ibm, PCI_IO_LIMIT, 0x00);	/* ??? */
+		}
+#endif
+		if (!minfo->devflags.noinit) {
+			if (x7AF4 & 8) {
+				hw->MXoptionReg |= 0x40;	/* FIXME... */
+				pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
+			}
+			mga_setr(M_EXTVGA_INDEX, 0x06, 0x00);
+		}
+	}
+	if (minfo->devflags.g450dac) {
+		/* either leave MCLK as is... or they were set in preinit */
+		hw->DACclk[3] = inDAC1064(minfo, DAC1064_XSYSPLLM);
+		hw->DACclk[4] = inDAC1064(minfo, DAC1064_XSYSPLLN);
+		hw->DACclk[5] = inDAC1064(minfo, DAC1064_XSYSPLLP);
+	} else {
+		DAC1064_setmclk(minfo, DAC1064_OPT_RESERVED | DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV1 | DAC1064_OPT_SCLK_PLL, 133333);
+	}
+	if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400) {
+		if (minfo->devflags.dfp_type == -1) {
+			minfo->devflags.dfp_type = inDAC1064(minfo, 0x1F);
+		}
+	}
+	if (minfo->devflags.noinit)
+		return;
+	if (minfo->devflags.g450dac) {
+	} else {
+		MGAG100_setPixClock(minfo, 4, 25175);
+		MGAG100_setPixClock(minfo, 5, 28322);
+		if (x7AF4 & 0x10) {
+			b = inDAC1064(minfo, M1064_XGENIODATA) & ~1;
+			outDAC1064(minfo, M1064_XGENIODATA, b);
+			b = inDAC1064(minfo, M1064_XGENIOCTRL) | 1;
+			outDAC1064(minfo, M1064_XGENIOCTRL, b);
+		}
+	}
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static void MGA1064_restore(struct matrox_fb_info *minfo)
+{
+	int i;
+	struct matrox_hw_state *hw = &minfo->hw;
+
+	CRITFLAGS
+
+	DBG(__func__)
+
+	CRITBEGIN
+
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
+	mga_outb(M_IEN, 0x00);
+	mga_outb(M_CACHEFLUSH, 0x00);
+
+	CRITEND
+
+	DAC1064_restore_1(minfo);
+	matroxfb_vgaHWrestore(minfo);
+	minfo->crtc1.panpos = -1;
+	for (i = 0; i < 6; i++)
+		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
+	DAC1064_restore_2(minfo);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_G
+static void MGAG100_restore(struct matrox_fb_info *minfo)
+{
+	int i;
+	struct matrox_hw_state *hw = &minfo->hw;
+
+	CRITFLAGS
+
+	DBG(__func__)
+
+	CRITBEGIN
+
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
+	CRITEND
+
+	DAC1064_restore_1(minfo);
+	matroxfb_vgaHWrestore(minfo);
+	if (minfo->devflags.support32MB)
+		mga_setr(M_EXTVGA_INDEX, 8, hw->CRTCEXT[8]);
+	minfo->crtc1.panpos = -1;
+	for (i = 0; i < 6; i++)
+		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
+	DAC1064_restore_2(minfo);
+}
+#endif
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+struct matrox_switch matrox_mystique = {
+	.preinit	= MGA1064_preinit,
+	.reset		= MGA1064_reset,
+	.init		= MGA1064_init,
+	.restore	= MGA1064_restore,
+};
+EXPORT_SYMBOL(matrox_mystique);
+#endif
+
+#ifdef CONFIG_FB_MATROX_G
+struct matrox_switch matrox_G100 = {
+	.preinit	= MGAG100_preinit,
+	.reset		= MGAG100_reset,
+	.init		= MGAG100_init,
+	.restore	= MGAG100_restore,
+};
+EXPORT_SYMBOL(matrox_G100);
+#endif
+
+#ifdef NEED_DAC1064
+EXPORT_SYMBOL(DAC1064_global_init);
+EXPORT_SYMBOL(DAC1064_global_restore);
+#endif
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/mgakms/matroxfb_DAC1064.h b/drivers/staging/mgakms/matroxfb_DAC1064.h
new file mode 100644
index 000000000000..3b2a6fd35fff
--- /dev/null
+++ b/drivers/staging/mgakms/matroxfb_DAC1064.h
@@ -0,0 +1,180 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __MATROXFB_DAC1064_H__
+#define __MATROXFB_DAC1064_H__
+
+
+#include "matroxfb_base.h"
+
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+extern struct matrox_switch matrox_mystique;
+#endif
+#ifdef CONFIG_FB_MATROX_G
+extern struct matrox_switch matrox_G100;
+#endif
+#ifdef NEED_DAC1064
+void DAC1064_global_init(struct matrox_fb_info *minfo);
+void DAC1064_global_restore(struct matrox_fb_info *minfo);
+#endif
+
+#define M1064_INDEX	0x00
+#define M1064_PALWRADD	0x00
+#define M1064_PALDATA	0x01
+#define M1064_PIXRDMSK	0x02
+#define M1064_PALRDADD	0x03
+#define M1064_X_DATAREG	0x0A
+#define M1064_CURPOSXL	0x0C	/* can be accessed as DWORD */
+#define M1064_CURPOSXH	0x0D
+#define M1064_CURPOSYL	0x0E
+#define M1064_CURPOSYH	0x0F
+
+#define M1064_XCURADDL		0x04
+#define M1064_XCURADDH		0x05
+#define M1064_XCURCTRL		0x06
+#define     M1064_XCURCTRL_DIS		0x00	/* transparent, transparent, transparent, transparent */
+#define     M1064_XCURCTRL_3COLOR	0x01	/* transparent, 0, 1, 2 */
+#define     M1064_XCURCTRL_XGA		0x02	/* 0, 1, transparent, complement */
+#define     M1064_XCURCTRL_XWIN		0x03	/* transparent, transparent, 0, 1 */
+	/* drive DVI by standard(0)/DVI(1) PLL */
+	/* if set(1), C?DVICLKEN and C?DVICLKSEL must be set(1) */
+#define      M1064_XDVICLKCTRL_DVIDATAPATHSEL   0x01
+	/* drive CRTC1 by standard(0)/DVI(1) PLL */
+#define      M1064_XDVICLKCTRL_C1DVICLKSEL      0x02
+	/* drive CRTC2 by standard(0)/DVI(1) PLL */
+#define      M1064_XDVICLKCTRL_C2DVICLKSEL      0x04
+	/* pixel clock allowed to(0)/blocked from(1) driving CRTC1 */
+#define      M1064_XDVICLKCTRL_C1DVICLKEN       0x08
+	/* DVI PLL loop filter bandwidth selection bits */
+#define      M1064_XDVICLKCTRL_DVILOOPCTL       0x30
+	/* CRTC2 pixel clock allowed to(0)/blocked from(1) driving CRTC2 */
+#define      M1064_XDVICLKCTRL_C2DVICLKEN       0x40
+	/* P1PLL loop filter bandwidth selection */
+#define      M1064_XDVICLKCTRL_P1LOOPBWDTCTL    0x80
+#define M1064_XCURCOL0RED	0x08
+#define M1064_XCURCOL0GREEN	0x09
+#define M1064_XCURCOL0BLUE	0x0A
+#define M1064_XCURCOL1RED	0x0C
+#define M1064_XCURCOL1GREEN	0x0D
+#define M1064_XCURCOL1BLUE	0x0E
+#define M1064_XDVICLKCTRL	0x0F
+#define M1064_XCURCOL2RED	0x10
+#define M1064_XCURCOL2GREEN	0x11
+#define M1064_XCURCOL2BLUE	0x12
+#define DAC1064_XVREFCTRL	0x18
+#define      DAC1064_XVREFCTRL_INTERNAL		0x3F
+#define      DAC1064_XVREFCTRL_EXTERNAL		0x00
+#define      DAC1064_XVREFCTRL_G100_DEFAULT	0x03
+#define M1064_XMULCTRL		0x19
+#define      M1064_XMULCTRL_DEPTH_8BPP		0x00	/* 8 bpp paletized */
+#define      M1064_XMULCTRL_DEPTH_15BPP_1BPP	0x01	/* 15 bpp paletized + 1 bpp overlay */
+#define      M1064_XMULCTRL_DEPTH_16BPP		0x02	/* 16 bpp paletized */
+#define      M1064_XMULCTRL_DEPTH_24BPP		0x03	/* 24 bpp paletized */
+#define      M1064_XMULCTRL_DEPTH_24BPP_8BPP	0x04	/* 24 bpp direct + 8 bpp overlay paletized */
+#define      M1064_XMULCTRL_2G8V16		0x05	/* 15 bpp video direct, half xres, 8bpp paletized */
+#define      M1064_XMULCTRL_G16V16		0x06	/* 15 bpp video, 15bpp graphics, one of them paletized */
+#define      M1064_XMULCTRL_DEPTH_32BPP		0x07	/* 24 bpp paletized + 8 bpp unused */
+#define      M1064_XMULCTRL_GRAPHICS_PALETIZED	0x00
+#define      M1064_XMULCTRL_VIDEO_PALETIZED	0x08
+#define M1064_XPIXCLKCTRL	0x1A
+#define      M1064_XPIXCLKCTRL_SRC_PCI		0x00
+#define      M1064_XPIXCLKCTRL_SRC_PLL		0x01
+#define      M1064_XPIXCLKCTRL_SRC_EXT		0x02
+#define	     M1064_XPIXCLKCTRL_SRC_SYS		0x03	/* G200/G400 */
+#define      M1064_XPIXCLKCTRL_SRC_PLL2		0x03	/* G450 */
+#define      M1064_XPIXCLKCTRL_SRC_MASK		0x03
+#define      M1064_XPIXCLKCTRL_EN		0x00
+#define      M1064_XPIXCLKCTRL_DIS		0x04
+#define      M1064_XPIXCLKCTRL_PLL_DOWN		0x00
+#define      M1064_XPIXCLKCTRL_PLL_UP		0x08
+#define M1064_XGENCTRL		0x1D
+#define      M1064_XGENCTRL_VS_0		0x00
+#define      M1064_XGENCTRL_VS_1		0x01
+#define      M1064_XGENCTRL_ALPHA_DIS		0x00
+#define      M1064_XGENCTRL_ALPHA_EN		0x02
+#define      M1064_XGENCTRL_BLACK_0IRE		0x00
+#define      M1064_XGENCTRL_BLACK_75IRE		0x10
+#define      M1064_XGENCTRL_SYNC_ON_GREEN	0x00
+#define      M1064_XGENCTRL_NO_SYNC_ON_GREEN	0x20
+#define      M1064_XGENCTRL_SYNC_ON_GREEN_MASK	0x20
+#define M1064_XMISCCTRL		0x1E
+#define      M1064_XMISCCTRL_DAC_DIS		0x00
+#define      M1064_XMISCCTRL_DAC_EN		0x01
+#define      M1064_XMISCCTRL_MFC_VGA		0x00
+#define      M1064_XMISCCTRL_MFC_MAFC		0x02
+#define      M1064_XMISCCTRL_MFC_DIS		0x06
+#define      GX00_XMISCCTRL_MFC_MAFC		0x02
+#define      GX00_XMISCCTRL_MFC_PANELLINK	0x04
+#define      GX00_XMISCCTRL_MFC_DIS		0x06
+#define      GX00_XMISCCTRL_MFC_MASK		0x06
+#define      M1064_XMISCCTRL_DAC_6BIT		0x00
+#define      M1064_XMISCCTRL_DAC_8BIT		0x08
+#define      M1064_XMISCCTRL_DAC_WIDTHMASK	0x08
+#define      M1064_XMISCCTRL_LUT_DIS		0x00
+#define      M1064_XMISCCTRL_LUT_EN		0x10
+#define      G400_XMISCCTRL_VDO_MAFC12		0x00
+#define      G400_XMISCCTRL_VDO_BYPASS656	0x40
+#define      G400_XMISCCTRL_VDO_C2_MAFC12	0x80
+#define      G400_XMISCCTRL_VDO_C2_BYPASS656	0xC0
+#define      G400_XMISCCTRL_VDO_MASK		0xE0
+#define M1064_XGENIOCTRL	0x2A
+#define M1064_XGENIODATA	0x2B
+#define DAC1064_XSYSPLLM	0x2C
+#define DAC1064_XSYSPLLN	0x2D
+#define DAC1064_XSYSPLLP	0x2E
+#define DAC1064_XSYSPLLSTAT	0x2F
+#define M1064_XZOOMCTRL		0x38
+#define      M1064_XZOOMCTRL_1			0x00
+#define      M1064_XZOOMCTRL_2			0x01
+#define      M1064_XZOOMCTRL_4			0x03
+#define M1064_XSENSETEST	0x3A
+#define      M1064_XSENSETEST_BCOMP		0x01
+#define      M1064_XSENSETEST_GCOMP		0x02
+#define      M1064_XSENSETEST_RCOMP		0x04
+#define      M1064_XSENSETEST_PDOWN		0x00
+#define      M1064_XSENSETEST_PUP		0x80
+#define M1064_XCRCREML		0x3C
+#define M1064_XCRCREMH		0x3D
+#define M1064_XCRCBITSEL	0x3E
+#define M1064_XCOLKEYMASKL	0x40
+#define M1064_XCOLKEYMASKH	0x41
+#define M1064_XCOLKEYL		0x42
+#define M1064_XCOLKEYH		0x43
+#define M1064_XPIXPLLAM		0x44
+#define M1064_XPIXPLLAN		0x45
+#define M1064_XPIXPLLAP		0x46
+#define M1064_XPIXPLLBM		0x48
+#define M1064_XPIXPLLBN		0x49
+#define M1064_XPIXPLLBP		0x4A
+#define M1064_XPIXPLLCM		0x4C
+#define M1064_XPIXPLLCN		0x4D
+#define M1064_XPIXPLLCP		0x4E
+#define M1064_XPIXPLLSTAT	0x4F
+
+#define M1064_XTVO_IDX		0x87
+#define M1064_XTVO_DATA		0x88
+
+#define M1064_XOUTPUTCONN	0x8A
+#define M1064_XSYNCCTRL		0x8B
+#define M1064_XVIDPLLSTAT	0x8C
+#define M1064_XVIDPLLP		0x8D
+#define M1064_XVIDPLLM		0x8E
+#define M1064_XVIDPLLN		0x8F
+
+#define M1064_XPWRCTRL		0xA0
+#define     M1064_XPWRCTRL_PANELPDN	0x04
+
+#define M1064_XPANMODE		0xA2
+
+enum POS1064 {
+	POS1064_XCURADDL=0, POS1064_XCURADDH, POS1064_XCURCTRL,
+	POS1064_XCURCOL0RED, POS1064_XCURCOL0GREEN, POS1064_XCURCOL0BLUE,
+	POS1064_XCURCOL1RED, POS1064_XCURCOL1GREEN, POS1064_XCURCOL1BLUE,
+	POS1064_XCURCOL2RED, POS1064_XCURCOL2GREEN, POS1064_XCURCOL2BLUE,
+	POS1064_XVREFCTRL, POS1064_XMULCTRL, POS1064_XPIXCLKCTRL, POS1064_XGENCTRL,
+	POS1064_XMISCCTRL,
+	POS1064_XGENIOCTRL, POS1064_XGENIODATA, POS1064_XZOOMCTRL, POS1064_XSENSETEST,
+	POS1064_XCRCBITSEL,
+	POS1064_XCOLKEYMASKL, POS1064_XCOLKEYMASKH, POS1064_XCOLKEYL, POS1064_XCOLKEYH,
+	POS1064_XOUTPUTCONN, POS1064_XPANMODE, POS1064_XPWRCTRL };
+
+
+#endif	/* __MATROXFB_DAC1064_H__ */
diff --git a/drivers/staging/mgakms/matroxfb_Ti3026.c b/drivers/staging/mgakms/matroxfb_Ti3026.c
new file mode 100644
index 000000000000..9ff9be85759e
--- /dev/null
+++ b/drivers/staging/mgakms/matroxfb_Ti3026.c
@@ -0,0 +1,748 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Portions Copyright (c) 2001 Matrox Graphics Inc.
+ *
+ * Version: 1.65 2002/08/14
+ *
+ * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
+ *
+ * Contributors: "menion?" <menion@mindless.com>
+ *                     Betatesting, fixes, ideas
+ *
+ *               "Kurt Garloff" <garloff@suse.de>
+ *                     Betatesting, fixes, ideas, videomodes, videomodes timmings
+ *
+ *               "Tom Rini" <trini@kernel.crashing.org>
+ *                     MTRR stuff, PPC cleanups, betatesting, fixes, ideas
+ *
+ *               "Bibek Sahu" <scorpio@dodds.net>
+ *                     Access device through readb|w|l and write b|w|l
+ *                     Extensive debugging stuff
+ *
+ *               "Daniel Haun" <haund@usa.net>
+ *                     Testing, hardware cursor fixes
+ *
+ *               "Scott Wood" <sawst46+@pitt.edu>
+ *                     Fixes
+ *
+ *               "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
+ *                     Betatesting
+ *
+ *               "Kelly French" <targon@hazmat.com>
+ *               "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
+ *                     Betatesting, bug reporting
+ *
+ *               "Pablo Bianucci" <pbian@pccp.com.ar>
+ *                     Fixes, ideas, betatesting
+ *
+ *               "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
+ *                     Fixes, enhandcements, ideas, betatesting
+ *
+ *               "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
+ *                     PPC betatesting, PPC support, backward compatibility
+ *
+ *               "Paul Womar" <Paul@pwomar.demon.co.uk>
+ *               "Owen Waller" <O.Waller@ee.qub.ac.uk>
+ *                     PPC betatesting
+ *
+ *               "Thomas Pornin" <pornin@bolet.ens.fr>
+ *                     Alpha betatesting
+ *
+ *               "Pieter van Leuven" <pvl@iae.nl>
+ *               "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
+ *                     G100 testing
+ *
+ *               "H. Peter Arvin" <hpa@transmeta.com>
+ *                     Ideas
+ *
+ *               "Cort Dougan" <cort@cs.nmt.edu>
+ *                     CHRP fixes and PReP cleanup
+ *
+ *               "Mark Vojkovich" <mvojkovi@ucsd.edu>
+ *                     G400 support
+ *
+ * (following author is not in any relation with this code, but his code
+ *  is included in this driver)
+ *
+ * Based on framebuffer driver for VBE 2.0 compliant graphic boards
+ *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * (following author is not in any relation with this code, but his ideas
+ *  were used when writing this driver)
+ *
+ *		 FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
+ *
+ */
+
+
+#include "matroxfb_Ti3026.h"
+#include "matroxfb_misc.h"
+#include "matroxfb_accel.h"
+#include <linux/matroxfb.h>
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+#define outTi3026 matroxfb_DAC_out
+#define inTi3026 matroxfb_DAC_in
+
+#define TVP3026_INDEX		0x00
+#define TVP3026_PALWRADD	0x00
+#define TVP3026_PALDATA		0x01
+#define TVP3026_PIXRDMSK	0x02
+#define TVP3026_PALRDADD	0x03
+#define TVP3026_CURCOLWRADD	0x04
+#define     TVP3026_CLOVERSCAN		0x00
+#define     TVP3026_CLCOLOR0		0x01
+#define     TVP3026_CLCOLOR1		0x02
+#define     TVP3026_CLCOLOR2		0x03
+#define TVP3026_CURCOLDATA	0x05
+#define TVP3026_CURCOLRDADD	0x07
+#define TVP3026_CURCTRL		0x09
+#define TVP3026_X_DATAREG	0x0A
+#define TVP3026_CURRAMDATA	0x0B
+#define TVP3026_CURPOSXL	0x0C
+#define TVP3026_CURPOSXH	0x0D
+#define TVP3026_CURPOSYL	0x0E
+#define TVP3026_CURPOSYH	0x0F
+
+#define TVP3026_XSILICONREV	0x01
+#define TVP3026_XCURCTRL	0x06
+#define     TVP3026_XCURCTRL_DIS	0x00	/* transparent, transparent, transparent, transparent */
+#define     TVP3026_XCURCTRL_3COLOR	0x01	/* transparent, 0, 1, 2 */
+#define     TVP3026_XCURCTRL_XGA	0x02	/* 0, 1, transparent, complement */
+#define     TVP3026_XCURCTRL_XWIN	0x03	/* transparent, transparent, 0, 1 */
+#define     TVP3026_XCURCTRL_BLANK2048	0x00
+#define     TVP3026_XCURCTRL_BLANK4096	0x10
+#define     TVP3026_XCURCTRL_INTERLACED	0x20
+#define     TVP3026_XCURCTRL_ODD	0x00 /* ext.signal ODD/\EVEN */
+#define     TVP3026_XCURCTRL_EVEN	0x40 /* ext.signal EVEN/\ODD */
+#define     TVP3026_XCURCTRL_INDIRECT	0x00
+#define     TVP3026_XCURCTRL_DIRECT	0x80
+#define TVP3026_XLATCHCTRL	0x0F
+#define     TVP3026_XLATCHCTRL_1_1	0x06
+#define     TVP3026_XLATCHCTRL_2_1	0x07
+#define     TVP3026_XLATCHCTRL_4_1	0x06
+#define     TVP3026_XLATCHCTRL_8_1	0x06
+#define     TVP3026_XLATCHCTRL_16_1	0x06
+#define     TVP3026A_XLATCHCTRL_4_3	0x06	/* ??? do not understand... but it works... !!! */
+#define     TVP3026A_XLATCHCTRL_8_3	0x07
+#define     TVP3026B_XLATCHCTRL_4_3	0x08
+#define     TVP3026B_XLATCHCTRL_8_3	0x06	/* ??? do not understand... but it works... !!! */
+#define TVP3026_XTRUECOLORCTRL	0x18
+#define     TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_ACCEL	0x00
+#define     TVP3026_XTRUECOLORCTRL_VRAM_SHIFT_TVP	0x20
+#define     TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR		0x80
+#define     TVP3026_XTRUECOLORCTRL_TRUECOLOR		0x40 /* paletized */
+#define     TVP3026_XTRUECOLORCTRL_DIRECTCOLOR		0x00
+#define     TVP3026_XTRUECOLORCTRL_24_ALTERNATE		0x08 /* 5:4/5:2 instead of 4:3/8:3 */
+#define     TVP3026_XTRUECOLORCTRL_RGB_888		0x16 /* 4:3/8:3 (or 5:4/5:2) */
+#define	    TVP3026_XTRUECOLORCTRL_BGR_888		0x17
+#define     TVP3026_XTRUECOLORCTRL_ORGB_8888		0x06
+#define     TVP3026_XTRUECOLORCTRL_BGRO_8888		0x07
+#define     TVP3026_XTRUECOLORCTRL_RGB_565		0x05
+#define     TVP3026_XTRUECOLORCTRL_ORGB_1555		0x04
+#define     TVP3026_XTRUECOLORCTRL_RGB_664		0x03
+#define     TVP3026_XTRUECOLORCTRL_RGBO_4444		0x01
+#define TVP3026_XMUXCTRL	0x19
+#define     TVP3026_XMUXCTRL_MEMORY_8BIT			0x01 /* - */
+#define     TVP3026_XMUXCTRL_MEMORY_16BIT			0x02 /* - */
+#define     TVP3026_XMUXCTRL_MEMORY_32BIT			0x03 /* 2MB RAM, 512K * 4 */
+#define     TVP3026_XMUXCTRL_MEMORY_64BIT			0x04 /* >2MB RAM, 512K * 8 & more */
+#define     TVP3026_XMUXCTRL_PIXEL_4BIT				0x40 /* L0,H0,L1,H1... */
+#define     TVP3026_XMUXCTRL_PIXEL_4BIT_SWAPPED			0x60 /* H0,L0,H1,L1... */
+#define     TVP3026_XMUXCTRL_PIXEL_8BIT				0x48
+#define     TVP3026_XMUXCTRL_PIXEL_16BIT			0x50
+#define     TVP3026_XMUXCTRL_PIXEL_32BIT			0x58
+#define     TVP3026_XMUXCTRL_VGA				0x98 /* VGA MEMORY, 8BIT PIXEL */
+#define TVP3026_XCLKCTRL	0x1A
+#define     TVP3026_XCLKCTRL_DIV1	0x00
+#define     TVP3026_XCLKCTRL_DIV2	0x10
+#define     TVP3026_XCLKCTRL_DIV4	0x20
+#define     TVP3026_XCLKCTRL_DIV8	0x30
+#define     TVP3026_XCLKCTRL_DIV16	0x40
+#define     TVP3026_XCLKCTRL_DIV32	0x50
+#define     TVP3026_XCLKCTRL_DIV64	0x60
+#define     TVP3026_XCLKCTRL_CLKSTOPPED	0x70
+#define     TVP3026_XCLKCTRL_SRC_CLK0	0x00
+#define     TVP3026_XCLKCTRL_SRC_CLK1   0x01
+#define     TVP3026_XCLKCTRL_SRC_CLK2	0x02	/* CLK2 is TTL source*/
+#define     TVP3026_XCLKCTRL_SRC_NCLK2	0x03	/* not CLK2 is TTL source */
+#define     TVP3026_XCLKCTRL_SRC_ECLK2	0x04	/* CLK2 and not CLK2 is ECL source */
+#define     TVP3026_XCLKCTRL_SRC_PLL	0x05
+#define     TVP3026_XCLKCTRL_SRC_DIS	0x06	/* disable & poweroff internal clock */
+#define     TVP3026_XCLKCTRL_SRC_CLK0VGA 0x07
+#define TVP3026_XPALETTEPAGE	0x1C
+#define TVP3026_XGENCTRL	0x1D
+#define     TVP3026_XGENCTRL_HSYNC_POS	0x00
+#define     TVP3026_XGENCTRL_HSYNC_NEG	0x01
+#define     TVP3026_XGENCTRL_VSYNC_POS	0x00
+#define     TVP3026_XGENCTRL_VSYNC_NEG	0x02
+#define     TVP3026_XGENCTRL_LITTLE_ENDIAN 0x00
+#define     TVP3026_XGENCTRL_BIG_ENDIAN    0x08
+#define     TVP3026_XGENCTRL_BLACK_0IRE		0x00
+#define     TVP3026_XGENCTRL_BLACK_75IRE	0x10
+#define     TVP3026_XGENCTRL_NO_SYNC_ON_GREEN	0x00
+#define     TVP3026_XGENCTRL_SYNC_ON_GREEN	0x20
+#define     TVP3026_XGENCTRL_OVERSCAN_DIS	0x00
+#define     TVP3026_XGENCTRL_OVERSCAN_EN	0x40
+#define TVP3026_XMISCCTRL	0x1E
+#define     TVP3026_XMISCCTRL_DAC_PUP	0x00
+#define     TVP3026_XMISCCTRL_DAC_PDOWN	0x01
+#define     TVP3026_XMISCCTRL_DAC_EXT	0x00 /* or 8, bit 3 is ignored */
+#define     TVP3026_XMISCCTRL_DAC_6BIT	0x04
+#define     TVP3026_XMISCCTRL_DAC_8BIT	0x0C
+#define     TVP3026_XMISCCTRL_PSEL_DIS	0x00
+#define     TVP3026_XMISCCTRL_PSEL_EN	0x10
+#define     TVP3026_XMISCCTRL_PSEL_LOW	0x00 /* PSEL high selects directcolor */
+#define     TVP3026_XMISCCTRL_PSEL_HIGH 0x20 /* PSEL high selects truecolor or pseudocolor */
+#define TVP3026_XGENIOCTRL	0x2A
+#define TVP3026_XGENIODATA	0x2B
+#define TVP3026_XPLLADDR	0x2C
+#define     TVP3026_XPLLADDR_X(LOOP,MCLK,PIX) (((LOOP)<<4) | ((MCLK)<<2) | (PIX))
+#define     TVP3026_XPLLDATA_N		0x00
+#define     TVP3026_XPLLDATA_M		0x01
+#define     TVP3026_XPLLDATA_P		0x02
+#define     TVP3026_XPLLDATA_STAT	0x03
+#define TVP3026_XPIXPLLDATA	0x2D
+#define TVP3026_XMEMPLLDATA	0x2E
+#define TVP3026_XLOOPPLLDATA	0x2F
+#define TVP3026_XCOLKEYOVRMIN	0x30
+#define TVP3026_XCOLKEYOVRMAX	0x31
+#define TVP3026_XCOLKEYREDMIN	0x32
+#define TVP3026_XCOLKEYREDMAX	0x33
+#define TVP3026_XCOLKEYGREENMIN	0x34
+#define TVP3026_XCOLKEYGREENMAX	0x35
+#define TVP3026_XCOLKEYBLUEMIN	0x36
+#define TVP3026_XCOLKEYBLUEMAX	0x37
+#define TVP3026_XCOLKEYCTRL	0x38
+#define     TVP3026_XCOLKEYCTRL_OVR_EN	0x01
+#define     TVP3026_XCOLKEYCTRL_RED_EN	0x02
+#define     TVP3026_XCOLKEYCTRL_GREEN_EN 0x04
+#define     TVP3026_XCOLKEYCTRL_BLUE_EN	0x08
+#define     TVP3026_XCOLKEYCTRL_NEGATE	0x10
+#define     TVP3026_XCOLKEYCTRL_ZOOM1	0x00
+#define     TVP3026_XCOLKEYCTRL_ZOOM2	0x20
+#define     TVP3026_XCOLKEYCTRL_ZOOM4	0x40
+#define     TVP3026_XCOLKEYCTRL_ZOOM8	0x60
+#define     TVP3026_XCOLKEYCTRL_ZOOM16	0x80
+#define     TVP3026_XCOLKEYCTRL_ZOOM32	0xA0
+#define TVP3026_XMEMPLLCTRL	0x39
+#define     TVP3026_XMEMPLLCTRL_DIV(X)	(((X)-1)>>1)	/* 2,4,6,8,10,12,14,16, division applied to LOOP PLL after divide by 2^P */
+#define     TVP3026_XMEMPLLCTRL_STROBEMKC4	0x08
+#define     TVP3026_XMEMPLLCTRL_MCLK_DOTCLOCK	0x00	/* MKC4 */
+#define     TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL	0x10	/* MKC4 */
+#define     TVP3026_XMEMPLLCTRL_RCLK_PIXPLL	0x00
+#define     TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL	0x20
+#define     TVP3026_XMEMPLLCTRL_RCLK_DOTDIVN	0x40	/* dot clock divided by loop pclk N prescaler */
+#define TVP3026_XSENSETEST	0x3A
+#define TVP3026_XTESTMODEDATA	0x3B
+#define TVP3026_XCRCREML	0x3C
+#define TVP3026_XCRCREMH	0x3D
+#define TVP3026_XCRCBITSEL	0x3E
+#define TVP3026_XID		0x3F
+
+static const unsigned char DACseq[] =
+{ TVP3026_XLATCHCTRL, TVP3026_XTRUECOLORCTRL,
+  TVP3026_XMUXCTRL, TVP3026_XCLKCTRL,
+  TVP3026_XPALETTEPAGE,
+  TVP3026_XGENCTRL,
+  TVP3026_XMISCCTRL,
+  TVP3026_XGENIOCTRL,
+  TVP3026_XGENIODATA,
+  TVP3026_XCOLKEYOVRMIN, TVP3026_XCOLKEYOVRMAX, TVP3026_XCOLKEYREDMIN, TVP3026_XCOLKEYREDMAX,
+  TVP3026_XCOLKEYGREENMIN, TVP3026_XCOLKEYGREENMAX, TVP3026_XCOLKEYBLUEMIN, TVP3026_XCOLKEYBLUEMAX,
+  TVP3026_XCOLKEYCTRL,
+  TVP3026_XMEMPLLCTRL, TVP3026_XSENSETEST, TVP3026_XCURCTRL };
+
+#define POS3026_XLATCHCTRL	0
+#define POS3026_XTRUECOLORCTRL	1
+#define POS3026_XMUXCTRL	2
+#define POS3026_XCLKCTRL	3
+#define POS3026_XGENCTRL	5
+#define POS3026_XMISCCTRL	6
+#define POS3026_XMEMPLLCTRL	18
+#define POS3026_XCURCTRL	20
+
+static const unsigned char MGADACbpp32[] =
+{ TVP3026_XLATCHCTRL_2_1, TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_8888,
+  0x00, TVP3026_XCLKCTRL_DIV1 | TVP3026_XCLKCTRL_SRC_PLL,
+  0x00,
+  TVP3026_XGENCTRL_HSYNC_POS | TVP3026_XGENCTRL_VSYNC_POS | TVP3026_XGENCTRL_LITTLE_ENDIAN | TVP3026_XGENCTRL_BLACK_0IRE | TVP3026_XGENCTRL_NO_SYNC_ON_GREEN | TVP3026_XGENCTRL_OVERSCAN_DIS,
+  TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_HIGH,
+  0x00,
+  0x1E,
+  0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF,
+  TVP3026_XCOLKEYCTRL_ZOOM1,
+  0x00, 0x00, TVP3026_XCURCTRL_DIS };
+
+static int Ti3026_calcclock(const struct matrox_fb_info *minfo,
+			    unsigned int freq, unsigned int fmax, int *in,
+			    int *feed, int *post)
+{
+	unsigned int fvco;
+	unsigned int lin, lfeed, lpost;
+
+	DBG(__func__)
+
+	fvco = PLL_calcclock(minfo, freq, fmax, &lin, &lfeed, &lpost);
+	fvco >>= (*post = lpost);
+	*in = 64 - lin;
+	*feed = 64 - lfeed;
+	return fvco;
+}
+
+static int Ti3026_setpclk(struct matrox_fb_info *minfo, int clk)
+{
+	unsigned int f_pll;
+	unsigned int pixfeed, pixin, pixpost;
+	struct matrox_hw_state *hw = &minfo->hw;
+
+	DBG(__func__)
+
+	f_pll = Ti3026_calcclock(minfo, clk, minfo->max_pixel_clock, &pixin, &pixfeed, &pixpost);
+
+	hw->DACclk[0] = pixin | 0xC0;
+	hw->DACclk[1] = pixfeed;
+	hw->DACclk[2] = pixpost | 0xB0;
+
+	{
+		unsigned int loopfeed, loopin, looppost, loopdiv, z;
+		unsigned int Bpp;
+
+		Bpp = minfo->curr.final_bppShift;
+
+		if (minfo->fbcon.var.bits_per_pixel == 24) {
+			loopfeed = 3;		/* set lm to any possible value */
+			loopin = 3 * 32 / Bpp;
+		} else {
+			loopfeed = 4;
+			loopin = 4 * 32 / Bpp;
+		}
+		z = (110000 * loopin) / (f_pll * loopfeed);
+		loopdiv = 0; /* div 2 */
+		if (z < 2)
+			looppost = 0;
+		else if (z < 4)
+			looppost = 1;
+		else if (z < 8)
+			looppost = 2;
+		else {
+			looppost = 3;
+			loopdiv = z/16;
+		}
+		if (minfo->fbcon.var.bits_per_pixel == 24) {
+			hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
+			hw->DACclk[4] = (65 - loopfeed) | 0x80;
+			if (minfo->accel.ramdac_rev > 0x20) {
+				if (isInterleave(minfo))
+					hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_8_3;
+				else {
+					hw->DACclk[4] &= ~0xC0;
+					hw->DACreg[POS3026_XLATCHCTRL] = TVP3026B_XLATCHCTRL_4_3;
+				}
+			} else {
+				if (isInterleave(minfo))
+					;	/* default... */
+				else {
+					hw->DACclk[4] ^= 0xC0;	/* change from 0x80 to 0x40 */
+					hw->DACreg[POS3026_XLATCHCTRL] = TVP3026A_XLATCHCTRL_4_3;
+				}
+			}
+			hw->DACclk[5] = looppost | 0xF8;
+			if (minfo->devflags.mga_24bpp_fix)
+				hw->DACclk[5] ^= 0x40;
+		} else {
+			hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0;
+			hw->DACclk[4] = 65 - loopfeed;
+			hw->DACclk[5] = looppost | 0xF0;
+		}
+		hw->DACreg[POS3026_XMEMPLLCTRL] = loopdiv | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_LOOPPLL;
+	}
+	return 0;
+}
+
+static int Ti3026_init(struct matrox_fb_info *minfo, struct my_timming *m)
+{
+	u_int8_t muxctrl = isInterleave(minfo) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT;
+	struct matrox_hw_state *hw = &minfo->hw;
+
+	DBG(__func__)
+
+	memcpy(hw->DACreg, MGADACbpp32, sizeof(MGADACbpp32));
+	switch (minfo->fbcon.var.bits_per_pixel) {
+		case 4:	hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_16_1;	/* or _8_1, they are same */
+			hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
+			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_4BIT;
+			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV8;
+			hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
+			break;
+		case 8: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1;	/* or _4_1, they are same */
+			hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR;
+			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_8BIT;
+			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
+			hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW;
+			break;
+		case 16:
+			/* XLATCHCTRL should be _4_1 / _2_1... Why is not? (_2_1 is used every time) */
+			hw->DACreg[POS3026_XTRUECOLORCTRL] = (minfo->fbcon.var.green.length == 5) ? (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_1555) : (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_565);
+			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_16BIT;
+			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV2;
+			break;
+		case 24:
+			/* XLATCHCTRL is: for (A) use _4_3 (?_8_3 is same? TBD), for (B) it is set in setpclk */
+			hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_888;
+			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
+			hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4;
+			break;
+		case 32:
+			/* XLATCHCTRL should be _2_1 / _1_1... Why is not? (_2_1 is used every time) */
+			hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT;
+			break;
+		default:
+			return 1;	/* TODO: failed */
+	}
+	if (matroxfb_vgaHWinit(minfo, m)) return 1;
+
+	/* set SYNC */
+	hw->MiscOutReg = 0xCB;
+	if (m->sync & FB_SYNC_HOR_HIGH_ACT)
+		hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_HSYNC_NEG;
+	if (m->sync & FB_SYNC_VERT_HIGH_ACT)
+		hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_VSYNC_NEG;
+	if (m->sync & FB_SYNC_ON_GREEN)
+		hw->DACreg[POS3026_XGENCTRL] |= TVP3026_XGENCTRL_SYNC_ON_GREEN;
+
+	/* set DELAY */
+	if (minfo->video.len < 0x400000)
+		hw->CRTCEXT[3] |= 0x08;
+	else if (minfo->video.len > 0x400000)
+		hw->CRTCEXT[3] |= 0x10;
+
+	/* set HWCURSOR */
+	if (m->interlaced) {
+		hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_INTERLACED;
+	}
+	if (m->HTotal >= 1536)
+		hw->DACreg[POS3026_XCURCTRL] |= TVP3026_XCURCTRL_BLANK4096;
+
+	/* set interleaving */
+	hw->MXoptionReg &= ~0x00001000;
+	if (isInterleave(minfo)) hw->MXoptionReg |= 0x00001000;
+
+	/* set DAC */
+	Ti3026_setpclk(minfo, m->pixclock);
+	return 0;
+}
+
+static void ti3026_setMCLK(struct matrox_fb_info *minfo, int fout)
+{
+	unsigned int f_pll;
+	unsigned int pclk_m, pclk_n, pclk_p;
+	unsigned int mclk_m, mclk_n, mclk_p;
+	unsigned int rfhcnt, mclk_ctl;
+	int tmout;
+
+	DBG(__func__)
+
+	f_pll = Ti3026_calcclock(minfo, fout, minfo->max_pixel_clock, &mclk_n, &mclk_m, &mclk_p);
+
+	/* save pclk */
+	outTi3026(minfo, TVP3026_XPLLADDR, 0xFC);
+	pclk_n = inTi3026(minfo, TVP3026_XPIXPLLDATA);
+	outTi3026(minfo, TVP3026_XPLLADDR, 0xFD);
+	pclk_m = inTi3026(minfo, TVP3026_XPIXPLLDATA);
+	outTi3026(minfo, TVP3026_XPLLADDR, 0xFE);
+	pclk_p = inTi3026(minfo, TVP3026_XPIXPLLDATA);
+
+	/* stop pclk */
+	outTi3026(minfo, TVP3026_XPLLADDR, 0xFE);
+	outTi3026(minfo, TVP3026_XPIXPLLDATA, 0x00);
+
+	/* set pclk to new mclk */
+	outTi3026(minfo, TVP3026_XPLLADDR, 0xFC);
+	outTi3026(minfo, TVP3026_XPIXPLLDATA, mclk_n | 0xC0);
+	outTi3026(minfo, TVP3026_XPIXPLLDATA, mclk_m);
+	outTi3026(minfo, TVP3026_XPIXPLLDATA, mclk_p | 0xB0);
+
+	/* wait for PLL to lock */
+	for (tmout = 500000; tmout; tmout--) {
+		if (inTi3026(minfo, TVP3026_XPIXPLLDATA) & 0x40)
+			break;
+		udelay(10);
+	}
+	if (!tmout)
+		printk(KERN_ERR "matroxfb: Temporary pixel PLL not locked after 5 secs\n");
+
+	/* output pclk on mclk pin */
+	mclk_ctl = inTi3026(minfo, TVP3026_XMEMPLLCTRL);
+	outTi3026(minfo, TVP3026_XMEMPLLCTRL, mclk_ctl & 0xE7);
+	outTi3026(minfo, TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_STROBEMKC4);
+
+	/* stop MCLK */
+	outTi3026(minfo, TVP3026_XPLLADDR, 0xFB);
+	outTi3026(minfo, TVP3026_XMEMPLLDATA, 0x00);
+
+	/* set mclk to new freq */
+	outTi3026(minfo, TVP3026_XPLLADDR, 0xF3);
+	outTi3026(minfo, TVP3026_XMEMPLLDATA, mclk_n | 0xC0);
+	outTi3026(minfo, TVP3026_XMEMPLLDATA, mclk_m);
+	outTi3026(minfo, TVP3026_XMEMPLLDATA, mclk_p | 0xB0);
+
+	/* wait for PLL to lock */
+	for (tmout = 500000; tmout; tmout--) {
+		if (inTi3026(minfo, TVP3026_XMEMPLLDATA) & 0x40)
+			break;
+		udelay(10);
+	}
+	if (!tmout)
+		printk(KERN_ERR "matroxfb: Memory PLL not locked after 5 secs\n");
+
+	f_pll = f_pll * 333 / (10000 << mclk_p);
+	if (isMilleniumII(minfo)) {
+		rfhcnt = (f_pll - 128) / 256;
+		if (rfhcnt > 15)
+			rfhcnt = 15;
+	} else {
+		rfhcnt = (f_pll - 64) / 128;
+		if (rfhcnt > 15)
+			rfhcnt = 0;
+	}
+	minfo->hw.MXoptionReg = (minfo->hw.MXoptionReg & ~0x000F0000) | (rfhcnt << 16);
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
+
+	/* output MCLK to MCLK pin */
+	outTi3026(minfo, TVP3026_XMEMPLLCTRL, (mclk_ctl & 0xE7) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
+	outTi3026(minfo, TVP3026_XMEMPLLCTRL, (mclk_ctl       ) | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_STROBEMKC4);
+
+	/* stop PCLK */
+	outTi3026(minfo, TVP3026_XPLLADDR, 0xFE);
+	outTi3026(minfo, TVP3026_XPIXPLLDATA, 0x00);
+
+	/* restore pclk */
+	outTi3026(minfo, TVP3026_XPLLADDR, 0xFC);
+	outTi3026(minfo, TVP3026_XPIXPLLDATA, pclk_n);
+	outTi3026(minfo, TVP3026_XPIXPLLDATA, pclk_m);
+	outTi3026(minfo, TVP3026_XPIXPLLDATA, pclk_p);
+
+	/* wait for PLL to lock */
+	for (tmout = 500000; tmout; tmout--) {
+		if (inTi3026(minfo, TVP3026_XPIXPLLDATA) & 0x40)
+			break;
+		udelay(10);
+	}
+	if (!tmout)
+		printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
+}
+
+static void ti3026_ramdac_init(struct matrox_fb_info *minfo)
+{
+	DBG(__func__)
+
+	minfo->features.pll.vco_freq_min = 110000;
+	minfo->features.pll.ref_freq	 = 114545;
+	minfo->features.pll.feed_div_min = 2;
+	minfo->features.pll.feed_div_max = 24;
+	minfo->features.pll.in_div_min	 = 2;
+	minfo->features.pll.in_div_max	 = 63;
+	minfo->features.pll.post_shift_max = 3;
+	if (minfo->devflags.noinit)
+		return;
+	ti3026_setMCLK(minfo, 60000);
+}
+
+static void Ti3026_restore(struct matrox_fb_info *minfo)
+{
+	int i;
+	unsigned char progdac[6];
+	struct matrox_hw_state *hw = &minfo->hw;
+	CRITFLAGS
+
+	DBG(__func__)
+
+#ifdef DEBUG
+	dprintk(KERN_INFO "EXTVGA regs: ");
+	for (i = 0; i < 6; i++)
+		dprintk("%02X:", hw->CRTCEXT[i]);
+	dprintk("\n");
+#endif
+
+	CRITBEGIN
+
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
+
+	CRITEND
+
+	matroxfb_vgaHWrestore(minfo);
+
+	CRITBEGIN
+
+	minfo->crtc1.panpos = -1;
+	for (i = 0; i < 6; i++)
+		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
+
+	for (i = 0; i < 21; i++) {
+		outTi3026(minfo, DACseq[i], hw->DACreg[i]);
+	}
+
+	outTi3026(minfo, TVP3026_XPLLADDR, 0x00);
+	progdac[0] = inTi3026(minfo, TVP3026_XPIXPLLDATA);
+	progdac[3] = inTi3026(minfo, TVP3026_XLOOPPLLDATA);
+	outTi3026(minfo, TVP3026_XPLLADDR, 0x15);
+	progdac[1] = inTi3026(minfo, TVP3026_XPIXPLLDATA);
+	progdac[4] = inTi3026(minfo, TVP3026_XLOOPPLLDATA);
+	outTi3026(minfo, TVP3026_XPLLADDR, 0x2A);
+	progdac[2] = inTi3026(minfo, TVP3026_XPIXPLLDATA);
+	progdac[5] = inTi3026(minfo, TVP3026_XLOOPPLLDATA);
+
+	CRITEND
+	if (memcmp(hw->DACclk, progdac, 6)) {
+		/* agrhh... setting up PLL is very slow on Millennium... */
+		/* Mystique PLL is locked in few ms, but Millennium PLL lock takes about 0.15 s... */
+		/* Maybe even we should call schedule() ? */
+
+		CRITBEGIN
+		outTi3026(minfo, TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]);
+		outTi3026(minfo, TVP3026_XPLLADDR, 0x2A);
+		outTi3026(minfo, TVP3026_XLOOPPLLDATA, 0);
+		outTi3026(minfo, TVP3026_XPIXPLLDATA, 0);
+
+		outTi3026(minfo, TVP3026_XPLLADDR, 0x00);
+		for (i = 0; i < 3; i++)
+			outTi3026(minfo, TVP3026_XPIXPLLDATA, hw->DACclk[i]);
+		/* wait for PLL only if PLL clock requested (always for PowerMode, never for VGA) */
+		if (hw->MiscOutReg & 0x08) {
+			int tmout;
+			outTi3026(minfo, TVP3026_XPLLADDR, 0x3F);
+			for (tmout = 500000; tmout; --tmout) {
+				if (inTi3026(minfo, TVP3026_XPIXPLLDATA) & 0x40)
+					break;
+				udelay(10);
+			}
+
+			CRITEND
+
+			if (!tmout)
+				printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
+			else
+				dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout);
+			CRITBEGIN
+		}
+		outTi3026(minfo, TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]);
+		outTi3026(minfo, TVP3026_XPLLADDR, 0x00);
+		for (i = 3; i < 6; i++)
+			outTi3026(minfo, TVP3026_XLOOPPLLDATA, hw->DACclk[i]);
+		CRITEND
+		if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[5] & 0x80) == 0x80)) {
+			int tmout;
+
+			CRITBEGIN
+			outTi3026(minfo, TVP3026_XPLLADDR, 0x3F);
+			for (tmout = 500000; tmout; --tmout) {
+				if (inTi3026(minfo, TVP3026_XLOOPPLLDATA) & 0x40)
+					break;
+				udelay(10);
+			}
+			CRITEND
+			if (!tmout)
+				printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n");
+			else
+				dprintk(KERN_INFO "LoopPLL: %d\n", 500000-tmout);
+		}
+	}
+
+#ifdef DEBUG
+	dprintk(KERN_DEBUG "3026DACregs ");
+	for (i = 0; i < 21; i++) {
+		dprintk("R%02X=%02X ", DACseq[i], hw->DACreg[i]);
+		if ((i & 0x7) == 0x7) dprintk(KERN_DEBUG "continuing... ");
+	}
+	dprintk(KERN_DEBUG "DACclk ");
+	for (i = 0; i < 6; i++)
+		dprintk("C%02X=%02X ", i, hw->DACclk[i]);
+	dprintk("\n");
+#endif
+}
+
+static void Ti3026_reset(struct matrox_fb_info *minfo)
+{
+	DBG(__func__)
+
+	ti3026_ramdac_init(minfo);
+}
+
+static struct matrox_altout ti3026_output = {
+	.name	 = "Primary output",
+};
+
+static int Ti3026_preinit(struct matrox_fb_info *minfo)
+{
+	static const int vxres_mill2[] = { 512,        640, 768,  800,  832,  960,
+					  1024, 1152, 1280,      1600, 1664, 1920,
+					  2048, 0};
+	static const int vxres_mill1[] = {             640, 768,  800,        960,
+					  1024, 1152, 1280,      1600,       1920,
+					  2048, 0};
+	struct matrox_hw_state *hw = &minfo->hw;
+
+	DBG(__func__)
+
+	minfo->millenium = 1;
+	minfo->milleniumII = (minfo->pcidev->device != PCI_DEVICE_ID_MATROX_MIL);
+	minfo->capable.cfb4 = 1;
+	minfo->capable.text = 1; /* isMilleniumII(minfo); */
+	minfo->capable.vxres = isMilleniumII(minfo) ? vxres_mill2 : vxres_mill1;
+
+	minfo->outputs[0].data = minfo;
+	minfo->outputs[0].output = &ti3026_output;
+	minfo->outputs[0].src = minfo->outputs[0].default_src;
+	minfo->outputs[0].mode = MATROXFB_OUTPUT_MODE_MONITOR;
+
+	if (minfo->devflags.noinit)
+		return 0;
+	/* preserve VGA I/O, BIOS and PPC */
+	hw->MXoptionReg &= 0xC0000100;
+	hw->MXoptionReg |= 0x002C0000;
+	if (minfo->devflags.novga)
+		hw->MXoptionReg &= ~0x00000100;
+	if (minfo->devflags.nobios)
+		hw->MXoptionReg &= ~0x40000000;
+	if (minfo->devflags.nopciretry)
+		hw->MXoptionReg |=  0x20000000;
+	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, hw->MXoptionReg);
+
+	minfo->accel.ramdac_rev = inTi3026(minfo, TVP3026_XSILICONREV);
+
+	outTi3026(minfo, TVP3026_XCLKCTRL, TVP3026_XCLKCTRL_SRC_CLK0VGA | TVP3026_XCLKCTRL_CLKSTOPPED);
+	outTi3026(minfo, TVP3026_XTRUECOLORCTRL, TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR);
+	outTi3026(minfo, TVP3026_XMUXCTRL, TVP3026_XMUXCTRL_VGA);
+
+	outTi3026(minfo, TVP3026_XPLLADDR, 0x2A);
+	outTi3026(minfo, TVP3026_XLOOPPLLDATA, 0x00);
+	outTi3026(minfo, TVP3026_XPIXPLLDATA, 0x00);
+
+	mga_outb(M_MISC_REG, 0x67);
+
+	outTi3026(minfo, TVP3026_XMEMPLLCTRL, TVP3026_XMEMPLLCTRL_STROBEMKC4 | TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL);
+
+	mga_outl(M_RESET, 1);
+	udelay(250);
+	mga_outl(M_RESET, 0);
+	udelay(250);
+	mga_outl(M_MACCESS, 0x00008000);
+	udelay(10);
+	return 0;
+}
+
+struct matrox_switch matrox_millennium = {
+	.preinit	= Ti3026_preinit,
+	.reset		= Ti3026_reset,
+	.init		= Ti3026_init,
+	.restore	= Ti3026_restore
+};
+EXPORT_SYMBOL(matrox_millennium);
+#endif
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/mgakms/matroxfb_Ti3026.h b/drivers/staging/mgakms/matroxfb_Ti3026.h
new file mode 100644
index 000000000000..faee149d0ba0
--- /dev/null
+++ b/drivers/staging/mgakms/matroxfb_Ti3026.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __MATROXFB_TI3026_H__
+#define __MATROXFB_TI3026_H__
+
+
+#include "matroxfb_base.h"
+
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+extern struct matrox_switch matrox_millennium;
+#endif
+
+#endif	/* __MATROXFB_TI3026_H__ */
diff --git a/drivers/staging/mgakms/matroxfb_accel.c b/drivers/staging/mgakms/matroxfb_accel.c
new file mode 100644
index 000000000000..0d5cb85d071a
--- /dev/null
+++ b/drivers/staging/mgakms/matroxfb_accel.c
@@ -0,0 +1,519 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Version: 1.65 2002/08/14
+ *
+ * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
+ *
+ * Contributors: "menion?" <menion@mindless.com>
+ *                     Betatesting, fixes, ideas
+ *
+ *               "Kurt Garloff" <garloff@suse.de>
+ *                     Betatesting, fixes, ideas, videomodes, videomodes timmings
+ *
+ *               "Tom Rini" <trini@kernel.crashing.org>
+ *                     MTRR stuff, PPC cleanups, betatesting, fixes, ideas
+ *
+ *               "Bibek Sahu" <scorpio@dodds.net>
+ *                     Access device through readb|w|l and write b|w|l
+ *                     Extensive debugging stuff
+ *
+ *               "Daniel Haun" <haund@usa.net>
+ *                     Testing, hardware cursor fixes
+ *
+ *               "Scott Wood" <sawst46+@pitt.edu>
+ *                     Fixes
+ *
+ *               "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
+ *                     Betatesting
+ *
+ *               "Kelly French" <targon@hazmat.com>
+ *               "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
+ *                     Betatesting, bug reporting
+ *
+ *               "Pablo Bianucci" <pbian@pccp.com.ar>
+ *                     Fixes, ideas, betatesting
+ *
+ *               "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
+ *                     Fixes, enhandcements, ideas, betatesting
+ *
+ *               "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
+ *                     PPC betatesting, PPC support, backward compatibility
+ *
+ *               "Paul Womar" <Paul@pwomar.demon.co.uk>
+ *               "Owen Waller" <O.Waller@ee.qub.ac.uk>
+ *                     PPC betatesting
+ *
+ *               "Thomas Pornin" <pornin@bolet.ens.fr>
+ *                     Alpha betatesting
+ *
+ *               "Pieter van Leuven" <pvl@iae.nl>
+ *               "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
+ *                     G100 testing
+ *
+ *               "H. Peter Arvin" <hpa@transmeta.com>
+ *                     Ideas
+ *
+ *               "Cort Dougan" <cort@cs.nmt.edu>
+ *                     CHRP fixes and PReP cleanup
+ *
+ *               "Mark Vojkovich" <mvojkovi@ucsd.edu>
+ *                     G400 support
+ *
+ * (following author is not in any relation with this code, but his code
+ *  is included in this driver)
+ *
+ * Based on framebuffer driver for VBE 2.0 compliant graphic boards
+ *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * (following author is not in any relation with this code, but his ideas
+ *  were used when writing this driver)
+ *
+ *		 FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
+ *
+ */
+
+#include "matroxfb_accel.h"
+#include "matroxfb_DAC1064.h"
+#include "matroxfb_Ti3026.h"
+#include "matroxfb_misc.h"
+
+#define curr_ydstorg(x)	((x)->curr.ydstorg.pixels)
+
+#define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l))
+
+static inline void matrox_cfb4_pal(u_int32_t* pal) {
+	unsigned int i;
+	
+	for (i = 0; i < 16; i++) {
+		pal[i] = i * 0x11111111U;
+	}
+}
+
+static inline void matrox_cfb8_pal(u_int32_t* pal) {
+	unsigned int i;
+	
+	for (i = 0; i < 16; i++) {
+		pal[i] = i * 0x01010101U;
+	}
+}
+
+static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area);
+static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect);
+static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image);
+static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect);
+static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area);
+
+void matrox_cfbX_init(struct matrox_fb_info *minfo)
+{
+	u_int32_t maccess;
+	u_int32_t mpitch;
+	u_int32_t mopmode;
+	int accel;
+
+	DBG(__func__)
+
+	mpitch = minfo->fbcon.var.xres_virtual;
+
+	minfo->fbops.fb_copyarea = cfb_copyarea;
+	minfo->fbops.fb_fillrect = cfb_fillrect;
+	minfo->fbops.fb_imageblit = cfb_imageblit;
+	minfo->fbops.fb_cursor = NULL;
+
+	accel = (minfo->fbcon.var.accel_flags & FB_ACCELF_TEXT) == FB_ACCELF_TEXT;
+
+	switch (minfo->fbcon.var.bits_per_pixel) {
+		case 4:		maccess = 0x00000000;	/* accelerate as 8bpp video */
+				mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */
+				mopmode = M_OPMODE_4BPP;
+				matrox_cfb4_pal(minfo->cmap);
+				if (accel && !(mpitch & 1)) {
+					minfo->fbops.fb_copyarea = matroxfb_cfb4_copyarea;
+					minfo->fbops.fb_fillrect = matroxfb_cfb4_fillrect;
+				}
+				break;
+		case 8:		maccess = 0x00000000;
+				mopmode = M_OPMODE_8BPP;
+				matrox_cfb8_pal(minfo->cmap);
+				if (accel) {
+					minfo->fbops.fb_copyarea = matroxfb_copyarea;
+					minfo->fbops.fb_fillrect = matroxfb_fillrect;
+					minfo->fbops.fb_imageblit = matroxfb_imageblit;
+				}
+				break;
+		case 16:	if (minfo->fbcon.var.green.length == 5)
+					maccess = 0xC0000001;
+				else
+					maccess = 0x40000001;
+				mopmode = M_OPMODE_16BPP;
+				if (accel) {
+					minfo->fbops.fb_copyarea = matroxfb_copyarea;
+					minfo->fbops.fb_fillrect = matroxfb_fillrect;
+					minfo->fbops.fb_imageblit = matroxfb_imageblit;
+				}
+				break;
+		case 24:	maccess = 0x00000003;
+				mopmode = M_OPMODE_24BPP;
+				if (accel) {
+					minfo->fbops.fb_copyarea = matroxfb_copyarea;
+					minfo->fbops.fb_fillrect = matroxfb_fillrect;
+					minfo->fbops.fb_imageblit = matroxfb_imageblit;
+				}
+				break;
+		case 32:	maccess = 0x00000002;
+				mopmode = M_OPMODE_32BPP;
+				if (accel) {
+					minfo->fbops.fb_copyarea = matroxfb_copyarea;
+					minfo->fbops.fb_fillrect = matroxfb_fillrect;
+					minfo->fbops.fb_imageblit = matroxfb_imageblit;
+				}
+				break;
+		default:	maccess = 0x00000000;
+				mopmode = 0x00000000;
+				break;	/* turn off acceleration!!! */
+	}
+	mga_fifo(8);
+	mga_outl(M_PITCH, mpitch);
+	mga_outl(M_YDSTORG, curr_ydstorg(minfo));
+	if (minfo->capable.plnwt)
+		mga_outl(M_PLNWT, -1);
+	if (minfo->capable.srcorg) {
+		mga_outl(M_SRCORG, 0);
+		mga_outl(M_DSTORG, 0);
+	}
+	mga_outl(M_OPMODE, mopmode);
+	mga_outl(M_CXBNDRY, 0xFFFF0000);
+	mga_outl(M_YTOP, 0);
+	mga_outl(M_YBOT, 0x01FFFFFF);
+	mga_outl(M_MACCESS, maccess);
+	minfo->accel.m_dwg_rect = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO;
+	if (isMilleniumII(minfo)) minfo->accel.m_dwg_rect |= M_DWG_TRANSC;
+	minfo->accel.m_opmode = mopmode;
+	minfo->accel.m_access = maccess;
+	minfo->accel.m_pitch = mpitch;
+}
+
+EXPORT_SYMBOL(matrox_cfbX_init);
+
+static void matrox_accel_restore_maccess(struct matrox_fb_info *minfo)
+{
+	mga_outl(M_MACCESS, minfo->accel.m_access);
+	mga_outl(M_PITCH, minfo->accel.m_pitch);
+}
+
+static void matrox_accel_bmove(struct matrox_fb_info *minfo, int vxres, int sy,
+			       int sx, int dy, int dx, int height, int width)
+{
+	int start, end;
+	CRITFLAGS
+
+	DBG(__func__)
+
+	CRITBEGIN
+
+	if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
+		mga_fifo(4);
+		matrox_accel_restore_maccess(minfo);
+		mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
+			 M_DWG_BFCOL | M_DWG_REPLACE);
+		mga_outl(M_AR5, vxres);
+		width--;
+		start = sy*vxres+sx+curr_ydstorg(minfo);
+		end = start+width;
+	} else {
+		mga_fifo(5);
+		matrox_accel_restore_maccess(minfo);
+		mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
+		mga_outl(M_SGN, 5);
+		mga_outl(M_AR5, -vxres);
+		width--;
+		end = (sy+height-1)*vxres+sx+curr_ydstorg(minfo);
+		start = end+width;
+		dy += height-1;
+	}
+	mga_fifo(6);
+	matrox_accel_restore_maccess(minfo);
+	mga_outl(M_AR0, end);
+	mga_outl(M_AR3, start);
+	mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
+	mga_ydstlen(dy, height);
+	WaitTillIdle();
+
+	CRITEND
+}
+
+static void matrox_accel_bmove_lin(struct matrox_fb_info *minfo, int vxres,
+				   int sy, int sx, int dy, int dx, int height,
+				   int width)
+{
+	int start, end;
+	CRITFLAGS
+
+	DBG(__func__)
+
+	CRITBEGIN
+
+	if ((dy < sy) || ((dy == sy) && (dx <= sx))) {
+		mga_fifo(4);
+		matrox_accel_restore_maccess(minfo);
+		mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO |
+			M_DWG_BFCOL | M_DWG_REPLACE);
+		mga_outl(M_AR5, vxres);
+		width--;
+		start = sy*vxres+sx+curr_ydstorg(minfo);
+		end = start+width;
+	} else {
+		mga_fifo(5);
+		matrox_accel_restore_maccess(minfo);
+		mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE);
+		mga_outl(M_SGN, 5);
+		mga_outl(M_AR5, -vxres);
+		width--;
+		end = (sy+height-1)*vxres+sx+curr_ydstorg(minfo);
+		start = end+width;
+		dy += height-1;
+	}
+	mga_fifo(7);
+	matrox_accel_restore_maccess(minfo);
+	mga_outl(M_AR0, end);
+	mga_outl(M_AR3, start);
+	mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
+	mga_outl(M_YDST, dy*vxres >> 5);
+	mga_outl(M_LEN | M_EXEC, height);
+	WaitTillIdle();
+
+	CRITEND
+}
+
+static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area) {
+	struct matrox_fb_info *minfo = info2minfo(info);
+
+	if ((area->sx | area->dx | area->width) & 1)
+		cfb_copyarea(info, area);
+	else
+		matrox_accel_bmove_lin(minfo, minfo->fbcon.var.xres_virtual >> 1, area->sy, area->sx >> 1, area->dy, area->dx >> 1, area->height, area->width >> 1);
+}
+
+static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area) {
+	struct matrox_fb_info *minfo = info2minfo(info);
+
+	matrox_accel_bmove(minfo, minfo->fbcon.var.xres_virtual, area->sy, area->sx, area->dy, area->dx, area->height, area->width);
+}
+
+static void matroxfb_accel_clear(struct matrox_fb_info *minfo, u_int32_t color,
+				 int sy, int sx, int height, int width)
+{
+	CRITFLAGS
+
+	DBG(__func__)
+
+	CRITBEGIN
+
+	mga_fifo(7);
+	matrox_accel_restore_maccess(minfo);
+	mga_outl(M_DWGCTL, minfo->accel.m_dwg_rect | M_DWG_REPLACE);
+	mga_outl(M_FCOL, color);
+	mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
+	mga_ydstlen(sy, height);
+	WaitTillIdle();
+
+	CRITEND
+}
+
+static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect) {
+	struct matrox_fb_info *minfo = info2minfo(info);
+
+	switch (rect->rop) {
+		case ROP_COPY:
+			matroxfb_accel_clear(minfo, ((u_int32_t *)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width);
+			break;
+	}
+}
+
+static void matroxfb_cfb4_clear(struct matrox_fb_info *minfo, u_int32_t bgx,
+				int sy, int sx, int height, int width)
+{
+	int whattodo;
+	CRITFLAGS
+
+	DBG(__func__)
+
+	CRITBEGIN
+
+	whattodo = 0;
+	if (sx & 1) {
+		sx ++;
+		if (!width) return;
+		width --;
+		whattodo = 1;
+	}
+	if (width & 1) {
+		whattodo |= 2;
+	}
+	width >>= 1;
+	sx >>= 1;
+	if (width) {
+		mga_fifo(7);
+		matrox_accel_restore_maccess(minfo);
+		mga_outl(M_DWGCTL, minfo->accel.m_dwg_rect | M_DWG_REPLACE2);
+		mga_outl(M_FCOL, bgx);
+		mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
+		mga_outl(M_YDST, sy * minfo->fbcon.var.xres_virtual >> 6);
+		mga_outl(M_LEN | M_EXEC, height);
+		WaitTillIdle();
+	}
+	if (whattodo) {
+		u_int32_t step = minfo->fbcon.var.xres_virtual >> 1;
+		vaddr_t vbase = minfo->video.vbase;
+		if (whattodo & 1) {
+			unsigned int uaddr = sy * step + sx - 1;
+			u_int32_t loop;
+			u_int8_t bgx2 = bgx & 0xF0;
+			for (loop = height; loop > 0; loop --) {
+				mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0x0F) | bgx2);
+				uaddr += step;
+			}
+		}
+		if (whattodo & 2) {
+			unsigned int uaddr = sy * step + sx + width;
+			u_int32_t loop;
+			u_int8_t bgx2 = bgx & 0x0F;
+			for (loop = height; loop > 0; loop --) {
+				mga_writeb(vbase, uaddr, (mga_readb(vbase, uaddr) & 0xF0) | bgx2);
+				uaddr += step;
+			}
+		}
+	}
+
+	CRITEND
+}
+
+static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect) {
+	struct matrox_fb_info *minfo = info2minfo(info);
+
+	switch (rect->rop) {
+		case ROP_COPY:
+			matroxfb_cfb4_clear(minfo, ((u_int32_t *)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width);
+			break;
+	}
+}
+
+static void matroxfb_1bpp_imageblit(struct matrox_fb_info *minfo, u_int32_t fgx,
+				    u_int32_t bgx, const u_int8_t *chardata,
+				    int width, int height, int yy, int xx)
+{
+	u_int32_t step;
+	u_int32_t ydstlen;
+	u_int32_t xlen;
+	u_int32_t ar0;
+	u_int32_t charcell;
+	u_int32_t fxbndry;
+	vaddr_t mmio;
+	int easy;
+	CRITFLAGS
+
+	DBG_HEAVY(__func__);
+
+	step = (width + 7) >> 3;
+	charcell = height * step;
+	xlen = (charcell + 3) & ~3;
+	ydstlen = (yy << 16) | height;
+	if (width == step << 3) {
+		ar0 = height * width - 1;
+		easy = 1;
+	} else {
+		ar0 = width - 1;
+		easy = 0;
+	}
+
+	CRITBEGIN
+
+	mga_fifo(5);
+	matrox_accel_restore_maccess(minfo);
+	if (easy)
+		mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
+	else
+		mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE);
+	mga_outl(M_FCOL, fgx);
+	mga_outl(M_BCOL, bgx);
+	fxbndry = ((xx + width - 1) << 16) | xx;
+	mmio = minfo->mmio.vbase;
+
+	mga_fifo(8);
+	matrox_accel_restore_maccess(minfo);
+	mga_writel(mmio, M_FXBNDRY, fxbndry);
+	mga_writel(mmio, M_AR0, ar0);
+	mga_writel(mmio, M_AR3, 0);
+	if (easy) {
+		mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
+		mga_memcpy_toio(mmio, chardata, xlen);
+	} else {
+		mga_writel(mmio, M_AR5, 0);
+		mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen);
+		if ((step & 3) == 0) {
+			/* Great. Source has 32bit aligned lines, so we can feed them
+			   directly to the accelerator. */
+			mga_memcpy_toio(mmio, chardata, charcell);
+		} else if (step == 1) {
+			/* Special case for 1..8bit widths */
+			while (height--) {
+#if defined(__BIG_ENDIAN)
+				fb_writel((*chardata) << 24, mmio.vaddr);
+#else
+				fb_writel(*chardata, mmio.vaddr);
+#endif
+				chardata++;
+			}
+		} else if (step == 2) {
+			/* Special case for 9..15bit widths */
+			while (height--) {
+#if defined(__BIG_ENDIAN)
+				fb_writel((*(u_int16_t*)chardata) << 16, mmio.vaddr);
+#else
+				fb_writel(*(u_int16_t*)chardata, mmio.vaddr);
+#endif
+				chardata += 2;
+			}
+		} else {
+			/* Tell... well, why bother... */
+			while (height--) {
+				size_t i;
+				
+				for (i = 0; i < step; i += 4) {
+					/* Hope that there are at least three readable bytes beyond the end of bitmap */
+					fb_writel(get_unaligned((u_int32_t*)(chardata + i)),mmio.vaddr);
+				}
+				chardata += step;
+			}
+		}
+	}
+	WaitTillIdle();
+	CRITEND
+}
+
+
+static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image) {
+	struct matrox_fb_info *minfo = info2minfo(info);
+
+	DBG_HEAVY(__func__);
+
+	if (image->depth == 1) {
+		u_int32_t fgx, bgx;
+
+		fgx = ((u_int32_t*)info->pseudo_palette)[image->fg_color];
+		bgx = ((u_int32_t*)info->pseudo_palette)[image->bg_color];
+		matroxfb_1bpp_imageblit(minfo, fgx, bgx, image->data, image->width, image->height, image->dy, image->dx);
+	} else {
+		/* Danger! image->depth is useless: logo painting code always
+		   passes framebuffer color depth here, although logo data are
+		   always 8bpp and info->pseudo_palette is changed to contain
+		   logo palette to be used (but only for true/direct-color... sic...).
+		   So do it completely in software... */
+		cfb_imageblit(info, image);
+	}
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/mgakms/matroxfb_accel.h b/drivers/staging/mgakms/matroxfb_accel.h
new file mode 100644
index 000000000000..a7aa9a1d26c0
--- /dev/null
+++ b/drivers/staging/mgakms/matroxfb_accel.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __MATROXFB_ACCEL_H__
+#define __MATROXFB_ACCEL_H__
+
+#include "matroxfb_base.h"
+
+void matrox_cfbX_init(struct matrox_fb_info *minfo);
+
+#endif
diff --git a/drivers/staging/mgakms/matroxfb_base.c b/drivers/staging/mgakms/matroxfb_base.c
new file mode 100644
index 000000000000..d11b5e6210ed
--- /dev/null
+++ b/drivers/staging/mgakms/matroxfb_base.c
@@ -0,0 +1,2607 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Portions Copyright (c) 2001 Matrox Graphics Inc.
+ *
+ * Version: 1.65 2002/08/14
+ *
+ * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
+ *
+ * Contributors: "menion?" <menion@mindless.com>
+ *                     Betatesting, fixes, ideas
+ *
+ *               "Kurt Garloff" <garloff@suse.de>
+ *                     Betatesting, fixes, ideas, videomodes, videomodes timmings
+ *
+ *               "Tom Rini" <trini@kernel.crashing.org>
+ *                     MTRR stuff, PPC cleanups, betatesting, fixes, ideas
+ *
+ *               "Bibek Sahu" <scorpio@dodds.net>
+ *                     Access device through readb|w|l and write b|w|l
+ *                     Extensive debugging stuff
+ *
+ *               "Daniel Haun" <haund@usa.net>
+ *                     Testing, hardware cursor fixes
+ *
+ *               "Scott Wood" <sawst46+@pitt.edu>
+ *                     Fixes
+ *
+ *               "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
+ *                     Betatesting
+ *
+ *               "Kelly French" <targon@hazmat.com>
+ *               "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
+ *                     Betatesting, bug reporting
+ *
+ *               "Pablo Bianucci" <pbian@pccp.com.ar>
+ *                     Fixes, ideas, betatesting
+ *
+ *               "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
+ *                     Fixes, enhandcements, ideas, betatesting
+ *
+ *               "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
+ *                     PPC betatesting, PPC support, backward compatibility
+ *
+ *               "Paul Womar" <Paul@pwomar.demon.co.uk>
+ *               "Owen Waller" <O.Waller@ee.qub.ac.uk>
+ *                     PPC betatesting
+ *
+ *               "Thomas Pornin" <pornin@bolet.ens.fr>
+ *                     Alpha betatesting
+ *
+ *               "Pieter van Leuven" <pvl@iae.nl>
+ *               "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
+ *                     G100 testing
+ *
+ *               "H. Peter Arvin" <hpa@transmeta.com>
+ *                     Ideas
+ *
+ *               "Cort Dougan" <cort@cs.nmt.edu>
+ *                     CHRP fixes and PReP cleanup
+ *
+ *               "Mark Vojkovich" <mvojkovi@ucsd.edu>
+ *                     G400 support
+ *
+ *               "Samuel Hocevar" <sam@via.ecp.fr>
+ *                     Fixes
+ *
+ *               "Anton Altaparmakov" <AntonA@bigfoot.com>
+ *                     G400 MAX/non-MAX distinction
+ *
+ *               "Ken Aaker" <kdaaker@rchland.vnet.ibm.com>
+ *                     memtype extension (needed for GXT130P RS/6000 adapter)
+ *
+ *               "Uns Lider" <unslider@miranda.org>
+ *                     G100 PLNWT fixes
+ *
+ *               "Denis Zaitsev" <zzz@cd-club.ru>
+ *                     Fixes
+ *
+ *               "Mike Pieper" <mike@pieper-family.de>
+ *                     TVOut enhandcements, V4L2 control interface.
+ *
+ *               "Diego Biurrun" <diego@biurrun.de>
+ *                     DFP testing
+ *
+ * (following author is not in any relation with this code, but his code
+ *  is included in this driver)
+ *
+ * Based on framebuffer driver for VBE 2.0 compliant graphic boards
+ *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * (following author is not in any relation with this code, but his ideas
+ *  were used when writing this driver)
+ *
+ *		 FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
+ *
+ */
+
+#include <linux/version.h>
+
+#include "matroxfb_base.h"
+#include "matroxfb_misc.h"
+#include "matroxfb_accel.h"
+#include "matroxfb_DAC1064.h"
+#include "matroxfb_Ti3026.h"
+#include "matroxfb_maven.h"
+#include "matroxfb_crtc2.h"
+#include "matroxfb_g450.h"
+#include <linux/matroxfb.h>
+#include <linux/interrupt.h>
+#include <linux/nvram.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#ifdef CONFIG_PPC_PMAC
+#include <asm/machdep.h>
+static int default_vmode = VMODE_NVRAM;
+static int default_cmode = CMODE_NVRAM;
+#endif
+
+static void matroxfb_unregister_device(struct matrox_fb_info* minfo);
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * card parameters
+ */
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo vesafb_defined = {
+	640,480,640,480,/* W,H, W, H (virtual) load xres,xres_virtual*/
+	0,0,		/* virtual -> visible no offset */
+	8,		/* depth -> load bits_per_pixel */
+	0,		/* greyscale ? */
+	{0,0,0},	/* R */
+	{0,0,0},	/* G */
+	{0,0,0},	/* B */
+	{0,0,0},	/* transparency */
+	0,		/* standard pixel format */
+	FB_ACTIVATE_NOW,
+	-1,-1,
+	FB_ACCELF_TEXT,	/* accel flags */
+	39721L,48L,16L,33L,10L,
+	96L,2L,~0,	/* No sync info */
+	FB_VMODE_NONINTERLACED,
+};
+
+
+
+/* --------------------------------------------------------------------- */
+static void update_crtc2(struct matrox_fb_info *minfo, unsigned int pos)
+{
+	struct matroxfb_dh_fb_info *info = minfo->crtc2.info;
+
+	/* Make sure that displays are compatible */
+	if (info && (info->fbcon.var.bits_per_pixel == minfo->fbcon.var.bits_per_pixel)
+		 && (info->fbcon.var.xres_virtual == minfo->fbcon.var.xres_virtual)
+		 && (info->fbcon.var.green.length == minfo->fbcon.var.green.length)
+		 ) {
+		switch (minfo->fbcon.var.bits_per_pixel) {
+			case 16:
+			case 32:
+				pos = pos * 8;
+				if (info->interlaced) {
+					mga_outl(0x3C2C, pos);
+					mga_outl(0x3C28, pos + minfo->fbcon.var.xres_virtual * minfo->fbcon.var.bits_per_pixel / 8);
+				} else {
+					mga_outl(0x3C28, pos);
+				}
+				break;
+		}
+	}
+}
+
+static void matroxfb_crtc1_panpos(struct matrox_fb_info *minfo)
+{
+	if (minfo->crtc1.panpos >= 0) {
+		unsigned long flags;
+		int panpos;
+
+		matroxfb_DAC_lock_irqsave(flags);
+		panpos = minfo->crtc1.panpos;
+		if (panpos >= 0) {
+			unsigned int extvga_reg;
+
+			minfo->crtc1.panpos = -1; /* No update pending anymore */
+			extvga_reg = mga_inb(M_EXTVGA_INDEX);
+			mga_setr(M_EXTVGA_INDEX, 0x00, panpos);
+			if (extvga_reg != 0x00) {
+				mga_outb(M_EXTVGA_INDEX, extvga_reg);
+			}
+		}
+		matroxfb_DAC_unlock_irqrestore(flags);
+	}
+}
+
+static irqreturn_t matrox_irq(int irq, void *dev_id)
+{
+	u_int32_t status;
+	int handled = 0;
+	struct matrox_fb_info *minfo = dev_id;
+
+	status = mga_inl(M_STATUS);
+
+	if (status & 0x20) {
+		mga_outl(M_ICLEAR, 0x20);
+		minfo->crtc1.vsync.cnt++;
+		matroxfb_crtc1_panpos(minfo);
+		wake_up_interruptible(&minfo->crtc1.vsync.wait);
+		handled = 1;
+	}
+	if (status & 0x200) {
+		mga_outl(M_ICLEAR, 0x200);
+		minfo->crtc2.vsync.cnt++;
+		wake_up_interruptible(&minfo->crtc2.vsync.wait);
+		handled = 1;
+	}
+	return IRQ_RETVAL(handled);
+}
+
+int matroxfb_enable_irq(struct matrox_fb_info *minfo, int reenable)
+{
+	u_int32_t bm;
+
+	if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400)
+		bm = 0x220;
+	else
+		bm = 0x020;
+
+	if (!test_and_set_bit(0, &minfo->irq_flags)) {
+		if (request_irq(minfo->pcidev->irq, matrox_irq,
+				IRQF_SHARED, "matroxfb", minfo)) {
+			clear_bit(0, &minfo->irq_flags);
+			return -EINVAL;
+		}
+		/* Clear any pending field interrupts */
+		mga_outl(M_ICLEAR, bm);
+		mga_outl(M_IEN, mga_inl(M_IEN) | bm);
+	} else if (reenable) {
+		u_int32_t ien;
+
+		ien = mga_inl(M_IEN);
+		if ((ien & bm) != bm) {
+			printk(KERN_DEBUG "matroxfb: someone disabled IRQ [%08X]\n", ien);
+			mga_outl(M_IEN, ien | bm);
+		}
+	}
+	return 0;
+}
+
+static void matroxfb_disable_irq(struct matrox_fb_info *minfo)
+{
+	if (test_and_clear_bit(0, &minfo->irq_flags)) {
+		/* Flush pending pan-at-vbl request... */
+		matroxfb_crtc1_panpos(minfo);
+		if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400)
+			mga_outl(M_IEN, mga_inl(M_IEN) & ~0x220);
+		else
+			mga_outl(M_IEN, mga_inl(M_IEN) & ~0x20);
+		free_irq(minfo->pcidev->irq, minfo);
+	}
+}
+
+int matroxfb_wait_for_sync(struct matrox_fb_info *minfo, u_int32_t crtc)
+{
+	struct matrox_vsync *vs;
+	unsigned int cnt;
+	int ret;
+
+	switch (crtc) {
+		case 0:
+			vs = &minfo->crtc1.vsync;
+			break;
+		case 1:
+			if (minfo->devflags.accelerator != FB_ACCEL_MATROX_MGAG400) {
+				return -ENODEV;
+			}
+			vs = &minfo->crtc2.vsync;
+			break;
+		default:
+			return -ENODEV;
+	}
+	ret = matroxfb_enable_irq(minfo, 0);
+	if (ret) {
+		return ret;
+	}
+
+	cnt = vs->cnt;
+	ret = wait_event_interruptible_timeout(vs->wait, cnt != vs->cnt, HZ/10);
+	if (ret < 0) {
+		return ret;
+	}
+	if (ret == 0) {
+		matroxfb_enable_irq(minfo, 1);
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void matrox_pan_var(struct matrox_fb_info *minfo,
+			   struct fb_var_screeninfo *var)
+{
+	unsigned int pos;
+	unsigned short p0, p1, p2;
+	unsigned int p3;
+	int vbl;
+	unsigned long flags;
+
+	CRITFLAGS
+
+	DBG(__func__)
+
+	if (minfo->dead)
+		return;
+
+	minfo->fbcon.var.xoffset = var->xoffset;
+	minfo->fbcon.var.yoffset = var->yoffset;
+	pos = (minfo->fbcon.var.yoffset * minfo->fbcon.var.xres_virtual + minfo->fbcon.var.xoffset) * minfo->curr.final_bppShift / 32;
+	pos += minfo->curr.ydstorg.chunks;
+	p0 = minfo->hw.CRTC[0x0D] = pos & 0xFF;
+	p1 = minfo->hw.CRTC[0x0C] = (pos & 0xFF00) >> 8;
+	p2 = minfo->hw.CRTCEXT[0] = (minfo->hw.CRTCEXT[0] & 0xB0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
+	p3 = minfo->hw.CRTCEXT[8] = pos >> 21;
+
+	/* FB_ACTIVATE_VBL and we can acquire interrupts? Honor FB_ACTIVATE_VBL then... */
+	vbl = (var->activate & FB_ACTIVATE_VBL) && (matroxfb_enable_irq(minfo, 0) == 0);
+
+	CRITBEGIN
+
+	matroxfb_DAC_lock_irqsave(flags);
+	mga_setr(M_CRTC_INDEX, 0x0D, p0);
+	mga_setr(M_CRTC_INDEX, 0x0C, p1);
+	if (minfo->devflags.support32MB)
+		mga_setr(M_EXTVGA_INDEX, 0x08, p3);
+	if (vbl) {
+		minfo->crtc1.panpos = p2;
+	} else {
+		/* Abort any pending change */
+		minfo->crtc1.panpos = -1;
+		mga_setr(M_EXTVGA_INDEX, 0x00, p2);
+	}
+	matroxfb_DAC_unlock_irqrestore(flags);
+
+	update_crtc2(minfo, pos);
+
+	CRITEND
+}
+
+static void matroxfb_remove(struct matrox_fb_info *minfo, int dummy)
+{
+	/* Currently we are holding big kernel lock on all dead & usecount updates.
+	 * Destroy everything after all users release it. Especially do not unregister
+	 * framebuffer and iounmap memory, neither fbmem nor fbcon-cfb* does not check
+	 * for device unplugged when in use.
+	 * In future we should point mmio.vbase & video.vbase somewhere where we can
+	 * write data without causing too much damage...
+	 */
+
+	minfo->dead = 1;
+	if (minfo->usecount) {
+		/* destroy it later */
+		return;
+	}
+	matroxfb_unregister_device(minfo);
+	unregister_framebuffer(&minfo->fbcon);
+	matroxfb_g450_shutdown(minfo);
+	arch_phys_wc_del(minfo->wc_cookie);
+	iounmap(minfo->mmio.vbase.vaddr);
+	iounmap(minfo->video.vbase.vaddr);
+	release_mem_region(minfo->video.base, minfo->video.len_maximum);
+	release_mem_region(minfo->mmio.base, 16384);
+	kfree(minfo);
+}
+
+	/*
+	 * Open/Release the frame buffer device
+	 */
+
+static int matroxfb_open(struct fb_info *info, int user)
+{
+	struct matrox_fb_info *minfo = info2minfo(info);
+
+	DBG_LOOP(__func__)
+
+	if (minfo->dead) {
+		return -ENXIO;
+	}
+	minfo->usecount++;
+	if (user) {
+		minfo->userusecount++;
+	}
+	return(0);
+}
+
+static int matroxfb_release(struct fb_info *info, int user)
+{
+	struct matrox_fb_info *minfo = info2minfo(info);
+
+	DBG_LOOP(__func__)
+
+	if (user) {
+		if (0 == --minfo->userusecount) {
+			matroxfb_disable_irq(minfo);
+		}
+	}
+	if (!(--minfo->usecount) && minfo->dead) {
+		matroxfb_remove(minfo, 0);
+	}
+	return(0);
+}
+
+static int matroxfb_pan_display(struct fb_var_screeninfo *var,
+		struct fb_info* info) {
+	struct matrox_fb_info *minfo = info2minfo(info);
+
+	DBG(__func__)
+
+	matrox_pan_var(minfo, var);
+	return 0;
+}
+
+static int matroxfb_get_final_bppShift(const struct matrox_fb_info *minfo,
+				       int bpp)
+{
+	int bppshft2;
+
+	DBG(__func__)
+
+	bppshft2 = bpp;
+	if (!bppshft2) {
+		return 8;
+	}
+	if (isInterleave(minfo))
+		bppshft2 >>= 1;
+	if (minfo->devflags.video64bits)
+		bppshft2 >>= 1;
+	return bppshft2;
+}
+
+static int matroxfb_test_and_set_rounding(const struct matrox_fb_info *minfo,
+					  int xres, int bpp)
+{
+	int over;
+	int rounding;
+
+	DBG(__func__)
+
+	switch (bpp) {
+		case 0:		return xres;
+		case 4:		rounding = 128;
+				break;
+		case 8:		rounding = 64;	/* doc says 64; 32 is OK for G400 */
+				break;
+		case 16:	rounding = 32;
+				break;
+		case 24:	rounding = 64;	/* doc says 64; 32 is OK for G400 */
+				break;
+		default:	rounding = 16;
+				/* on G400, 16 really does not work */
+				if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400)
+					rounding = 32;
+				break;
+	}
+	if (isInterleave(minfo)) {
+		rounding *= 2;
+	}
+	over = xres % rounding;
+	if (over)
+		xres += rounding-over;
+	return xres;
+}
+
+static int matroxfb_pitch_adjust(const struct matrox_fb_info *minfo, int xres,
+				 int bpp)
+{
+	const int* width;
+	int xres_new;
+
+	DBG(__func__)
+
+	if (!bpp) return xres;
+
+	width = minfo->capable.vxres;
+
+	if (minfo->devflags.precise_width) {
+		while (*width) {
+			if ((*width >= xres) && (matroxfb_test_and_set_rounding(minfo, *width, bpp) == *width)) {
+				break;
+			}
+			width++;
+		}
+		xres_new = *width;
+	} else {
+		xres_new = matroxfb_test_and_set_rounding(minfo, xres, bpp);
+	}
+	return xres_new;
+}
+
+static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) {
+
+	DBG(__func__)
+
+	switch (var->bits_per_pixel) {
+		case 4:
+			return 16;	/* pseudocolor... 16 entries HW palette */
+		case 8:
+			return 256;	/* pseudocolor... 256 entries HW palette */
+		case 16:
+			return 16;	/* directcolor... 16 entries SW palette */
+					/* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+		case 24:
+			return 16;	/* directcolor... 16 entries SW palette */
+					/* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+		case 32:
+			return 16;	/* directcolor... 16 entries SW palette */
+					/* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+	}
+	return 16;	/* return something reasonable... or panic()? */
+}
+
+static int matroxfb_decode_var(const struct matrox_fb_info *minfo,
+			       struct fb_var_screeninfo *var, int *visual,
+			       int *video_cmap_len, unsigned int* ydstorg)
+{
+	struct RGBT {
+		unsigned char bpp;
+		struct {
+			unsigned char offset,
+				      length;
+		} red,
+		  green,
+		  blue,
+		  transp;
+		signed char visual;
+	};
+	static const struct RGBT table[]= {
+		{ 8,{ 0,8},{0,8},{0,8},{ 0,0},MX_VISUAL_PSEUDOCOLOR},
+		{15,{10,5},{5,5},{0,5},{15,1},MX_VISUAL_DIRECTCOLOR},
+		{16,{11,5},{5,6},{0,5},{ 0,0},MX_VISUAL_DIRECTCOLOR},
+		{24,{16,8},{8,8},{0,8},{ 0,0},MX_VISUAL_DIRECTCOLOR},
+		{32,{16,8},{8,8},{0,8},{24,8},MX_VISUAL_DIRECTCOLOR}
+	};
+	struct RGBT const *rgbt;
+	unsigned int bpp = var->bits_per_pixel;
+	unsigned int vramlen;
+	unsigned int memlen;
+
+	DBG(__func__)
+
+	switch (bpp) {
+		case 4:	 if (!minfo->capable.cfb4) return -EINVAL;
+			 break;
+		case 8:	 break;
+		case 16: break;
+		case 24: break;
+		case 32: break;
+		default: return -EINVAL;
+	}
+	*ydstorg = 0;
+	vramlen = minfo->video.len_usable;
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+	if (var->xres_virtual < var->xres)
+		var->xres_virtual = var->xres;
+
+	var->xres_virtual = matroxfb_pitch_adjust(minfo, var->xres_virtual, bpp);
+	memlen = var->xres_virtual * bpp * var->yres_virtual / 8;
+	if (memlen > vramlen) {
+		var->yres_virtual = vramlen * 8 / (var->xres_virtual * bpp);
+		memlen = var->xres_virtual * bpp * var->yres_virtual / 8;
+	}
+	/* There is hardware bug that no line can cross 4MB boundary */
+	/* give up for CFB24, it is impossible to easy workaround it */
+	/* for other try to do something */
+	if (!minfo->capable.cross4MB && (memlen > 0x400000)) {
+		if (bpp == 24) {
+			/* sorry */
+		} else {
+			unsigned int linelen;
+			unsigned int m1 = linelen = var->xres_virtual * bpp / 8;
+			unsigned int m2 = PAGE_SIZE;	/* or 128 if you do not need PAGE ALIGNED address */
+			unsigned int max_yres;
+
+			while (m1) {
+				while (m2 >= m1) m2 -= m1;
+				swap(m1, m2);
+			}
+			m2 = linelen * PAGE_SIZE / m2;
+			*ydstorg = m2 = 0x400000 % m2;
+			max_yres = (vramlen - m2) / linelen;
+			if (var->yres_virtual > max_yres)
+				var->yres_virtual = max_yres;
+		}
+	}
+	/* YDSTLEN contains only signed 16bit value */
+	if (var->yres_virtual > 32767)
+		var->yres_virtual = 32767;
+	/* we must round yres/xres down, we already rounded y/xres_virtual up
+	   if it was possible. We should return -EINVAL, but I disagree */
+	if (var->yres_virtual < var->yres)
+		var->yres = var->yres_virtual;
+	if (var->xres_virtual < var->xres)
+		var->xres = var->xres_virtual;
+	if (var->xoffset + var->xres > var->xres_virtual)
+		var->xoffset = var->xres_virtual - var->xres;
+	if (var->yoffset + var->yres > var->yres_virtual)
+		var->yoffset = var->yres_virtual - var->yres;
+
+	if (bpp == 16 && var->green.length == 5) {
+		bpp--; /* an artificial value - 15 */
+	}
+
+	for (rgbt = table; rgbt->bpp < bpp; rgbt++);
+#define	SETCLR(clr)\
+	var->clr.offset = rgbt->clr.offset;\
+	var->clr.length = rgbt->clr.length
+	SETCLR(red);
+	SETCLR(green);
+	SETCLR(blue);
+	SETCLR(transp);
+#undef	SETCLR
+	*visual = rgbt->visual;
+
+	if (bpp > 8)
+		dprintk("matroxfb: truecolor: "
+			"size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+			var->transp.length, var->red.length, var->green.length, var->blue.length,
+			var->transp.offset, var->red.offset, var->green.offset, var->blue.offset);
+
+	*video_cmap_len = matroxfb_get_cmap_len(var);
+	dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel,
+				var->xres_virtual, var->yres_virtual);
+	return 0;
+}
+
+static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			      unsigned blue, unsigned transp,
+			      struct fb_info *fb_info)
+{
+	struct matrox_fb_info* minfo = container_of(fb_info, struct matrox_fb_info, fbcon);
+
+	DBG(__func__)
+
+	/*
+	 *  Set a single color register. The values supplied are
+	 *  already rounded down to the hardware's capabilities
+	 *  (according to the entries in the `var' structure). Return
+	 *  != 0 for invalid regno.
+	 */
+
+	if (regno >= minfo->curr.cmap_len)
+		return 1;
+
+	if (minfo->fbcon.var.grayscale) {
+		/* gray = 0.30*R + 0.59*G + 0.11*B */
+		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+	}
+
+	red = CNVT_TOHW(red, minfo->fbcon.var.red.length);
+	green = CNVT_TOHW(green, minfo->fbcon.var.green.length);
+	blue = CNVT_TOHW(blue, minfo->fbcon.var.blue.length);
+	transp = CNVT_TOHW(transp, minfo->fbcon.var.transp.length);
+
+	switch (minfo->fbcon.var.bits_per_pixel) {
+	case 4:
+	case 8:
+		mga_outb(M_DAC_REG, regno);
+		mga_outb(M_DAC_VAL, red);
+		mga_outb(M_DAC_VAL, green);
+		mga_outb(M_DAC_VAL, blue);
+		break;
+	case 16:
+		if (regno >= 16)
+			break;
+		{
+			u_int16_t col =
+				(red << minfo->fbcon.var.red.offset)     |
+				(green << minfo->fbcon.var.green.offset) |
+				(blue << minfo->fbcon.var.blue.offset)   |
+				(transp << minfo->fbcon.var.transp.offset); /* for 1:5:5:5 */
+			minfo->cmap[regno] = col | (col << 16);
+		}
+		break;
+	case 24:
+	case 32:
+		if (regno >= 16)
+			break;
+		minfo->cmap[regno] =
+			(red   << minfo->fbcon.var.red.offset)   |
+			(green << minfo->fbcon.var.green.offset) |
+			(blue  << minfo->fbcon.var.blue.offset)  |
+			(transp << minfo->fbcon.var.transp.offset);	/* 8:8:8:8 */
+		break;
+	}
+	return 0;
+}
+
+static void matroxfb_init_fix(struct matrox_fb_info *minfo)
+{
+	struct fb_fix_screeninfo *fix = &minfo->fbcon.fix;
+	DBG(__func__)
+
+	strcpy(fix->id,"MATROX");
+
+	fix->xpanstep = 8;	/* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */
+	fix->ypanstep = 1;
+	fix->ywrapstep = 0;
+	fix->mmio_start = minfo->mmio.base;
+	fix->mmio_len = minfo->mmio.len;
+	fix->accel = minfo->devflags.accelerator;
+}
+
+static void matroxfb_update_fix(struct matrox_fb_info *minfo)
+{
+	struct fb_fix_screeninfo *fix = &minfo->fbcon.fix;
+	DBG(__func__)
+
+	mutex_lock(&minfo->fbcon.mm_lock);
+	fix->smem_start = minfo->video.base + minfo->curr.ydstorg.bytes;
+	fix->smem_len = minfo->video.len_usable - minfo->curr.ydstorg.bytes;
+	mutex_unlock(&minfo->fbcon.mm_lock);
+}
+
+static int matroxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	int err;
+	int visual;
+	int cmap_len;
+	unsigned int ydstorg;
+	struct matrox_fb_info *minfo = info2minfo(info);
+
+	if (minfo->dead) {
+		return -ENXIO;
+	}
+	if ((err = matroxfb_decode_var(minfo, var, &visual, &cmap_len, &ydstorg)) != 0)
+		return err;
+	return 0;
+}
+
+static int matroxfb_set_par(struct fb_info *info)
+{
+	int err;
+	int visual;
+	int cmap_len;
+	unsigned int ydstorg;
+	struct fb_var_screeninfo *var;
+	struct matrox_fb_info *minfo = info2minfo(info);
+
+	DBG(__func__)
+
+	if (minfo->dead) {
+		return -ENXIO;
+	}
+
+	var = &info->var;
+	if ((err = matroxfb_decode_var(minfo, var, &visual, &cmap_len, &ydstorg)) != 0)
+		return err;
+	minfo->fbcon.screen_base = vaddr_va(minfo->video.vbase) + ydstorg;
+	matroxfb_update_fix(minfo);
+	minfo->fbcon.fix.visual = visual;
+	minfo->fbcon.fix.type = FB_TYPE_PACKED_PIXELS;
+	minfo->fbcon.fix.type_aux = 0;
+	minfo->fbcon.fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
+	{
+		unsigned int pos;
+
+		minfo->curr.cmap_len = cmap_len;
+		ydstorg += minfo->devflags.ydstorg;
+		minfo->curr.ydstorg.bytes = ydstorg;
+		minfo->curr.ydstorg.chunks = ydstorg >> (isInterleave(minfo) ? 3 : 2);
+		if (var->bits_per_pixel == 4)
+			minfo->curr.ydstorg.pixels = ydstorg;
+		else
+			minfo->curr.ydstorg.pixels = (ydstorg * 8) / var->bits_per_pixel;
+		minfo->curr.final_bppShift = matroxfb_get_final_bppShift(minfo, var->bits_per_pixel);
+		{	struct my_timming mt;
+			struct matrox_hw_state* hw;
+			int out;
+
+			matroxfb_var2my(var, &mt);
+			mt.crtc = MATROXFB_SRC_CRTC1;
+			/* CRTC1 delays */
+			switch (var->bits_per_pixel) {
+				case  0:	mt.delay = 31 + 0; break;
+				case 16:	mt.delay = 21 + 8; break;
+				case 24:	mt.delay = 17 + 8; break;
+				case 32:	mt.delay = 16 + 8; break;
+				default:	mt.delay = 31 + 8; break;
+			}
+
+			hw = &minfo->hw;
+
+			down_read(&minfo->altout.lock);
+			for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+				if (minfo->outputs[out].src == MATROXFB_SRC_CRTC1 &&
+				    minfo->outputs[out].output->compute) {
+					minfo->outputs[out].output->compute(minfo->outputs[out].data, &mt);
+				}
+			}
+			up_read(&minfo->altout.lock);
+			minfo->crtc1.pixclock = mt.pixclock;
+			minfo->crtc1.mnp = mt.mnp;
+			minfo->hw_switch->init(minfo, &mt);
+			pos = (var->yoffset * var->xres_virtual + var->xoffset) * minfo->curr.final_bppShift / 32;
+			pos += minfo->curr.ydstorg.chunks;
+
+			hw->CRTC[0x0D] = pos & 0xFF;
+			hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
+			hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
+			hw->CRTCEXT[8] = pos >> 21;
+			minfo->hw_switch->restore(minfo);
+			update_crtc2(minfo, pos);
+			down_read(&minfo->altout.lock);
+			for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+				if (minfo->outputs[out].src == MATROXFB_SRC_CRTC1 &&
+				    minfo->outputs[out].output->program) {
+					minfo->outputs[out].output->program(minfo->outputs[out].data);
+				}
+			}
+			for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+				if (minfo->outputs[out].src == MATROXFB_SRC_CRTC1 &&
+				    minfo->outputs[out].output->start) {
+					minfo->outputs[out].output->start(minfo->outputs[out].data);
+				}
+			}
+			up_read(&minfo->altout.lock);
+			matrox_cfbX_init(minfo);
+		}
+	}
+	minfo->initialized = 1;
+	return 0;
+}
+
+static int matroxfb_get_vblank(struct matrox_fb_info *minfo,
+			       struct fb_vblank *vblank)
+{
+	unsigned int sts1;
+
+	matroxfb_enable_irq(minfo, 0);
+	memset(vblank, 0, sizeof(*vblank));
+	vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VSYNC |
+			FB_VBLANK_HAVE_VBLANK | FB_VBLANK_HAVE_HBLANK;
+	sts1 = mga_inb(M_INSTS1);
+	vblank->vcount = mga_inl(M_VCOUNT);
+	/* BTW, on my PIII/450 with G400, reading M_INSTS1
+	   byte makes this call about 12% slower (1.70 vs. 2.05 us
+	   per ioctl()) */
+	if (sts1 & 1)
+		vblank->flags |= FB_VBLANK_HBLANKING;
+	if (sts1 & 8)
+		vblank->flags |= FB_VBLANK_VSYNCING;
+	if (vblank->vcount >= minfo->fbcon.var.yres)
+		vblank->flags |= FB_VBLANK_VBLANKING;
+	if (test_bit(0, &minfo->irq_flags)) {
+		vblank->flags |= FB_VBLANK_HAVE_COUNT;
+		/* Only one writer, aligned int value...
+		   it should work without lock and without atomic_t */
+		vblank->count = minfo->crtc1.vsync.cnt;
+	}
+	return 0;
+}
+
+static struct matrox_altout panellink_output = {
+	.name	 = "Panellink output",
+};
+
+static int matroxfb_ioctl(struct fb_info *info,
+			  unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	struct matrox_fb_info *minfo = info2minfo(info);
+
+	DBG(__func__)
+
+	if (minfo->dead) {
+		return -ENXIO;
+	}
+
+	switch (cmd) {
+		case FBIOGET_VBLANK:
+			{
+				struct fb_vblank vblank;
+				int err;
+
+				err = matroxfb_get_vblank(minfo, &vblank);
+				if (err)
+					return err;
+				if (copy_to_user(argp, &vblank, sizeof(vblank)))
+					return -EFAULT;
+				return 0;
+			}
+		case FBIO_WAITFORVSYNC:
+			{
+				u_int32_t crt;
+
+				if (get_user(crt, (u_int32_t __user *)arg))
+					return -EFAULT;
+
+				return matroxfb_wait_for_sync(minfo, crt);
+			}
+		case MATROXFB_SET_OUTPUT_MODE:
+			{
+				struct matroxioc_output_mode mom;
+				struct matrox_altout *oproc;
+				int val;
+
+				if (copy_from_user(&mom, argp, sizeof(mom)))
+					return -EFAULT;
+				if (mom.output >= MATROXFB_MAX_OUTPUTS)
+					return -ENXIO;
+				down_read(&minfo->altout.lock);
+				oproc = minfo->outputs[mom.output].output;
+				if (!oproc) {
+					val = -ENXIO;
+				} else if (!oproc->verifymode) {
+					if (mom.mode == MATROXFB_OUTPUT_MODE_MONITOR) {
+						val = 0;
+					} else {
+						val = -EINVAL;
+					}
+				} else {
+					val = oproc->verifymode(minfo->outputs[mom.output].data, mom.mode);
+				}
+				if (!val) {
+					if (minfo->outputs[mom.output].mode != mom.mode) {
+						minfo->outputs[mom.output].mode = mom.mode;
+						val = 1;
+					}
+				}
+				up_read(&minfo->altout.lock);
+				if (val != 1)
+					return val;
+				switch (minfo->outputs[mom.output].src) {
+					case MATROXFB_SRC_CRTC1:
+						matroxfb_set_par(info);
+						break;
+					case MATROXFB_SRC_CRTC2:
+						{
+							struct matroxfb_dh_fb_info* crtc2;
+
+							down_read(&minfo->crtc2.lock);
+							crtc2 = minfo->crtc2.info;
+							if (crtc2)
+								crtc2->fbcon.fbops->fb_set_par(&crtc2->fbcon);
+							up_read(&minfo->crtc2.lock);
+						}
+						break;
+				}
+				return 0;
+			}
+		case MATROXFB_GET_OUTPUT_MODE:
+			{
+				struct matroxioc_output_mode mom;
+				struct matrox_altout *oproc;
+				int val;
+
+				if (copy_from_user(&mom, argp, sizeof(mom)))
+					return -EFAULT;
+				if (mom.output >= MATROXFB_MAX_OUTPUTS)
+					return -ENXIO;
+				down_read(&minfo->altout.lock);
+				oproc = minfo->outputs[mom.output].output;
+				if (!oproc) {
+					val = -ENXIO;
+				} else {
+					mom.mode = minfo->outputs[mom.output].mode;
+					val = 0;
+				}
+				up_read(&minfo->altout.lock);
+				if (val)
+					return val;
+				if (copy_to_user(argp, &mom, sizeof(mom)))
+					return -EFAULT;
+				return 0;
+			}
+		case MATROXFB_SET_OUTPUT_CONNECTION:
+			{
+				u_int32_t tmp;
+				int i;
+				int changes;
+
+				if (copy_from_user(&tmp, argp, sizeof(tmp)))
+					return -EFAULT;
+				for (i = 0; i < 32; i++) {
+					if (tmp & (1 << i)) {
+						if (i >= MATROXFB_MAX_OUTPUTS)
+							return -ENXIO;
+						if (!minfo->outputs[i].output)
+							return -ENXIO;
+						switch (minfo->outputs[i].src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC1:
+								break;
+							default:
+								return -EBUSY;
+						}
+					}
+				}
+				if (minfo->devflags.panellink) {
+					if (tmp & MATROXFB_OUTPUT_CONN_DFP) {
+						if (tmp & MATROXFB_OUTPUT_CONN_SECONDARY)
+							return -EINVAL;
+						for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+							if (minfo->outputs[i].src == MATROXFB_SRC_CRTC2) {
+								return -EBUSY;
+							}
+						}
+					}
+				}
+				changes = 0;
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (tmp & (1 << i)) {
+						if (minfo->outputs[i].src != MATROXFB_SRC_CRTC1) {
+							changes = 1;
+							minfo->outputs[i].src = MATROXFB_SRC_CRTC1;
+						}
+					} else if (minfo->outputs[i].src == MATROXFB_SRC_CRTC1) {
+						changes = 1;
+						minfo->outputs[i].src = MATROXFB_SRC_NONE;
+					}
+				}
+				if (!changes)
+					return 0;
+				matroxfb_set_par(info);
+				return 0;
+			}
+		case MATROXFB_GET_OUTPUT_CONNECTION:
+			{
+				u_int32_t conn = 0;
+				int i;
+
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (minfo->outputs[i].src == MATROXFB_SRC_CRTC1) {
+						conn |= 1 << i;
+					}
+				}
+				if (put_user(conn, (u_int32_t __user *)arg))
+					return -EFAULT;
+				return 0;
+			}
+		case MATROXFB_GET_AVAILABLE_OUTPUTS:
+			{
+				u_int32_t conn = 0;
+				int i;
+
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (minfo->outputs[i].output) {
+						switch (minfo->outputs[i].src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC1:
+								conn |= 1 << i;
+								break;
+						}
+					}
+				}
+				if (minfo->devflags.panellink) {
+					if (conn & MATROXFB_OUTPUT_CONN_DFP)
+						conn &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
+					if (conn & MATROXFB_OUTPUT_CONN_SECONDARY)
+						conn &= ~MATROXFB_OUTPUT_CONN_DFP;
+				}
+				if (put_user(conn, (u_int32_t __user *)arg))
+					return -EFAULT;
+				return 0;
+			}
+		case MATROXFB_GET_ALL_OUTPUTS:
+			{
+				u_int32_t conn = 0;
+				int i;
+
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (minfo->outputs[i].output) {
+						conn |= 1 << i;
+					}
+				}
+				if (put_user(conn, (u_int32_t __user *)arg))
+					return -EFAULT;
+				return 0;
+			}
+		case VIDIOC_QUERYCAP:
+			{
+				struct v4l2_capability r;
+
+				memset(&r, 0, sizeof(r));
+				strcpy(r.driver, "matroxfb");
+				strcpy(r.card, "Matrox");
+				sprintf(r.bus_info, "PCI:%s", pci_name(minfo->pcidev));
+				r.version = KERNEL_VERSION(1,0,0);
+				r.capabilities = V4L2_CAP_VIDEO_OUTPUT;
+				if (copy_to_user(argp, &r, sizeof(r)))
+					return -EFAULT;
+				return 0;
+
+			}
+		case VIDIOC_QUERYCTRL:
+			{
+				struct v4l2_queryctrl qctrl;
+				int err;
+
+				if (copy_from_user(&qctrl, argp, sizeof(qctrl)))
+					return -EFAULT;
+
+				down_read(&minfo->altout.lock);
+				if (!minfo->outputs[1].output) {
+					err = -ENXIO;
+				} else if (minfo->outputs[1].output->getqueryctrl) {
+					err = minfo->outputs[1].output->getqueryctrl(minfo->outputs[1].data, &qctrl);
+				} else {
+					err = -EINVAL;
+				}
+				up_read(&minfo->altout.lock);
+				if (err >= 0 &&
+				    copy_to_user(argp, &qctrl, sizeof(qctrl)))
+					return -EFAULT;
+				return err;
+			}
+		case VIDIOC_G_CTRL:
+			{
+				struct v4l2_control ctrl;
+				int err;
+
+				if (copy_from_user(&ctrl, argp, sizeof(ctrl)))
+					return -EFAULT;
+
+				down_read(&minfo->altout.lock);
+				if (!minfo->outputs[1].output) {
+					err = -ENXIO;
+				} else if (minfo->outputs[1].output->getctrl) {
+					err = minfo->outputs[1].output->getctrl(minfo->outputs[1].data, &ctrl);
+				} else {
+					err = -EINVAL;
+				}
+				up_read(&minfo->altout.lock);
+				if (err >= 0 &&
+				    copy_to_user(argp, &ctrl, sizeof(ctrl)))
+					return -EFAULT;
+				return err;
+			}
+		case VIDIOC_S_CTRL:
+			{
+				struct v4l2_control ctrl;
+				int err;
+
+				if (copy_from_user(&ctrl, argp, sizeof(ctrl)))
+					return -EFAULT;
+
+				down_read(&minfo->altout.lock);
+				if (!minfo->outputs[1].output) {
+					err = -ENXIO;
+				} else if (minfo->outputs[1].output->setctrl) {
+					err = minfo->outputs[1].output->setctrl(minfo->outputs[1].data, &ctrl);
+				} else {
+					err = -EINVAL;
+				}
+				up_read(&minfo->altout.lock);
+				return err;
+			}
+	}
+	return -ENOTTY;
+}
+
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static int matroxfb_blank(int blank, struct fb_info *info)
+{
+	int seq;
+	int crtc;
+	CRITFLAGS
+	struct matrox_fb_info *minfo = info2minfo(info);
+
+	DBG(__func__)
+
+	if (minfo->dead)
+		return 1;
+
+	switch (blank) {
+	case FB_BLANK_NORMAL:  seq = 0x20; crtc = 0x00; break; /* works ??? */
+	case FB_BLANK_VSYNC_SUSPEND:  seq = 0x20; crtc = 0x10; break;
+	case FB_BLANK_HSYNC_SUSPEND:  seq = 0x20; crtc = 0x20; break;
+	case FB_BLANK_POWERDOWN:  seq = 0x20; crtc = 0x30; break;
+	default: seq = 0x00; crtc = 0x00; break;
+	}
+
+	CRITBEGIN
+
+	mga_outb(M_SEQ_INDEX, 1);
+	mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq);
+	mga_outb(M_EXTVGA_INDEX, 1);
+	mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc);
+
+	CRITEND
+	return 0;
+}
+
+static const struct fb_ops matroxfb_ops = {
+	.owner =	THIS_MODULE,
+	.fb_open =	matroxfb_open,
+	.fb_release =	matroxfb_release,
+	.fb_check_var =	matroxfb_check_var,
+	.fb_set_par =	matroxfb_set_par,
+	.fb_setcolreg =	matroxfb_setcolreg,
+	.fb_pan_display =matroxfb_pan_display,
+	.fb_blank =	matroxfb_blank,
+	.fb_ioctl =	matroxfb_ioctl,
+/*	.fb_fillrect =	<set by matrox_cfbX_init>, */
+/*	.fb_copyarea =	<set by matrox_cfbX_init>, */
+/*	.fb_imageblit =	<set by matrox_cfbX_init>, */
+/*	.fb_cursor =	<set by matrox_cfbX_init>, */
+};
+
+#define RSDepth(X)	(((X) >> 8) & 0x0F)
+#define RS8bpp		0x1
+#define RS15bpp		0x2
+#define RS16bpp		0x3
+#define RS32bpp		0x4
+#define RS4bpp		0x5
+#define RS24bpp		0x6
+#define RSText		0x7
+#define RSText8		0x8
+/* 9-F */
+static struct { struct fb_bitfield red, green, blue, transp; int bits_per_pixel; } colors[] = {
+	{ {  0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, {  0, 0, 0},  8 },
+	{ { 10, 5, 0}, { 5, 5, 0}, { 0, 5, 0}, { 15, 1, 0}, 16 },
+	{ { 11, 5, 0}, { 5, 6, 0}, { 0, 5, 0}, {  0, 0, 0}, 16 },
+	{ { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 24, 8, 0}, 32 },
+	{ {  0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, {  0, 0, 0},  4 },
+	{ { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, {  0, 0, 0}, 24 },
+	{ {  0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, {  0, 0, 0},  0 },	/* textmode with (default) VGA8x16 */
+	{ {  0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, {  0, 0, 0},  0 },	/* textmode hardwired to VGA8x8 */
+};
+
+/* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */
+static unsigned int mem;		/* "matroxfb:mem:xxxxxM" */
+static int option_precise_width = 1;	/* cannot be changed, option_precise_width==0 must imply noaccel */
+static int inv24;			/* "matroxfb:inv24" */
+static int cross4MB = -1;		/* "matroxfb:cross4MB" */
+static int disabled;			/* "matroxfb:disabled" */
+static int noaccel;			/* "matroxfb:noaccel" */
+static int nopan;			/* "matroxfb:nopan" */
+static int no_pci_retry;		/* "matroxfb:nopciretry" */
+static int novga;			/* "matroxfb:novga" */
+static int nobios;			/* "matroxfb:nobios" */
+static int noinit = 1;			/* "matroxfb:init" */
+static int inverse;			/* "matroxfb:inverse" */
+static int sgram;			/* "matroxfb:sgram" */
+static int mtrr = 1;			/* "matroxfb:nomtrr" */
+static int grayscale;			/* "matroxfb:grayscale" */
+static int dev = -1;			/* "matroxfb:dev:xxxxx" */
+static unsigned int vesa = ~0;		/* "matroxfb:vesa:xxxxx" */
+static int depth = -1;			/* "matroxfb:depth:xxxxx" */
+static unsigned int xres;		/* "matroxfb:xres:xxxxx" */
+static unsigned int yres;		/* "matroxfb:yres:xxxxx" */
+static unsigned int upper = ~0;		/* "matroxfb:upper:xxxxx" */
+static unsigned int lower = ~0;		/* "matroxfb:lower:xxxxx" */
+static unsigned int vslen;		/* "matroxfb:vslen:xxxxx" */
+static unsigned int left = ~0;		/* "matroxfb:left:xxxxx" */
+static unsigned int right = ~0;		/* "matroxfb:right:xxxxx" */
+static unsigned int hslen;		/* "matroxfb:hslen:xxxxx" */
+static unsigned int pixclock;		/* "matroxfb:pixclock:xxxxx" */
+static int sync = -1;			/* "matroxfb:sync:xxxxx" */
+static unsigned int fv;			/* "matroxfb:fv:xxxxx" */
+static unsigned int fh;			/* "matroxfb:fh:xxxxxk" */
+static unsigned int maxclk;		/* "matroxfb:maxclk:xxxxM" */
+static int dfp;				/* "matroxfb:dfp */
+static int dfp_type = -1;		/* "matroxfb:dfp:xxx */
+static int memtype = -1;		/* "matroxfb:memtype:xxx" */
+static char outputs[8];			/* "matroxfb:outputs:xxx" */
+
+#ifndef MODULE
+static char videomode[64];		/* "matroxfb:mode:xxxxx" or "matroxfb:xxxxx" */
+#endif
+
+static int matroxfb_getmemory(struct matrox_fb_info *minfo,
+			      unsigned int maxSize, unsigned int *realSize)
+{
+	vaddr_t vm;
+	unsigned int offs;
+	unsigned int offs2;
+	unsigned char orig;
+	unsigned char bytes[32];
+	unsigned char* tmp;
+
+	DBG(__func__)
+
+	vm = minfo->video.vbase;
+	maxSize &= ~0x1FFFFF;	/* must be X*2MB (really it must be 2 or X*4MB) */
+	/* at least 2MB */
+	if (maxSize < 0x0200000) return 0;
+	if (maxSize > 0x2000000) maxSize = 0x2000000;
+
+	mga_outb(M_EXTVGA_INDEX, 0x03);
+	orig = mga_inb(M_EXTVGA_DATA);
+	mga_outb(M_EXTVGA_DATA, orig | 0x80);
+
+	tmp = bytes;
+	for (offs = 0x100000; offs < maxSize; offs += 0x200000)
+		*tmp++ = mga_readb(vm, offs);
+	for (offs = 0x100000; offs < maxSize; offs += 0x200000)
+		mga_writeb(vm, offs, 0x02);
+	mga_outb(M_CACHEFLUSH, 0x00);
+	for (offs = 0x100000; offs < maxSize; offs += 0x200000) {
+		if (mga_readb(vm, offs) != 0x02)
+			break;
+		mga_writeb(vm, offs, mga_readb(vm, offs) - 0x02);
+		if (mga_readb(vm, offs))
+			break;
+	}
+	tmp = bytes;
+	for (offs2 = 0x100000; offs2 < maxSize; offs2 += 0x200000)
+		mga_writeb(vm, offs2, *tmp++);
+
+	mga_outb(M_EXTVGA_INDEX, 0x03);
+	mga_outb(M_EXTVGA_DATA, orig);
+
+	*realSize = offs - 0x100000;
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+	minfo->interleave = !(!isMillenium(minfo) || ((offs - 0x100000) & 0x3FFFFF));
+#endif
+	return 1;
+}
+
+struct video_board {
+	int maxvram;
+	int maxdisplayable;
+	int accelID;
+	struct matrox_switch* lowlevel;
+		 };
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+static struct video_board vbMillennium = {
+	.maxvram = 0x0800000,
+	.maxdisplayable = 0x0800000,
+	.accelID = FB_ACCEL_MATROX_MGA2064W,
+	.lowlevel = &matrox_millennium
+};
+
+static struct video_board vbMillennium2 = {
+	.maxvram = 0x1000000,
+	.maxdisplayable = 0x0800000,
+	.accelID = FB_ACCEL_MATROX_MGA2164W,
+	.lowlevel = &matrox_millennium
+};
+
+static struct video_board vbMillennium2A = {
+	.maxvram = 0x1000000,
+	.maxdisplayable = 0x0800000,
+	.accelID = FB_ACCEL_MATROX_MGA2164W_AGP,
+	.lowlevel = &matrox_millennium
+};
+#endif	/* CONFIG_FB_MATROX_MILLENIUM */
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+static struct video_board vbMystique = {
+	.maxvram = 0x0800000,
+	.maxdisplayable = 0x0800000,
+	.accelID = FB_ACCEL_MATROX_MGA1064SG,
+	.lowlevel = &matrox_mystique
+};
+#endif	/* CONFIG_FB_MATROX_MYSTIQUE */
+#ifdef CONFIG_FB_MATROX_G
+static struct video_board vbG100 = {
+	.maxvram = 0x0800000,
+	.maxdisplayable = 0x0800000,
+	.accelID = FB_ACCEL_MATROX_MGAG100,
+	.lowlevel = &matrox_G100
+};
+
+static struct video_board vbG200 = {
+	.maxvram = 0x1000000,
+	.maxdisplayable = 0x1000000,
+	.accelID = FB_ACCEL_MATROX_MGAG200,
+	.lowlevel = &matrox_G100
+};
+/* from doc it looks like that accelerator can draw only to low 16MB :-( Direct accesses & displaying are OK for
+   whole 32MB */
+static struct video_board vbG400 = {
+	.maxvram = 0x2000000,
+	.maxdisplayable = 0x1000000,
+	.accelID = FB_ACCEL_MATROX_MGAG400,
+	.lowlevel = &matrox_G100
+};
+#endif
+
+#define DEVF_VIDEO64BIT		0x0001
+#define	DEVF_SWAPS		0x0002
+#define DEVF_SRCORG		0x0004
+#define DEVF_DUALHEAD		0x0008
+#define DEVF_CROSS4MB		0x0010
+#define DEVF_TEXT4B		0x0020
+/* #define DEVF_recycled	0x0040	*/
+/* #define DEVF_recycled	0x0080	*/
+#define DEVF_SUPPORT32MB	0x0100
+#define DEVF_ANY_VXRES		0x0200
+#define DEVF_TEXT16B		0x0400
+#define DEVF_CRTC2		0x0800
+#define DEVF_MAVEN_CAPABLE	0x1000
+#define DEVF_PANELLINK_CAPABLE	0x2000
+#define DEVF_G450DAC		0x4000
+
+#define DEVF_GCORE	(DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB)
+#define DEVF_G2CORE	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE | DEVF_SRCORG | DEVF_DUALHEAD)
+#define DEVF_G100	(DEVF_GCORE) /* no doc, no vxres... */
+#define DEVF_G200	(DEVF_G2CORE)
+#define DEVF_G400	(DEVF_G2CORE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2)
+/* if you'll find how to drive DFP... */
+#define DEVF_G450	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG | DEVF_DUALHEAD)
+#define DEVF_G550	(DEVF_G450)
+
+static struct board {
+	unsigned short vendor, device, rev, svid, sid;
+	unsigned int flags;
+	unsigned int maxclk;
+	enum mga_chip chip;
+	struct video_board* base;
+	const char* name;
+		} dev_list[] = {
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL,	0xFF,
+		0,			0,
+		DEVF_TEXT4B,
+		230000,
+		MGA_2064,
+		&vbMillennium,
+		"Millennium (PCI)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL_2,	0xFF,
+		0,			0,
+		DEVF_SWAPS,
+		220000,
+		MGA_2164,
+		&vbMillennium2,
+		"Millennium II (PCI)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL_2_AGP,	0xFF,
+		0,			0,
+		DEVF_SWAPS,
+		250000,
+		MGA_2164,
+		&vbMillennium2A,
+		"Millennium II (AGP)"},
+#endif
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MYS,	0x02,
+		0,			0,
+		DEVF_VIDEO64BIT | DEVF_CROSS4MB,
+		180000,
+		MGA_1064,
+		&vbMystique,
+		"Mystique (PCI)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MYS,	0xFF,
+		0,			0,
+		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		220000,
+		MGA_1164,
+		&vbMystique,
+		"Mystique 220 (PCI)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MYS_AGP,	0x02,
+		0,			0,
+		DEVF_VIDEO64BIT | DEVF_CROSS4MB,
+		180000,
+		MGA_1064,
+		&vbMystique,
+		"Mystique (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MYS_AGP,	0xFF,
+		0,			0,
+		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		220000,
+		MGA_1164,
+		&vbMystique,
+		"Mystique 220 (AGP)"},
+#endif
+#ifdef CONFIG_FB_MATROX_G
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_MM,	0xFF,
+		0,			0,
+		DEVF_G100,
+		230000,
+		MGA_G100,
+		&vbG100,
+		"MGA-G100 (PCI)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
+		0,			0,
+		DEVF_G100,
+		230000,
+		MGA_G100,
+		&vbG100,
+		"MGA-G100 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_PCI,	0xFF,
+		0,			0,
+		DEVF_G200,
+		250000,
+		MGA_G200,
+		&vbG200,
+		"MGA-G200 (PCI)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
+		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_GENERIC,
+		DEVF_G200,
+		220000,
+		MGA_G200,
+		&vbG200,
+		"MGA-G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
+		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP,
+		DEVF_G200,
+		230000,
+		MGA_G200,
+		&vbG200,
+		"Mystique G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
+		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MILLENIUM_G200_AGP,
+		DEVF_G200,
+		250000,
+		MGA_G200,
+		&vbG200,
+		"Millennium G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
+		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MARVEL_G200_AGP,
+		DEVF_G200,
+		230000,
+		MGA_G200,
+		&vbG200,
+		"Marvel G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
+		PCI_SS_VENDOR_ID_SIEMENS_NIXDORF,	PCI_SS_ID_SIEMENS_MGA_G200_AGP,
+		DEVF_G200,
+		230000,
+		MGA_G200,
+		&vbG200,
+		"MGA-G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
+		0,			0,
+		DEVF_G200,
+		230000,
+		MGA_G200,
+		&vbG200,
+		"G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G400,	0x80,
+		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MILLENNIUM_G400_MAX_AGP,
+		DEVF_G400,
+		360000,
+		MGA_G400,
+		&vbG400,
+		"Millennium G400 MAX (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G400,	0x80,
+		0,			0,
+		DEVF_G400,
+		300000,
+		MGA_G400,
+		&vbG400,
+		"G400 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G400,	0xFF,
+		0,			0,
+		DEVF_G450,
+		360000,
+		MGA_G450,
+		&vbG400,
+		"G450"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G550,	0xFF,
+		0,			0,
+		DEVF_G550,
+		360000,
+		MGA_G550,
+		&vbG400,
+		"G550"},
+#endif
+	{0,			0,				0xFF,
+		0,			0,
+		0,
+		0,
+		0,
+		NULL,
+		NULL}};
+
+#ifndef MODULE
+static const struct fb_videomode defaultmode = {
+	/* 640x480 @ 60Hz, 31.5 kHz */
+	NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2,
+	0, FB_VMODE_NONINTERLACED
+};
+
+static int hotplug = 0;
+#endif /* !MODULE */
+
+static void setDefaultOutputs(struct matrox_fb_info *minfo)
+{
+	unsigned int i;
+	const char* ptr;
+
+	minfo->outputs[0].default_src = MATROXFB_SRC_CRTC1;
+	if (minfo->devflags.g450dac) {
+		minfo->outputs[1].default_src = MATROXFB_SRC_CRTC1;
+		minfo->outputs[2].default_src = MATROXFB_SRC_CRTC1;
+	} else if (dfp) {
+		minfo->outputs[2].default_src = MATROXFB_SRC_CRTC1;
+	}
+	ptr = outputs;
+	for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+		char c = *ptr++;
+
+		if (c == 0) {
+			break;
+		}
+		if (c == '0') {
+			minfo->outputs[i].default_src = MATROXFB_SRC_NONE;
+		} else if (c == '1') {
+			minfo->outputs[i].default_src = MATROXFB_SRC_CRTC1;
+		} else if (c == '2' && minfo->devflags.crtc2) {
+			minfo->outputs[i].default_src = MATROXFB_SRC_CRTC2;
+		} else {
+			printk(KERN_ERR "matroxfb: Unknown outputs setting\n");
+			break;
+		}
+	}
+	/* Nullify this option for subsequent adapters */
+	outputs[0] = 0;
+}
+
+static int initMatrox2(struct matrox_fb_info *minfo, struct board *b)
+{
+	unsigned long ctrlptr_phys = 0;
+	unsigned long video_base_phys = 0;
+	unsigned int memsize;
+	int err;
+
+	static const struct pci_device_id intel_82437[] = {
+		{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437) },
+		{ },
+	};
+
+	DBG(__func__)
+
+	/* set default values... */
+	vesafb_defined.accel_flags = FB_ACCELF_TEXT;
+
+	minfo->hw_switch = b->base->lowlevel;
+	minfo->devflags.accelerator = b->base->accelID;
+	minfo->max_pixel_clock = b->maxclk;
+
+	printk(KERN_INFO "matroxfb: Matrox %s detected\n", b->name);
+	minfo->capable.plnwt = 1;
+	minfo->chip = b->chip;
+	minfo->capable.srcorg = b->flags & DEVF_SRCORG;
+	minfo->devflags.video64bits = b->flags & DEVF_VIDEO64BIT;
+	if (b->flags & DEVF_TEXT4B) {
+		minfo->devflags.vgastep = 4;
+		minfo->devflags.textmode = 4;
+		minfo->devflags.text_type_aux = FB_AUX_TEXT_MGA_STEP16;
+	} else if (b->flags & DEVF_TEXT16B) {
+		minfo->devflags.vgastep = 16;
+		minfo->devflags.textmode = 1;
+		minfo->devflags.text_type_aux = FB_AUX_TEXT_MGA_STEP16;
+	} else {
+		minfo->devflags.vgastep = 8;
+		minfo->devflags.textmode = 1;
+		minfo->devflags.text_type_aux = FB_AUX_TEXT_MGA_STEP8;
+	}
+	minfo->devflags.support32MB = (b->flags & DEVF_SUPPORT32MB) != 0;
+	minfo->devflags.precise_width = !(b->flags & DEVF_ANY_VXRES);
+	minfo->devflags.crtc2 = (b->flags & DEVF_CRTC2) != 0;
+	minfo->devflags.maven_capable = (b->flags & DEVF_MAVEN_CAPABLE) != 0;
+	minfo->devflags.dualhead = (b->flags & DEVF_DUALHEAD) != 0;
+	minfo->devflags.dfp_type = dfp_type;
+	minfo->devflags.g450dac = (b->flags & DEVF_G450DAC) != 0;
+	minfo->devflags.textstep = minfo->devflags.vgastep * minfo->devflags.textmode;
+	minfo->devflags.textvram = 65536 / minfo->devflags.textmode;
+	setDefaultOutputs(minfo);
+	if (b->flags & DEVF_PANELLINK_CAPABLE) {
+		minfo->outputs[2].data = minfo;
+		minfo->outputs[2].output = &panellink_output;
+		minfo->outputs[2].src = minfo->outputs[2].default_src;
+		minfo->outputs[2].mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		minfo->devflags.panellink = 1;
+	}
+
+	if (minfo->capable.cross4MB < 0)
+		minfo->capable.cross4MB = b->flags & DEVF_CROSS4MB;
+	if (b->flags & DEVF_SWAPS) {
+		ctrlptr_phys = pci_resource_start(minfo->pcidev, 1);
+		video_base_phys = pci_resource_start(minfo->pcidev, 0);
+		minfo->devflags.fbResource = PCI_BASE_ADDRESS_0;
+	} else {
+		ctrlptr_phys = pci_resource_start(minfo->pcidev, 0);
+		video_base_phys = pci_resource_start(minfo->pcidev, 1);
+		minfo->devflags.fbResource = PCI_BASE_ADDRESS_1;
+	}
+	err = -EINVAL;
+	if (!ctrlptr_phys) {
+		printk(KERN_ERR "matroxfb: control registers are not available, matroxfb disabled\n");
+		goto fail;
+	}
+	if (!video_base_phys) {
+		printk(KERN_ERR "matroxfb: video RAM is not available in PCI address space, matroxfb disabled\n");
+		goto fail;
+	}
+	memsize = b->base->maxvram;
+	if (!request_mem_region(ctrlptr_phys, 16384, "matroxfb MMIO")) {
+		goto fail;
+	}
+	if (!request_mem_region(video_base_phys, memsize, "matroxfb FB")) {
+		goto failCtrlMR;
+	}
+	minfo->video.len_maximum = memsize;
+	/* convert mem (autodetect k, M) */
+	if (mem < 1024) mem *= 1024;
+	if (mem < 0x00100000) mem *= 1024;
+
+	if (mem && (mem < memsize))
+		memsize = mem;
+	err = -ENOMEM;
+
+	minfo->mmio.vbase.vaddr = ioremap_nocache(ctrlptr_phys, 16384);
+	if (!minfo->mmio.vbase.vaddr) {
+		printk(KERN_ERR "matroxfb: cannot ioremap(%lX, 16384), matroxfb disabled\n", ctrlptr_phys);
+		goto failVideoMR;
+	}
+	minfo->mmio.base = ctrlptr_phys;
+	minfo->mmio.len = 16384;
+	minfo->video.base = video_base_phys;
+	minfo->video.vbase.vaddr = ioremap_wc(video_base_phys, memsize);
+	if (!minfo->video.vbase.vaddr) {
+		printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n",
+			video_base_phys, memsize);
+		goto failCtrlIO;
+	}
+	{
+		u_int32_t cmd;
+		u_int32_t mga_option;
+
+		pci_read_config_dword(minfo->pcidev, PCI_OPTION_REG, &mga_option);
+		pci_read_config_dword(minfo->pcidev, PCI_COMMAND, &cmd);
+		mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */
+		mga_option |= MX_OPTION_BSWAP;
+		/* disable palette snooping */
+		cmd &= ~PCI_COMMAND_VGA_PALETTE;
+		if (pci_dev_present(intel_82437)) {
+			if (!(mga_option & 0x20000000) && !minfo->devflags.nopciretry) {
+				printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n");
+			}
+			mga_option |= 0x20000000;
+			minfo->devflags.nopciretry = 1;
+		}
+		pci_write_config_dword(minfo->pcidev, PCI_COMMAND, cmd);
+		pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mga_option);
+		minfo->hw.MXoptionReg = mga_option;
+
+		/* select non-DMA memory for PCI_MGA_DATA, otherwise dump of PCI cfg space can lock PCI bus */
+		/* maybe preinit() candidate, but it is same... for all devices... at this time... */
+		pci_write_config_dword(minfo->pcidev, PCI_MGA_INDEX, 0x00003C00);
+	}
+
+	err = -ENXIO;
+	matroxfb_read_pins(minfo);
+	if (minfo->hw_switch->preinit(minfo)) {
+		goto failVideoIO;
+	}
+
+	err = -ENOMEM;
+	if (!matroxfb_getmemory(minfo, memsize, &minfo->video.len) || !minfo->video.len) {
+		printk(KERN_ERR "matroxfb: cannot determine memory size\n");
+		goto failVideoIO;
+	}
+	minfo->devflags.ydstorg = 0;
+
+	minfo->video.base = video_base_phys;
+	minfo->video.len_usable = minfo->video.len;
+	if (minfo->video.len_usable > b->base->maxdisplayable)
+		minfo->video.len_usable = b->base->maxdisplayable;
+	if (mtrr)
+		minfo->wc_cookie = arch_phys_wc_add(video_base_phys,
+						    minfo->video.len);
+
+	if (!minfo->devflags.novga)
+		request_region(0x3C0, 32, "matrox");
+	matroxfb_g450_connect(minfo);
+	minfo->hw_switch->reset(minfo);
+
+	minfo->fbcon.monspecs.hfmin = 0;
+	minfo->fbcon.monspecs.hfmax = fh;
+	minfo->fbcon.monspecs.vfmin = 0;
+	minfo->fbcon.monspecs.vfmax = fv;
+	minfo->fbcon.monspecs.dpms = 0;	/* TBD */
+
+	/* static settings */
+	vesafb_defined.red = colors[depth-1].red;
+	vesafb_defined.green = colors[depth-1].green;
+	vesafb_defined.blue = colors[depth-1].blue;
+	vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel;
+	vesafb_defined.grayscale = grayscale;
+	vesafb_defined.vmode = 0;
+	if (noaccel)
+		vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT;
+
+	minfo->fbops = matroxfb_ops;
+	minfo->fbcon.fbops = &minfo->fbops;
+	minfo->fbcon.pseudo_palette = minfo->cmap;
+	minfo->fbcon.flags = FBINFO_PARTIAL_PAN_OK | 	 /* Prefer panning for scroll under MC viewer/edit */
+				      FBINFO_HWACCEL_COPYAREA |  /* We have hw-assisted bmove */
+				      FBINFO_HWACCEL_FILLRECT |  /* And fillrect */
+				      FBINFO_HWACCEL_IMAGEBLIT | /* And imageblit */
+				      FBINFO_HWACCEL_XPAN |      /* And we support both horizontal */
+				      FBINFO_HWACCEL_YPAN |      /* And vertical panning */
+				      FBINFO_READS_FAST;
+	minfo->video.len_usable &= PAGE_MASK;
+	fb_alloc_cmap(&minfo->fbcon.cmap, 256, 1);
+
+#ifndef MODULE
+	/* mode database is marked __init!!! */
+	if (!hotplug) {
+		fb_find_mode(&vesafb_defined, &minfo->fbcon, videomode[0] ? videomode : NULL,
+			NULL, 0, &defaultmode, vesafb_defined.bits_per_pixel);
+	}
+#endif /* !MODULE */
+
+	/* mode modifiers */
+	if (hslen)
+		vesafb_defined.hsync_len = hslen;
+	if (vslen)
+		vesafb_defined.vsync_len = vslen;
+	if (left != ~0)
+		vesafb_defined.left_margin = left;
+	if (right != ~0)
+		vesafb_defined.right_margin = right;
+	if (upper != ~0)
+		vesafb_defined.upper_margin = upper;
+	if (lower != ~0)
+		vesafb_defined.lower_margin = lower;
+	if (xres)
+		vesafb_defined.xres = xres;
+	if (yres)
+		vesafb_defined.yres = yres;
+	if (sync != -1)
+		vesafb_defined.sync = sync;
+	else if (vesafb_defined.sync == ~0) {
+		vesafb_defined.sync = 0;
+		if (yres < 400)
+			vesafb_defined.sync |= FB_SYNC_HOR_HIGH_ACT;
+		else if (yres < 480)
+			vesafb_defined.sync |= FB_SYNC_VERT_HIGH_ACT;
+	}
+
+	/* fv, fh, maxclk limits was specified */
+	{
+		unsigned int tmp;
+
+		if (fv) {
+			tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres
+				  + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
+			if ((tmp < fh) || (fh == 0)) fh = tmp;
+		}
+		if (fh) {
+			tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres
+				  + vesafb_defined.right_margin + vesafb_defined.hsync_len);
+			if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
+		}
+		tmp = (maxclk + 499) / 500;
+		if (tmp) {
+			tmp = (2000000000 + tmp) / tmp;
+			if (tmp > pixclock) pixclock = tmp;
+		}
+	}
+	if (pixclock) {
+		if (pixclock < 2000)		/* > 500MHz */
+			pixclock = 4000;	/* 250MHz */
+		if (pixclock > 1000000)
+			pixclock = 1000000;	/* 1MHz */
+		vesafb_defined.pixclock = pixclock;
+	}
+
+	/* FIXME: Where to move this?! */
+#if defined(CONFIG_PPC_PMAC)
+#ifndef MODULE
+	if (machine_is(powermac)) {
+		struct fb_var_screeninfo var;
+
+		if (default_vmode <= 0 || default_vmode > VMODE_MAX)
+			default_vmode = VMODE_640_480_60;
+#if defined(CONFIG_PPC32)
+		if (IS_REACHABLE(CONFIG_NVRAM) && default_cmode == CMODE_NVRAM)
+			default_cmode = nvram_read_byte(NV_CMODE);
+#endif
+		if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
+			default_cmode = CMODE_8;
+		if (!mac_vmode_to_var(default_vmode, default_cmode, &var)) {
+			var.accel_flags = vesafb_defined.accel_flags;
+			var.xoffset = var.yoffset = 0;
+			/* Note: mac_vmode_to_var() does not set all parameters */
+			vesafb_defined = var;
+		}
+	}
+#endif /* !MODULE */
+#endif /* CONFIG_PPC_PMAC */
+	vesafb_defined.xres_virtual = vesafb_defined.xres;
+	if (nopan) {
+		vesafb_defined.yres_virtual = vesafb_defined.yres;
+	} else {
+		vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough
+							to yres_virtual * xres_virtual < 2^32 */
+	}
+	matroxfb_init_fix(minfo);
+	minfo->fbcon.screen_base = vaddr_va(minfo->video.vbase);
+	/* Normalize values (namely yres_virtual) */
+	matroxfb_check_var(&vesafb_defined, &minfo->fbcon);
+	/* And put it into "current" var. Do NOT program hardware yet, or we'll not take over
+	 * vgacon correctly. fbcon_startup will call fb_set_par for us, WITHOUT check_var,
+	 * and unfortunately it will do it BEFORE vgacon contents is saved, so it won't work
+	 * anyway. But we at least tried... */
+	minfo->fbcon.var = vesafb_defined;
+	err = -EINVAL;
+
+	printk(KERN_INFO "matroxfb: %dx%dx%dbpp (virtual: %dx%d)\n",
+		vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel,
+		vesafb_defined.xres_virtual, vesafb_defined.yres_virtual);
+	printk(KERN_INFO "matroxfb: framebuffer at 0x%lX, mapped to 0x%p, size %d\n",
+		minfo->video.base, vaddr_va(minfo->video.vbase), minfo->video.len);
+
+/* We do not have to set currcon to 0... register_framebuffer do it for us on first console
+ * and we do not want currcon == 0 for subsequent framebuffers */
+
+	minfo->fbcon.device = &minfo->pcidev->dev;
+	if (register_framebuffer(&minfo->fbcon) < 0) {
+		goto failVideoIO;
+	}
+	fb_info(&minfo->fbcon, "%s frame buffer device\n", minfo->fbcon.fix.id);
+
+	/* there is no console on this fb... but we have to initialize hardware
+	 * until someone tells me what is proper thing to do */
+	if (!minfo->initialized) {
+		fb_info(&minfo->fbcon, "initializing hardware\n");
+		/* We have to use FB_ACTIVATE_FORCE, as we had to put vesafb_defined to the fbcon.var
+		 * already before, so register_framebuffer works correctly. */
+		vesafb_defined.activate |= FB_ACTIVATE_FORCE;
+		fb_set_var(&minfo->fbcon, &vesafb_defined);
+	}
+
+	return 0;
+failVideoIO:;
+	matroxfb_g450_shutdown(minfo);
+	iounmap(minfo->video.vbase.vaddr);
+failCtrlIO:;
+	iounmap(minfo->mmio.vbase.vaddr);
+failVideoMR:;
+	release_mem_region(video_base_phys, minfo->video.len_maximum);
+failCtrlMR:;
+	release_mem_region(ctrlptr_phys, 16384);
+fail:;
+	return err;
+}
+
+static LIST_HEAD(matroxfb_list);
+static LIST_HEAD(matroxfb_driver_list);
+
+#define matroxfb_l(x) list_entry(x, struct matrox_fb_info, next_fb)
+#define matroxfb_driver_l(x) list_entry(x, struct matroxfb_driver, node)
+int matroxfb_register_driver(struct matroxfb_driver* drv) {
+	struct matrox_fb_info* minfo;
+
+	list_add(&drv->node, &matroxfb_driver_list);
+	for (minfo = matroxfb_l(matroxfb_list.next);
+	     minfo != matroxfb_l(&matroxfb_list);
+	     minfo = matroxfb_l(minfo->next_fb.next)) {
+		void* p;
+
+		if (minfo->drivers_count == MATROXFB_MAX_FB_DRIVERS)
+			continue;
+		p = drv->probe(minfo);
+		if (p) {
+			minfo->drivers_data[minfo->drivers_count] = p;
+			minfo->drivers[minfo->drivers_count++] = drv;
+		}
+	}
+	return 0;
+}
+
+void matroxfb_unregister_driver(struct matroxfb_driver* drv) {
+	struct matrox_fb_info* minfo;
+
+	list_del(&drv->node);
+	for (minfo = matroxfb_l(matroxfb_list.next);
+	     minfo != matroxfb_l(&matroxfb_list);
+	     minfo = matroxfb_l(minfo->next_fb.next)) {
+		int i;
+
+		for (i = 0; i < minfo->drivers_count; ) {
+			if (minfo->drivers[i] == drv) {
+				if (drv && drv->remove)
+					drv->remove(minfo, minfo->drivers_data[i]);
+				minfo->drivers[i] = minfo->drivers[--minfo->drivers_count];
+				minfo->drivers_data[i] = minfo->drivers_data[minfo->drivers_count];
+			} else
+				i++;
+		}
+	}
+}
+
+static void matroxfb_register_device(struct matrox_fb_info* minfo) {
+	struct matroxfb_driver* drv;
+	int i = 0;
+	list_add(&minfo->next_fb, &matroxfb_list);
+	for (drv = matroxfb_driver_l(matroxfb_driver_list.next);
+	     drv != matroxfb_driver_l(&matroxfb_driver_list);
+	     drv = matroxfb_driver_l(drv->node.next)) {
+		if (drv->probe) {
+			void *p = drv->probe(minfo);
+			if (p) {
+				minfo->drivers_data[i] = p;
+				minfo->drivers[i++] = drv;
+				if (i == MATROXFB_MAX_FB_DRIVERS)
+					break;
+			}
+		}
+	}
+	minfo->drivers_count = i;
+}
+
+static void matroxfb_unregister_device(struct matrox_fb_info* minfo) {
+	int i;
+
+	list_del(&minfo->next_fb);
+	for (i = 0; i < minfo->drivers_count; i++) {
+		struct matroxfb_driver* drv = minfo->drivers[i];
+
+		if (drv && drv->remove)
+			drv->remove(minfo, minfo->drivers_data[i]);
+	}
+}
+
+static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dummy) {
+	struct board* b;
+	u_int16_t svid;
+	u_int16_t sid;
+	struct matrox_fb_info* minfo;
+	int err;
+	u_int32_t cmd;
+	DBG(__func__)
+
+	svid = pdev->subsystem_vendor;
+	sid = pdev->subsystem_device;
+	for (b = dev_list; b->vendor; b++) {
+		if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < pdev->revision)) continue;
+		if (b->svid)
+			if ((b->svid != svid) || (b->sid != sid)) continue;
+		break;
+	}
+	/* not match... */
+	if (!b->vendor)
+		return -ENODEV;
+	if (dev > 0) {
+		/* not requested one... */
+		dev--;
+		return -ENODEV;
+	}
+	pci_read_config_dword(pdev, PCI_COMMAND, &cmd);
+	if (pci_enable_device(pdev)) {
+		return -1;
+	}
+
+	minfo = kzalloc(sizeof(*minfo), GFP_KERNEL);
+	if (!minfo)
+		return -ENOMEM;
+
+	minfo->pcidev = pdev;
+	minfo->dead = 0;
+	minfo->usecount = 0;
+	minfo->userusecount = 0;
+
+	pci_set_drvdata(pdev, minfo);
+	/* DEVFLAGS */
+	minfo->devflags.memtype = memtype;
+	if (memtype != -1)
+		noinit = 0;
+	if (cmd & PCI_COMMAND_MEMORY) {
+		minfo->devflags.novga = novga;
+		minfo->devflags.nobios = nobios;
+		minfo->devflags.noinit = noinit;
+		/* subsequent heads always needs initialization and must not enable BIOS */
+		novga = 1;
+		nobios = 1;
+		noinit = 0;
+	} else {
+		minfo->devflags.novga = 1;
+		minfo->devflags.nobios = 1;
+		minfo->devflags.noinit = 0;
+	}
+
+	minfo->devflags.nopciretry = no_pci_retry;
+	minfo->devflags.mga_24bpp_fix = inv24;
+	minfo->devflags.precise_width = option_precise_width;
+	minfo->devflags.sgram = sgram;
+	minfo->capable.cross4MB = cross4MB;
+
+	spin_lock_init(&minfo->lock.DAC);
+	spin_lock_init(&minfo->lock.accel);
+	init_rwsem(&minfo->crtc2.lock);
+	init_rwsem(&minfo->altout.lock);
+	mutex_init(&minfo->fbcon.mm_lock);
+	minfo->irq_flags = 0;
+	init_waitqueue_head(&minfo->crtc1.vsync.wait);
+	init_waitqueue_head(&minfo->crtc2.vsync.wait);
+	minfo->crtc1.panpos = -1;
+
+	err = initMatrox2(minfo, b);
+	if (!err) {
+		matroxfb_register_device(minfo);
+		return 0;
+	}
+	kfree(minfo);
+	return -1;
+}
+
+static void pci_remove_matrox(struct pci_dev* pdev) {
+	struct matrox_fb_info* minfo;
+
+	minfo = pci_get_drvdata(pdev);
+	matroxfb_remove(minfo, 1);
+}
+
+static const struct pci_device_id matroxfb_devices[] = {
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL_2,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL_2_AGP,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+#endif
+#ifdef CONFIG_FB_MATROX_MYSTIQUE
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MYS,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+#endif
+#ifdef CONFIG_FB_MATROX_G
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_MM,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_PCI,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G400,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G550,
+		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
+#endif
+	{0,			0,
+		0,		0,		0, 0, 0}
+};
+
+MODULE_DEVICE_TABLE(pci, matroxfb_devices);
+
+
+static struct pci_driver matroxfb_driver = {
+	.name =		"matroxfb",
+	.id_table =	matroxfb_devices,
+	.probe =	matroxfb_probe,
+	.remove =	pci_remove_matrox,
+};
+
+/* **************************** init-time only **************************** */
+
+#define RSResolution(X)	((X) & 0x0F)
+#define RS640x400	1
+#define RS640x480	2
+#define RS800x600	3
+#define RS1024x768	4
+#define RS1280x1024	5
+#define RS1600x1200	6
+#define RS768x576	7
+#define RS960x720	8
+#define RS1152x864	9
+#define RS1408x1056	10
+#define RS640x350	11
+#define RS1056x344	12	/* 132 x 43 text */
+#define RS1056x400	13	/* 132 x 50 text */
+#define RS1056x480	14	/* 132 x 60 text */
+#define RSNoxNo		15
+/* 10-FF */
+static struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = {
+	{  640,  400,  48, 16, 39,  8,  96, 2, 70 },
+	{  640,  480,  48, 16, 33, 10,  96, 2, 60 },
+	{  800,  600, 144, 24, 28,  8, 112, 6, 60 },
+	{ 1024,  768, 160, 32, 30,  4, 128, 4, 60 },
+	{ 1280, 1024, 224, 32, 32,  4, 136, 4, 60 },
+	{ 1600, 1200, 272, 48, 32,  5, 152, 5, 60 },
+	{  768,  576, 144, 16, 28,  6, 112, 4, 60 },
+	{  960,  720, 144, 24, 28,  8, 112, 4, 60 },
+	{ 1152,  864, 192, 32, 30,  4, 128, 4, 60 },
+	{ 1408, 1056, 256, 40, 32,  5, 144, 5, 60 },
+	{  640,  350,  48, 16, 39,  8,  96, 2, 70 },
+	{ 1056,  344,  96, 24, 59, 44, 160, 2, 70 },
+	{ 1056,  400,  96, 24, 39,  8, 160, 2, 70 },
+	{ 1056,  480,  96, 24, 36, 12, 160, 3, 60 },
+	{    0,    0,  ~0, ~0, ~0, ~0,   0, 0,  0 }
+};
+
+#define RSCreate(X,Y)	((X) | ((Y) << 8))
+static struct { unsigned int vesa; unsigned int info; } *RSptr, vesamap[] __initdata = {
+/* default must be first */
+	{    ~0, RSCreate(RSNoxNo,     RS8bpp ) },
+	{ 0x101, RSCreate(RS640x480,   RS8bpp ) },
+	{ 0x100, RSCreate(RS640x400,   RS8bpp ) },
+	{ 0x180, RSCreate(RS768x576,   RS8bpp ) },
+	{ 0x103, RSCreate(RS800x600,   RS8bpp ) },
+	{ 0x188, RSCreate(RS960x720,   RS8bpp ) },
+	{ 0x105, RSCreate(RS1024x768,  RS8bpp ) },
+	{ 0x190, RSCreate(RS1152x864,  RS8bpp ) },
+	{ 0x107, RSCreate(RS1280x1024, RS8bpp ) },
+	{ 0x198, RSCreate(RS1408x1056, RS8bpp ) },
+	{ 0x11C, RSCreate(RS1600x1200, RS8bpp ) },
+	{ 0x110, RSCreate(RS640x480,   RS15bpp) },
+	{ 0x181, RSCreate(RS768x576,   RS15bpp) },
+	{ 0x113, RSCreate(RS800x600,   RS15bpp) },
+	{ 0x189, RSCreate(RS960x720,   RS15bpp) },
+	{ 0x116, RSCreate(RS1024x768,  RS15bpp) },
+	{ 0x191, RSCreate(RS1152x864,  RS15bpp) },
+	{ 0x119, RSCreate(RS1280x1024, RS15bpp) },
+	{ 0x199, RSCreate(RS1408x1056, RS15bpp) },
+	{ 0x11D, RSCreate(RS1600x1200, RS15bpp) },
+	{ 0x111, RSCreate(RS640x480,   RS16bpp) },
+	{ 0x182, RSCreate(RS768x576,   RS16bpp) },
+	{ 0x114, RSCreate(RS800x600,   RS16bpp) },
+	{ 0x18A, RSCreate(RS960x720,   RS16bpp) },
+	{ 0x117, RSCreate(RS1024x768,  RS16bpp) },
+	{ 0x192, RSCreate(RS1152x864,  RS16bpp) },
+	{ 0x11A, RSCreate(RS1280x1024, RS16bpp) },
+	{ 0x19A, RSCreate(RS1408x1056, RS16bpp) },
+	{ 0x11E, RSCreate(RS1600x1200, RS16bpp) },
+	{ 0x1B2, RSCreate(RS640x480,   RS24bpp) },
+	{ 0x184, RSCreate(RS768x576,   RS24bpp) },
+	{ 0x1B5, RSCreate(RS800x600,   RS24bpp) },
+	{ 0x18C, RSCreate(RS960x720,   RS24bpp) },
+	{ 0x1B8, RSCreate(RS1024x768,  RS24bpp) },
+	{ 0x194, RSCreate(RS1152x864,  RS24bpp) },
+	{ 0x1BB, RSCreate(RS1280x1024, RS24bpp) },
+	{ 0x19C, RSCreate(RS1408x1056, RS24bpp) },
+	{ 0x1BF, RSCreate(RS1600x1200, RS24bpp) },
+	{ 0x112, RSCreate(RS640x480,   RS32bpp) },
+	{ 0x183, RSCreate(RS768x576,   RS32bpp) },
+	{ 0x115, RSCreate(RS800x600,   RS32bpp) },
+	{ 0x18B, RSCreate(RS960x720,   RS32bpp) },
+	{ 0x118, RSCreate(RS1024x768,  RS32bpp) },
+	{ 0x193, RSCreate(RS1152x864,  RS32bpp) },
+	{ 0x11B, RSCreate(RS1280x1024, RS32bpp) },
+	{ 0x19B, RSCreate(RS1408x1056, RS32bpp) },
+	{ 0x11F, RSCreate(RS1600x1200, RS32bpp) },
+	{ 0x010, RSCreate(RS640x350,   RS4bpp ) },
+	{ 0x012, RSCreate(RS640x480,   RS4bpp ) },
+	{ 0x102, RSCreate(RS800x600,   RS4bpp ) },
+	{ 0x104, RSCreate(RS1024x768,  RS4bpp ) },
+	{ 0x106, RSCreate(RS1280x1024, RS4bpp ) },
+	{     0, 0				}};
+
+static void __init matroxfb_init_params(void) {
+	/* fh from kHz to Hz */
+	if (fh < 1000)
+		fh *= 1000;	/* 1kHz minimum */
+	/* maxclk */
+	if (maxclk < 1000) maxclk *= 1000;	/* kHz -> Hz, MHz -> kHz */
+	if (maxclk < 1000000) maxclk *= 1000;	/* kHz -> Hz, 1MHz minimum */
+	/* fix VESA number */
+	if (vesa != ~0)
+		vesa &= 0x1DFF;		/* mask out clearscreen, acceleration and so on */
+
+	/* static settings */
+	for (RSptr = vesamap; RSptr->vesa; RSptr++) {
+		if (RSptr->vesa == vesa) break;
+	}
+	if (!RSptr->vesa) {
+		printk(KERN_ERR "Invalid vesa mode 0x%04X\n", vesa);
+		RSptr = vesamap;
+	}
+	{
+		int res = RSResolution(RSptr->info)-1;
+		if (left == ~0)
+			left = timmings[res].left;
+		if (!xres)
+			xres = timmings[res].xres;
+		if (right == ~0)
+			right = timmings[res].right;
+		if (!hslen)
+			hslen = timmings[res].hslen;
+		if (upper == ~0)
+			upper = timmings[res].upper;
+		if (!yres)
+			yres = timmings[res].yres;
+		if (lower == ~0)
+			lower = timmings[res].lower;
+		if (!vslen)
+			vslen = timmings[res].vslen;
+		if (!(fv||fh||maxclk||pixclock))
+			fv = timmings[res].vfreq;
+		if (depth == -1)
+			depth = RSDepth(RSptr->info);
+	}
+}
+
+static int __init matrox_init(void) {
+	int err;
+
+	matroxfb_init_params();
+	err = pci_register_driver(&matroxfb_driver);
+	dev = -1;	/* accept all new devices... */
+	return err;
+}
+
+/* **************************** exit-time only **************************** */
+
+static void __exit matrox_done(void) {
+	pci_unregister_driver(&matroxfb_driver);
+}
+
+#ifndef MODULE
+
+/* ************************* init in-kernel code ************************** */
+
+static int __init matroxfb_setup(char *options) {
+	char *this_opt;
+
+	DBG(__func__)
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt) continue;
+
+		dprintk("matroxfb_setup: option %s\n", this_opt);
+
+		if (!strncmp(this_opt, "dev:", 4))
+			dev = simple_strtoul(this_opt+4, NULL, 0);
+		else if (!strncmp(this_opt, "depth:", 6)) {
+			switch (simple_strtoul(this_opt+6, NULL, 0)) {
+				case 0: depth = RSText; break;
+				case 4: depth = RS4bpp; break;
+				case 8: depth = RS8bpp; break;
+				case 15:depth = RS15bpp; break;
+				case 16:depth = RS16bpp; break;
+				case 24:depth = RS24bpp; break;
+				case 32:depth = RS32bpp; break;
+				default:
+					printk(KERN_ERR "matroxfb: unsupported color depth\n");
+			}
+		} else if (!strncmp(this_opt, "xres:", 5))
+			xres = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "yres:", 5))
+			yres = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "vslen:", 6))
+			vslen = simple_strtoul(this_opt+6, NULL, 0);
+		else if (!strncmp(this_opt, "hslen:", 6))
+			hslen = simple_strtoul(this_opt+6, NULL, 0);
+		else if (!strncmp(this_opt, "left:", 5))
+			left = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "right:", 6))
+			right = simple_strtoul(this_opt+6, NULL, 0);
+		else if (!strncmp(this_opt, "upper:", 6))
+			upper = simple_strtoul(this_opt+6, NULL, 0);
+		else if (!strncmp(this_opt, "lower:", 6))
+			lower = simple_strtoul(this_opt+6, NULL, 0);
+		else if (!strncmp(this_opt, "pixclock:", 9))
+			pixclock = simple_strtoul(this_opt+9, NULL, 0);
+		else if (!strncmp(this_opt, "sync:", 5))
+			sync = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "vesa:", 5))
+			vesa = simple_strtoul(this_opt+5, NULL, 0);
+		else if (!strncmp(this_opt, "maxclk:", 7))
+			maxclk = simple_strtoul(this_opt+7, NULL, 0);
+		else if (!strncmp(this_opt, "fh:", 3))
+			fh = simple_strtoul(this_opt+3, NULL, 0);
+		else if (!strncmp(this_opt, "fv:", 3))
+			fv = simple_strtoul(this_opt+3, NULL, 0);
+		else if (!strncmp(this_opt, "mem:", 4))
+			mem = simple_strtoul(this_opt+4, NULL, 0);
+		else if (!strncmp(this_opt, "mode:", 5))
+			strlcpy(videomode, this_opt+5, sizeof(videomode));
+		else if (!strncmp(this_opt, "outputs:", 8))
+			strlcpy(outputs, this_opt+8, sizeof(outputs));
+		else if (!strncmp(this_opt, "dfp:", 4)) {
+			dfp_type = simple_strtoul(this_opt+4, NULL, 0);
+			dfp = 1;
+		}
+#ifdef CONFIG_PPC_PMAC
+		else if (!strncmp(this_opt, "vmode:", 6)) {
+			unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
+			if (vmode > 0 && vmode <= VMODE_MAX)
+				default_vmode = vmode;
+		} else if (!strncmp(this_opt, "cmode:", 6)) {
+			unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0);
+			switch (cmode) {
+				case 0:
+				case 8:
+					default_cmode = CMODE_8;
+					break;
+				case 15:
+				case 16:
+					default_cmode = CMODE_16;
+					break;
+				case 24:
+				case 32:
+					default_cmode = CMODE_32;
+					break;
+			}
+		}
+#endif
+		else if (!strcmp(this_opt, "disabled"))	/* nodisabled does not exist */
+			disabled = 1;
+		else if (!strcmp(this_opt, "enabled"))	/* noenabled does not exist */
+			disabled = 0;
+		else if (!strcmp(this_opt, "sgram"))	/* nosgram == sdram */
+			sgram = 1;
+		else if (!strcmp(this_opt, "sdram"))
+			sgram = 0;
+		else if (!strncmp(this_opt, "memtype:", 8))
+			memtype = simple_strtoul(this_opt+8, NULL, 0);
+		else {
+			int value = 1;
+
+			if (!strncmp(this_opt, "no", 2)) {
+				value = 0;
+				this_opt += 2;
+			}
+			if (! strcmp(this_opt, "inverse"))
+				inverse = value;
+			else if (!strcmp(this_opt, "accel"))
+				noaccel = !value;
+			else if (!strcmp(this_opt, "pan"))
+				nopan = !value;
+			else if (!strcmp(this_opt, "pciretry"))
+				no_pci_retry = !value;
+			else if (!strcmp(this_opt, "vga"))
+				novga = !value;
+			else if (!strcmp(this_opt, "bios"))
+				nobios = !value;
+			else if (!strcmp(this_opt, "init"))
+				noinit = !value;
+			else if (!strcmp(this_opt, "mtrr"))
+				mtrr = value;
+			else if (!strcmp(this_opt, "inv24"))
+				inv24 = value;
+			else if (!strcmp(this_opt, "cross4MB"))
+				cross4MB = value;
+			else if (!strcmp(this_opt, "grayscale"))
+				grayscale = value;
+			else if (!strcmp(this_opt, "dfp"))
+				dfp = value;
+			else {
+				strlcpy(videomode, this_opt, sizeof(videomode));
+			}
+		}
+	}
+	return 0;
+}
+
+static int __initdata initialized = 0;
+
+static int __init matroxfb_init(void)
+{
+	char *option = NULL;
+	int err = 0;
+
+	DBG(__func__)
+
+	if (fb_get_options("matroxfb", &option))
+		return -ENODEV;
+	matroxfb_setup(option);
+
+	if (disabled)
+		return -ENXIO;
+	if (!initialized) {
+		initialized = 1;
+		err = matrox_init();
+	}
+	hotplug = 1;
+	/* never return failure, user can hotplug matrox later... */
+	return err;
+}
+
+module_init(matroxfb_init);
+
+#else
+
+/* *************************** init module code **************************** */
+
+MODULE_AUTHOR("(c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400/G450/G550");
+MODULE_LICENSE("GPL");
+
+module_param(mem, int, 0);
+MODULE_PARM_DESC(mem, "Size of available memory in MB, KB or B (2,4,8,12,16MB, default=autodetect)");
+module_param(disabled, int, 0);
+MODULE_PARM_DESC(disabled, "Disabled (0 or 1=disabled) (default=0)");
+module_param(noaccel, int, 0);
+MODULE_PARM_DESC(noaccel, "Do not use accelerating engine (0 or 1=disabled) (default=0)");
+module_param(nopan, int, 0);
+MODULE_PARM_DESC(nopan, "Disable pan on startup (0 or 1=disabled) (default=0)");
+module_param(no_pci_retry, int, 0);
+MODULE_PARM_DESC(no_pci_retry, "PCI retries enabled (0 or 1=disabled) (default=0)");
+module_param(novga, int, 0);
+MODULE_PARM_DESC(novga, "VGA I/O (0x3C0-0x3DF) disabled (0 or 1=disabled) (default=0)");
+module_param(nobios, int, 0);
+MODULE_PARM_DESC(nobios, "Disables ROM BIOS (0 or 1=disabled) (default=do not change BIOS state)");
+module_param(noinit, int, 0);
+MODULE_PARM_DESC(noinit, "Disables W/SG/SD-RAM and bus interface initialization (0 or 1=do not initialize) (default=0)");
+module_param(memtype, int, 0);
+MODULE_PARM_DESC(memtype, "Memory type for G200/G400 (see Documentation/fb/matroxfb.txt for explanation) (default=3 for G200, 0 for G400)");
+module_param(mtrr, int, 0);
+MODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)");
+module_param(sgram, int, 0);
+MODULE_PARM_DESC(sgram, "Indicates that G100/G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)");
+module_param(inv24, int, 0);
+MODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)");
+module_param(inverse, int, 0);
+MODULE_PARM_DESC(inverse, "Inverse (0 or 1) (default=0)");
+module_param(dev, int, 0);
+MODULE_PARM_DESC(dev, "Multihead support, attach to device ID (0..N) (default=all working)");
+module_param(vesa, int, 0);
+MODULE_PARM_DESC(vesa, "Startup videomode (0x000-0x1FF) (default=0x101)");
+module_param(xres, int, 0);
+MODULE_PARM_DESC(xres, "Horizontal resolution (px), overrides xres from vesa (default=vesa)");
+module_param(yres, int, 0);
+MODULE_PARM_DESC(yres, "Vertical resolution (scans), overrides yres from vesa (default=vesa)");
+module_param(upper, int, 0);
+MODULE_PARM_DESC(upper, "Upper blank space (scans), overrides upper from vesa (default=vesa)");
+module_param(lower, int, 0);
+MODULE_PARM_DESC(lower, "Lower blank space (scans), overrides lower from vesa (default=vesa)");
+module_param(vslen, int, 0);
+MODULE_PARM_DESC(vslen, "Vertical sync length (scans), overrides lower from vesa (default=vesa)");
+module_param(left, int, 0);
+MODULE_PARM_DESC(left, "Left blank space (px), overrides left from vesa (default=vesa)");
+module_param(right, int, 0);
+MODULE_PARM_DESC(right, "Right blank space (px), overrides right from vesa (default=vesa)");
+module_param(hslen, int, 0);
+MODULE_PARM_DESC(hslen, "Horizontal sync length (px), overrides hslen from vesa (default=vesa)");
+module_param(pixclock, int, 0);
+MODULE_PARM_DESC(pixclock, "Pixelclock (ns), overrides pixclock from vesa (default=vesa)");
+module_param(sync, int, 0);
+MODULE_PARM_DESC(sync, "Sync polarity, overrides sync from vesa (default=vesa)");
+module_param(depth, int, 0);
+MODULE_PARM_DESC(depth, "Color depth (0=text,8,15,16,24,32) (default=vesa)");
+module_param(maxclk, int, 0);
+MODULE_PARM_DESC(maxclk, "Startup maximal clock, 0-999MHz, 1000-999999kHz, 1000000-INF Hz");
+module_param(fh, int, 0);
+MODULE_PARM_DESC(fh, "Startup horizontal frequency, 0-999kHz, 1000-INF Hz");
+module_param(fv, int, 0);
+MODULE_PARM_DESC(fv, "Startup vertical frequency, 0-INF Hz\n"
+"You should specify \"fv:max_monitor_vsync,fh:max_monitor_hsync,maxclk:max_monitor_dotclock\"");
+module_param(grayscale, int, 0);
+MODULE_PARM_DESC(grayscale, "Sets display into grayscale. Works perfectly with paletized videomode (4, 8bpp), some limitations apply to 16, 24 and 32bpp videomodes (default=nograyscale)");
+module_param(cross4MB, int, 0);
+MODULE_PARM_DESC(cross4MB, "Specifies that 4MB boundary can be in middle of line. (default=autodetected)");
+module_param(dfp, int, 0);
+MODULE_PARM_DESC(dfp, "Specifies whether to use digital flat panel interface of G200/G400 (0 or 1) (default=0)");
+module_param(dfp_type, int, 0);
+MODULE_PARM_DESC(dfp_type, "Specifies DFP interface type (0 to 255) (default=read from hardware)");
+module_param_string(outputs, outputs, sizeof(outputs), 0);
+MODULE_PARM_DESC(outputs, "Specifies which CRTC is mapped to which output (string of up to three letters, consisting of 0 (disabled), 1 (CRTC1), 2 (CRTC2)) (default=111 for Gx50, 101 for G200/G400 with DFP, and 100 for all other devices)");
+#ifdef CONFIG_PPC_PMAC
+module_param_named(vmode, default_vmode, int, 0);
+MODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)");
+module_param_named(cmode, default_cmode, int, 0);
+MODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit default)");
+#endif
+
+int __init init_module(void){
+
+	DBG(__func__)
+
+	if (disabled)
+		return -ENXIO;
+
+	if (depth == 0)
+		depth = RSText;
+	else if (depth == 4)
+		depth = RS4bpp;
+	else if (depth == 8)
+		depth = RS8bpp;
+	else if (depth == 15)
+		depth = RS15bpp;
+	else if (depth == 16)
+		depth = RS16bpp;
+	else if (depth == 24)
+		depth = RS24bpp;
+	else if (depth == 32)
+		depth = RS32bpp;
+	else if (depth != -1) {
+		printk(KERN_ERR "matroxfb: depth %d is not supported, using default\n", depth);
+		depth = -1;
+	}
+	matrox_init();
+	/* never return failure; user can hotplug matrox later... */
+	return 0;
+}
+#endif	/* MODULE */
+
+module_exit(matrox_done);
+EXPORT_SYMBOL(matroxfb_register_driver);
+EXPORT_SYMBOL(matroxfb_unregister_driver);
+EXPORT_SYMBOL(matroxfb_wait_for_sync);
+EXPORT_SYMBOL(matroxfb_enable_irq);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff --git a/drivers/staging/mgakms/matroxfb_base.h b/drivers/staging/mgakms/matroxfb_base.h
new file mode 100644
index 000000000000..f85ad25659e5
--- /dev/null
+++ b/drivers/staging/mgakms/matroxfb_base.h
@@ -0,0 +1,710 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ */
+#ifndef __MATROXFB_H__
+#define __MATROXFB_H__
+
+/* general, but fairly heavy, debugging */
+#undef MATROXFB_DEBUG
+
+/* heavy debugging: */
+/* -- logs putc[s], so every time a char is displayed, it's logged */
+#undef MATROXFB_DEBUG_HEAVY
+
+/* This one _could_ cause infinite loops */
+/* It _does_ cause lots and lots of messages during idle loops */
+#undef MATROXFB_DEBUG_LOOP
+
+/* Debug register calls, too? */
+#undef MATROXFB_DEBUG_REG
+
+/* Guard accelerator accesses with spin_lock_irqsave... */
+#undef MATROXFB_USE_SPINLOCKS
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/kd.h>
+
+#include <asm/io.h>
+#include <asm/unaligned.h>
+
+#if defined(CONFIG_PPC_PMAC)
+#include <asm/prom.h>
+#include "../macmodes.h"
+#endif
+
+#ifdef MATROXFB_DEBUG
+
+#define DEBUG
+#define DBG(x)		printk(KERN_DEBUG "matroxfb: %s\n", (x));
+
+#ifdef MATROXFB_DEBUG_HEAVY
+#define DBG_HEAVY(x)	DBG(x)
+#else /* MATROXFB_DEBUG_HEAVY */
+#define DBG_HEAVY(x)	/* DBG_HEAVY */
+#endif /* MATROXFB_DEBUG_HEAVY */
+
+#ifdef MATROXFB_DEBUG_LOOP
+#define DBG_LOOP(x)	DBG(x)
+#else /* MATROXFB_DEBUG_LOOP */
+#define DBG_LOOP(x)	/* DBG_LOOP */
+#endif /* MATROXFB_DEBUG_LOOP */
+
+#ifdef MATROXFB_DEBUG_REG
+#define DBG_REG(x)	DBG(x)
+#else /* MATROXFB_DEBUG_REG */
+#define DBG_REG(x)	/* DBG_REG */
+#endif /* MATROXFB_DEBUG_REG */
+
+#else /* MATROXFB_DEBUG */
+
+#define DBG(x)		/* DBG */
+#define DBG_HEAVY(x)	/* DBG_HEAVY */
+#define DBG_REG(x)	/* DBG_REG */
+#define DBG_LOOP(x)	/* DBG_LOOP */
+
+#endif /* MATROXFB_DEBUG */
+
+#ifdef DEBUG
+#define dprintk(X...)	printk(X)
+#else
+#define dprintk(X...)
+#endif
+
+#ifndef PCI_SS_VENDOR_ID_SIEMENS_NIXDORF
+#define PCI_SS_VENDOR_ID_SIEMENS_NIXDORF	0x110A
+#endif
+#ifndef PCI_SS_VENDOR_ID_MATROX
+#define PCI_SS_VENDOR_ID_MATROX		PCI_VENDOR_ID_MATROX
+#endif
+
+#ifndef PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP
+#define PCI_SS_ID_MATROX_GENERIC		0xFF00
+#define PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP	0xFF01
+#define PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP	0xFF02
+#define PCI_SS_ID_MATROX_MILLENIUM_G200_AGP	0xFF03
+#define PCI_SS_ID_MATROX_MARVEL_G200_AGP	0xFF04
+#define PCI_SS_ID_MATROX_MGA_G100_PCI		0xFF05
+#define PCI_SS_ID_MATROX_MGA_G100_AGP		0x1001
+#define PCI_SS_ID_MATROX_MILLENNIUM_G400_MAX_AGP	0x2179
+#define PCI_SS_ID_SIEMENS_MGA_G100_AGP		0x001E /* 30 */
+#define PCI_SS_ID_SIEMENS_MGA_G200_AGP		0x0032 /* 50 */
+#endif
+
+#define MX_VISUAL_TRUECOLOR	FB_VISUAL_DIRECTCOLOR
+#define MX_VISUAL_DIRECTCOLOR	FB_VISUAL_TRUECOLOR
+#define MX_VISUAL_PSEUDOCOLOR	FB_VISUAL_PSEUDOCOLOR
+
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+
+/* G-series and Mystique have (almost) same DAC */
+#undef NEED_DAC1064
+#if defined(CONFIG_FB_MATROX_MYSTIQUE) || defined(CONFIG_FB_MATROX_G)
+#define NEED_DAC1064 1
+#endif
+
+typedef struct {
+	void __iomem*	vaddr;
+} vaddr_t;
+
+static inline unsigned int mga_readb(vaddr_t va, unsigned int offs) {
+	return readb(va.vaddr + offs);
+}
+
+static inline void mga_writeb(vaddr_t va, unsigned int offs, u_int8_t value) {
+	writeb(value, va.vaddr + offs);
+}
+
+static inline void mga_writew(vaddr_t va, unsigned int offs, u_int16_t value) {
+	writew(value, va.vaddr + offs);
+}
+
+static inline u_int32_t mga_readl(vaddr_t va, unsigned int offs) {
+	return readl(va.vaddr + offs);
+}
+
+static inline void mga_writel(vaddr_t va, unsigned int offs, u_int32_t value) {
+	writel(value, va.vaddr + offs);
+}
+
+static inline void mga_memcpy_toio(vaddr_t va, const void* src, int len) {
+#if defined(__alpha__) || defined(__i386__) || defined(__x86_64__)
+	/*
+	 * iowrite32_rep works for us if:
+	 *  (1) Copies data as 32bit quantities, not byte after byte,
+	 *  (2) Performs LE ordered stores, and
+	 *  (3) It copes with unaligned source (destination is guaranteed to be page
+	 *      aligned and length is guaranteed to be multiple of 4).
+	 */
+	iowrite32_rep(va.vaddr, src, len >> 2);
+#else
+        u_int32_t __iomem* addr = va.vaddr;
+
+	if ((unsigned long)src & 3) {
+		while (len >= 4) {
+			fb_writel(get_unaligned((u32 *)src), addr);
+			addr++;
+			len -= 4;
+			src += 4;
+		}
+	} else {
+		while (len >= 4) {
+			fb_writel(*(u32 *)src, addr);
+			addr++;
+			len -= 4;
+			src += 4;
+		}
+	}
+#endif
+}
+
+static inline void vaddr_add(vaddr_t* va, unsigned long offs) {
+	va->vaddr += offs;
+}
+
+static inline void __iomem* vaddr_va(vaddr_t va) {
+	return va.vaddr;
+}
+
+struct my_timming {
+	unsigned int pixclock;
+	int mnp;
+	unsigned int crtc;
+	unsigned int HDisplay;
+	unsigned int HSyncStart;
+	unsigned int HSyncEnd;
+	unsigned int HTotal;
+	unsigned int VDisplay;
+	unsigned int VSyncStart;
+	unsigned int VSyncEnd;
+	unsigned int VTotal;
+	unsigned int sync;
+	int	     dblscan;
+	int	     interlaced;
+	unsigned int delay;	/* CRTC delay */
+};
+
+enum { M_SYSTEM_PLL, M_PIXEL_PLL_A, M_PIXEL_PLL_B, M_PIXEL_PLL_C, M_VIDEO_PLL };
+
+struct matrox_pll_cache {
+	unsigned int	valid;
+	struct {
+		unsigned int	mnp_key;
+		unsigned int	mnp_value;
+		      } data[4];
+};
+
+struct matrox_pll_limits {
+	unsigned int	vcomin;
+	unsigned int	vcomax;
+};
+
+struct matrox_pll_features {
+	unsigned int	vco_freq_min;
+	unsigned int	ref_freq;
+	unsigned int	feed_div_min;
+	unsigned int	feed_div_max;
+	unsigned int	in_div_min;
+	unsigned int	in_div_max;
+	unsigned int	post_shift_max;
+};
+
+struct matroxfb_par
+{
+	unsigned int	final_bppShift;
+	unsigned int	cmap_len;
+	struct {
+		unsigned int bytes;
+		unsigned int pixels;
+		unsigned int chunks;
+		      } ydstorg;
+};
+
+struct matrox_fb_info;
+
+struct matrox_DAC1064_features {
+	u_int8_t	xvrefctrl;
+	u_int8_t	xmiscctrl;
+};
+
+/* current hardware status */
+struct mavenregs {
+	u_int8_t regs[256];
+	int	 mode;
+	int	 vlines;
+	int	 xtal;
+	int	 fv;
+
+	u_int16_t htotal;
+	u_int16_t hcorr;
+};
+
+struct matrox_crtc2 {
+	u_int32_t ctl;
+};
+
+struct matrox_hw_state {
+	u_int32_t	MXoptionReg;
+	unsigned char	DACclk[6];
+	unsigned char	DACreg[80];
+	unsigned char	MiscOutReg;
+	unsigned char	DACpal[768];
+	unsigned char	CRTC[25];
+	unsigned char	CRTCEXT[9];
+	unsigned char	SEQ[5];
+	/* unused for MGA mode, but who knows... */
+	unsigned char	GCTL[9];
+	/* unused for MGA mode, but who knows... */
+	unsigned char	ATTR[21];
+
+	/* TVOut only */
+	struct mavenregs	maven;
+
+	struct matrox_crtc2	crtc2;
+};
+
+struct matrox_accel_data {
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+	unsigned char	ramdac_rev;
+#endif
+	u_int32_t	m_dwg_rect;
+	u_int32_t	m_opmode;
+	u_int32_t	m_access;
+	u_int32_t	m_pitch;
+};
+
+struct v4l2_queryctrl;
+struct v4l2_control;
+
+struct matrox_altout {
+	const char	*name;
+	int		(*compute)(void* altout_dev, struct my_timming* input);
+	int		(*program)(void* altout_dev);
+	int		(*start)(void* altout_dev);
+	int		(*verifymode)(void* altout_dev, u_int32_t mode);
+	int		(*getqueryctrl)(void* altout_dev,
+					struct v4l2_queryctrl* ctrl);
+	int		(*getctrl)(void* altout_dev, 
+				   struct v4l2_control* ctrl);
+	int		(*setctrl)(void* altout_dev, 
+				   struct v4l2_control* ctrl);
+};
+
+#define MATROXFB_SRC_NONE	0
+#define MATROXFB_SRC_CRTC1	1
+#define MATROXFB_SRC_CRTC2	2
+
+enum mga_chip { MGA_2064, MGA_2164, MGA_1064, MGA_1164, MGA_G100, MGA_G200, MGA_G400, MGA_G450, MGA_G550 };
+
+struct matrox_bios {
+	unsigned int	bios_valid : 1;
+	unsigned int	pins_len;
+	unsigned char	pins[128];
+	struct {
+		unsigned char vMaj, vMin, vRev;
+		      } version;
+	struct {
+		unsigned char state, tvout;
+		      } output;
+};
+
+struct matrox_switch;
+struct matroxfb_driver;
+struct matroxfb_dh_fb_info;
+
+struct matrox_vsync {
+	wait_queue_head_t	wait;
+	unsigned int		cnt;
+};
+
+struct matrox_fb_info {
+	struct fb_info		fbcon;
+
+	struct list_head	next_fb;
+
+	int			dead;
+	int                     initialized;
+	unsigned int		usecount;
+
+	unsigned int		userusecount;
+	unsigned long		irq_flags;
+
+	struct matroxfb_par	curr;
+	struct matrox_hw_state	hw;
+
+	struct matrox_accel_data accel;
+
+	struct pci_dev*		pcidev;
+
+	struct {
+		struct matrox_vsync	vsync;
+		unsigned int	pixclock;
+		int		mnp;
+		int		panpos;
+			      } crtc1;
+	struct {
+		struct matrox_vsync	vsync;
+		unsigned int 	pixclock;
+		int		mnp;
+	struct matroxfb_dh_fb_info*	info;
+	struct rw_semaphore	lock;
+			      } crtc2;
+	struct {
+	struct rw_semaphore	lock;
+	struct {
+		int brightness, contrast, saturation, hue, gamma;
+		int testout, deflicker;
+				} tvo_params;
+			      } altout;
+#define MATROXFB_MAX_OUTPUTS		3
+	struct {
+	unsigned int		src;
+	struct matrox_altout*	output;
+	void*			data;
+	unsigned int		mode;
+	unsigned int		default_src;
+			      } outputs[MATROXFB_MAX_OUTPUTS];
+
+#define MATROXFB_MAX_FB_DRIVERS		5
+	struct matroxfb_driver* (drivers[MATROXFB_MAX_FB_DRIVERS]);
+	void*			(drivers_data[MATROXFB_MAX_FB_DRIVERS]);
+	unsigned int		drivers_count;
+
+	struct {
+	unsigned long	base;	/* physical */
+	vaddr_t		vbase;	/* CPU view */
+	unsigned int	len;
+	unsigned int	len_usable;
+	unsigned int	len_maximum;
+		      } video;
+
+	struct {
+	unsigned long	base;	/* physical */
+	vaddr_t		vbase;	/* CPU view */
+	unsigned int	len;
+		      } mmio;
+
+	unsigned int	max_pixel_clock;
+	unsigned int	max_pixel_clock_panellink;
+
+	struct matrox_switch*	hw_switch;
+
+	struct {
+		struct matrox_pll_features pll;
+		struct matrox_DAC1064_features DAC1064;
+			      } features;
+	struct {
+		spinlock_t	DAC;
+		spinlock_t	accel;
+			      } lock;
+
+	enum mga_chip		chip;
+
+	int			interleave;
+	int			millenium;
+	int			milleniumII;
+	struct {
+		int		cfb4;
+		const int*	vxres;
+		int		cross4MB;
+		int		text;
+		int		plnwt;
+		int		srcorg;
+			      } capable;
+	int			wc_cookie;
+	struct {
+		int		precise_width;
+		int		mga_24bpp_fix;
+		int		novga;
+		int		nobios;
+		int		nopciretry;
+		int		noinit;
+		int		sgram;
+		int		support32MB;
+
+		int		accelerator;
+		int		text_type_aux;
+		int		video64bits;
+		int		crtc2;
+		int		maven_capable;
+		unsigned int	vgastep;
+		unsigned int	textmode;
+		unsigned int	textstep;
+		unsigned int	textvram;	/* character cells */
+		unsigned int	ydstorg;	/* offset in bytes from video start to usable memory */
+						/* 0 except for 6MB Millenium */
+		int		memtype;
+		int		g450dac;
+		int		dfp_type;
+		int		panellink;	/* G400 DFP possible (not G450/G550) */
+		int		dualhead;
+		unsigned int	fbResource;
+			      } devflags;
+	struct fb_ops		fbops;
+	struct matrox_bios	bios;
+	struct {
+		struct matrox_pll_limits	pixel;
+		struct matrox_pll_limits	system;
+		struct matrox_pll_limits	video;
+			      } limits;
+	struct {
+		struct matrox_pll_cache	pixel;
+		struct matrox_pll_cache	system;
+		struct matrox_pll_cache	video;
+				      } cache;
+	struct {
+		struct {
+			unsigned int	video;
+			unsigned int	system;
+				      } pll;
+		struct {
+			u_int32_t	opt;
+			u_int32_t	opt2;
+			u_int32_t	opt3;
+			u_int32_t	mctlwtst;
+			u_int32_t	mctlwtst_core;
+			u_int32_t	memmisc;
+			u_int32_t	memrdbk;
+			u_int32_t	maccess;
+				      } reg;
+		struct {
+			unsigned int	ddr:1,
+			                emrswen:1,
+					dll:1;
+				      } memory;
+			      } values;
+	u_int32_t cmap[16];
+};
+
+#define info2minfo(info) container_of(info, struct matrox_fb_info, fbcon)
+
+struct matrox_switch {
+	int	(*preinit)(struct matrox_fb_info *minfo);
+	void	(*reset)(struct matrox_fb_info *minfo);
+	int	(*init)(struct matrox_fb_info *minfo, struct my_timming*);
+	void	(*restore)(struct matrox_fb_info *minfo);
+};
+
+struct matroxfb_driver {
+	struct list_head	node;
+	char*			name;
+	void*			(*probe)(struct matrox_fb_info* info);
+	void			(*remove)(struct matrox_fb_info* info, void* data);
+};
+
+int matroxfb_register_driver(struct matroxfb_driver* drv);
+void matroxfb_unregister_driver(struct matroxfb_driver* drv);
+
+#define PCI_OPTION_REG	0x40
+#define   PCI_OPTION_ENABLE_ROM		0x40000000
+
+#define PCI_MGA_INDEX	0x44
+#define PCI_MGA_DATA	0x48
+#define PCI_OPTION2_REG	0x50
+#define PCI_OPTION3_REG	0x54
+#define PCI_MEMMISC_REG	0x58
+
+#define M_DWGCTL	0x1C00
+#define M_MACCESS	0x1C04
+#define M_CTLWTST	0x1C08
+
+#define M_PLNWT		0x1C1C
+
+#define M_BCOL		0x1C20
+#define M_FCOL		0x1C24
+
+#define M_SGN		0x1C58
+#define M_LEN		0x1C5C
+#define M_AR0		0x1C60
+#define M_AR1		0x1C64
+#define M_AR2		0x1C68
+#define M_AR3		0x1C6C
+#define M_AR4		0x1C70
+#define M_AR5		0x1C74
+#define M_AR6		0x1C78
+
+#define M_CXBNDRY	0x1C80
+#define M_FXBNDRY	0x1C84
+#define M_YDSTLEN	0x1C88
+#define M_PITCH		0x1C8C
+#define M_YDST		0x1C90
+#define M_YDSTORG	0x1C94
+#define M_YTOP		0x1C98
+#define M_YBOT		0x1C9C
+
+/* mystique only */
+#define M_CACHEFLUSH	0x1FFF
+
+#define M_EXEC		0x0100
+
+#define M_DWG_TRAP	0x04
+#define M_DWG_BITBLT	0x08
+#define M_DWG_ILOAD	0x09
+
+#define M_DWG_LINEAR	0x0080
+#define M_DWG_SOLID	0x0800
+#define M_DWG_ARZERO	0x1000
+#define M_DWG_SGNZERO	0x2000
+#define M_DWG_SHIFTZERO	0x4000
+
+#define M_DWG_REPLACE	0x000C0000
+#define M_DWG_REPLACE2	(M_DWG_REPLACE | 0x40)
+#define M_DWG_XOR	0x00060010
+
+#define M_DWG_BFCOL	0x04000000
+#define M_DWG_BMONOWF	0x08000000
+
+#define M_DWG_TRANSC	0x40000000
+
+#define M_FIFOSTATUS	0x1E10
+#define M_STATUS	0x1E14
+#define M_ICLEAR	0x1E18
+#define M_IEN		0x1E1C
+
+#define M_VCOUNT	0x1E20
+
+#define M_RESET		0x1E40
+#define M_MEMRDBK	0x1E44
+
+#define M_AGP2PLL	0x1E4C
+
+#define M_OPMODE	0x1E54
+#define     M_OPMODE_DMA_GEN_WRITE	0x00
+#define     M_OPMODE_DMA_BLIT		0x04
+#define     M_OPMODE_DMA_VECTOR_WRITE	0x08
+#define     M_OPMODE_DMA_LE		0x0000		/* little endian - no transformation */
+#define     M_OPMODE_DMA_BE_8BPP	0x0000
+#define     M_OPMODE_DMA_BE_16BPP	0x0100
+#define     M_OPMODE_DMA_BE_32BPP	0x0200
+#define     M_OPMODE_DIR_LE		0x000000	/* little endian - no transformation */
+#define     M_OPMODE_DIR_BE_8BPP	0x000000
+#define     M_OPMODE_DIR_BE_16BPP	0x010000
+#define     M_OPMODE_DIR_BE_32BPP	0x020000
+
+#define M_ATTR_INDEX	0x1FC0
+#define M_ATTR_DATA	0x1FC1
+
+#define M_MISC_REG	0x1FC2
+#define M_3C2_RD	0x1FC2
+
+#define M_SEQ_INDEX	0x1FC4
+#define M_SEQ_DATA	0x1FC5
+#define     M_SEQ1		0x01
+#define        M_SEQ1_SCROFF		0x20
+
+#define M_MISC_REG_READ	0x1FCC
+
+#define M_GRAPHICS_INDEX 0x1FCE
+#define M_GRAPHICS_DATA	0x1FCF
+
+#define M_CRTC_INDEX	0x1FD4
+
+#define M_ATTR_RESET	0x1FDA
+#define M_3DA_WR	0x1FDA
+#define M_INSTS1	0x1FDA
+
+#define M_EXTVGA_INDEX	0x1FDE
+#define M_EXTVGA_DATA	0x1FDF
+
+/* G200 only */
+#define M_SRCORG	0x2CB4
+#define M_DSTORG	0x2CB8
+
+#define M_RAMDAC_BASE	0x3C00
+
+/* fortunately, same on TVP3026 and MGA1064 */
+#define M_DAC_REG	(M_RAMDAC_BASE+0)
+#define M_DAC_VAL	(M_RAMDAC_BASE+1)
+#define M_PALETTE_MASK	(M_RAMDAC_BASE+2)
+
+#define M_X_INDEX	0x00
+#define M_X_DATAREG	0x0A
+
+#define DAC_XGENIOCTRL		0x2A
+#define DAC_XGENIODATA		0x2B
+
+#define M_C2CTL		0x3C10
+
+#define MX_OPTION_BSWAP         0x00000000
+
+#ifdef __LITTLE_ENDIAN
+#define M_OPMODE_4BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_8BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_16BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_24BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_32BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_LE | M_OPMODE_DMA_BLIT)
+#else
+#ifdef __BIG_ENDIAN
+#define M_OPMODE_4BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_LE       | M_OPMODE_DMA_BLIT)	/* TODO */
+#define M_OPMODE_8BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_BE_8BPP  | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_16BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_BE_16BPP | M_OPMODE_DMA_BLIT)
+#define M_OPMODE_24BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_BE_8BPP  | M_OPMODE_DMA_BLIT)	/* TODO, ?32 */
+#define M_OPMODE_32BPP	(M_OPMODE_DMA_LE | M_OPMODE_DIR_BE_32BPP | M_OPMODE_DMA_BLIT)
+#else
+#error "Byte ordering have to be defined. Cannot continue."
+#endif
+#endif
+
+#define mga_inb(addr)		mga_readb(minfo->mmio.vbase, (addr))
+#define mga_inl(addr)		mga_readl(minfo->mmio.vbase, (addr))
+#define mga_outb(addr,val)	mga_writeb(minfo->mmio.vbase, (addr), (val))
+#define mga_outw(addr,val)	mga_writew(minfo->mmio.vbase, (addr), (val))
+#define mga_outl(addr,val)	mga_writel(minfo->mmio.vbase, (addr), (val))
+#define mga_readr(port,idx)	(mga_outb((port),(idx)), mga_inb((port)+1))
+#define mga_setr(addr,port,val)	mga_outw(addr, ((val)<<8) | (port))
+
+#define mga_fifo(n)	do {} while ((mga_inl(M_FIFOSTATUS) & 0xFF) < (n))
+
+#define WaitTillIdle()	do { mga_inl(M_STATUS); do {} while (mga_inl(M_STATUS) & 0x10000); } while (0)
+
+/* code speedup */
+#ifdef CONFIG_FB_MATROX_MILLENIUM
+#define isInterleave(x)	 (x->interleave)
+#define isMillenium(x)	 (x->millenium)
+#define isMilleniumII(x) (x->milleniumII)
+#else
+#define isInterleave(x)  (0)
+#define isMillenium(x)	 (0)
+#define isMilleniumII(x) (0)
+#endif
+
+#define matroxfb_DAC_lock()                   spin_lock(&minfo->lock.DAC)
+#define matroxfb_DAC_unlock()                 spin_unlock(&minfo->lock.DAC)
+#define matroxfb_DAC_lock_irqsave(flags)      spin_lock_irqsave(&minfo->lock.DAC, flags)
+#define matroxfb_DAC_unlock_irqrestore(flags) spin_unlock_irqrestore(&minfo->lock.DAC, flags)
+extern void matroxfb_DAC_out(const struct matrox_fb_info *minfo, int reg,
+			     int val);
+extern int matroxfb_DAC_in(const struct matrox_fb_info *minfo, int reg);
+extern void matroxfb_var2my(struct fb_var_screeninfo* fvsi, struct my_timming* mt);
+extern int matroxfb_wait_for_sync(struct matrox_fb_info *minfo, u_int32_t crtc);
+extern int matroxfb_enable_irq(struct matrox_fb_info *minfo, int reenable);
+
+#ifdef MATROXFB_USE_SPINLOCKS
+#define CRITBEGIN  spin_lock_irqsave(&minfo->lock.accel, critflags);
+#define CRITEND	   spin_unlock_irqrestore(&minfo->lock.accel, critflags);
+#define CRITFLAGS  unsigned long critflags;
+#else
+#define CRITBEGIN
+#define CRITEND
+#define CRITFLAGS
+#endif
+
+#endif	/* __MATROXFB_H__ */
diff --git a/drivers/staging/mgakms/matroxfb_crtc2.h b/drivers/staging/mgakms/matroxfb_crtc2.h
new file mode 100644
index 000000000000..23e90e210905
--- /dev/null
+++ b/drivers/staging/mgakms/matroxfb_crtc2.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __MATROXFB_CRTC2_H__
+#define __MATROXFB_CRTC2_H__
+
+#include <linux/ioctl.h>
+#include "matroxfb_base.h"
+
+struct matroxfb_dh_fb_info {
+	struct fb_info		fbcon;
+	int			fbcon_registered;
+	int                     initialized;
+
+	struct matrox_fb_info*	primary_dev;
+
+	struct {
+		unsigned long	base;	/* physical */
+		vaddr_t		vbase;	/* virtual */
+		unsigned int	len;
+		unsigned int	len_usable;
+		unsigned int	len_maximum;
+		unsigned int 	offbase;
+		unsigned int	borrowed;
+			      } video;
+	struct {
+		unsigned long	base;
+		vaddr_t		vbase;
+		unsigned int	len;
+			      } mmio;
+
+	unsigned int		interlaced:1;
+
+	u_int32_t cmap[16];
+};
+
+#endif /* __MATROXFB_CRTC2_H__ */
diff --git a/drivers/staging/mgakms/matroxfb_g450.c b/drivers/staging/mgakms/matroxfb_g450.c
new file mode 100644
index 000000000000..f108ae66fc83
--- /dev/null
+++ b/drivers/staging/mgakms/matroxfb_g450.c
@@ -0,0 +1,640 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Portions Copyright (c) 2001 Matrox Graphics Inc.
+ *
+ * Version: 1.65 2002/08/14
+ *
+ * See matroxfb_base.c for contributors.
+ *
+ */
+
+#include "matroxfb_base.h"
+#include "matroxfb_misc.h"
+#include "matroxfb_DAC1064.h"
+#include "g450_pll.h"
+#include <linux/matroxfb.h>
+#include <asm/div64.h>
+
+#include "matroxfb_g450.h"
+
+/* Definition of the various controls */
+struct mctl {
+	struct v4l2_queryctrl desc;
+	size_t control;
+};
+
+#define BLMIN	0xF3
+#define WLMAX	0x3FF
+
+static const struct mctl g450_controls[] =
+{	{ { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER, 
+	  "brightness",
+	  0, WLMAX-BLMIN, 1, 370-BLMIN, 
+	  0,
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) },
+	{ { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER, 
+	  "contrast",
+	  0, 1023, 1, 127, 
+	  0,
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) },
+	{ { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER,
+	  "saturation",
+	  0, 255, 1, 165, 
+	  0,
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) },
+	{ { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER,
+	  "hue",
+	  0, 255, 1, 0, 
+	  0,
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
+	{ { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN,
+	  "test output",
+	  0, 1, 1, 0, 
+	  0,
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
+};
+
+#define G450CTRLS ARRAY_SIZE(g450_controls)
+
+/* Return: positive number: id found
+           -EINVAL:         id not found, return failure
+	   -ENOENT:         id not found, create fake disabled control */
+static int get_ctrl_id(__u32 v4l2_id) {
+	int i;
+
+	for (i = 0; i < G450CTRLS; i++) {
+		if (v4l2_id < g450_controls[i].desc.id) {
+			if (g450_controls[i].desc.id == 0x08000000) {
+				return -EINVAL;
+			}
+			return -ENOENT;
+		}
+		if (v4l2_id == g450_controls[i].desc.id) {
+			return i;
+		}
+	}
+	return -EINVAL;
+}
+
+static inline int *get_ctrl_ptr(struct matrox_fb_info *minfo, unsigned int idx)
+{
+	return (int*)((char*)minfo + g450_controls[idx].control);
+}
+
+static void tvo_fill_defaults(struct matrox_fb_info *minfo)
+{
+	unsigned int i;
+	
+	for (i = 0; i < G450CTRLS; i++) {
+		*get_ctrl_ptr(minfo, i) = g450_controls[i].desc.default_value;
+	}
+}
+
+static int cve2_get_reg(struct matrox_fb_info *minfo, int reg)
+{
+	unsigned long flags;
+	int val;
+	
+	matroxfb_DAC_lock_irqsave(flags);
+	matroxfb_DAC_out(minfo, 0x87, reg);
+	val = matroxfb_DAC_in(minfo, 0x88);
+	matroxfb_DAC_unlock_irqrestore(flags);
+	return val;
+}
+
+static void cve2_set_reg(struct matrox_fb_info *minfo, int reg, int val)
+{
+	unsigned long flags;
+
+	matroxfb_DAC_lock_irqsave(flags);
+	matroxfb_DAC_out(minfo, 0x87, reg);
+	matroxfb_DAC_out(minfo, 0x88, val);
+	matroxfb_DAC_unlock_irqrestore(flags);
+}
+
+static void cve2_set_reg10(struct matrox_fb_info *minfo, int reg, int val)
+{
+	unsigned long flags;
+
+	matroxfb_DAC_lock_irqsave(flags);
+	matroxfb_DAC_out(minfo, 0x87, reg);
+	matroxfb_DAC_out(minfo, 0x88, val >> 2);
+	matroxfb_DAC_out(minfo, 0x87, reg + 1);
+	matroxfb_DAC_out(minfo, 0x88, val & 3);
+	matroxfb_DAC_unlock_irqrestore(flags);
+}
+
+static void g450_compute_bwlevel(const struct matrox_fb_info *minfo, int *bl,
+				 int *wl)
+{
+	const int b = minfo->altout.tvo_params.brightness + BLMIN;
+	const int c = minfo->altout.tvo_params.contrast;
+
+	*bl = max(b - c, BLMIN);
+	*wl = min(b + c, WLMAX);
+}
+
+static int g450_query_ctrl(void* md, struct v4l2_queryctrl *p) {
+	int i;
+	
+	i = get_ctrl_id(p->id);
+	if (i >= 0) {
+		*p = g450_controls[i].desc;
+		return 0;
+	}
+	if (i == -ENOENT) {
+		static const struct v4l2_queryctrl disctrl = 
+			{ .flags = V4L2_CTRL_FLAG_DISABLED };
+			
+		i = p->id;
+		*p = disctrl;
+		p->id = i;
+		sprintf(p->name, "Ctrl #%08X", i);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int g450_set_ctrl(void* md, struct v4l2_control *p) {
+	int i;
+	struct matrox_fb_info *minfo = md;
+	
+	i = get_ctrl_id(p->id);
+	if (i < 0) return -EINVAL;
+
+	/*
+	 * Check if changed.
+	 */
+	if (p->value == *get_ctrl_ptr(minfo, i)) return 0;
+
+	/*
+	 * Check limits.
+	 */
+	if (p->value > g450_controls[i].desc.maximum) return -EINVAL;
+	if (p->value < g450_controls[i].desc.minimum) return -EINVAL;
+
+	/*
+	 * Store new value.
+	 */
+	*get_ctrl_ptr(minfo, i) = p->value;
+
+	switch (p->id) {
+		case V4L2_CID_BRIGHTNESS:
+		case V4L2_CID_CONTRAST:
+			{
+				int blacklevel, whitelevel;
+				g450_compute_bwlevel(minfo, &blacklevel, &whitelevel);
+				cve2_set_reg10(minfo, 0x0e, blacklevel);
+				cve2_set_reg10(minfo, 0x1e, whitelevel);
+			}
+			break;
+		case V4L2_CID_SATURATION:
+			cve2_set_reg(minfo, 0x20, p->value);
+			cve2_set_reg(minfo, 0x22, p->value);
+			break;
+		case V4L2_CID_HUE:
+			cve2_set_reg(minfo, 0x25, p->value);
+			break;
+		case MATROXFB_CID_TESTOUT:
+			{
+				unsigned char val = cve2_get_reg(minfo, 0x05);
+				if (p->value) val |=  0x02;
+				else          val &= ~0x02;
+				cve2_set_reg(minfo, 0x05, val);
+			}
+			break;
+	}
+	
+
+	return 0;
+}
+
+static int g450_get_ctrl(void* md, struct v4l2_control *p) {
+	int i;
+	struct matrox_fb_info *minfo = md;
+	
+	i = get_ctrl_id(p->id);
+	if (i < 0) return -EINVAL;
+	p->value = *get_ctrl_ptr(minfo, i);
+	return 0;
+}
+
+struct output_desc {
+	unsigned int	h_vis;
+	unsigned int	h_f_porch;
+	unsigned int	h_sync;
+	unsigned int	h_b_porch;
+	unsigned long long int	chromasc;
+	unsigned int	burst;
+	unsigned int	v_total;
+};
+
+static void computeRegs(struct matrox_fb_info *minfo, struct mavenregs *r,
+			struct my_timming *mt, const struct output_desc *outd)
+{
+	u_int32_t chromasc;
+	u_int32_t hlen;
+	u_int32_t hsl;
+	u_int32_t hbp;
+	u_int32_t hfp;
+	u_int32_t hvis;
+	unsigned int pixclock;
+	unsigned long long piic;
+	int mnp;
+	int over;
+	
+	r->regs[0x80] = 0x03;	/* | 0x40 for SCART */
+
+	hvis = ((mt->HDisplay << 1) + 3) & ~3;
+	
+	if (hvis >= 2048) {
+		hvis = 2044;
+	}
+	
+	piic = 1000000000ULL * hvis;
+	do_div(piic, outd->h_vis);
+
+	dprintk(KERN_DEBUG "Want %u kHz pixclock\n", (unsigned int)piic);
+	
+	mnp = matroxfb_g450_setclk(minfo, piic, M_VIDEO_PLL);
+	
+	mt->mnp = mnp;
+	mt->pixclock = g450_mnp2f(minfo, mnp);
+
+	dprintk(KERN_DEBUG "MNP=%08X\n", mnp);
+
+	pixclock = 1000000000U / mt->pixclock;
+
+	dprintk(KERN_DEBUG "Got %u ps pixclock\n", pixclock);
+
+	piic = outd->chromasc;
+	do_div(piic, mt->pixclock);
+	chromasc = piic;
+	
+	dprintk(KERN_DEBUG "Chroma is %08X\n", chromasc);
+
+	r->regs[0] = piic >> 24;
+	r->regs[1] = piic >> 16;
+	r->regs[2] = piic >>  8;
+	r->regs[3] = piic >>  0;
+	hbp = (((outd->h_b_porch + pixclock) / pixclock)) & ~1;
+	hfp = (((outd->h_f_porch + pixclock) / pixclock)) & ~1;
+	hsl = (((outd->h_sync + pixclock) / pixclock)) & ~1;
+	hlen = hvis + hfp + hsl + hbp;
+	over = hlen & 0x0F;
+	
+	dprintk(KERN_DEBUG "WL: vis=%u, hf=%u, hs=%u, hb=%u, total=%u\n", hvis, hfp, hsl, hbp, hlen);
+
+	if (over) {
+		hfp -= over;
+		hlen -= over;
+		if (over <= 2) {
+		} else if (over < 10) {
+			hfp += 4;
+			hlen += 4;
+		} else {
+			hfp += 16;
+			hlen += 16;
+		}
+	}
+
+	/* maybe cve2 has requirement 800 < hlen < 1184 */
+	r->regs[0x08] = hsl;
+	r->regs[0x09] = (outd->burst + pixclock - 1) / pixclock;	/* burst length */
+	r->regs[0x0A] = hbp;
+	r->regs[0x2C] = hfp;
+	r->regs[0x31] = hvis / 8;
+	r->regs[0x32] = hvis & 7;
+	
+	dprintk(KERN_DEBUG "PG: vis=%04X, hf=%02X, hs=%02X, hb=%02X, total=%04X\n", hvis, hfp, hsl, hbp, hlen);
+
+	r->regs[0x84] = 1;	/* x sync point */
+	r->regs[0x85] = 0;
+	hvis = hvis >> 1;
+	hlen = hlen >> 1;
+	
+	dprintk(KERN_DEBUG "hlen=%u hvis=%u\n", hlen, hvis);
+
+	mt->interlaced = 1;
+
+	mt->HDisplay = hvis & ~7;
+	mt->HSyncStart = mt->HDisplay + 8;
+	mt->HSyncEnd = (hlen & ~7) - 8;
+	mt->HTotal = hlen;
+
+	{
+		int upper;
+		unsigned int vtotal;
+		unsigned int vsyncend;
+		unsigned int vdisplay;
+		
+		vtotal = mt->VTotal;
+		vsyncend = mt->VSyncEnd;
+		vdisplay = mt->VDisplay;
+		if (vtotal < outd->v_total) {
+			unsigned int yovr = outd->v_total - vtotal;
+			
+			vsyncend += yovr >> 1;
+		} else if (vtotal > outd->v_total) {
+			vdisplay = outd->v_total - 4;
+			vsyncend = outd->v_total;
+		}
+		upper = (outd->v_total - vsyncend) >> 1;	/* in field lines */
+		r->regs[0x17] = outd->v_total / 4;
+		r->regs[0x18] = outd->v_total & 3;
+		r->regs[0x33] = upper - 1;	/* upper blanking */
+		r->regs[0x82] = upper;		/* y sync point */
+		r->regs[0x83] = upper >> 8;
+		
+		mt->VDisplay = vdisplay;
+		mt->VSyncStart = outd->v_total - 2;
+		mt->VSyncEnd = outd->v_total;
+		mt->VTotal = outd->v_total;
+	}
+}
+
+static void cve2_init_TVdata(int norm, struct mavenregs* data, const struct output_desc** outd) {
+	static const struct output_desc paloutd = {
+		.h_vis	   = 52148148,	// ps
+		.h_f_porch =  1407407,	// ps
+		.h_sync    =  4666667,	// ps
+		.h_b_porch =  5777778,	// ps
+		.chromasc  = 19042247534182ULL,	// 4433618.750 Hz
+		.burst     =  2518518,	// ps
+		.v_total   =      625,
+	};
+	static const struct output_desc ntscoutd = {
+		.h_vis     = 52888889,	// ps
+		.h_f_porch =  1333333,	// ps
+		.h_sync    =  4666667,	// ps
+		.h_b_porch =  4666667,	// ps
+		.chromasc  = 15374030659475ULL,	// 3579545.454 Hz
+		.burst     =  2418418,	// ps
+		.v_total   =      525,	// lines
+	};
+
+	static const struct mavenregs palregs = { {
+		0x2A, 0x09, 0x8A, 0xCB,	/* 00: chroma subcarrier */
+		0x00,
+		0x00,	/* test */
+		0xF9,	/* modified by code (F9 written...) */
+		0x00,	/* ? not written */
+		0x7E,	/* 08 */
+		0x44,	/* 09 */
+		0x9C,	/* 0A */
+		0x2E,	/* 0B */
+		0x21,	/* 0C */
+		0x00,	/* ? not written */
+//		0x3F, 0x03, /* 0E-0F */
+		0x3C, 0x03,
+		0x3C, 0x03, /* 10-11 */
+		0x1A,	/* 12 */
+		0x2A,	/* 13 */
+		0x1C, 0x3D, 0x14, /* 14-16 */
+		0x9C, 0x01, /* 17-18 */
+		0x00,	/* 19 */
+		0xFE,	/* 1A */
+		0x7E,	/* 1B */
+		0x60,	/* 1C */
+		0x05,	/* 1D */
+//		0x89, 0x03, /* 1E-1F */
+		0xAD, 0x03,
+//		0x72,	/* 20 */
+		0xA5,
+		0x07,	/* 21 */
+//		0x72,	/* 22 */
+		0xA5,
+		0x00,	/* 23 */
+		0x00,	/* 24 */
+		0x00,	/* 25 */
+		0x08,	/* 26 */
+		0x04,	/* 27 */
+		0x00,	/* 28 */
+		0x1A,	/* 29 */
+		0x55, 0x01, /* 2A-2B */
+		0x26,	/* 2C */
+		0x07, 0x7E, /* 2D-2E */
+		0x02, 0x54, /* 2F-30 */
+		0xB0, 0x00, /* 31-32 */
+		0x14,	/* 33 */
+		0x49,	/* 34 */
+		0x00,	/* 35 written multiple times */
+		0x00,	/* 36 not written */
+		0xA3,	/* 37 */
+		0xC8,	/* 38 */
+		0x22,	/* 39 */
+		0x02,	/* 3A */
+		0x22,	/* 3B */
+		0x3F, 0x03, /* 3C-3D */
+		0x00,	/* 3E written multiple times */
+		0x00,	/* 3F not written */
+	} };
+	static const struct mavenregs ntscregs = { {
+		0x21, 0xF0, 0x7C, 0x1F,	/* 00: chroma subcarrier */
+		0x00,
+		0x00,	/* test */
+		0xF9,	/* modified by code (F9 written...) */
+		0x00,	/* ? not written */
+		0x7E,	/* 08 */
+		0x43,	/* 09 */
+		0x7E,	/* 0A */
+		0x3D,	/* 0B */
+		0x00,	/* 0C */
+		0x00,	/* ? not written */
+		0x41, 0x00, /* 0E-0F */
+		0x3C, 0x00, /* 10-11 */
+		0x17,	/* 12 */
+		0x21,	/* 13 */
+		0x1B, 0x1B, 0x24, /* 14-16 */
+		0x83, 0x01, /* 17-18 */
+		0x00,	/* 19 */
+		0x0F,	/* 1A */
+		0x0F,	/* 1B */
+		0x60,	/* 1C */
+		0x05,	/* 1D */
+		//0x89, 0x02, /* 1E-1F */
+		0xC0, 0x02, /* 1E-1F */
+		//0x5F,	/* 20 */
+		0x9C,	/* 20 */
+		0x04,	/* 21 */
+		//0x5F,	/* 22 */
+		0x9C,	/* 22 */
+		0x01,	/* 23 */
+		0x02,	/* 24 */
+		0x00,	/* 25 */
+		0x0A,	/* 26 */
+		0x05,	/* 27 */
+		0x00,	/* 28 */
+		0x10,	/* 29 */
+		0xFF, 0x03, /* 2A-2B */
+		0x24,	/* 2C */
+		0x0F, 0x78, /* 2D-2E */
+		0x00, 0x00, /* 2F-30 */
+		0xB2, 0x04, /* 31-32 */
+		0x14,	/* 33 */
+		0x02,	/* 34 */
+		0x00,	/* 35 written multiple times */
+		0x00,	/* 36 not written */
+		0xA3,	/* 37 */
+		0xC8,	/* 38 */
+		0x15,	/* 39 */
+		0x05,	/* 3A */
+		0x3B,	/* 3B */
+		0x3C, 0x00, /* 3C-3D */
+		0x00,	/* 3E written multiple times */
+		0x00,	/* never written */
+	} };
+
+	if (norm == MATROXFB_OUTPUT_MODE_PAL) {
+		*data = palregs;
+		*outd = &paloutd;
+	} else {
+  		*data = ntscregs;
+		*outd = &ntscoutd;
+	}
+ 	return;
+}
+
+#define LR(x) cve2_set_reg(minfo, (x), m->regs[(x)])
+static void cve2_init_TV(struct matrox_fb_info *minfo,
+			 const struct mavenregs *m)
+{
+	int i;
+
+	LR(0x80);
+	LR(0x82); LR(0x83);
+	LR(0x84); LR(0x85);
+	
+	cve2_set_reg(minfo, 0x3E, 0x01);
+	
+	for (i = 0; i < 0x3E; i++) {
+		LR(i);
+	}
+	cve2_set_reg(minfo, 0x3E, 0x00);
+}
+
+static int matroxfb_g450_compute(void* md, struct my_timming* mt) {
+	struct matrox_fb_info *minfo = md;
+
+	dprintk(KERN_DEBUG "Computing, mode=%u\n", minfo->outputs[1].mode);
+
+	if (mt->crtc == MATROXFB_SRC_CRTC2 &&
+	    minfo->outputs[1].mode != MATROXFB_OUTPUT_MODE_MONITOR) {
+		const struct output_desc* outd;
+
+		cve2_init_TVdata(minfo->outputs[1].mode, &minfo->hw.maven, &outd);
+		{
+			int blacklevel, whitelevel;
+			g450_compute_bwlevel(minfo, &blacklevel, &whitelevel);
+			minfo->hw.maven.regs[0x0E] = blacklevel >> 2;
+			minfo->hw.maven.regs[0x0F] = blacklevel & 3;
+			minfo->hw.maven.regs[0x1E] = whitelevel >> 2;
+			minfo->hw.maven.regs[0x1F] = whitelevel & 3;
+
+			minfo->hw.maven.regs[0x20] =
+			minfo->hw.maven.regs[0x22] = minfo->altout.tvo_params.saturation;
+
+			minfo->hw.maven.regs[0x25] = minfo->altout.tvo_params.hue;
+
+			if (minfo->altout.tvo_params.testout) {
+				minfo->hw.maven.regs[0x05] |= 0x02;
+			}
+		}
+		computeRegs(minfo, &minfo->hw.maven, mt, outd);
+	} else if (mt->mnp < 0) {
+		/* We must program clocks before CRTC2, otherwise interlaced mode
+		   startup may fail */
+		mt->mnp = matroxfb_g450_setclk(minfo, mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
+		mt->pixclock = g450_mnp2f(minfo, mt->mnp);
+	}
+	dprintk(KERN_DEBUG "Pixclock = %u\n", mt->pixclock);
+	return 0;
+}
+
+static int matroxfb_g450_program(void* md) {
+	struct matrox_fb_info *minfo = md;
+	
+	if (minfo->outputs[1].mode != MATROXFB_OUTPUT_MODE_MONITOR) {
+		cve2_init_TV(minfo, &minfo->hw.maven);
+	}
+	return 0;
+}
+
+static int matroxfb_g450_verify_mode(void* md, u_int32_t arg) {
+	switch (arg) {
+		case MATROXFB_OUTPUT_MODE_PAL:
+		case MATROXFB_OUTPUT_MODE_NTSC:
+		case MATROXFB_OUTPUT_MODE_MONITOR:
+			return 0;
+	}
+	return -EINVAL;
+}
+
+static int g450_dvi_compute(void* md, struct my_timming* mt) {
+	struct matrox_fb_info *minfo = md;
+
+	if (mt->mnp < 0) {
+		mt->mnp = matroxfb_g450_setclk(minfo, mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
+		mt->pixclock = g450_mnp2f(minfo, mt->mnp);
+	}
+	return 0;
+}
+
+static struct matrox_altout matroxfb_g450_altout = {
+	.name		= "Secondary output",
+	.compute	= matroxfb_g450_compute,
+	.program	= matroxfb_g450_program,
+	.verifymode	= matroxfb_g450_verify_mode,
+	.getqueryctrl	= g450_query_ctrl,
+	.getctrl	= g450_get_ctrl,
+	.setctrl	= g450_set_ctrl,
+};
+
+static struct matrox_altout matroxfb_g450_dvi = {
+	.name		= "DVI output",
+	.compute	= g450_dvi_compute,
+};
+
+void matroxfb_g450_connect(struct matrox_fb_info *minfo)
+{
+	if (minfo->devflags.g450dac) {
+		down_write(&minfo->altout.lock);
+		tvo_fill_defaults(minfo);
+		minfo->outputs[1].src = minfo->outputs[1].default_src;
+		minfo->outputs[1].data = minfo;
+		minfo->outputs[1].output = &matroxfb_g450_altout;
+		minfo->outputs[1].mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		minfo->outputs[2].src = minfo->outputs[2].default_src;
+		minfo->outputs[2].data = minfo;
+		minfo->outputs[2].output = &matroxfb_g450_dvi;
+		minfo->outputs[2].mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		up_write(&minfo->altout.lock);
+	}
+}
+
+void matroxfb_g450_shutdown(struct matrox_fb_info *minfo)
+{
+	if (minfo->devflags.g450dac) {
+		down_write(&minfo->altout.lock);
+		minfo->outputs[1].src = MATROXFB_SRC_NONE;
+		minfo->outputs[1].output = NULL;
+		minfo->outputs[1].data = NULL;
+		minfo->outputs[1].mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		minfo->outputs[2].src = MATROXFB_SRC_NONE;
+		minfo->outputs[2].output = NULL;
+		minfo->outputs[2].data = NULL;
+		minfo->outputs[2].mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		up_write(&minfo->altout.lock);
+	}
+}
+
+EXPORT_SYMBOL(matroxfb_g450_connect);
+EXPORT_SYMBOL(matroxfb_g450_shutdown);
+
+MODULE_AUTHOR("(c) 2000-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Matrox G450/G550 output driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/mgakms/matroxfb_g450.h b/drivers/staging/mgakms/matroxfb_g450.h
new file mode 100644
index 000000000000..b5f17b86eae5
--- /dev/null
+++ b/drivers/staging/mgakms/matroxfb_g450.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __MATROXFB_G450_H__
+#define __MATROXFB_G450_H__
+
+#include "matroxfb_base.h"
+
+#ifdef CONFIG_FB_MATROX_G
+void matroxfb_g450_connect(struct matrox_fb_info *minfo);
+void matroxfb_g450_shutdown(struct matrox_fb_info *minfo);
+#else
+static inline void matroxfb_g450_connect(struct matrox_fb_info *minfo) { };
+static inline void matroxfb_g450_shutdown(struct matrox_fb_info *minfo) { };
+#endif
+
+#endif /* __MATROXFB_G450_H__ */
diff --git a/drivers/staging/mgakms/matroxfb_maven.h b/drivers/staging/mgakms/matroxfb_maven.h
new file mode 100644
index 000000000000..f896b78836b1
--- /dev/null
+++ b/drivers/staging/mgakms/matroxfb_maven.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __MATROXFB_MAVEN_H__
+#define __MATROXFB_MAVEN_H__
+
+#include <linux/ioctl.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include "matroxfb_base.h"
+
+struct i2c_bit_adapter {
+	struct i2c_adapter		adapter;
+	int				initialized;
+	struct i2c_algo_bit_data	bac;
+	struct matrox_fb_info*		minfo;
+	struct {
+		unsigned int		data;
+		unsigned int		clock;
+				      } mask;
+};
+
+#endif /* __MATROXFB_MAVEN_H__ */
diff --git a/drivers/staging/mgakms/matroxfb_misc.c b/drivers/staging/mgakms/matroxfb_misc.c
new file mode 100644
index 000000000000..9948ca2a3046
--- /dev/null
+++ b/drivers/staging/mgakms/matroxfb_misc.c
@@ -0,0 +1,815 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Portions Copyright (c) 2001 Matrox Graphics Inc.
+ *
+ * Version: 1.65 2002/08/14
+ *
+ * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
+ *
+ * Contributors: "menion?" <menion@mindless.com>
+ *                     Betatesting, fixes, ideas
+ *
+ *               "Kurt Garloff" <garloff@suse.de>
+ *                     Betatesting, fixes, ideas, videomodes, videomodes timmings
+ *
+ *               "Tom Rini" <trini@kernel.crashing.org>
+ *                     MTRR stuff, PPC cleanups, betatesting, fixes, ideas
+ *
+ *               "Bibek Sahu" <scorpio@dodds.net>
+ *                     Access device through readb|w|l and write b|w|l
+ *                     Extensive debugging stuff
+ *
+ *               "Daniel Haun" <haund@usa.net>
+ *                     Testing, hardware cursor fixes
+ *
+ *               "Scott Wood" <sawst46+@pitt.edu>
+ *                     Fixes
+ *
+ *               "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
+ *                     Betatesting
+ *
+ *               "Kelly French" <targon@hazmat.com>
+ *               "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
+ *                     Betatesting, bug reporting
+ *
+ *               "Pablo Bianucci" <pbian@pccp.com.ar>
+ *                     Fixes, ideas, betatesting
+ *
+ *               "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
+ *                     Fixes, enhandcements, ideas, betatesting
+ *
+ *               "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
+ *                     PPC betatesting, PPC support, backward compatibility
+ *
+ *               "Paul Womar" <Paul@pwomar.demon.co.uk>
+ *               "Owen Waller" <O.Waller@ee.qub.ac.uk>
+ *                     PPC betatesting
+ *
+ *               "Thomas Pornin" <pornin@bolet.ens.fr>
+ *                     Alpha betatesting
+ *
+ *               "Pieter van Leuven" <pvl@iae.nl>
+ *               "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
+ *                     G100 testing
+ *
+ *               "H. Peter Arvin" <hpa@transmeta.com>
+ *                     Ideas
+ *
+ *               "Cort Dougan" <cort@cs.nmt.edu>
+ *                     CHRP fixes and PReP cleanup
+ *
+ *               "Mark Vojkovich" <mvojkovi@ucsd.edu>
+ *                     G400 support
+ *
+ *               "David C. Hansen" <haveblue@us.ibm.com>
+ *                     Fixes
+ *
+ *               "Ian Romanick" <idr@us.ibm.com>
+ *                     Find PInS data in BIOS on PowerPC systems.
+ *
+ * (following author is not in any relation with this code, but his code
+ *  is included in this driver)
+ *
+ * Based on framebuffer driver for VBE 2.0 compliant graphic boards
+ *     (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * (following author is not in any relation with this code, but his ideas
+ *  were used when writing this driver)
+ *
+ *		 FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
+ *
+ */
+
+
+#include "matroxfb_misc.h"
+#include <linux/interrupt.h>
+#include <linux/matroxfb.h>
+
+void matroxfb_DAC_out(const struct matrox_fb_info *minfo, int reg, int val)
+{
+	DBG_REG(__func__)
+	mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg);
+	mga_outb(M_RAMDAC_BASE+M_X_DATAREG, val);
+}
+
+int matroxfb_DAC_in(const struct matrox_fb_info *minfo, int reg)
+{
+	DBG_REG(__func__)
+	mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg);
+	return mga_inb(M_RAMDAC_BASE+M_X_DATAREG);
+}
+
+void matroxfb_var2my(struct fb_var_screeninfo* var, struct my_timming* mt) {
+	unsigned int pixclock = var->pixclock;
+
+	DBG(__func__)
+
+	if (!pixclock) pixclock = 10000;	/* 10ns = 100MHz */
+	mt->pixclock = 1000000000 / pixclock;
+	if (mt->pixclock < 1) mt->pixclock = 1;
+	mt->mnp = -1;
+	mt->dblscan = var->vmode & FB_VMODE_DOUBLE;
+	mt->interlaced = var->vmode & FB_VMODE_INTERLACED;
+	mt->HDisplay = var->xres;
+	mt->HSyncStart = mt->HDisplay + var->right_margin;
+	mt->HSyncEnd = mt->HSyncStart + var->hsync_len;
+	mt->HTotal = mt->HSyncEnd + var->left_margin;
+	mt->VDisplay = var->yres;
+	mt->VSyncStart = mt->VDisplay + var->lower_margin;
+	mt->VSyncEnd = mt->VSyncStart + var->vsync_len;
+	mt->VTotal = mt->VSyncEnd + var->upper_margin;
+	mt->sync = var->sync;
+}
+
+int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int freq, unsigned int fmax,
+		unsigned int* in, unsigned int* feed, unsigned int* post) {
+	unsigned int bestdiff = ~0;
+	unsigned int bestvco = 0;
+	unsigned int fxtal = pll->ref_freq;
+	unsigned int fwant;
+	unsigned int p;
+
+	DBG(__func__)
+
+	fwant = freq;
+
+#ifdef DEBUG
+	printk(KERN_ERR "post_shift_max: %d\n", pll->post_shift_max);
+	printk(KERN_ERR "ref_freq: %d\n", pll->ref_freq);
+	printk(KERN_ERR "freq: %d\n", freq);
+	printk(KERN_ERR "vco_freq_min: %d\n", pll->vco_freq_min);
+	printk(KERN_ERR "in_div_min: %d\n", pll->in_div_min);
+	printk(KERN_ERR "in_div_max: %d\n", pll->in_div_max);
+	printk(KERN_ERR "feed_div_min: %d\n", pll->feed_div_min);
+	printk(KERN_ERR "feed_div_max: %d\n", pll->feed_div_max);
+	printk(KERN_ERR "fmax: %d\n", fmax);
+#endif
+	for (p = 1; p <= pll->post_shift_max; p++) {
+		if (fwant * 2 > fmax)
+			break;
+		fwant *= 2;
+	}
+	if (fwant < pll->vco_freq_min) fwant = pll->vco_freq_min;
+	if (fwant > fmax) fwant = fmax;
+	for (; p-- > 0; fwant >>= 1, bestdiff >>= 1) {
+		unsigned int m;
+
+		if (fwant < pll->vco_freq_min) break;
+		for (m = pll->in_div_min; m <= pll->in_div_max; m++) {
+			unsigned int diff, fvco;
+			unsigned int n;
+
+			n = (fwant * (m + 1) + (fxtal >> 1)) / fxtal - 1;
+			if (n > pll->feed_div_max)
+				break;
+			if (n < pll->feed_div_min)
+				n = pll->feed_div_min;
+			fvco = (fxtal * (n + 1)) / (m + 1);
+			if (fvco < fwant)
+				diff = fwant - fvco;
+			else
+				diff = fvco - fwant;
+			if (diff < bestdiff) {
+				bestdiff = diff;
+				*post = p;
+				*in = m;
+				*feed = n;
+				bestvco = fvco;
+			}
+		}
+	}
+	dprintk(KERN_ERR "clk: %02X %02X %02X %d %d %d\n", *in, *feed, *post, fxtal, bestvco, fwant);
+	return bestvco;
+}
+
+int matroxfb_vgaHWinit(struct matrox_fb_info *minfo, struct my_timming *m)
+{
+	unsigned int hd, hs, he, hbe, ht;
+	unsigned int vd, vs, ve, vt, lc;
+	unsigned int wd;
+	unsigned int divider;
+	int i;
+	struct matrox_hw_state * const hw = &minfo->hw;
+
+	DBG(__func__)
+
+	hw->SEQ[0] = 0x00;
+	hw->SEQ[1] = 0x01;	/* or 0x09 */
+	hw->SEQ[2] = 0x0F;	/* bitplanes */
+	hw->SEQ[3] = 0x00;
+	hw->SEQ[4] = 0x0E;
+	/* CRTC 0..7, 9, 16..19, 21, 22 are reprogrammed by Matrox Millennium code... Hope that by MGA1064 too */
+	if (m->dblscan) {
+		m->VTotal <<= 1;
+		m->VDisplay <<= 1;
+		m->VSyncStart <<= 1;
+		m->VSyncEnd <<= 1;
+	}
+	if (m->interlaced) {
+		m->VTotal >>= 1;
+		m->VDisplay >>= 1;
+		m->VSyncStart >>= 1;
+		m->VSyncEnd >>= 1;
+	}
+
+	/* GCTL is ignored when not using 0xA0000 aperture */
+	hw->GCTL[0] = 0x00;
+	hw->GCTL[1] = 0x00;
+	hw->GCTL[2] = 0x00;
+	hw->GCTL[3] = 0x00;
+	hw->GCTL[4] = 0x00;
+	hw->GCTL[5] = 0x40;
+	hw->GCTL[6] = 0x05;
+	hw->GCTL[7] = 0x0F;
+	hw->GCTL[8] = 0xFF;
+
+	/* Whole ATTR is ignored in PowerGraphics mode */
+	for (i = 0; i < 16; i++)
+		hw->ATTR[i] = i;
+	hw->ATTR[16] = 0x41;
+	hw->ATTR[17] = 0xFF;
+	hw->ATTR[18] = 0x0F;
+	hw->ATTR[19] = 0x00;
+	hw->ATTR[20] = 0x00;
+
+	hd = m->HDisplay >> 3;
+	hs = m->HSyncStart >> 3;
+	he = m->HSyncEnd >> 3;
+	ht = m->HTotal >> 3;
+	/* standard timmings are in 8pixels, but for interleaved we cannot */
+	/* do it for 4bpp (because of (4bpp >> 1(interleaved))/4 == 0) */
+	/* using 16 or more pixels per unit can save us */
+	divider = minfo->curr.final_bppShift;
+	while (divider & 3) {
+		hd >>= 1;
+		hs >>= 1;
+		he >>= 1;
+		ht >>= 1;
+		divider <<= 1;
+	}
+	divider = divider / 4;
+	/* divider can be from 1 to 8 */
+	while (divider > 8) {
+		hd <<= 1;
+		hs <<= 1;
+		he <<= 1;
+		ht <<= 1;
+		divider >>= 1;
+	}
+	hd = hd - 1;
+	hs = hs - 1;
+	he = he - 1;
+	ht = ht - 1;
+	vd = m->VDisplay - 1;
+	vs = m->VSyncStart - 1;
+	ve = m->VSyncEnd - 1;
+	vt = m->VTotal - 2;
+	lc = vd;
+	/* G200 cannot work with (ht & 7) == 6 */
+	if (((ht & 0x07) == 0x06) || ((ht & 0x0F) == 0x04))
+		ht++;
+	hbe = ht;
+	wd = minfo->fbcon.var.xres_virtual * minfo->curr.final_bppShift / 64;
+
+	hw->CRTCEXT[0] = 0;
+	hw->CRTCEXT[5] = 0;
+	if (m->interlaced) {
+		hw->CRTCEXT[0] = 0x80;
+		hw->CRTCEXT[5] = (hs + he - ht) >> 1;
+		if (!m->dblscan)
+			wd <<= 1;
+		vt &= ~1;
+	}
+	hw->CRTCEXT[0] |=  (wd & 0x300) >> 4;
+	hw->CRTCEXT[1] = (((ht - 4) & 0x100) >> 8) |
+			  ((hd      & 0x100) >> 7) | /* blanking */
+			  ((hs      & 0x100) >> 6) | /* sync start */
+			   (hbe     & 0x040);	 /* end hor. blanking */
+	/* FIXME: Enable vidrst only on G400, and only if TV-out is used */
+	if (minfo->outputs[1].src == MATROXFB_SRC_CRTC1)
+		hw->CRTCEXT[1] |= 0x88;		/* enable horizontal and vertical vidrst */
+	hw->CRTCEXT[2] =  ((vt & 0xC00) >> 10) |
+			  ((vd & 0x400) >>  8) |	/* disp end */
+			  ((vd & 0xC00) >>  7) |	/* vblanking start */
+			  ((vs & 0xC00) >>  5) |
+			  ((lc & 0x400) >>  3);
+	hw->CRTCEXT[3] = (divider - 1) | 0x80;
+	hw->CRTCEXT[4] = 0;
+
+	hw->CRTC[0] = ht-4;
+	hw->CRTC[1] = hd;
+	hw->CRTC[2] = hd;
+	hw->CRTC[3] = (hbe & 0x1F) | 0x80;
+	hw->CRTC[4] = hs;
+	hw->CRTC[5] = ((hbe & 0x20) << 2) | (he & 0x1F);
+	hw->CRTC[6] = vt & 0xFF;
+	hw->CRTC[7] = ((vt & 0x100) >> 8) |
+		      ((vd & 0x100) >> 7) |
+		      ((vs & 0x100) >> 6) |
+		      ((vd & 0x100) >> 5) |
+		      ((lc & 0x100) >> 4) |
+		      ((vt & 0x200) >> 4) |
+		      ((vd & 0x200) >> 3) |
+		      ((vs & 0x200) >> 2);
+	hw->CRTC[8] = 0x00;
+	hw->CRTC[9] = ((vd & 0x200) >> 4) |
+		      ((lc & 0x200) >> 3);
+	if (m->dblscan && !m->interlaced)
+		hw->CRTC[9] |= 0x80;
+	for (i = 10; i < 16; i++)
+		hw->CRTC[i] = 0x00;
+	hw->CRTC[16] = vs /* & 0xFF */;
+	hw->CRTC[17] = (ve & 0x0F) | 0x20;
+	hw->CRTC[18] = vd /* & 0xFF */;
+	hw->CRTC[19] = wd /* & 0xFF */;
+	hw->CRTC[20] = 0x00;
+	hw->CRTC[21] = vd /* & 0xFF */;
+	hw->CRTC[22] = (vt + 1) /* & 0xFF */;
+	hw->CRTC[23] = 0xC3;
+	hw->CRTC[24] = lc;
+	return 0;
+};
+
+void matroxfb_vgaHWrestore(struct matrox_fb_info *minfo)
+{
+	int i;
+	struct matrox_hw_state * const hw = &minfo->hw;
+	CRITFLAGS
+
+	DBG(__func__)
+
+	dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg);
+	dprintk(KERN_INFO "SEQ regs:   ");
+	for (i = 0; i < 5; i++)
+		dprintk("%02X:", hw->SEQ[i]);
+	dprintk("\n");
+	dprintk(KERN_INFO "GDC regs:   ");
+	for (i = 0; i < 9; i++)
+		dprintk("%02X:", hw->GCTL[i]);
+	dprintk("\n");
+	dprintk(KERN_INFO "CRTC regs: ");
+	for (i = 0; i < 25; i++)
+		dprintk("%02X:", hw->CRTC[i]);
+	dprintk("\n");
+	dprintk(KERN_INFO "ATTR regs: ");
+	for (i = 0; i < 21; i++)
+		dprintk("%02X:", hw->ATTR[i]);
+	dprintk("\n");
+
+	CRITBEGIN
+
+	mga_inb(M_ATTR_RESET);
+	mga_outb(M_ATTR_INDEX, 0);
+	mga_outb(M_MISC_REG, hw->MiscOutReg);
+	for (i = 1; i < 5; i++)
+		mga_setr(M_SEQ_INDEX, i, hw->SEQ[i]);
+	mga_setr(M_CRTC_INDEX, 17, hw->CRTC[17] & 0x7F);
+	for (i = 0; i < 25; i++)
+		mga_setr(M_CRTC_INDEX, i, hw->CRTC[i]);
+	for (i = 0; i < 9; i++)
+		mga_setr(M_GRAPHICS_INDEX, i, hw->GCTL[i]);
+	for (i = 0; i < 21; i++) {
+		mga_inb(M_ATTR_RESET);
+		mga_outb(M_ATTR_INDEX, i);
+		mga_outb(M_ATTR_INDEX, hw->ATTR[i]);
+	}
+	mga_outb(M_PALETTE_MASK, 0xFF);
+	mga_outb(M_DAC_REG, 0x00);
+	for (i = 0; i < 768; i++)
+		mga_outb(M_DAC_VAL, hw->DACpal[i]);
+	mga_inb(M_ATTR_RESET);
+	mga_outb(M_ATTR_INDEX, 0x20);
+
+	CRITEND
+}
+
+static void get_pins(unsigned char __iomem* pins, struct matrox_bios* bd) {
+	unsigned int b0 = readb(pins);
+	
+	if (b0 == 0x2E && readb(pins+1) == 0x41) {
+		unsigned int pins_len = readb(pins+2);
+		unsigned int i;
+		unsigned char cksum;
+		unsigned char* dst = bd->pins;
+
+		if (pins_len < 3 || pins_len > 128) {
+			return;
+		}
+		*dst++ = 0x2E;
+		*dst++ = 0x41;
+		*dst++ = pins_len;
+		cksum = 0x2E + 0x41 + pins_len;
+		for (i = 3; i < pins_len; i++) {
+			cksum += *dst++ = readb(pins+i);
+		}
+		if (cksum) {
+			return;
+		}
+		bd->pins_len = pins_len;
+	} else if (b0 == 0x40 && readb(pins+1) == 0x00) {
+		unsigned int i;
+		unsigned char* dst = bd->pins;
+
+		*dst++ = 0x40;
+		*dst++ = 0;
+		for (i = 2; i < 0x40; i++) {
+			*dst++ = readb(pins+i);
+		}
+		bd->pins_len = 0x40;
+	}
+}
+
+static void get_bios_version(unsigned char __iomem * vbios, struct matrox_bios* bd) {
+	unsigned int pcir_offset;
+	
+	pcir_offset = readb(vbios + 24) | (readb(vbios + 25) << 8);
+	if (pcir_offset >= 26 && pcir_offset < 0xFFE0 &&
+	    readb(vbios + pcir_offset    ) == 'P' &&
+	    readb(vbios + pcir_offset + 1) == 'C' &&
+	    readb(vbios + pcir_offset + 2) == 'I' &&
+	    readb(vbios + pcir_offset + 3) == 'R') {
+		unsigned char h;
+
+		h = readb(vbios + pcir_offset + 0x12);
+		bd->version.vMaj = (h >> 4) & 0xF;
+		bd->version.vMin = h & 0xF;
+		bd->version.vRev = readb(vbios + pcir_offset + 0x13);
+	} else {
+		unsigned char h;
+
+		h = readb(vbios + 5);
+		bd->version.vMaj = (h >> 4) & 0xF;
+		bd->version.vMin = h & 0xF;
+		bd->version.vRev = 0;
+	}
+}
+
+static void get_bios_output(unsigned char __iomem* vbios, struct matrox_bios* bd) {
+	unsigned char b;
+	
+	b = readb(vbios + 0x7FF1);
+	if (b == 0xFF) {
+		b = 0;
+	}
+	bd->output.state = b;
+}
+
+static void get_bios_tvout(unsigned char __iomem* vbios, struct matrox_bios* bd) {
+	unsigned int i;
+	
+	/* Check for 'IBM .*(V....TVO' string - it means TVO BIOS */
+	bd->output.tvout = 0;
+	if (readb(vbios + 0x1D) != 'I' ||
+	    readb(vbios + 0x1E) != 'B' ||
+	    readb(vbios + 0x1F) != 'M' ||
+	    readb(vbios + 0x20) != ' ') {
+	    	return;
+	}
+	for (i = 0x2D; i < 0x2D + 128; i++) {
+		unsigned char b = readb(vbios + i);
+		
+		if (b == '(' && readb(vbios + i + 1) == 'V') {
+			if (readb(vbios + i + 6) == 'T' &&
+			    readb(vbios + i + 7) == 'V' &&
+			    readb(vbios + i + 8) == 'O') {
+				bd->output.tvout = 1;
+			}
+			return;
+		}
+		if (b == 0)
+			break;
+	}
+}
+
+static void parse_bios(unsigned char __iomem* vbios, struct matrox_bios* bd) {
+	unsigned int pins_offset;
+	
+	if (readb(vbios) != 0x55 || readb(vbios + 1) != 0xAA) {
+		return;
+	}
+	bd->bios_valid = 1;
+	get_bios_version(vbios, bd);
+	get_bios_output(vbios, bd);
+	get_bios_tvout(vbios, bd);
+#if defined(__powerpc__)
+	/* On PowerPC cards, the PInS offset isn't stored at the end of the
+	 * BIOS image.  Instead, you must search the entire BIOS image for
+	 * the magic PInS signature.
+	 *
+	 * This actually applies to all OpenFirmware base cards.  Since these
+	 * cards could be put in a MIPS or SPARC system, should the condition
+	 * be something different?
+	 */
+	for ( pins_offset = 0 ; pins_offset <= 0xFF80 ; pins_offset++ ) {
+		unsigned char header[3];
+
+		header[0] = readb(vbios + pins_offset);
+		header[1] = readb(vbios + pins_offset + 1);
+		header[2] = readb(vbios + pins_offset + 2);
+		if ( (header[0] == 0x2E) && (header[1] == 0x41)
+		     && ((header[2] == 0x40) || (header[2] == 0x80)) ) {
+			printk(KERN_INFO "PInS data found at offset %u\n",
+			       pins_offset);
+			get_pins(vbios + pins_offset, bd);
+			break;
+		}
+	}
+#else
+	pins_offset = readb(vbios + 0x7FFC) | (readb(vbios + 0x7FFD) << 8);
+	if (pins_offset <= 0xFF80) {
+		get_pins(vbios + pins_offset, bd);
+	}
+#endif
+}
+
+static int parse_pins1(struct matrox_fb_info *minfo,
+		       const struct matrox_bios *bd)
+{
+	unsigned int maxdac;
+
+	switch (bd->pins[22]) {
+		case 0:		maxdac = 175000; break;
+		case 1:		maxdac = 220000; break;
+		default:	maxdac = 240000; break;
+	}
+	if (get_unaligned_le16(bd->pins + 24)) {
+		maxdac = get_unaligned_le16(bd->pins + 24) * 10;
+	}
+	minfo->limits.pixel.vcomax = maxdac;
+	minfo->values.pll.system = get_unaligned_le16(bd->pins + 28) ?
+		get_unaligned_le16(bd->pins + 28) * 10 : 50000;
+	/* ignore 4MB, 8MB, module clocks */
+	minfo->features.pll.ref_freq = 14318;
+	minfo->values.reg.mctlwtst	= 0x00030101;
+	return 0;
+}
+
+static void default_pins1(struct matrox_fb_info *minfo)
+{
+	/* Millennium */
+	minfo->limits.pixel.vcomax	= 220000;
+	minfo->values.pll.system	=  50000;
+	minfo->features.pll.ref_freq	=  14318;
+	minfo->values.reg.mctlwtst	= 0x00030101;
+}
+
+static int parse_pins2(struct matrox_fb_info *minfo,
+		       const struct matrox_bios *bd)
+{
+	minfo->limits.pixel.vcomax	=
+	minfo->limits.system.vcomax	= (bd->pins[41] == 0xFF) ? 230000 : ((bd->pins[41] + 100) * 1000);
+	minfo->values.reg.mctlwtst	= ((bd->pins[51] & 0x01) ? 0x00000001 : 0) |
+					  ((bd->pins[51] & 0x02) ? 0x00000100 : 0) |
+					  ((bd->pins[51] & 0x04) ? 0x00010000 : 0) |
+					  ((bd->pins[51] & 0x08) ? 0x00020000 : 0);
+	minfo->values.pll.system	= (bd->pins[43] == 0xFF) ? 50000 : ((bd->pins[43] + 100) * 1000);
+	minfo->features.pll.ref_freq	= 14318;
+	return 0;
+}
+
+static void default_pins2(struct matrox_fb_info *minfo)
+{
+	/* Millennium II, Mystique */
+	minfo->limits.pixel.vcomax	=
+	minfo->limits.system.vcomax	= 230000;
+	minfo->values.reg.mctlwtst	= 0x00030101;
+	minfo->values.pll.system	=  50000;
+	minfo->features.pll.ref_freq	=  14318;
+}
+
+static int parse_pins3(struct matrox_fb_info *minfo,
+		       const struct matrox_bios *bd)
+{
+	minfo->limits.pixel.vcomax	=
+	minfo->limits.system.vcomax	= (bd->pins[36] == 0xFF) ? 230000			: ((bd->pins[36] + 100) * 1000);
+	minfo->values.reg.mctlwtst	= get_unaligned_le32(bd->pins + 48) == 0xFFFFFFFF ?
+		0x01250A21 : get_unaligned_le32(bd->pins + 48);
+	/* memory config */
+	minfo->values.reg.memrdbk	= ((bd->pins[57] << 21) & 0x1E000000) |
+					  ((bd->pins[57] << 22) & 0x00C00000) |
+					  ((bd->pins[56] <<  1) & 0x000001E0) |
+					  ( bd->pins[56]        & 0x0000000F);
+	minfo->values.reg.opt		= (bd->pins[54] & 7) << 10;
+	minfo->values.reg.opt2		= bd->pins[58] << 12;
+	minfo->features.pll.ref_freq	= (bd->pins[52] & 0x20) ? 14318 : 27000;
+	return 0;
+}
+
+static void default_pins3(struct matrox_fb_info *minfo)
+{
+	/* G100, G200 */
+	minfo->limits.pixel.vcomax	=
+	minfo->limits.system.vcomax	= 230000;
+	minfo->values.reg.mctlwtst	= 0x01250A21;
+	minfo->values.reg.memrdbk	= 0x00000000;
+	minfo->values.reg.opt		= 0x00000C00;
+	minfo->values.reg.opt2		= 0x00000000;
+	minfo->features.pll.ref_freq	=  27000;
+}
+
+static int parse_pins4(struct matrox_fb_info *minfo,
+		       const struct matrox_bios *bd)
+{
+	minfo->limits.pixel.vcomax	= (bd->pins[ 39] == 0xFF) ? 230000			: bd->pins[ 39] * 4000;
+	minfo->limits.system.vcomax	= (bd->pins[ 38] == 0xFF) ? minfo->limits.pixel.vcomax	: bd->pins[ 38] * 4000;
+	minfo->values.reg.mctlwtst	= get_unaligned_le32(bd->pins + 71);
+	minfo->values.reg.memrdbk	= ((bd->pins[87] << 21) & 0x1E000000) |
+					  ((bd->pins[87] << 22) & 0x00C00000) |
+					  ((bd->pins[86] <<  1) & 0x000001E0) |
+					  ( bd->pins[86]        & 0x0000000F);
+	minfo->values.reg.opt		= ((bd->pins[53] << 15) & 0x00400000) |
+					  ((bd->pins[53] << 22) & 0x10000000) |
+					  ((bd->pins[53] <<  7) & 0x00001C00);
+	minfo->values.reg.opt3		= get_unaligned_le32(bd->pins + 67);
+	minfo->values.pll.system	= (bd->pins[ 65] == 0xFF) ? 200000 			: bd->pins[ 65] * 4000;
+	minfo->features.pll.ref_freq	= (bd->pins[ 92] & 0x01) ? 14318 : 27000;
+	return 0;
+}
+
+static void default_pins4(struct matrox_fb_info *minfo)
+{
+	/* G400 */
+	minfo->limits.pixel.vcomax	=
+	minfo->limits.system.vcomax	= 252000;
+	minfo->values.reg.mctlwtst	= 0x04A450A1;
+	minfo->values.reg.memrdbk	= 0x000000E7;
+	minfo->values.reg.opt		= 0x10000400;
+	minfo->values.reg.opt3		= 0x0190A419;
+	minfo->values.pll.system	= 200000;
+	minfo->features.pll.ref_freq	= 27000;
+}
+
+static int parse_pins5(struct matrox_fb_info *minfo,
+		       const struct matrox_bios *bd)
+{
+	unsigned int mult;
+	
+	mult = bd->pins[4]?8000:6000;
+	
+	minfo->limits.pixel.vcomax	= (bd->pins[ 38] == 0xFF) ? 600000			: bd->pins[ 38] * mult;
+	minfo->limits.system.vcomax	= (bd->pins[ 36] == 0xFF) ? minfo->limits.pixel.vcomax	: bd->pins[ 36] * mult;
+	minfo->limits.video.vcomax	= (bd->pins[ 37] == 0xFF) ? minfo->limits.system.vcomax	: bd->pins[ 37] * mult;
+	minfo->limits.pixel.vcomin	= (bd->pins[123] == 0xFF) ? 256000			: bd->pins[123] * mult;
+	minfo->limits.system.vcomin	= (bd->pins[121] == 0xFF) ? minfo->limits.pixel.vcomin	: bd->pins[121] * mult;
+	minfo->limits.video.vcomin	= (bd->pins[122] == 0xFF) ? minfo->limits.system.vcomin	: bd->pins[122] * mult;
+	minfo->values.pll.system	=
+	minfo->values.pll.video		= (bd->pins[ 92] == 0xFF) ? 284000			: bd->pins[ 92] * 4000;
+	minfo->values.reg.opt		= get_unaligned_le32(bd->pins + 48);
+	minfo->values.reg.opt2		= get_unaligned_le32(bd->pins + 52);
+	minfo->values.reg.opt3		= get_unaligned_le32(bd->pins + 94);
+	minfo->values.reg.mctlwtst	= get_unaligned_le32(bd->pins + 98);
+	minfo->values.reg.memmisc	= get_unaligned_le32(bd->pins + 102);
+	minfo->values.reg.memrdbk	= get_unaligned_le32(bd->pins + 106);
+	minfo->features.pll.ref_freq	= (bd->pins[110] & 0x01) ? 14318 : 27000;
+	minfo->values.memory.ddr	= (bd->pins[114] & 0x60) == 0x20;
+	minfo->values.memory.dll	= (bd->pins[115] & 0x02) != 0;
+	minfo->values.memory.emrswen	= (bd->pins[115] & 0x01) != 0;
+	minfo->values.reg.maccess	= minfo->values.memory.emrswen ? 0x00004000 : 0x00000000;
+	if (bd->pins[115] & 4) {
+		minfo->values.reg.mctlwtst_core = minfo->values.reg.mctlwtst;
+	} else {
+		u_int32_t wtst_xlat[] = { 0, 1, 5, 6, 7, 5, 2, 3 };
+		minfo->values.reg.mctlwtst_core = (minfo->values.reg.mctlwtst & ~7) |
+						  wtst_xlat[minfo->values.reg.mctlwtst & 7];
+	}
+	minfo->max_pixel_clock_panellink = bd->pins[47] * 4000;
+	return 0;
+}
+
+static void default_pins5(struct matrox_fb_info *minfo)
+{
+	/* Mine 16MB G450 with SDRAM DDR */
+	minfo->limits.pixel.vcomax	=
+	minfo->limits.system.vcomax	=
+	minfo->limits.video.vcomax	= 600000;
+	minfo->limits.pixel.vcomin	=
+	minfo->limits.system.vcomin	=
+	minfo->limits.video.vcomin	= 256000;
+	minfo->values.pll.system	=
+	minfo->values.pll.video		= 284000;
+	minfo->values.reg.opt		= 0x404A1160;
+	minfo->values.reg.opt2		= 0x0000AC00;
+	minfo->values.reg.opt3		= 0x0090A409;
+	minfo->values.reg.mctlwtst_core	=
+	minfo->values.reg.mctlwtst	= 0x0C81462B;
+	minfo->values.reg.memmisc	= 0x80000004;
+	minfo->values.reg.memrdbk	= 0x01001103;
+	minfo->features.pll.ref_freq	= 27000;
+	minfo->values.memory.ddr	= 1;
+	minfo->values.memory.dll	= 1;
+	minfo->values.memory.emrswen	= 1;
+	minfo->values.reg.maccess	= 0x00004000;
+}
+
+static int matroxfb_set_limits(struct matrox_fb_info *minfo,
+			       const struct matrox_bios *bd)
+{
+	unsigned int pins_version;
+	static const unsigned int pinslen[] = { 64, 64, 64, 128, 128 };
+
+	switch (minfo->chip) {
+		case MGA_2064:	default_pins1(minfo); break;
+		case MGA_2164:
+		case MGA_1064:
+		case MGA_1164:	default_pins2(minfo); break;
+		case MGA_G100:
+		case MGA_G200:	default_pins3(minfo); break;
+		case MGA_G400:	default_pins4(minfo); break;
+		case MGA_G450:
+		case MGA_G550:	default_pins5(minfo); break;
+	}
+	if (!bd->bios_valid) {
+		printk(KERN_INFO "matroxfb: Your Matrox device does not have BIOS\n");
+		return -1;
+	}
+	if (bd->pins_len < 64) {
+		printk(KERN_INFO "matroxfb: BIOS on your Matrox device does not contain powerup info\n");
+		return -1;
+	}
+	if (bd->pins[0] == 0x2E && bd->pins[1] == 0x41) {
+		pins_version = bd->pins[5];
+		if (pins_version < 2 || pins_version > 5) {
+			printk(KERN_INFO "matroxfb: Unknown version (%u) of powerup info\n", pins_version);
+			return -1;
+		}
+	} else {
+		pins_version = 1;
+	}
+	if (bd->pins_len != pinslen[pins_version - 1]) {
+		printk(KERN_INFO "matroxfb: Invalid powerup info\n");
+		return -1;
+	}
+	switch (pins_version) {
+		case 1:
+			return parse_pins1(minfo, bd);
+		case 2:
+			return parse_pins2(minfo, bd);
+		case 3:
+			return parse_pins3(minfo, bd);
+		case 4:
+			return parse_pins4(minfo, bd);
+		case 5:
+			return parse_pins5(minfo, bd);
+		default:
+			printk(KERN_DEBUG "matroxfb: Powerup info version %u is not yet supported\n", pins_version);
+			return -1;
+	}
+}
+
+void matroxfb_read_pins(struct matrox_fb_info *minfo)
+{
+	u32 opt;
+	u32 biosbase;
+	u32 fbbase;
+	struct pci_dev *pdev = minfo->pcidev;
+	
+	memset(&minfo->bios, 0, sizeof(minfo->bios));
+	pci_read_config_dword(pdev, PCI_OPTION_REG, &opt);
+	pci_write_config_dword(pdev, PCI_OPTION_REG, opt | PCI_OPTION_ENABLE_ROM);
+	pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &biosbase);
+	pci_read_config_dword(pdev, minfo->devflags.fbResource, &fbbase);
+	pci_write_config_dword(pdev, PCI_ROM_ADDRESS, (fbbase & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
+	parse_bios(vaddr_va(minfo->video.vbase), &minfo->bios);
+	pci_write_config_dword(pdev, PCI_ROM_ADDRESS, biosbase);
+	pci_write_config_dword(pdev, PCI_OPTION_REG, opt);
+#ifdef CONFIG_X86
+	if (!minfo->bios.bios_valid) {
+		unsigned char __iomem* b;
+
+		b = ioremap(0x000C0000, 65536);
+		if (!b) {
+			printk(KERN_INFO "matroxfb: Unable to map legacy BIOS\n");
+		} else {
+			unsigned int ven = readb(b+0x64+0) | (readb(b+0x64+1) << 8);
+			unsigned int dev = readb(b+0x64+2) | (readb(b+0x64+3) << 8);
+			
+			if (ven != pdev->vendor || dev != pdev->device) {
+				printk(KERN_INFO "matroxfb: Legacy BIOS is for %04X:%04X, while this device is %04X:%04X\n",
+					ven, dev, pdev->vendor, pdev->device);
+			} else {
+				parse_bios(b, &minfo->bios);
+			}
+			iounmap(b);
+		}
+	}
+#endif
+	matroxfb_set_limits(minfo, &minfo->bios);
+	printk(KERN_INFO "PInS memtype = %u\n",
+	       (minfo->values.reg.opt & 0x1C00) >> 10);
+}
+
+EXPORT_SYMBOL(matroxfb_DAC_in);
+EXPORT_SYMBOL(matroxfb_DAC_out);
+EXPORT_SYMBOL(matroxfb_var2my);
+EXPORT_SYMBOL(matroxfb_PLL_calcclock);
+EXPORT_SYMBOL(matroxfb_vgaHWinit);		/* DAC1064, Ti3026 */
+EXPORT_SYMBOL(matroxfb_vgaHWrestore);		/* DAC1064, Ti3026 */
+EXPORT_SYMBOL(matroxfb_read_pins);
+
+MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Miscellaneous support for Matrox video cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/mgakms/matroxfb_misc.h b/drivers/staging/mgakms/matroxfb_misc.h
new file mode 100644
index 000000000000..9cb6686d309e
--- /dev/null
+++ b/drivers/staging/mgakms/matroxfb_misc.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __MATROXFB_MISC_H__
+#define __MATROXFB_MISC_H__
+
+#include "matroxfb_base.h"
+
+/* also for modules */
+int matroxfb_PLL_calcclock(const struct matrox_pll_features* pll, unsigned int freq, unsigned int fmax,
+	unsigned int* in, unsigned int* feed, unsigned int* post);
+static inline int PLL_calcclock(const struct matrox_fb_info *minfo,
+				unsigned int freq, unsigned int fmax,
+				unsigned int *in, unsigned int *feed,
+				unsigned int *post)
+{
+	return matroxfb_PLL_calcclock(&minfo->features.pll, freq, fmax, in, feed, post);
+}
+
+int matroxfb_vgaHWinit(struct matrox_fb_info *minfo, struct my_timming* m);
+void matroxfb_vgaHWrestore(struct matrox_fb_info *minfo);
+void matroxfb_read_pins(struct matrox_fb_info *minfo);
+
+#endif	/* __MATROXFB_MISC_H__ */
-- 
2.23.0

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

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

* [PATCH v2 15/15] staging/mgakms: Update matroxfb driver code for DRM
  2019-10-14 14:04 ` Thomas Zimmermann
@ 2019-10-14 14:04   ` Thomas Zimmermann
  -1 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

With the update, all driver code coming from matroxfb is build
unconditionally. The driver registers itself with the mgakms driver,
instead of the fbdev core.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/staging/mgakms/Kconfig            |  5 ++
 drivers/staging/mgakms/Makefile           | 11 ++++
 drivers/staging/mgakms/matroxfb_DAC1064.c | 77 +++++++----------------
 drivers/staging/mgakms/matroxfb_DAC1064.h |  6 --
 drivers/staging/mgakms/matroxfb_Ti3026.c  |  2 -
 drivers/staging/mgakms/matroxfb_Ti3026.h  |  2 -
 drivers/staging/mgakms/matroxfb_base.c    | 29 +++------
 drivers/staging/mgakms/matroxfb_base.h    | 20 ++----
 drivers/staging/mgakms/matroxfb_g450.h    |  5 --
 9 files changed, 51 insertions(+), 106 deletions(-)

diff --git a/drivers/staging/mgakms/Kconfig b/drivers/staging/mgakms/Kconfig
index de23e76317bd..66c5b3b8669f 100644
--- a/drivers/staging/mgakms/Kconfig
+++ b/drivers/staging/mgakms/Kconfig
@@ -4,6 +4,11 @@ config DRM_MGAKMS
 	select DRM_FBCONV_HELPER
 	select DRM_GEM_SHMEM_HELPER
 	select DRM_KMS_HELPER
+	select FB_CFB_COPYAREA
+	select FB_CFB_FILLRECT
+	select FB_CFB_IMAGEBLIT
+	select FB_MACMODES if PPC_PMAC
+	select FB_TILEBLITTING
 	help
 	  Choose this option if you have a Matrox Millennium,
 	  Matrox Millennium II, Matrox Mystique, Matrox Mystique 220,
diff --git a/drivers/staging/mgakms/Makefile b/drivers/staging/mgakms/Makefile
index 65695f04eb7f..b368f8a5e38a 100644
--- a/drivers/staging/mgakms/Makefile
+++ b/drivers/staging/mgakms/Makefile
@@ -3,4 +3,15 @@
 mgakms-y	:= mga_device.o \
 		   mga_drv.o
 
+# Old matroxfb driver code. Keep this separate and
+# remove it after conversion.
+mgakms-y	+= g450_pll.o \
+		   i2c-matroxfb.o \
+		   matroxfb_accel.o \
+		   matroxfb_base.o \
+		   matroxfb_DAC1064.o \
+		   matroxfb_g450.o \
+		   matroxfb_misc.o \
+		   matroxfb_Ti3026.o
+
 obj-$(CONFIG_DRM_MGAKMS)	+= mgakms.o
diff --git a/drivers/staging/mgakms/matroxfb_DAC1064.c b/drivers/staging/mgakms/matroxfb_DAC1064.c
index b380a393cbc3..6bb214c548af 100644
--- a/drivers/staging/mgakms/matroxfb_DAC1064.c
+++ b/drivers/staging/mgakms/matroxfb_DAC1064.c
@@ -19,7 +19,6 @@
 #include "g450_pll.h"
 #include <linux/matroxfb.h>
 
-#ifdef NEED_DAC1064
 #define outDAC1064 matroxfb_DAC_out
 #define inDAC1064 matroxfb_DAC_in
 
@@ -42,11 +41,11 @@ static void DAC1064_calcclock(const struct matrox_fb_info *minfo,
 	unsigned int p;
 
 	DBG(__func__)
-	
+
 	/* only for devices older than G450 */
 
 	fvco = PLL_calcclock(minfo, freq, fmax, in, feed, &p);
-	
+
 	p = (1 << p) - 1;
 	if (fvco <= 100000)
 		;
@@ -160,7 +159,6 @@ static void DAC1064_setmclk(struct matrox_fb_info *minfo, int oscinfo,
 	hw->MXoptionReg = mx;
 }
 
-#ifdef CONFIG_FB_MATROX_G
 static void g450_set_plls(struct matrox_fb_info *minfo)
 {
 	u_int32_t c2_ctl;
@@ -168,7 +166,7 @@ static void g450_set_plls(struct matrox_fb_info *minfo)
 	struct matrox_hw_state *hw = &minfo->hw;
 	int pixelmnp;
 	int videomnp;
-	
+
 	c2_ctl = hw->crtc2.ctl & ~0x4007;	/* Clear PLL + enable for CRTC2 */
 	c2_ctl |= 0x0001;			/* Enable CRTC2 */
 	hw->DACreg[POS1064_XPWRCTRL] &= ~0x02;	/* Stop VIDEO PLL */
@@ -191,7 +189,7 @@ static void g450_set_plls(struct matrox_fb_info *minfo)
 		}
 		c2_ctl |=  0x0006;	/* Use video PLL */
 		hw->DACreg[POS1064_XPWRCTRL] |= 0x02;
-		
+
 		outDAC1064(minfo, M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
 		matroxfb_g450_setpll_cond(minfo, videomnp, M_VIDEO_PLL);
 	}
@@ -199,7 +197,7 @@ static void g450_set_plls(struct matrox_fb_info *minfo)
 	hw->DACreg[POS1064_XPIXCLKCTRL] &= ~M1064_XPIXCLKCTRL_PLL_UP;
 	if (pixelmnp >= 0) {
 		hw->DACreg[POS1064_XPIXCLKCTRL] |= M1064_XPIXCLKCTRL_PLL_UP;
-		
+
 		outDAC1064(minfo, M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]);
 		matroxfb_g450_setpll_cond(minfo, pixelmnp, M_PIXEL_PLL_C);
 	}
@@ -251,7 +249,6 @@ static void g450_set_plls(struct matrox_fb_info *minfo)
 		}
 	}
 }
-#endif
 
 void DAC1064_global_init(struct matrox_fb_info *minfo)
 {
@@ -260,7 +257,6 @@ void DAC1064_global_init(struct matrox_fb_info *minfo)
 	hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK;
 	hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN;
 	hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL;
-#ifdef CONFIG_FB_MATROX_G
 	if (minfo->devflags.g450dac) {
 		hw->DACreg[POS1064_XPWRCTRL] = 0x1F;	/* powerup everything */
 		hw->DACreg[POS1064_XOUTPUTCONN] = 0x00;	/* disable outputs */
@@ -302,15 +298,14 @@ void DAC1064_global_init(struct matrox_fb_info *minfo)
 				   poweroff TMDS. But if we boot with DFP connected,
 				   TMDS generated clocks are used instead of ALL pixclocks
 				   available... If someone knows which register
-				   handles it, please reveal this secret to me... */			
+				   handles it, please reveal this secret to me... */
 				hw->DACreg[POS1064_XPWRCTRL] &= ~0x04;		/* Poweroff TMDS */
-#endif				
+#endif
 				break;
 		}
 		/* Now set timming related variables... */
 		g450_set_plls(minfo);
 	} else
-#endif
 	{
 		if (minfo->outputs[1].src = MATROXFB_SRC_CRTC1) {
 			hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT;
@@ -510,7 +505,6 @@ static struct matrox_altout m1064 = {
 	.compute = m1064_compute,
 };
 
-#ifdef CONFIG_FB_MATROX_G
 static int g450_compute(void* out, struct my_timming* m) {
 #define minfo ((struct matrox_fb_info*)out)
 	if (m->mnp < 0) {
@@ -527,11 +521,7 @@ static struct matrox_altout g450out = {
 	.name	 = "Primary output",
 	.compute = g450_compute,
 };
-#endif
 
-#endif /* NEED_DAC1064 */
-
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
 static int MGA1064_init(struct matrox_fb_info *minfo, struct my_timming *m)
 {
 	struct matrox_hw_state *hw = &minfo->hw;
@@ -552,9 +542,7 @@ static int MGA1064_init(struct matrox_fb_info *minfo, struct my_timming *m)
 	if (DAC1064_init_2(minfo, m)) return 1;
 	return 0;
 }
-#endif
 
-#ifdef CONFIG_FB_MATROX_G
 static int MGAG100_init(struct matrox_fb_info *minfo, struct my_timming *m)
 {
 	struct matrox_hw_state *hw = &minfo->hw;
@@ -576,9 +564,7 @@ static int MGAG100_init(struct matrox_fb_info *minfo, struct my_timming *m)
 	if (DAC1064_init_2(minfo, m)) return 1;
 	return 0;
 }
-#endif	/* G */
 
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
 static void MGA1064_ramdac_init(struct matrox_fb_info *minfo)
 {
 
@@ -596,9 +582,7 @@ static void MGA1064_ramdac_init(struct matrox_fb_info *minfo)
 	/* maybe cmdline MCLK= ?, doc says gclkDMHz, mclkfMHz... it was 55/83 with old values */
 	DAC1064_setmclk(minfo, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333);
 }
-#endif
 
-#ifdef CONFIG_FB_MATROX_G
 /* BIOS environ */
 static int x7AF4 = 0x10;	/* flags, maybe 0x10 = SDRAM, 0x00 = SGRAM??? */
 				/* G100 wants 0x10, G200 SGRAM does not care... */
@@ -662,9 +646,7 @@ static void MGAG100_setPixClock(const struct matrox_fb_info *minfo, int flags,
 	DAC1064_calcclock(minfo, freq, minfo->max_pixel_clock, &m, &n, &p);
 	MGAG100_progPixClock(minfo, flags, m, n, p);
 }
-#endif
 
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
 static int MGA1064_preinit(struct matrox_fb_info *minfo)
 {
 	static const int vxres_mystique[] = { 512,        640, 768,  800,  832,  960,
@@ -710,9 +692,7 @@ static void MGA1064_reset(struct matrox_fb_info *minfo)
 
 	MGA1064_ramdac_init(minfo);
 }
-#endif
 
-#ifdef CONFIG_FB_MATROX_G
 static void g450_mclk_init(struct matrox_fb_info *minfo)
 {
 	/* switch all clocks to PCI source */
@@ -727,14 +707,14 @@ static void g450_mclk_init(struct matrox_fb_info *minfo)
 	} else {
 		unsigned long flags;
 		unsigned int pwr;
-		
+
 		matroxfb_DAC_lock_irqsave(flags);
 		pwr = inDAC1064(minfo, M1064_XPWRCTRL) & ~0x02;
 		outDAC1064(minfo, M1064_XPWRCTRL, pwr);
 		matroxfb_DAC_unlock_irqrestore(flags);
 	}
 	matroxfb_g450_setclk(minfo, minfo->values.pll.system, M_SYSTEM_PLL);
-	
+
 	/* switch clocks to their real PLL source(s) */
 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg | 4);
 	pci_write_config_dword(minfo->pcidev, PCI_OPTION3_REG, minfo->values.reg.opt3);
@@ -747,15 +727,15 @@ static void g450_memory_init(struct matrox_fb_info *minfo)
 	/* disable memory refresh */
 	minfo->hw.MXoptionReg &= ~0x001F8000;
 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
-	
+
 	/* set memory interface parameters */
 	minfo->hw.MXoptionReg &= ~0x00207E00;
 	minfo->hw.MXoptionReg |= 0x00207E00 & minfo->values.reg.opt;
 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
 	pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, minfo->values.reg.opt2);
-	
+
 	mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst);
-	
+
 	/* first set up memory interface with disabled memory interface clocks */
 	pci_write_config_dword(minfo->pcidev, PCI_MEMMISC_REG, minfo->values.reg.memmisc & ~0x80000000U);
 	mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk);
@@ -764,25 +744,25 @@ static void g450_memory_init(struct matrox_fb_info *minfo)
 	pci_write_config_dword(minfo->pcidev, PCI_MEMMISC_REG, minfo->values.reg.memmisc | 0x80000000U);
 
 	udelay(200);
-	
+
 	if (minfo->values.memory.ddr && (!minfo->values.memory.emrswen || !minfo->values.memory.dll)) {
 		mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk & ~0x1000);
 	}
 	mga_outl(M_MACCESS, minfo->values.reg.maccess | 0x8000);
-	
+
 	udelay(200);
-	
+
 	minfo->hw.MXoptionReg |= 0x001F8000 & minfo->values.reg.opt;
 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
-	
+
 	/* value is written to memory chips only if old != new */
 	mga_outl(M_PLNWT, 0);
 	mga_outl(M_PLNWT, ~0);
-	
+
 	if (minfo->values.reg.mctlwtst != minfo->values.reg.mctlwtst_core) {
 		mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst_core);
 	}
-	
+
 }
 
 static void g450_preinit(struct matrox_fb_info *minfo)
@@ -790,7 +770,7 @@ static void g450_preinit(struct matrox_fb_info *minfo)
 	u_int32_t c2ctl;
 	u_int8_t curctl;
 	u_int8_t c1ctl;
-	
+
 	/* minfo->hw.MXoptionReg = minfo->values.reg.opt; */
 	minfo->hw.MXoptionReg &= 0xC0000100;
 	minfo->hw.MXoptionReg |= 0x00000020;
@@ -804,7 +784,7 @@ static void g450_preinit(struct matrox_fb_info *minfo)
 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
 
 	/* Init system clocks */
-		
+
 	/* stop crtc2 */
 	c2ctl = mga_inl(M_C2CTL);
 	mga_outl(M_C2CTL, c2ctl & ~1);
@@ -817,20 +797,20 @@ static void g450_preinit(struct matrox_fb_info *minfo)
 
 	g450_mclk_init(minfo);
 	g450_memory_init(minfo);
-	
+
 	/* set legacy VGA clock sources for DOSEmu or VMware... */
 	matroxfb_g450_setclk(minfo, 25175, M_PIXEL_PLL_A);
 	matroxfb_g450_setclk(minfo, 28322, M_PIXEL_PLL_B);
 
 	/* restore crtc1 */
 	mga_setr(M_SEQ_INDEX, 1, c1ctl);
-	
+
 	/* restore cursor */
 	outDAC1064(minfo, M1064_XCURCTRL, curctl);
 
 	/* restore crtc2 */
 	mga_outl(M_C2CTL, c2ctl);
-	
+
 	return;
 }
 
@@ -1031,9 +1011,7 @@ static void MGAG100_reset(struct matrox_fb_info *minfo)
 		}
 	}
 }
-#endif
 
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
 static void MGA1064_restore(struct matrox_fb_info *minfo)
 {
 	int i;
@@ -1058,9 +1036,7 @@ static void MGA1064_restore(struct matrox_fb_info *minfo)
 		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
 	DAC1064_restore_2(minfo);
 }
-#endif
 
-#ifdef CONFIG_FB_MATROX_G
 static void MGAG100_restore(struct matrox_fb_info *minfo)
 {
 	int i;
@@ -1084,9 +1060,7 @@ static void MGAG100_restore(struct matrox_fb_info *minfo)
 		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
 	DAC1064_restore_2(minfo);
 }
-#endif
 
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
 struct matrox_switch matrox_mystique = {
 	.preinit	= MGA1064_preinit,
 	.reset		= MGA1064_reset,
@@ -1094,9 +1068,7 @@ struct matrox_switch matrox_mystique = {
 	.restore	= MGA1064_restore,
 };
 EXPORT_SYMBOL(matrox_mystique);
-#endif
 
-#ifdef CONFIG_FB_MATROX_G
 struct matrox_switch matrox_G100 = {
 	.preinit	= MGAG100_preinit,
 	.reset		= MGAG100_reset,
@@ -1104,10 +1076,7 @@ struct matrox_switch matrox_G100 = {
 	.restore	= MGAG100_restore,
 };
 EXPORT_SYMBOL(matrox_G100);
-#endif
 
-#ifdef NEED_DAC1064
 EXPORT_SYMBOL(DAC1064_global_init);
 EXPORT_SYMBOL(DAC1064_global_restore);
-#endif
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/mgakms/matroxfb_DAC1064.h b/drivers/staging/mgakms/matroxfb_DAC1064.h
index 3b2a6fd35fff..3d388941b51d 100644
--- a/drivers/staging/mgakms/matroxfb_DAC1064.h
+++ b/drivers/staging/mgakms/matroxfb_DAC1064.h
@@ -5,16 +5,10 @@
 
 #include "matroxfb_base.h"
 
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
 extern struct matrox_switch matrox_mystique;
-#endif
-#ifdef CONFIG_FB_MATROX_G
 extern struct matrox_switch matrox_G100;
-#endif
-#ifdef NEED_DAC1064
 void DAC1064_global_init(struct matrox_fb_info *minfo);
 void DAC1064_global_restore(struct matrox_fb_info *minfo);
-#endif
 
 #define M1064_INDEX	0x00
 #define M1064_PALWRADD	0x00
diff --git a/drivers/staging/mgakms/matroxfb_Ti3026.c b/drivers/staging/mgakms/matroxfb_Ti3026.c
index 9ff9be85759e..e82e2a3cf76a 100644
--- a/drivers/staging/mgakms/matroxfb_Ti3026.c
+++ b/drivers/staging/mgakms/matroxfb_Ti3026.c
@@ -84,7 +84,6 @@
 #include "matroxfb_accel.h"
 #include <linux/matroxfb.h>
 
-#ifdef CONFIG_FB_MATROX_MILLENIUM
 #define outTi3026 matroxfb_DAC_out
 #define inTi3026 matroxfb_DAC_in
 
@@ -744,5 +743,4 @@ struct matrox_switch matrox_millennium = {
 	.restore	= Ti3026_restore
 };
 EXPORT_SYMBOL(matrox_millennium);
-#endif
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/mgakms/matroxfb_Ti3026.h b/drivers/staging/mgakms/matroxfb_Ti3026.h
index faee149d0ba0..2fda3b30b9e7 100644
--- a/drivers/staging/mgakms/matroxfb_Ti3026.h
+++ b/drivers/staging/mgakms/matroxfb_Ti3026.h
@@ -5,8 +5,6 @@
 
 #include "matroxfb_base.h"
 
-#ifdef CONFIG_FB_MATROX_MILLENIUM
 extern struct matrox_switch matrox_millennium;
-#endif
 
 #endif	/* __MATROXFB_TI3026_H__ */
diff --git a/drivers/staging/mgakms/matroxfb_base.c b/drivers/staging/mgakms/matroxfb_base.c
index d11b5e6210ed..7ee0ea046a5f 100644
--- a/drivers/staging/mgakms/matroxfb_base.c
+++ b/drivers/staging/mgakms/matroxfb_base.c
@@ -114,6 +114,7 @@
 #include <linux/nvram.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
+#include "mga_drv.h"
 
 #ifdef CONFIG_PPC_PMAC
 #include <asm/machdep.h>
@@ -368,7 +369,7 @@ static void matroxfb_remove(struct matrox_fb_info *minfo, int dummy)
 		return;
 	}
 	matroxfb_unregister_device(minfo);
-	unregister_framebuffer(&minfo->fbcon);
+	mga_unregister_framebuffer(minfo->mdev);
 	matroxfb_g450_shutdown(minfo);
 	arch_phys_wc_del(minfo->wc_cookie);
 	iounmap(minfo->mmio.vbase.vaddr);
@@ -1319,9 +1320,7 @@ static int matroxfb_getmemory(struct matrox_fb_info *minfo,
 	mga_outb(M_EXTVGA_DATA, orig);
 
 	*realSize = offs - 0x100000;
-#ifdef CONFIG_FB_MATROX_MILLENIUM
 	minfo->interleave = !(!isMillenium(minfo) || ((offs - 0x100000) & 0x3FFFFF));
-#endif
 	return 1;
 }
 
@@ -1331,7 +1330,6 @@ struct video_board {
 	int accelID;
 	struct matrox_switch* lowlevel;
 		 };
-#ifdef CONFIG_FB_MATROX_MILLENIUM
 static struct video_board vbMillennium = {
 	.maxvram = 0x0800000,
 	.maxdisplayable = 0x0800000,
@@ -1352,16 +1350,12 @@ static struct video_board vbMillennium2A = {
 	.accelID = FB_ACCEL_MATROX_MGA2164W_AGP,
 	.lowlevel = &matrox_millennium
 };
-#endif	/* CONFIG_FB_MATROX_MILLENIUM */
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
 static struct video_board vbMystique = {
 	.maxvram = 0x0800000,
 	.maxdisplayable = 0x0800000,
 	.accelID = FB_ACCEL_MATROX_MGA1064SG,
 	.lowlevel = &matrox_mystique
 };
-#endif	/* CONFIG_FB_MATROX_MYSTIQUE */
-#ifdef CONFIG_FB_MATROX_G
 static struct video_board vbG100 = {
 	.maxvram = 0x0800000,
 	.maxdisplayable = 0x0800000,
@@ -1383,7 +1377,6 @@ static struct video_board vbG400 = {
 	.accelID = FB_ACCEL_MATROX_MGAG400,
 	.lowlevel = &matrox_G100
 };
-#endif
 
 #define DEVF_VIDEO64BIT		0x0001
 #define	DEVF_SWAPS		0x0002
@@ -1418,7 +1411,6 @@ static struct board {
 	struct video_board* base;
 	const char* name;
 		} dev_list[] = {
-#ifdef CONFIG_FB_MATROX_MILLENIUM
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL,	0xFF,
 		0,			0,
 		DEVF_TEXT4B,
@@ -1440,8 +1432,6 @@ static struct board {
 		MGA_2164,
 		&vbMillennium2A,
 		"Millennium II (AGP)"},
-#endif
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MYS,	0x02,
 		0,			0,
 		DEVF_VIDEO64BIT | DEVF_CROSS4MB,
@@ -1470,8 +1460,6 @@ static struct board {
 		MGA_1164,
 		&vbMystique,
 		"Mystique 220 (AGP)"},
-#endif
-#ifdef CONFIG_FB_MATROX_G
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_MM,	0xFF,
 		0,			0,
 		DEVF_G100,
@@ -1563,7 +1551,6 @@ static struct board {
 		MGA_G550,
 		&vbG400,
 		"G550"},
-#endif
 	{0,			0,				0xFF,
 		0,			0,
 		0,
@@ -1622,6 +1609,7 @@ static int initMatrox2(struct matrox_fb_info *minfo, struct board *b)
 	unsigned long video_base_phys = 0;
 	unsigned int memsize;
 	int err;
+	struct mga_device *mdev;
 
 	static const struct pci_device_id intel_82437[] = {
 		{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437) },
@@ -1918,9 +1906,12 @@ static int initMatrox2(struct matrox_fb_info *minfo, struct board *b)
  * and we do not want currcon = 0 for subsequent framebuffers */
 
 	minfo->fbcon.device = &minfo->pcidev->dev;
-	if (register_framebuffer(&minfo->fbcon) < 0) {
+	mdev = mga_register_framebuffer(&minfo->fbcon, minfo->pcidev);
+	if (IS_ERR(mdev)) {
+		err = PTR_ERR(mdev);
 		goto failVideoIO;
 	}
+	minfo->mdev = mdev;
 	fb_info(&minfo->fbcon, "%s frame buffer device\n", minfo->fbcon.fix.id);
 
 	/* there is no console on this fb... but we have to initialize hardware
@@ -2116,19 +2107,14 @@ static void pci_remove_matrox(struct pci_dev* pdev) {
 }
 
 static const struct pci_device_id matroxfb_devices[] = {
-#ifdef CONFIG_FB_MATROX_MILLENIUM
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL,
 		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL_2,
 		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL_2_AGP,
 		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
-#endif
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MYS,
 		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
-#endif
-#ifdef CONFIG_FB_MATROX_G
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_MM,
 		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,
@@ -2141,7 +2127,6 @@ static const struct pci_device_id matroxfb_devices[] = {
 		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G550,
 		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
-#endif
 	{0,			0,
 		0,		0,		0, 0, 0}
 };
diff --git a/drivers/staging/mgakms/matroxfb_base.h b/drivers/staging/mgakms/matroxfb_base.h
index f85ad25659e5..f7548549b3a6 100644
--- a/drivers/staging/mgakms/matroxfb_base.h
+++ b/drivers/staging/mgakms/matroxfb_base.h
@@ -115,11 +115,7 @@
 
 #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
 
-/* G-series and Mystique have (almost) same DAC */
-#undef NEED_DAC1064
-#if defined(CONFIG_FB_MATROX_MYSTIQUE) || defined(CONFIG_FB_MATROX_G)
-#define NEED_DAC1064 1
-#endif
+struct mga_device;
 
 typedef struct {
 	void __iomem*	vaddr;
@@ -282,9 +278,7 @@ struct matrox_hw_state {
 };
 
 struct matrox_accel_data {
-#ifdef CONFIG_FB_MATROX_MILLENIUM
 	unsigned char	ramdac_rev;
-#endif
 	u_int32_t	m_dwg_rect;
 	u_int32_t	m_opmode;
 	u_int32_t	m_access;
@@ -302,9 +296,9 @@ struct matrox_altout {
 	int		(*verifymode)(void* altout_dev, u_int32_t mode);
 	int		(*getqueryctrl)(void* altout_dev,
 					struct v4l2_queryctrl* ctrl);
-	int		(*getctrl)(void* altout_dev, 
+	int		(*getctrl)(void* altout_dev,
 				   struct v4l2_control* ctrl);
-	int		(*setctrl)(void* altout_dev, 
+	int		(*setctrl)(void* altout_dev,
 				   struct v4l2_control* ctrl);
 };
 
@@ -338,6 +332,8 @@ struct matrox_vsync {
 struct matrox_fb_info {
 	struct fb_info		fbcon;
 
+	struct mga_device	*mdev;
+
 	struct list_head	next_fb;
 
 	int			dead;
@@ -676,15 +672,9 @@ void matroxfb_unregister_driver(struct matroxfb_driver* drv);
 #define WaitTillIdle()	do { mga_inl(M_STATUS); do {} while (mga_inl(M_STATUS) & 0x10000); } while (0)
 
 /* code speedup */
-#ifdef CONFIG_FB_MATROX_MILLENIUM
 #define isInterleave(x)	 (x->interleave)
 #define isMillenium(x)	 (x->millenium)
 #define isMilleniumII(x) (x->milleniumII)
-#else
-#define isInterleave(x)  (0)
-#define isMillenium(x)	 (0)
-#define isMilleniumII(x) (0)
-#endif
 
 #define matroxfb_DAC_lock()                   spin_lock(&minfo->lock.DAC)
 #define matroxfb_DAC_unlock()                 spin_unlock(&minfo->lock.DAC)
diff --git a/drivers/staging/mgakms/matroxfb_g450.h b/drivers/staging/mgakms/matroxfb_g450.h
index b5f17b86eae5..2cec778a2a81 100644
--- a/drivers/staging/mgakms/matroxfb_g450.h
+++ b/drivers/staging/mgakms/matroxfb_g450.h
@@ -4,12 +4,7 @@
 
 #include "matroxfb_base.h"
 
-#ifdef CONFIG_FB_MATROX_G
 void matroxfb_g450_connect(struct matrox_fb_info *minfo);
 void matroxfb_g450_shutdown(struct matrox_fb_info *minfo);
-#else
-static inline void matroxfb_g450_connect(struct matrox_fb_info *minfo) { };
-static inline void matroxfb_g450_shutdown(struct matrox_fb_info *minfo) { };
-#endif
 
 #endif /* __MATROXFB_G450_H__ */
-- 
2.23.0

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

* [PATCH v2 15/15] staging/mgakms: Update matroxfb driver code for DRM
@ 2019-10-14 14:04   ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-14 14:04 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel
  Cc: gregkh, linux-fbdev, Thomas Zimmermann, dri-devel, corbet

With the update, all driver code coming from matroxfb is build
unconditionally. The driver registers itself with the mgakms driver,
instead of the fbdev core.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/staging/mgakms/Kconfig            |  5 ++
 drivers/staging/mgakms/Makefile           | 11 ++++
 drivers/staging/mgakms/matroxfb_DAC1064.c | 77 +++++++----------------
 drivers/staging/mgakms/matroxfb_DAC1064.h |  6 --
 drivers/staging/mgakms/matroxfb_Ti3026.c  |  2 -
 drivers/staging/mgakms/matroxfb_Ti3026.h  |  2 -
 drivers/staging/mgakms/matroxfb_base.c    | 29 +++------
 drivers/staging/mgakms/matroxfb_base.h    | 20 ++----
 drivers/staging/mgakms/matroxfb_g450.h    |  5 --
 9 files changed, 51 insertions(+), 106 deletions(-)

diff --git a/drivers/staging/mgakms/Kconfig b/drivers/staging/mgakms/Kconfig
index de23e76317bd..66c5b3b8669f 100644
--- a/drivers/staging/mgakms/Kconfig
+++ b/drivers/staging/mgakms/Kconfig
@@ -4,6 +4,11 @@ config DRM_MGAKMS
 	select DRM_FBCONV_HELPER
 	select DRM_GEM_SHMEM_HELPER
 	select DRM_KMS_HELPER
+	select FB_CFB_COPYAREA
+	select FB_CFB_FILLRECT
+	select FB_CFB_IMAGEBLIT
+	select FB_MACMODES if PPC_PMAC
+	select FB_TILEBLITTING
 	help
 	  Choose this option if you have a Matrox Millennium,
 	  Matrox Millennium II, Matrox Mystique, Matrox Mystique 220,
diff --git a/drivers/staging/mgakms/Makefile b/drivers/staging/mgakms/Makefile
index 65695f04eb7f..b368f8a5e38a 100644
--- a/drivers/staging/mgakms/Makefile
+++ b/drivers/staging/mgakms/Makefile
@@ -3,4 +3,15 @@
 mgakms-y	:= mga_device.o \
 		   mga_drv.o
 
+# Old matroxfb driver code. Keep this separate and
+# remove it after conversion.
+mgakms-y	+= g450_pll.o \
+		   i2c-matroxfb.o \
+		   matroxfb_accel.o \
+		   matroxfb_base.o \
+		   matroxfb_DAC1064.o \
+		   matroxfb_g450.o \
+		   matroxfb_misc.o \
+		   matroxfb_Ti3026.o
+
 obj-$(CONFIG_DRM_MGAKMS)	+= mgakms.o
diff --git a/drivers/staging/mgakms/matroxfb_DAC1064.c b/drivers/staging/mgakms/matroxfb_DAC1064.c
index b380a393cbc3..6bb214c548af 100644
--- a/drivers/staging/mgakms/matroxfb_DAC1064.c
+++ b/drivers/staging/mgakms/matroxfb_DAC1064.c
@@ -19,7 +19,6 @@
 #include "g450_pll.h"
 #include <linux/matroxfb.h>
 
-#ifdef NEED_DAC1064
 #define outDAC1064 matroxfb_DAC_out
 #define inDAC1064 matroxfb_DAC_in
 
@@ -42,11 +41,11 @@ static void DAC1064_calcclock(const struct matrox_fb_info *minfo,
 	unsigned int p;
 
 	DBG(__func__)
-	
+
 	/* only for devices older than G450 */
 
 	fvco = PLL_calcclock(minfo, freq, fmax, in, feed, &p);
-	
+
 	p = (1 << p) - 1;
 	if (fvco <= 100000)
 		;
@@ -160,7 +159,6 @@ static void DAC1064_setmclk(struct matrox_fb_info *minfo, int oscinfo,
 	hw->MXoptionReg = mx;
 }
 
-#ifdef CONFIG_FB_MATROX_G
 static void g450_set_plls(struct matrox_fb_info *minfo)
 {
 	u_int32_t c2_ctl;
@@ -168,7 +166,7 @@ static void g450_set_plls(struct matrox_fb_info *minfo)
 	struct matrox_hw_state *hw = &minfo->hw;
 	int pixelmnp;
 	int videomnp;
-	
+
 	c2_ctl = hw->crtc2.ctl & ~0x4007;	/* Clear PLL + enable for CRTC2 */
 	c2_ctl |= 0x0001;			/* Enable CRTC2 */
 	hw->DACreg[POS1064_XPWRCTRL] &= ~0x02;	/* Stop VIDEO PLL */
@@ -191,7 +189,7 @@ static void g450_set_plls(struct matrox_fb_info *minfo)
 		}
 		c2_ctl |=  0x0006;	/* Use video PLL */
 		hw->DACreg[POS1064_XPWRCTRL] |= 0x02;
-		
+
 		outDAC1064(minfo, M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
 		matroxfb_g450_setpll_cond(minfo, videomnp, M_VIDEO_PLL);
 	}
@@ -199,7 +197,7 @@ static void g450_set_plls(struct matrox_fb_info *minfo)
 	hw->DACreg[POS1064_XPIXCLKCTRL] &= ~M1064_XPIXCLKCTRL_PLL_UP;
 	if (pixelmnp >= 0) {
 		hw->DACreg[POS1064_XPIXCLKCTRL] |= M1064_XPIXCLKCTRL_PLL_UP;
-		
+
 		outDAC1064(minfo, M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]);
 		matroxfb_g450_setpll_cond(minfo, pixelmnp, M_PIXEL_PLL_C);
 	}
@@ -251,7 +249,6 @@ static void g450_set_plls(struct matrox_fb_info *minfo)
 		}
 	}
 }
-#endif
 
 void DAC1064_global_init(struct matrox_fb_info *minfo)
 {
@@ -260,7 +257,6 @@ void DAC1064_global_init(struct matrox_fb_info *minfo)
 	hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK;
 	hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN;
 	hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL;
-#ifdef CONFIG_FB_MATROX_G
 	if (minfo->devflags.g450dac) {
 		hw->DACreg[POS1064_XPWRCTRL] = 0x1F;	/* powerup everything */
 		hw->DACreg[POS1064_XOUTPUTCONN] = 0x00;	/* disable outputs */
@@ -302,15 +298,14 @@ void DAC1064_global_init(struct matrox_fb_info *minfo)
 				   poweroff TMDS. But if we boot with DFP connected,
 				   TMDS generated clocks are used instead of ALL pixclocks
 				   available... If someone knows which register
-				   handles it, please reveal this secret to me... */			
+				   handles it, please reveal this secret to me... */
 				hw->DACreg[POS1064_XPWRCTRL] &= ~0x04;		/* Poweroff TMDS */
-#endif				
+#endif
 				break;
 		}
 		/* Now set timming related variables... */
 		g450_set_plls(minfo);
 	} else
-#endif
 	{
 		if (minfo->outputs[1].src == MATROXFB_SRC_CRTC1) {
 			hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT;
@@ -510,7 +505,6 @@ static struct matrox_altout m1064 = {
 	.compute = m1064_compute,
 };
 
-#ifdef CONFIG_FB_MATROX_G
 static int g450_compute(void* out, struct my_timming* m) {
 #define minfo ((struct matrox_fb_info*)out)
 	if (m->mnp < 0) {
@@ -527,11 +521,7 @@ static struct matrox_altout g450out = {
 	.name	 = "Primary output",
 	.compute = g450_compute,
 };
-#endif
 
-#endif /* NEED_DAC1064 */
-
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
 static int MGA1064_init(struct matrox_fb_info *minfo, struct my_timming *m)
 {
 	struct matrox_hw_state *hw = &minfo->hw;
@@ -552,9 +542,7 @@ static int MGA1064_init(struct matrox_fb_info *minfo, struct my_timming *m)
 	if (DAC1064_init_2(minfo, m)) return 1;
 	return 0;
 }
-#endif
 
-#ifdef CONFIG_FB_MATROX_G
 static int MGAG100_init(struct matrox_fb_info *minfo, struct my_timming *m)
 {
 	struct matrox_hw_state *hw = &minfo->hw;
@@ -576,9 +564,7 @@ static int MGAG100_init(struct matrox_fb_info *minfo, struct my_timming *m)
 	if (DAC1064_init_2(minfo, m)) return 1;
 	return 0;
 }
-#endif	/* G */
 
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
 static void MGA1064_ramdac_init(struct matrox_fb_info *minfo)
 {
 
@@ -596,9 +582,7 @@ static void MGA1064_ramdac_init(struct matrox_fb_info *minfo)
 	/* maybe cmdline MCLK= ?, doc says gclk=44MHz, mclk=66MHz... it was 55/83 with old values */
 	DAC1064_setmclk(minfo, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333);
 }
-#endif
 
-#ifdef CONFIG_FB_MATROX_G
 /* BIOS environ */
 static int x7AF4 = 0x10;	/* flags, maybe 0x10 = SDRAM, 0x00 = SGRAM??? */
 				/* G100 wants 0x10, G200 SGRAM does not care... */
@@ -662,9 +646,7 @@ static void MGAG100_setPixClock(const struct matrox_fb_info *minfo, int flags,
 	DAC1064_calcclock(minfo, freq, minfo->max_pixel_clock, &m, &n, &p);
 	MGAG100_progPixClock(minfo, flags, m, n, p);
 }
-#endif
 
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
 static int MGA1064_preinit(struct matrox_fb_info *minfo)
 {
 	static const int vxres_mystique[] = { 512,        640, 768,  800,  832,  960,
@@ -710,9 +692,7 @@ static void MGA1064_reset(struct matrox_fb_info *minfo)
 
 	MGA1064_ramdac_init(minfo);
 }
-#endif
 
-#ifdef CONFIG_FB_MATROX_G
 static void g450_mclk_init(struct matrox_fb_info *minfo)
 {
 	/* switch all clocks to PCI source */
@@ -727,14 +707,14 @@ static void g450_mclk_init(struct matrox_fb_info *minfo)
 	} else {
 		unsigned long flags;
 		unsigned int pwr;
-		
+
 		matroxfb_DAC_lock_irqsave(flags);
 		pwr = inDAC1064(minfo, M1064_XPWRCTRL) & ~0x02;
 		outDAC1064(minfo, M1064_XPWRCTRL, pwr);
 		matroxfb_DAC_unlock_irqrestore(flags);
 	}
 	matroxfb_g450_setclk(minfo, minfo->values.pll.system, M_SYSTEM_PLL);
-	
+
 	/* switch clocks to their real PLL source(s) */
 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg | 4);
 	pci_write_config_dword(minfo->pcidev, PCI_OPTION3_REG, minfo->values.reg.opt3);
@@ -747,15 +727,15 @@ static void g450_memory_init(struct matrox_fb_info *minfo)
 	/* disable memory refresh */
 	minfo->hw.MXoptionReg &= ~0x001F8000;
 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
-	
+
 	/* set memory interface parameters */
 	minfo->hw.MXoptionReg &= ~0x00207E00;
 	minfo->hw.MXoptionReg |= 0x00207E00 & minfo->values.reg.opt;
 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
 	pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, minfo->values.reg.opt2);
-	
+
 	mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst);
-	
+
 	/* first set up memory interface with disabled memory interface clocks */
 	pci_write_config_dword(minfo->pcidev, PCI_MEMMISC_REG, minfo->values.reg.memmisc & ~0x80000000U);
 	mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk);
@@ -764,25 +744,25 @@ static void g450_memory_init(struct matrox_fb_info *minfo)
 	pci_write_config_dword(minfo->pcidev, PCI_MEMMISC_REG, minfo->values.reg.memmisc | 0x80000000U);
 
 	udelay(200);
-	
+
 	if (minfo->values.memory.ddr && (!minfo->values.memory.emrswen || !minfo->values.memory.dll)) {
 		mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk & ~0x1000);
 	}
 	mga_outl(M_MACCESS, minfo->values.reg.maccess | 0x8000);
-	
+
 	udelay(200);
-	
+
 	minfo->hw.MXoptionReg |= 0x001F8000 & minfo->values.reg.opt;
 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
-	
+
 	/* value is written to memory chips only if old != new */
 	mga_outl(M_PLNWT, 0);
 	mga_outl(M_PLNWT, ~0);
-	
+
 	if (minfo->values.reg.mctlwtst != minfo->values.reg.mctlwtst_core) {
 		mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst_core);
 	}
-	
+
 }
 
 static void g450_preinit(struct matrox_fb_info *minfo)
@@ -790,7 +770,7 @@ static void g450_preinit(struct matrox_fb_info *minfo)
 	u_int32_t c2ctl;
 	u_int8_t curctl;
 	u_int8_t c1ctl;
-	
+
 	/* minfo->hw.MXoptionReg = minfo->values.reg.opt; */
 	minfo->hw.MXoptionReg &= 0xC0000100;
 	minfo->hw.MXoptionReg |= 0x00000020;
@@ -804,7 +784,7 @@ static void g450_preinit(struct matrox_fb_info *minfo)
 	pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg);
 
 	/* Init system clocks */
-		
+
 	/* stop crtc2 */
 	c2ctl = mga_inl(M_C2CTL);
 	mga_outl(M_C2CTL, c2ctl & ~1);
@@ -817,20 +797,20 @@ static void g450_preinit(struct matrox_fb_info *minfo)
 
 	g450_mclk_init(minfo);
 	g450_memory_init(minfo);
-	
+
 	/* set legacy VGA clock sources for DOSEmu or VMware... */
 	matroxfb_g450_setclk(minfo, 25175, M_PIXEL_PLL_A);
 	matroxfb_g450_setclk(minfo, 28322, M_PIXEL_PLL_B);
 
 	/* restore crtc1 */
 	mga_setr(M_SEQ_INDEX, 1, c1ctl);
-	
+
 	/* restore cursor */
 	outDAC1064(minfo, M1064_XCURCTRL, curctl);
 
 	/* restore crtc2 */
 	mga_outl(M_C2CTL, c2ctl);
-	
+
 	return;
 }
 
@@ -1031,9 +1011,7 @@ static void MGAG100_reset(struct matrox_fb_info *minfo)
 		}
 	}
 }
-#endif
 
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
 static void MGA1064_restore(struct matrox_fb_info *minfo)
 {
 	int i;
@@ -1058,9 +1036,7 @@ static void MGA1064_restore(struct matrox_fb_info *minfo)
 		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
 	DAC1064_restore_2(minfo);
 }
-#endif
 
-#ifdef CONFIG_FB_MATROX_G
 static void MGAG100_restore(struct matrox_fb_info *minfo)
 {
 	int i;
@@ -1084,9 +1060,7 @@ static void MGAG100_restore(struct matrox_fb_info *minfo)
 		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
 	DAC1064_restore_2(minfo);
 }
-#endif
 
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
 struct matrox_switch matrox_mystique = {
 	.preinit	= MGA1064_preinit,
 	.reset		= MGA1064_reset,
@@ -1094,9 +1068,7 @@ struct matrox_switch matrox_mystique = {
 	.restore	= MGA1064_restore,
 };
 EXPORT_SYMBOL(matrox_mystique);
-#endif
 
-#ifdef CONFIG_FB_MATROX_G
 struct matrox_switch matrox_G100 = {
 	.preinit	= MGAG100_preinit,
 	.reset		= MGAG100_reset,
@@ -1104,10 +1076,7 @@ struct matrox_switch matrox_G100 = {
 	.restore	= MGAG100_restore,
 };
 EXPORT_SYMBOL(matrox_G100);
-#endif
 
-#ifdef NEED_DAC1064
 EXPORT_SYMBOL(DAC1064_global_init);
 EXPORT_SYMBOL(DAC1064_global_restore);
-#endif
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/mgakms/matroxfb_DAC1064.h b/drivers/staging/mgakms/matroxfb_DAC1064.h
index 3b2a6fd35fff..3d388941b51d 100644
--- a/drivers/staging/mgakms/matroxfb_DAC1064.h
+++ b/drivers/staging/mgakms/matroxfb_DAC1064.h
@@ -5,16 +5,10 @@
 
 #include "matroxfb_base.h"
 
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
 extern struct matrox_switch matrox_mystique;
-#endif
-#ifdef CONFIG_FB_MATROX_G
 extern struct matrox_switch matrox_G100;
-#endif
-#ifdef NEED_DAC1064
 void DAC1064_global_init(struct matrox_fb_info *minfo);
 void DAC1064_global_restore(struct matrox_fb_info *minfo);
-#endif
 
 #define M1064_INDEX	0x00
 #define M1064_PALWRADD	0x00
diff --git a/drivers/staging/mgakms/matroxfb_Ti3026.c b/drivers/staging/mgakms/matroxfb_Ti3026.c
index 9ff9be85759e..e82e2a3cf76a 100644
--- a/drivers/staging/mgakms/matroxfb_Ti3026.c
+++ b/drivers/staging/mgakms/matroxfb_Ti3026.c
@@ -84,7 +84,6 @@
 #include "matroxfb_accel.h"
 #include <linux/matroxfb.h>
 
-#ifdef CONFIG_FB_MATROX_MILLENIUM
 #define outTi3026 matroxfb_DAC_out
 #define inTi3026 matroxfb_DAC_in
 
@@ -744,5 +743,4 @@ struct matrox_switch matrox_millennium = {
 	.restore	= Ti3026_restore
 };
 EXPORT_SYMBOL(matrox_millennium);
-#endif
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/mgakms/matroxfb_Ti3026.h b/drivers/staging/mgakms/matroxfb_Ti3026.h
index faee149d0ba0..2fda3b30b9e7 100644
--- a/drivers/staging/mgakms/matroxfb_Ti3026.h
+++ b/drivers/staging/mgakms/matroxfb_Ti3026.h
@@ -5,8 +5,6 @@
 
 #include "matroxfb_base.h"
 
-#ifdef CONFIG_FB_MATROX_MILLENIUM
 extern struct matrox_switch matrox_millennium;
-#endif
 
 #endif	/* __MATROXFB_TI3026_H__ */
diff --git a/drivers/staging/mgakms/matroxfb_base.c b/drivers/staging/mgakms/matroxfb_base.c
index d11b5e6210ed..7ee0ea046a5f 100644
--- a/drivers/staging/mgakms/matroxfb_base.c
+++ b/drivers/staging/mgakms/matroxfb_base.c
@@ -114,6 +114,7 @@
 #include <linux/nvram.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
+#include "mga_drv.h"
 
 #ifdef CONFIG_PPC_PMAC
 #include <asm/machdep.h>
@@ -368,7 +369,7 @@ static void matroxfb_remove(struct matrox_fb_info *minfo, int dummy)
 		return;
 	}
 	matroxfb_unregister_device(minfo);
-	unregister_framebuffer(&minfo->fbcon);
+	mga_unregister_framebuffer(minfo->mdev);
 	matroxfb_g450_shutdown(minfo);
 	arch_phys_wc_del(minfo->wc_cookie);
 	iounmap(minfo->mmio.vbase.vaddr);
@@ -1319,9 +1320,7 @@ static int matroxfb_getmemory(struct matrox_fb_info *minfo,
 	mga_outb(M_EXTVGA_DATA, orig);
 
 	*realSize = offs - 0x100000;
-#ifdef CONFIG_FB_MATROX_MILLENIUM
 	minfo->interleave = !(!isMillenium(minfo) || ((offs - 0x100000) & 0x3FFFFF));
-#endif
 	return 1;
 }
 
@@ -1331,7 +1330,6 @@ struct video_board {
 	int accelID;
 	struct matrox_switch* lowlevel;
 		 };
-#ifdef CONFIG_FB_MATROX_MILLENIUM
 static struct video_board vbMillennium = {
 	.maxvram = 0x0800000,
 	.maxdisplayable = 0x0800000,
@@ -1352,16 +1350,12 @@ static struct video_board vbMillennium2A = {
 	.accelID = FB_ACCEL_MATROX_MGA2164W_AGP,
 	.lowlevel = &matrox_millennium
 };
-#endif	/* CONFIG_FB_MATROX_MILLENIUM */
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
 static struct video_board vbMystique = {
 	.maxvram = 0x0800000,
 	.maxdisplayable = 0x0800000,
 	.accelID = FB_ACCEL_MATROX_MGA1064SG,
 	.lowlevel = &matrox_mystique
 };
-#endif	/* CONFIG_FB_MATROX_MYSTIQUE */
-#ifdef CONFIG_FB_MATROX_G
 static struct video_board vbG100 = {
 	.maxvram = 0x0800000,
 	.maxdisplayable = 0x0800000,
@@ -1383,7 +1377,6 @@ static struct video_board vbG400 = {
 	.accelID = FB_ACCEL_MATROX_MGAG400,
 	.lowlevel = &matrox_G100
 };
-#endif
 
 #define DEVF_VIDEO64BIT		0x0001
 #define	DEVF_SWAPS		0x0002
@@ -1418,7 +1411,6 @@ static struct board {
 	struct video_board* base;
 	const char* name;
 		} dev_list[] = {
-#ifdef CONFIG_FB_MATROX_MILLENIUM
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL,	0xFF,
 		0,			0,
 		DEVF_TEXT4B,
@@ -1440,8 +1432,6 @@ static struct board {
 		MGA_2164,
 		&vbMillennium2A,
 		"Millennium II (AGP)"},
-#endif
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MYS,	0x02,
 		0,			0,
 		DEVF_VIDEO64BIT | DEVF_CROSS4MB,
@@ -1470,8 +1460,6 @@ static struct board {
 		MGA_1164,
 		&vbMystique,
 		"Mystique 220 (AGP)"},
-#endif
-#ifdef CONFIG_FB_MATROX_G
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_MM,	0xFF,
 		0,			0,
 		DEVF_G100,
@@ -1563,7 +1551,6 @@ static struct board {
 		MGA_G550,
 		&vbG400,
 		"G550"},
-#endif
 	{0,			0,				0xFF,
 		0,			0,
 		0,
@@ -1622,6 +1609,7 @@ static int initMatrox2(struct matrox_fb_info *minfo, struct board *b)
 	unsigned long video_base_phys = 0;
 	unsigned int memsize;
 	int err;
+	struct mga_device *mdev;
 
 	static const struct pci_device_id intel_82437[] = {
 		{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437) },
@@ -1918,9 +1906,12 @@ static int initMatrox2(struct matrox_fb_info *minfo, struct board *b)
  * and we do not want currcon == 0 for subsequent framebuffers */
 
 	minfo->fbcon.device = &minfo->pcidev->dev;
-	if (register_framebuffer(&minfo->fbcon) < 0) {
+	mdev = mga_register_framebuffer(&minfo->fbcon, minfo->pcidev);
+	if (IS_ERR(mdev)) {
+		err = PTR_ERR(mdev);
 		goto failVideoIO;
 	}
+	minfo->mdev = mdev;
 	fb_info(&minfo->fbcon, "%s frame buffer device\n", minfo->fbcon.fix.id);
 
 	/* there is no console on this fb... but we have to initialize hardware
@@ -2116,19 +2107,14 @@ static void pci_remove_matrox(struct pci_dev* pdev) {
 }
 
 static const struct pci_device_id matroxfb_devices[] = {
-#ifdef CONFIG_FB_MATROX_MILLENIUM
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL,
 		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL_2,
 		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MIL_2_AGP,
 		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
-#endif
-#ifdef CONFIG_FB_MATROX_MYSTIQUE
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_MYS,
 		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
-#endif
-#ifdef CONFIG_FB_MATROX_G
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_MM,
 		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,
@@ -2141,7 +2127,6 @@ static const struct pci_device_id matroxfb_devices[] = {
 		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G550,
 		PCI_ANY_ID,	PCI_ANY_ID,	0, 0, 0},
-#endif
 	{0,			0,
 		0,		0,		0, 0, 0}
 };
diff --git a/drivers/staging/mgakms/matroxfb_base.h b/drivers/staging/mgakms/matroxfb_base.h
index f85ad25659e5..f7548549b3a6 100644
--- a/drivers/staging/mgakms/matroxfb_base.h
+++ b/drivers/staging/mgakms/matroxfb_base.h
@@ -115,11 +115,7 @@
 
 #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
 
-/* G-series and Mystique have (almost) same DAC */
-#undef NEED_DAC1064
-#if defined(CONFIG_FB_MATROX_MYSTIQUE) || defined(CONFIG_FB_MATROX_G)
-#define NEED_DAC1064 1
-#endif
+struct mga_device;
 
 typedef struct {
 	void __iomem*	vaddr;
@@ -282,9 +278,7 @@ struct matrox_hw_state {
 };
 
 struct matrox_accel_data {
-#ifdef CONFIG_FB_MATROX_MILLENIUM
 	unsigned char	ramdac_rev;
-#endif
 	u_int32_t	m_dwg_rect;
 	u_int32_t	m_opmode;
 	u_int32_t	m_access;
@@ -302,9 +296,9 @@ struct matrox_altout {
 	int		(*verifymode)(void* altout_dev, u_int32_t mode);
 	int		(*getqueryctrl)(void* altout_dev,
 					struct v4l2_queryctrl* ctrl);
-	int		(*getctrl)(void* altout_dev, 
+	int		(*getctrl)(void* altout_dev,
 				   struct v4l2_control* ctrl);
-	int		(*setctrl)(void* altout_dev, 
+	int		(*setctrl)(void* altout_dev,
 				   struct v4l2_control* ctrl);
 };
 
@@ -338,6 +332,8 @@ struct matrox_vsync {
 struct matrox_fb_info {
 	struct fb_info		fbcon;
 
+	struct mga_device	*mdev;
+
 	struct list_head	next_fb;
 
 	int			dead;
@@ -676,15 +672,9 @@ void matroxfb_unregister_driver(struct matroxfb_driver* drv);
 #define WaitTillIdle()	do { mga_inl(M_STATUS); do {} while (mga_inl(M_STATUS) & 0x10000); } while (0)
 
 /* code speedup */
-#ifdef CONFIG_FB_MATROX_MILLENIUM
 #define isInterleave(x)	 (x->interleave)
 #define isMillenium(x)	 (x->millenium)
 #define isMilleniumII(x) (x->milleniumII)
-#else
-#define isInterleave(x)  (0)
-#define isMillenium(x)	 (0)
-#define isMilleniumII(x) (0)
-#endif
 
 #define matroxfb_DAC_lock()                   spin_lock(&minfo->lock.DAC)
 #define matroxfb_DAC_unlock()                 spin_unlock(&minfo->lock.DAC)
diff --git a/drivers/staging/mgakms/matroxfb_g450.h b/drivers/staging/mgakms/matroxfb_g450.h
index b5f17b86eae5..2cec778a2a81 100644
--- a/drivers/staging/mgakms/matroxfb_g450.h
+++ b/drivers/staging/mgakms/matroxfb_g450.h
@@ -4,12 +4,7 @@
 
 #include "matroxfb_base.h"
 
-#ifdef CONFIG_FB_MATROX_G
 void matroxfb_g450_connect(struct matrox_fb_info *minfo);
 void matroxfb_g450_shutdown(struct matrox_fb_info *minfo);
-#else
-static inline void matroxfb_g450_connect(struct matrox_fb_info *minfo) { };
-static inline void matroxfb_g450_shutdown(struct matrox_fb_info *minfo) { };
-#endif
 
 #endif /* __MATROXFB_G450_H__ */
-- 
2.23.0

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

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

* Re: [PATCH v2 05/15] drm/fbconv: Add DRM <-> fbdev pixel-format conversion
  2019-10-14 14:04   ` Thomas Zimmermann
@ 2019-10-14 20:30     ` Sam Ravnborg
  -1 siblings, 0 replies; 77+ messages in thread
From: Sam Ravnborg @ 2019-10-14 20:30 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: linux-fbdev, b.zolnierkie, airlied, gregkh, michel, corbet,
	malat, dri-devel, sean

Hi Thomas.

On Mon, Oct 14, 2019 at 04:04:06PM +0200, Thomas Zimmermann wrote:
> DRM uses FOURCC constants to describe pixel formats, fbdev uses a
> per-component bitfield structure. The functions in this patch convert
> between the two.
> 

A few nits below.


> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
>  drivers/gpu/drm/drm_fbconv_helper.c | 435 ++++++++++++++++++++++++++++
>  include/drm/drm_fbconv_helper.h     |  23 ++
>  2 files changed, 458 insertions(+)
>  create mode 100644 include/drm/drm_fbconv_helper.h
> 
> diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
> index 0cb46d2c98c3..af45358a156a 100644
> --- a/drivers/gpu/drm/drm_fbconv_helper.c
> +++ b/drivers/gpu/drm/drm_fbconv_helper.c
> @@ -1 +1,436 @@
>  // SPDX-License-Identifier: GPL-2.0-or-later
> +
> +#include <asm/byteorder.h>
> +
> +#include <linux/fb.h>

<asm/*> after <linux/*>
So we in this way pick the more general include file first.

> +
> +struct format_map {
> +	bool (*is_format)(const struct fb_var_screeninfo *fb_var);
> +	uint32_t format;
> +};
We are in the kernel - where I think u32 is preferred over the longer
uint32_t.
If I grep in drm/* then they seems be be equally popular, so feel free
to ignore this comment.


> +static void set_fb_bitfield(struct fb_bitfield *bits, __u32 offset,
> +			    __u32 length)

This is not uapi - so u32 is preferred.

Both comments apply to the whole file.

I did not see that this was wired into the kernel-doc in Documentation/
but maybe I just missed it.

With my comments considered you can add:
Acked-by: Sam Ravnborg <sam@ravnborg.org>

All code looks sane, but as I have not grasped the bigger picture
this can hardly be a review.

	Sam

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

* Re: [PATCH v2 05/15] drm/fbconv: Add DRM <-> fbdev pixel-format conversion
@ 2019-10-14 20:30     ` Sam Ravnborg
  0 siblings, 0 replies; 77+ messages in thread
From: Sam Ravnborg @ 2019-10-14 20:30 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: linux-fbdev, b.zolnierkie, airlied, gregkh, michel, corbet,
	malat, dri-devel, sean

Hi Thomas.

On Mon, Oct 14, 2019 at 04:04:06PM +0200, Thomas Zimmermann wrote:
> DRM uses FOURCC constants to describe pixel formats, fbdev uses a
> per-component bitfield structure. The functions in this patch convert
> between the two.
> 

A few nits below.


> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
>  drivers/gpu/drm/drm_fbconv_helper.c | 435 ++++++++++++++++++++++++++++
>  include/drm/drm_fbconv_helper.h     |  23 ++
>  2 files changed, 458 insertions(+)
>  create mode 100644 include/drm/drm_fbconv_helper.h
> 
> diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
> index 0cb46d2c98c3..af45358a156a 100644
> --- a/drivers/gpu/drm/drm_fbconv_helper.c
> +++ b/drivers/gpu/drm/drm_fbconv_helper.c
> @@ -1 +1,436 @@
>  // SPDX-License-Identifier: GPL-2.0-or-later
> +
> +#include <asm/byteorder.h>
> +
> +#include <linux/fb.h>

<asm/*> after <linux/*>
So we in this way pick the more general include file first.

> +
> +struct format_map {
> +	bool (*is_format)(const struct fb_var_screeninfo *fb_var);
> +	uint32_t format;
> +};
We are in the kernel - where I think u32 is preferred over the longer
uint32_t.
If I grep in drm/* then they seems be be equally popular, so feel free
to ignore this comment.


> +static void set_fb_bitfield(struct fb_bitfield *bits, __u32 offset,
> +			    __u32 length)

This is not uapi - so u32 is preferred.

Both comments apply to the whole file.

I did not see that this was wired into the kernel-doc in Documentation/
but maybe I just missed it.

With my comments considered you can add:
Acked-by: Sam Ravnborg <sam@ravnborg.org>

All code looks sane, but as I have not grasped the bigger picture
this can hardly be a review.

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

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

* Re: [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers
  2019-10-14 14:04 ` Thomas Zimmermann
@ 2019-10-14 20:36   ` Sam Ravnborg
  -1 siblings, 0 replies; 77+ messages in thread
From: Sam Ravnborg @ 2019-10-14 20:36 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: linux-fbdev, b.zolnierkie, airlied, gregkh, michel, corbet,
	malat, dri-devel, sean

Hi Thomas.

On Mon, Oct 14, 2019 at 04:04:01PM +0200, Thomas Zimmermann wrote:
> (was: DRM driver for fbdev devices)
> 
> This is version 2 of the fbdev conversion helpers. It's more or less a
> rewrite of the original patchset.
> 
> The fbdev subsystem is considered legacy and will probably be removed at
> some point. This would mean the loss of a signifanct number of drivers.
> Some of the affected hardware is not in use any longer, but some hardware
> is still around and provides good(-enough) framebuffers.
> 
> The fbconv helpers allow for running the current DRM stack on top of fbdev
> drivers. It's a set of functions that convert between fbdev interfaces and
> DRM interfaces. Based on SHMEM and simple KMS helpers, it only offers the
> basic functionality of a framebuffer, but should be compatible with most
> existing fbdev drivers.
> 
> A DRM driver using fbconv helpers consists of
> 
>   * DRM stub code that calls into fbconv helpers, and
>   * the original fbdev driver code.
> 
> The fbdev driver code has to be modified to register itself with the
> stub driver instead of the fbdev core framework. A tutorial on how to use
> the helpers is part of this patchset. The resulting driver hybrid can be
> refactored into a first-class DRM driver. The fbconv helpers contain a
> number of comments, labeled 'DRM porting note', which explain the required
> steps.
> 
> I tested the current patchset with the following drivers: atyfb, aty128fb,
> matroxfb, pm2fb, pm3fb, rivafb, s3fb, savagefb, sisfb, tdfxfb and tridentfb.
> With each, I was able to successfully start with fbcon enabled, run weston and
> X11. The drivers are available at [1]. For reference, the patchset includes
> the Matrox stub driver.

In general I like the idea of modernizing the existing fbdev drivers.
What I fail to read in your intro above is if this allows us to phase
out the migrated fbdev drivers sooner?
Or do we end up with two drivers to maintain?

Obviously a full migration to a DRM driver was preferred - but this may
serve as a step in that direction.
But we should not end up with two drivers doing almost the same.

Another general question. Do we want the modernized DRM drivers to end
up in staging? Why should they not go direct into drm/*
I know they are not fully atomic but this is not new drivers so maybe
they can be excused.
Problem is that drm drivers in staging live a secret nonvisible life
where they are easy to forget when we change interfaces and such.

	Sam

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

* Re: [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers
@ 2019-10-14 20:36   ` Sam Ravnborg
  0 siblings, 0 replies; 77+ messages in thread
From: Sam Ravnborg @ 2019-10-14 20:36 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: linux-fbdev, b.zolnierkie, airlied, gregkh, michel, corbet,
	malat, dri-devel, sean

Hi Thomas.

On Mon, Oct 14, 2019 at 04:04:01PM +0200, Thomas Zimmermann wrote:
> (was: DRM driver for fbdev devices)
> 
> This is version 2 of the fbdev conversion helpers. It's more or less a
> rewrite of the original patchset.
> 
> The fbdev subsystem is considered legacy and will probably be removed at
> some point. This would mean the loss of a signifanct number of drivers.
> Some of the affected hardware is not in use any longer, but some hardware
> is still around and provides good(-enough) framebuffers.
> 
> The fbconv helpers allow for running the current DRM stack on top of fbdev
> drivers. It's a set of functions that convert between fbdev interfaces and
> DRM interfaces. Based on SHMEM and simple KMS helpers, it only offers the
> basic functionality of a framebuffer, but should be compatible with most
> existing fbdev drivers.
> 
> A DRM driver using fbconv helpers consists of
> 
>   * DRM stub code that calls into fbconv helpers, and
>   * the original fbdev driver code.
> 
> The fbdev driver code has to be modified to register itself with the
> stub driver instead of the fbdev core framework. A tutorial on how to use
> the helpers is part of this patchset. The resulting driver hybrid can be
> refactored into a first-class DRM driver. The fbconv helpers contain a
> number of comments, labeled 'DRM porting note', which explain the required
> steps.
> 
> I tested the current patchset with the following drivers: atyfb, aty128fb,
> matroxfb, pm2fb, pm3fb, rivafb, s3fb, savagefb, sisfb, tdfxfb and tridentfb.
> With each, I was able to successfully start with fbcon enabled, run weston and
> X11. The drivers are available at [1]. For reference, the patchset includes
> the Matrox stub driver.

In general I like the idea of modernizing the existing fbdev drivers.
What I fail to read in your intro above is if this allows us to phase
out the migrated fbdev drivers sooner?
Or do we end up with two drivers to maintain?

Obviously a full migration to a DRM driver was preferred - but this may
serve as a step in that direction.
But we should not end up with two drivers doing almost the same.

Another general question. Do we want the modernized DRM drivers to end
up in staging? Why should they not go direct into drm/*
I know they are not fully atomic but this is not new drivers so maybe
they can be excused.
Problem is that drm drivers in staging live a secret nonvisible life
where they are easy to forget when we change interfaces and such.

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

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

* Re: [PATCH v2 05/15] drm/fbconv: Add DRM <-> fbdev pixel-format conversion
  2019-10-14 20:30     ` Sam Ravnborg
@ 2019-10-15  5:48       ` Thomas Zimmermann
  -1 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-15  5:48 UTC (permalink / raw)
  To: Sam Ravnborg
  Cc: linux-fbdev, corbet, airlied, gregkh, michel, b.zolnierkie,
	dri-devel, malat, sean

Hi

Am 14.10.19 um 22:30 schrieb Sam Ravnborg:
> Hi Thomas.
> 
> On Mon, Oct 14, 2019 at 04:04:06PM +0200, Thomas Zimmermann wrote:
>> DRM uses FOURCC constants to describe pixel formats, fbdev uses a
>> per-component bitfield structure. The functions in this patch convert
>> between the two.
>>
> 
> A few nits below.
> 
> 
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> ---
>>   drivers/gpu/drm/drm_fbconv_helper.c | 435 ++++++++++++++++++++++++++++
>>   include/drm/drm_fbconv_helper.h     |  23 ++
>>   2 files changed, 458 insertions(+)
>>   create mode 100644 include/drm/drm_fbconv_helper.h
>>
>> diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
>> index 0cb46d2c98c3..af45358a156a 100644
>> --- a/drivers/gpu/drm/drm_fbconv_helper.c
>> +++ b/drivers/gpu/drm/drm_fbconv_helper.c
>> @@ -1 +1,436 @@
>>   // SPDX-License-Identifier: GPL-2.0-or-later
>> +
>> +#include <asm/byteorder.h>
>> +
>> +#include <linux/fb.h>
> 
> <asm/*> after <linux/*>
> So we in this way pick the more general include file first.

Ok.

>> +
>> +struct format_map {
>> +	bool (*is_format)(const struct fb_var_screeninfo *fb_var);
>> +	uint32_t format;
>> +};
> We are in the kernel - where I think u32 is preferred over the longer
> uint32_t.
> If I grep in drm/* then they seems be be equally popular, so feel free
> to ignore this comment.

I generally use types that are used by related interfaces. Here it's 
uint32_t because most other places use uint32_t for storing DRM_FORMAT 
constants.

> 
>> +static void set_fb_bitfield(struct fb_bitfield *bits, __u32 offset,
>> +			    __u32 length)
> 
> This is not uapi - so u32 is preferred.

Same as above. The __u32 comes from the fb_bitfield structure.

Best regards
Thomas

> Both comments apply to the whole file.
> 
> I did not see that this was wired into the kernel-doc in Documentation/
> but maybe I just missed it.
> 
> With my comments considered you can add:
> Acked-by: Sam Ravnborg <sam@ravnborg.org>
> 
> All code looks sane, but as I have not grasped the bigger picture
> this can hardly be a review.
> 
> 	Sam
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Linux GmbH, Maxfeldstrasse 5, 90409 Nuernberg, Germany
GF: Felix Imendörffer, Mary Higgins, Sri Rasiah
HRB 21284 (AG Nürnberg)

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

* Re: [PATCH v2 05/15] drm/fbconv: Add DRM <-> fbdev pixel-format conversion
@ 2019-10-15  5:48       ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-15  5:48 UTC (permalink / raw)
  To: Sam Ravnborg
  Cc: linux-fbdev, corbet, airlied, gregkh, michel, b.zolnierkie,
	dri-devel, malat, sean

Hi

Am 14.10.19 um 22:30 schrieb Sam Ravnborg:
> Hi Thomas.
> 
> On Mon, Oct 14, 2019 at 04:04:06PM +0200, Thomas Zimmermann wrote:
>> DRM uses FOURCC constants to describe pixel formats, fbdev uses a
>> per-component bitfield structure. The functions in this patch convert
>> between the two.
>>
> 
> A few nits below.
> 
> 
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> ---
>>   drivers/gpu/drm/drm_fbconv_helper.c | 435 ++++++++++++++++++++++++++++
>>   include/drm/drm_fbconv_helper.h     |  23 ++
>>   2 files changed, 458 insertions(+)
>>   create mode 100644 include/drm/drm_fbconv_helper.h
>>
>> diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
>> index 0cb46d2c98c3..af45358a156a 100644
>> --- a/drivers/gpu/drm/drm_fbconv_helper.c
>> +++ b/drivers/gpu/drm/drm_fbconv_helper.c
>> @@ -1 +1,436 @@
>>   // SPDX-License-Identifier: GPL-2.0-or-later
>> +
>> +#include <asm/byteorder.h>
>> +
>> +#include <linux/fb.h>
> 
> <asm/*> after <linux/*>
> So we in this way pick the more general include file first.

Ok.

>> +
>> +struct format_map {
>> +	bool (*is_format)(const struct fb_var_screeninfo *fb_var);
>> +	uint32_t format;
>> +};
> We are in the kernel - where I think u32 is preferred over the longer
> uint32_t.
> If I grep in drm/* then they seems be be equally popular, so feel free
> to ignore this comment.

I generally use types that are used by related interfaces. Here it's 
uint32_t because most other places use uint32_t for storing DRM_FORMAT 
constants.

> 
>> +static void set_fb_bitfield(struct fb_bitfield *bits, __u32 offset,
>> +			    __u32 length)
> 
> This is not uapi - so u32 is preferred.

Same as above. The __u32 comes from the fb_bitfield structure.

Best regards
Thomas

> Both comments apply to the whole file.
> 
> I did not see that this was wired into the kernel-doc in Documentation/
> but maybe I just missed it.
> 
> With my comments considered you can add:
> Acked-by: Sam Ravnborg <sam@ravnborg.org>
> 
> All code looks sane, but as I have not grasped the bigger picture
> this can hardly be a review.
> 
> 	Sam
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Linux GmbH, Maxfeldstrasse 5, 90409 Nuernberg, Germany
GF: Felix Imendörffer, Mary Higgins, Sri Rasiah
HRB 21284 (AG Nürnberg)
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers
  2019-10-14 20:36   ` Sam Ravnborg
@ 2019-10-15  6:11     ` Thomas Zimmermann
  -1 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-15  6:11 UTC (permalink / raw)
  To: Sam Ravnborg
  Cc: linux-fbdev, corbet, airlied, gregkh, michel, b.zolnierkie,
	dri-devel, malat, sean

Hi

Am 14.10.19 um 22:36 schrieb Sam Ravnborg:
> Hi Thomas.
> 
> On Mon, Oct 14, 2019 at 04:04:01PM +0200, Thomas Zimmermann wrote:
>> (was: DRM driver for fbdev devices)
>>
>> This is version 2 of the fbdev conversion helpers. It's more or less a
>> rewrite of the original patchset.
>>
>> The fbdev subsystem is considered legacy and will probably be removed at
>> some point. This would mean the loss of a signifanct number of drivers.
>> Some of the affected hardware is not in use any longer, but some hardware
>> is still around and provides good(-enough) framebuffers.
>>
>> The fbconv helpers allow for running the current DRM stack on top of fbdev
>> drivers. It's a set of functions that convert between fbdev interfaces and
>> DRM interfaces. Based on SHMEM and simple KMS helpers, it only offers the
>> basic functionality of a framebuffer, but should be compatible with most
>> existing fbdev drivers.
>>
>> A DRM driver using fbconv helpers consists of
>>
>>    * DRM stub code that calls into fbconv helpers, and
>>    * the original fbdev driver code.
>>
>> The fbdev driver code has to be modified to register itself with the
>> stub driver instead of the fbdev core framework. A tutorial on how to use
>> the helpers is part of this patchset. The resulting driver hybrid can be
>> refactored into a first-class DRM driver. The fbconv helpers contain a
>> number of comments, labeled 'DRM porting note', which explain the required
>> steps.
>>
>> I tested the current patchset with the following drivers: atyfb, aty128fb,
>> matroxfb, pm2fb, pm3fb, rivafb, s3fb, savagefb, sisfb, tdfxfb and tridentfb.
>> With each, I was able to successfully start with fbcon enabled, run weston and
>> X11. The drivers are available at [1]. For reference, the patchset includes
>> the Matrox stub driver.
> 
> In general I like the idea of modernizing the existing fbdev drivers.
> What I fail to read in your intro above is if this allows us to phase
> out the migrated fbdev drivers sooner?
> Or do we end up with two drivers to maintain?

The idea is that an fbdev driver is converted over to DRM and, once 
ready, the original fbdev driver gets removed. When a hybrid driver gets 
added, I'd want to see the rsp developer actually clean up and refactor 
the code. There shouldn't be multiple drivers for long.

But most of the fbdev drivers appear to be unmaintained anyway. I 
wouldn't expect having two drivers for a few releases would make much of 
a difference.

> Obviously a full migration to a DRM driver was preferred - but this may
> serve as a step in that direction.
> But we should not end up with two drivers doing almost the same.
> 
> Another general question. Do we want the modernized DRM drivers to end
> up in staging? Why should they not go direct into drm/*
> I know they are not fully atomic but this is not new drivers so maybe
> they can be excused.
> Problem is that drm drivers in staging live a secret nonvisible life
> where they are easy to forget when we change interfaces and such.

True. OTOH putting them next to the regular DRM code sends the message 
that the driver is already complete and in good shape. Those hybrid 
drivers are limited in functionality and don't really live up to 
anyone's requirements for code quality. It's the kind of code one would 
expect in staging.

Best regards
Thomas

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

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Linux GmbH, Maxfeldstrasse 5, 90409 Nuernberg, Germany
GF: Felix Imendörffer, Mary Higgins, Sri Rasiah
HRB 21284 (AG Nürnberg)

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

* Re: [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers
@ 2019-10-15  6:11     ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-15  6:11 UTC (permalink / raw)
  To: Sam Ravnborg
  Cc: linux-fbdev, corbet, airlied, gregkh, michel, b.zolnierkie,
	dri-devel, malat, sean

Hi

Am 14.10.19 um 22:36 schrieb Sam Ravnborg:
> Hi Thomas.
> 
> On Mon, Oct 14, 2019 at 04:04:01PM +0200, Thomas Zimmermann wrote:
>> (was: DRM driver for fbdev devices)
>>
>> This is version 2 of the fbdev conversion helpers. It's more or less a
>> rewrite of the original patchset.
>>
>> The fbdev subsystem is considered legacy and will probably be removed at
>> some point. This would mean the loss of a signifanct number of drivers.
>> Some of the affected hardware is not in use any longer, but some hardware
>> is still around and provides good(-enough) framebuffers.
>>
>> The fbconv helpers allow for running the current DRM stack on top of fbdev
>> drivers. It's a set of functions that convert between fbdev interfaces and
>> DRM interfaces. Based on SHMEM and simple KMS helpers, it only offers the
>> basic functionality of a framebuffer, but should be compatible with most
>> existing fbdev drivers.
>>
>> A DRM driver using fbconv helpers consists of
>>
>>    * DRM stub code that calls into fbconv helpers, and
>>    * the original fbdev driver code.
>>
>> The fbdev driver code has to be modified to register itself with the
>> stub driver instead of the fbdev core framework. A tutorial on how to use
>> the helpers is part of this patchset. The resulting driver hybrid can be
>> refactored into a first-class DRM driver. The fbconv helpers contain a
>> number of comments, labeled 'DRM porting note', which explain the required
>> steps.
>>
>> I tested the current patchset with the following drivers: atyfb, aty128fb,
>> matroxfb, pm2fb, pm3fb, rivafb, s3fb, savagefb, sisfb, tdfxfb and tridentfb.
>> With each, I was able to successfully start with fbcon enabled, run weston and
>> X11. The drivers are available at [1]. For reference, the patchset includes
>> the Matrox stub driver.
> 
> In general I like the idea of modernizing the existing fbdev drivers.
> What I fail to read in your intro above is if this allows us to phase
> out the migrated fbdev drivers sooner?
> Or do we end up with two drivers to maintain?

The idea is that an fbdev driver is converted over to DRM and, once 
ready, the original fbdev driver gets removed. When a hybrid driver gets 
added, I'd want to see the rsp developer actually clean up and refactor 
the code. There shouldn't be multiple drivers for long.

But most of the fbdev drivers appear to be unmaintained anyway. I 
wouldn't expect having two drivers for a few releases would make much of 
a difference.

> Obviously a full migration to a DRM driver was preferred - but this may
> serve as a step in that direction.
> But we should not end up with two drivers doing almost the same.
> 
> Another general question. Do we want the modernized DRM drivers to end
> up in staging? Why should they not go direct into drm/*
> I know they are not fully atomic but this is not new drivers so maybe
> they can be excused.
> Problem is that drm drivers in staging live a secret nonvisible life
> where they are easy to forget when we change interfaces and such.

True. OTOH putting them next to the regular DRM code sends the message 
that the driver is already complete and in good shape. Those hybrid 
drivers are limited in functionality and don't really live up to 
anyone's requirements for code quality. It's the kind of code one would 
expect in staging.

Best regards
Thomas

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

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Linux GmbH, Maxfeldstrasse 5, 90409 Nuernberg, Germany
GF: Felix Imendörffer, Mary Higgins, Sri Rasiah
HRB 21284 (AG Nürnberg)
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 08/15] drm/fbconv: Add plane-state check and update
  2019-10-14 14:04   ` Thomas Zimmermann
  (?)
@ 2019-10-15  8:30     ` kbuild test robot
  -1 siblings, 0 replies; 77+ messages in thread
From: kbuild test robot @ 2019-10-15  8:30 UTC (permalink / raw)
  Cc: linux-fbdev, kbuild-all, Thomas Zimmermann, b.zolnierkie,
	airlied, gregkh, michel, corbet, malat, dri-devel, sean

[-- Attachment #1: Type: text/plain, Size: 5472 bytes --]

Hi Thomas,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[cannot apply to v5.4-rc3 next-20191014]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Thomas-Zimmermann/DRM-fbconv-helpers-for-converting-fbdev-drivers/20191015-152231
config: mips-allmodconfig (attached as .config)
compiler: mips-linux-gcc (GCC) 7.4.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.4.0 make.cross ARCH=mips 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   In file included from arch/mips/include/asm/div64.h:12:0,
                    from include/linux/kernel.h:18,
                    from include/asm-generic/bug.h:19,
                    from arch/mips/include/asm/bug.h:42,
                    from include/linux/bug.h:5,
                    from arch/mips/include/asm/cmpxchg.h:11,
                    from arch/mips/include/asm/atomic.h:22,
                    from include/linux/atomic.h:7,
                    from include/linux/kgdb.h:18,
                    from include/linux/fb.h:5,
                    from drivers/gpu/drm/drm_fbconv_helper.c:5:
   drivers/gpu/drm/drm_fbconv_helper.c: In function 'drm_fbconv_update_fb_var_screeninfo_from_framebuffer':
   include/asm-generic/div64.h:226:28: warning: comparison of distinct pointer types lacks a cast
     (void)(((typeof((n)) *)0) == ((uint64_t *)0)); \
                               ^
>> drivers/gpu/drm/drm_fbconv_helper.c:899:2: note: in expansion of macro 'do_div'
     do_div(width, cpp);
     ^~~~~~
   In file included from include/uapi/linux/swab.h:6:0,
                    from include/linux/swab.h:5,
                    from include/uapi/linux/byteorder/big_endian.h:13,
                    from include/linux/byteorder/big_endian.h:5,
                    from arch/mips/include/uapi/asm/byteorder.h:13,
                    from drivers/gpu/drm/drm_fbconv_helper.c:3:
   include/asm-generic/div64.h:239:25: warning: right shift count >= width of type [-Wshift-count-overflow]
     } else if (likely(((n) >> 32) == 0)) {  \
                            ^
   include/linux/compiler.h:77:40: note: in definition of macro 'likely'
    # define likely(x) __builtin_expect(!!(x), 1)
                                           ^
>> drivers/gpu/drm/drm_fbconv_helper.c:899:2: note: in expansion of macro 'do_div'
     do_div(width, cpp);
     ^~~~~~
   In file included from arch/mips/include/asm/div64.h:12:0,
                    from include/linux/kernel.h:18,
                    from include/asm-generic/bug.h:19,
                    from arch/mips/include/asm/bug.h:42,
                    from include/linux/bug.h:5,
                    from arch/mips/include/asm/cmpxchg.h:11,
                    from arch/mips/include/asm/atomic.h:22,
                    from include/linux/atomic.h:7,
                    from include/linux/kgdb.h:18,
                    from include/linux/fb.h:5,
                    from drivers/gpu/drm/drm_fbconv_helper.c:5:
   include/asm-generic/div64.h:243:22: error: passing argument 1 of '__div64_32' from incompatible pointer type [-Werror=incompatible-pointer-types]
      __rem = __div64_32(&(n), __base); \
                         ^
>> drivers/gpu/drm/drm_fbconv_helper.c:899:2: note: in expansion of macro 'do_div'
     do_div(width, cpp);
     ^~~~~~
   include/asm-generic/div64.h:217:17: note: expected 'uint64_t * {aka long long unsigned int *}' but argument is of type 'unsigned int *'
    extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
                    ^~~~~~~~~~
   cc1: some warnings being treated as errors

vim +/do_div +899 drivers/gpu/drm/drm_fbconv_helper.c

   883	
   884	static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
   885		struct fb_var_screeninfo *fb_var, struct drm_framebuffer *fb,
   886		size_t vram_size)
   887	{
   888		unsigned int width, pitch;
   889		uint64_t cpp, lines;
   890		int ret;
   891	
   892		/* Our virtual screen covers all the graphics memory (sans some
   893		 * trailing bytes). This allows for setting the scanout buffer's
   894		 * address with fb_pan_display().
   895		 */
   896	
   897		width = fb->pitches[0];
   898		cpp = fb->format[0].cpp[0];
 > 899		do_div(width, cpp);
   900	
   901		if (width > (__u32)-1)
   902			return -EINVAL; /* would overflow fb_var->xres_virtual */
   903	
   904		pitch = fb->pitches[0];
   905		lines = vram_size;
   906		do_div(lines, pitch);
   907	
   908		if (lines > (__u32)-1)
   909			return -EINVAL; /* would overflow fb_var->yres_virtual */
   910	
   911		fb_var->xres_virtual = width;
   912		fb_var->yres_virtual = lines;
   913	
   914		ret = drm_fbconv_update_fb_var_screeninfo_from_format(
   915			fb_var, fb->format[0].format);
   916		if (ret)
   917			return ret;
   918	
   919		return 0;
   920	}
   921	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 62095 bytes --]

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

* Re: [PATCH v2 08/15] drm/fbconv: Add plane-state check and update
@ 2019-10-15  8:30     ` kbuild test robot
  0 siblings, 0 replies; 77+ messages in thread
From: kbuild test robot @ 2019-10-15  8:30 UTC (permalink / raw)
  Cc: linux-fbdev, kbuild-all, Thomas Zimmermann, b.zolnierkie,
	airlied, gregkh, michel, corbet, malat, dri-devel, sean

[-- Attachment #1: Type: text/plain, Size: 5472 bytes --]

Hi Thomas,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[cannot apply to v5.4-rc3 next-20191014]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Thomas-Zimmermann/DRM-fbconv-helpers-for-converting-fbdev-drivers/20191015-152231
config: mips-allmodconfig (attached as .config)
compiler: mips-linux-gcc (GCC) 7.4.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.4.0 make.cross ARCH=mips 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   In file included from arch/mips/include/asm/div64.h:12:0,
                    from include/linux/kernel.h:18,
                    from include/asm-generic/bug.h:19,
                    from arch/mips/include/asm/bug.h:42,
                    from include/linux/bug.h:5,
                    from arch/mips/include/asm/cmpxchg.h:11,
                    from arch/mips/include/asm/atomic.h:22,
                    from include/linux/atomic.h:7,
                    from include/linux/kgdb.h:18,
                    from include/linux/fb.h:5,
                    from drivers/gpu/drm/drm_fbconv_helper.c:5:
   drivers/gpu/drm/drm_fbconv_helper.c: In function 'drm_fbconv_update_fb_var_screeninfo_from_framebuffer':
   include/asm-generic/div64.h:226:28: warning: comparison of distinct pointer types lacks a cast
     (void)(((typeof((n)) *)0) == ((uint64_t *)0)); \
                               ^
>> drivers/gpu/drm/drm_fbconv_helper.c:899:2: note: in expansion of macro 'do_div'
     do_div(width, cpp);
     ^~~~~~
   In file included from include/uapi/linux/swab.h:6:0,
                    from include/linux/swab.h:5,
                    from include/uapi/linux/byteorder/big_endian.h:13,
                    from include/linux/byteorder/big_endian.h:5,
                    from arch/mips/include/uapi/asm/byteorder.h:13,
                    from drivers/gpu/drm/drm_fbconv_helper.c:3:
   include/asm-generic/div64.h:239:25: warning: right shift count >= width of type [-Wshift-count-overflow]
     } else if (likely(((n) >> 32) == 0)) {  \
                            ^
   include/linux/compiler.h:77:40: note: in definition of macro 'likely'
    # define likely(x) __builtin_expect(!!(x), 1)
                                           ^
>> drivers/gpu/drm/drm_fbconv_helper.c:899:2: note: in expansion of macro 'do_div'
     do_div(width, cpp);
     ^~~~~~
   In file included from arch/mips/include/asm/div64.h:12:0,
                    from include/linux/kernel.h:18,
                    from include/asm-generic/bug.h:19,
                    from arch/mips/include/asm/bug.h:42,
                    from include/linux/bug.h:5,
                    from arch/mips/include/asm/cmpxchg.h:11,
                    from arch/mips/include/asm/atomic.h:22,
                    from include/linux/atomic.h:7,
                    from include/linux/kgdb.h:18,
                    from include/linux/fb.h:5,
                    from drivers/gpu/drm/drm_fbconv_helper.c:5:
   include/asm-generic/div64.h:243:22: error: passing argument 1 of '__div64_32' from incompatible pointer type [-Werror=incompatible-pointer-types]
      __rem = __div64_32(&(n), __base); \
                         ^
>> drivers/gpu/drm/drm_fbconv_helper.c:899:2: note: in expansion of macro 'do_div'
     do_div(width, cpp);
     ^~~~~~
   include/asm-generic/div64.h:217:17: note: expected 'uint64_t * {aka long long unsigned int *}' but argument is of type 'unsigned int *'
    extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
                    ^~~~~~~~~~
   cc1: some warnings being treated as errors

vim +/do_div +899 drivers/gpu/drm/drm_fbconv_helper.c

   883	
   884	static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
   885		struct fb_var_screeninfo *fb_var, struct drm_framebuffer *fb,
   886		size_t vram_size)
   887	{
   888		unsigned int width, pitch;
   889		uint64_t cpp, lines;
   890		int ret;
   891	
   892		/* Our virtual screen covers all the graphics memory (sans some
   893		 * trailing bytes). This allows for setting the scanout buffer's
   894		 * address with fb_pan_display().
   895		 */
   896	
   897		width = fb->pitches[0];
   898		cpp = fb->format[0].cpp[0];
 > 899		do_div(width, cpp);
   900	
   901		if (width > (__u32)-1)
   902			return -EINVAL; /* would overflow fb_var->xres_virtual */
   903	
   904		pitch = fb->pitches[0];
   905		lines = vram_size;
   906		do_div(lines, pitch);
   907	
   908		if (lines > (__u32)-1)
   909			return -EINVAL; /* would overflow fb_var->yres_virtual */
   910	
   911		fb_var->xres_virtual = width;
   912		fb_var->yres_virtual = lines;
   913	
   914		ret = drm_fbconv_update_fb_var_screeninfo_from_format(
   915			fb_var, fb->format[0].format);
   916		if (ret)
   917			return ret;
   918	
   919		return 0;
   920	}
   921	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 62095 bytes --]

[-- Attachment #3: Type: text/plain, Size: 159 bytes --]

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

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

* Re: [PATCH v2 08/15] drm/fbconv: Add plane-state check and update
@ 2019-10-15  8:30     ` kbuild test robot
  0 siblings, 0 replies; 77+ messages in thread
From: kbuild test robot @ 2019-10-15  8:30 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 5596 bytes --]

Hi Thomas,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[cannot apply to v5.4-rc3 next-20191014]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Thomas-Zimmermann/DRM-fbconv-helpers-for-converting-fbdev-drivers/20191015-152231
config: mips-allmodconfig (attached as .config)
compiler: mips-linux-gcc (GCC) 7.4.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.4.0 make.cross ARCH=mips 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   In file included from arch/mips/include/asm/div64.h:12:0,
                    from include/linux/kernel.h:18,
                    from include/asm-generic/bug.h:19,
                    from arch/mips/include/asm/bug.h:42,
                    from include/linux/bug.h:5,
                    from arch/mips/include/asm/cmpxchg.h:11,
                    from arch/mips/include/asm/atomic.h:22,
                    from include/linux/atomic.h:7,
                    from include/linux/kgdb.h:18,
                    from include/linux/fb.h:5,
                    from drivers/gpu/drm/drm_fbconv_helper.c:5:
   drivers/gpu/drm/drm_fbconv_helper.c: In function 'drm_fbconv_update_fb_var_screeninfo_from_framebuffer':
   include/asm-generic/div64.h:226:28: warning: comparison of distinct pointer types lacks a cast
     (void)(((typeof((n)) *)0) == ((uint64_t *)0)); \
                               ^
>> drivers/gpu/drm/drm_fbconv_helper.c:899:2: note: in expansion of macro 'do_div'
     do_div(width, cpp);
     ^~~~~~
   In file included from include/uapi/linux/swab.h:6:0,
                    from include/linux/swab.h:5,
                    from include/uapi/linux/byteorder/big_endian.h:13,
                    from include/linux/byteorder/big_endian.h:5,
                    from arch/mips/include/uapi/asm/byteorder.h:13,
                    from drivers/gpu/drm/drm_fbconv_helper.c:3:
   include/asm-generic/div64.h:239:25: warning: right shift count >= width of type [-Wshift-count-overflow]
     } else if (likely(((n) >> 32) == 0)) {  \
                            ^
   include/linux/compiler.h:77:40: note: in definition of macro 'likely'
    # define likely(x) __builtin_expect(!!(x), 1)
                                           ^
>> drivers/gpu/drm/drm_fbconv_helper.c:899:2: note: in expansion of macro 'do_div'
     do_div(width, cpp);
     ^~~~~~
   In file included from arch/mips/include/asm/div64.h:12:0,
                    from include/linux/kernel.h:18,
                    from include/asm-generic/bug.h:19,
                    from arch/mips/include/asm/bug.h:42,
                    from include/linux/bug.h:5,
                    from arch/mips/include/asm/cmpxchg.h:11,
                    from arch/mips/include/asm/atomic.h:22,
                    from include/linux/atomic.h:7,
                    from include/linux/kgdb.h:18,
                    from include/linux/fb.h:5,
                    from drivers/gpu/drm/drm_fbconv_helper.c:5:
   include/asm-generic/div64.h:243:22: error: passing argument 1 of '__div64_32' from incompatible pointer type [-Werror=incompatible-pointer-types]
      __rem = __div64_32(&(n), __base); \
                         ^
>> drivers/gpu/drm/drm_fbconv_helper.c:899:2: note: in expansion of macro 'do_div'
     do_div(width, cpp);
     ^~~~~~
   include/asm-generic/div64.h:217:17: note: expected 'uint64_t * {aka long long unsigned int *}' but argument is of type 'unsigned int *'
    extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
                    ^~~~~~~~~~
   cc1: some warnings being treated as errors

vim +/do_div +899 drivers/gpu/drm/drm_fbconv_helper.c

   883	
   884	static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
   885		struct fb_var_screeninfo *fb_var, struct drm_framebuffer *fb,
   886		size_t vram_size)
   887	{
   888		unsigned int width, pitch;
   889		uint64_t cpp, lines;
   890		int ret;
   891	
   892		/* Our virtual screen covers all the graphics memory (sans some
   893		 * trailing bytes). This allows for setting the scanout buffer's
   894		 * address with fb_pan_display().
   895		 */
   896	
   897		width = fb->pitches[0];
   898		cpp = fb->format[0].cpp[0];
 > 899		do_div(width, cpp);
   900	
   901		if (width > (__u32)-1)
   902			return -EINVAL; /* would overflow fb_var->xres_virtual */
   903	
   904		pitch = fb->pitches[0];
   905		lines = vram_size;
   906		do_div(lines, pitch);
   907	
   908		if (lines > (__u32)-1)
   909			return -EINVAL; /* would overflow fb_var->yres_virtual */
   910	
   911		fb_var->xres_virtual = width;
   912		fb_var->yres_virtual = lines;
   913	
   914		ret = drm_fbconv_update_fb_var_screeninfo_from_format(
   915			fb_var, fb->format[0].format);
   916		if (ret)
   917			return ret;
   918	
   919		return 0;
   920	}
   921	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 62095 bytes --]

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

* Re: [PATCH v2 12/15] drm/fbconv: Add helper documentation
  2019-10-14 14:04   ` Thomas Zimmermann
  (?)
@ 2019-10-15  8:40     ` kbuild test robot
  -1 siblings, 0 replies; 77+ messages in thread
From: kbuild test robot @ 2019-10-15  8:40 UTC (permalink / raw)
  Cc: linux-fbdev, kbuild-all, Thomas Zimmermann, b.zolnierkie,
	airlied, gregkh, michel, corbet, malat, dri-devel, sean

[-- Attachment #1: Type: text/plain, Size: 24745 bytes --]

Hi Thomas,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[cannot apply to v5.4-rc3 next-20191014]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Thomas-Zimmermann/DRM-fbconv-helpers-for-converting-fbdev-drivers/20191015-152231
reproduce: make htmldocs

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   include/linux/skbuff.h:888: warning: Function parameter or member 'vlan_present' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'csum_complete_sw' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'csum_level' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'inner_protocol_type' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'remcsum_offload' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'sender_cpu' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'reserved_tailroom' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'inner_ipproto' not described in 'sk_buff'
   include/net/sock.h:233: warning: Function parameter or member 'skc_addrpair' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_portpair' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_ipv6only' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_net_refcnt' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_v6_daddr' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_v6_rcv_saddr' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_cookie' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_listener' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_tw_dr' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_rcv_wnd' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_tw_rcv_nxt' not described in 'sock_common'
   include/net/sock.h:515: warning: Function parameter or member 'sk_rx_skb_cache' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'sk_wq_raw' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'tcp_rtx_queue' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'sk_tx_skb_cache' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'sk_route_forced_caps' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'sk_txtime_report_errors' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'sk_validate_xmit_skb' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'sk_bpf_storage' not described in 'sock'
   include/net/sock.h:2439: warning: Function parameter or member 'tcp_rx_skb_cache_key' not described in 'DECLARE_STATIC_KEY_FALSE'
   include/net/sock.h:2439: warning: Excess function parameter 'sk' description in 'DECLARE_STATIC_KEY_FALSE'
   include/net/sock.h:2439: warning: Excess function parameter 'skb' description in 'DECLARE_STATIC_KEY_FALSE'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'gso_partial_features' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'l3mdev_ops' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'xfrmdev_ops' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'tlsdev_ops' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'name_assign_type' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'ieee802154_ptr' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'mpls_ptr' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'xdp_prog' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'gro_flush_timeout' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'nf_hooks_ingress' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member '____cacheline_aligned_in_smp' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'qdisc_hash' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'xps_cpus_map' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'xps_rxqs_map' not described in 'net_device'
   include/linux/phylink.h:56: warning: Function parameter or member '__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising' not described in 'phylink_link_state'
   include/linux/phylink.h:56: warning: Function parameter or member '__ETHTOOL_DECLARE_LINK_MODE_MASK(lp_advertising' not described in 'phylink_link_state'
   drivers/net/phy/phylink.c:595: warning: Function parameter or member 'config' not described in 'phylink_create'
   drivers/net/phy/phylink.c:595: warning: Excess function parameter 'ndev' description in 'phylink_create'
   lib/genalloc.c:1: warning: 'gen_pool_add_virt' not found
   lib/genalloc.c:1: warning: 'gen_pool_alloc' not found
   lib/genalloc.c:1: warning: 'gen_pool_free' not found
   lib/genalloc.c:1: warning: 'gen_pool_alloc_algo' not found
   include/linux/rculist.h:374: warning: Excess function parameter 'cond' description in 'list_for_each_entry_rcu'
   include/linux/rculist.h:651: warning: Excess function parameter 'cond' description in 'hlist_for_each_entry_rcu'
   mm/util.c:1: warning: 'get_user_pages_fast' not found
   drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c:335: warning: Excess function parameter 'dev' description in 'amdgpu_gem_prime_export'
   drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c:336: warning: Excess function parameter 'dev' description in 'amdgpu_gem_prime_export'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:142: warning: Function parameter or member 'blockable' not described in 'amdgpu_mn_read_lock'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:347: warning: cannot understand function prototype: 'struct amdgpu_vm_pt_cursor '
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:348: warning: cannot understand function prototype: 'struct amdgpu_vm_pt_cursor '
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:494: warning: Function parameter or member 'start' not described in 'amdgpu_vm_pt_first_dfs'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'adev' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'vm' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'start' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'cursor' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'entry' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:821: warning: Function parameter or member 'level' not described in 'amdgpu_vm_bo_param'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'params' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'bo' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'level' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'pe' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'addr' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'count' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'incr' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'flags' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:2821: warning: Function parameter or member 'pasid' not described in 'amdgpu_vm_make_compute'
   drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c:378: warning: Excess function parameter 'entry' description in 'amdgpu_irq_dispatch'
   drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c:379: warning: Function parameter or member 'ih' not described in 'amdgpu_irq_dispatch'
   drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c:379: warning: Excess function parameter 'entry' description in 'amdgpu_irq_dispatch'
   drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c:1: warning: no structured comments found
   drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c:1: warning: no structured comments found
   drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c:1: warning: 'pp_dpm_sclk pp_dpm_mclk pp_dpm_pcie' not found
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:132: warning: Incorrect use of kernel-doc format:          * @atomic_obj
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:238: warning: Incorrect use of kernel-doc format:          * gpu_info FW provided soc bounding box struct or 0 if not
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'atomic_obj' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'backlight_link' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'backlight_caps' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'freesync_module' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'fw_dmcu' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'dmcu_fw_version' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'soc_bounding_box' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c:1: warning: 'dm_crtc_high_irq' not found
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c:1: warning: 'dm_pflip_high_irq' not found
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c:1: warning: 'register_hpd_handlers' not found
   include/drm/drm_modeset_helper_vtables.h:1053: warning: Function parameter or member 'prepare_writeback_job' not described in 'drm_connector_helper_funcs'
   include/drm/drm_modeset_helper_vtables.h:1053: warning: Function parameter or member 'cleanup_writeback_job' not described in 'drm_connector_helper_funcs'
   include/drm/drm_atomic_state_helper.h:1: warning: no structured comments found
   include/drm/drm_gem_shmem_helper.h:87: warning: Function parameter or member 'madv' not described in 'drm_gem_shmem_object'
   include/drm/drm_gem_shmem_helper.h:87: warning: Function parameter or member 'madv_list' not described in 'drm_gem_shmem_object'
   drivers/gpu/drm/drm_fbconv_helper.c:370: warning: Excess function parameter 'fb_info' description in 'drm_fbconv_format_of_fb_var_screeninfo'
>> include/drm/drm_fbconv_helper.h:124: warning: Function parameter or member 'blit' not described in 'drm_fbconv_modeset'
>> drivers/gpu/drm/drm_fbconv_helper.c:371: warning: Function parameter or member 'fb_var' not described in 'drm_fbconv_format_of_fb_var_screeninfo'
   drivers/gpu/drm/drm_fbconv_helper.c:371: warning: Excess function parameter 'fb_info' description in 'drm_fbconv_format_of_fb_var_screeninfo'
   drivers/gpu/drm/i915/display/intel_dpll_mgr.h:158: warning: Enum value 'DPLL_ID_TGL_MGPLL5' not described in enum 'intel_dpll_id'
   drivers/gpu/drm/i915/display/intel_dpll_mgr.h:158: warning: Enum value 'DPLL_ID_TGL_MGPLL6' not described in enum 'intel_dpll_id'
   drivers/gpu/drm/i915/display/intel_dpll_mgr.h:158: warning: Excess enum value 'DPLL_ID_TGL_TCPLL5' description in 'intel_dpll_id'
   drivers/gpu/drm/i915/display/intel_dpll_mgr.h:158: warning: Excess enum value 'DPLL_ID_TGL_TCPLL6' description in 'intel_dpll_id'
   drivers/gpu/drm/i915/display/intel_dpll_mgr.h:342: warning: Function parameter or member 'wakeref' not described in 'intel_shared_dpll'
   Error: Cannot open file drivers/gpu/drm/i915/i915_gem_batch_pool.c
   Error: Cannot open file drivers/gpu/drm/i915/i915_gem_batch_pool.c
   Error: Cannot open file drivers/gpu/drm/i915/i915_gem_batch_pool.c
   drivers/gpu/drm/i915/i915_drv.h:1129: warning: Incorrect use of kernel-doc format:          * The OA context specific information.
   drivers/gpu/drm/i915/i915_drv.h:1143: warning: Incorrect use of kernel-doc format:          * State of the OA buffer.
   drivers/gpu/drm/i915/i915_drv.h:1154: warning: Incorrect use of kernel-doc format:                  * Locks reads and writes to all head/tail state
   drivers/gpu/drm/i915/i915_drv.h:1176: warning: Incorrect use of kernel-doc format:                  * One 'aging' tail pointer and one 'aged' tail pointer ready to
   drivers/gpu/drm/i915/i915_drv.h:1188: warning: Incorrect use of kernel-doc format:                  * Index for the aged tail ready to read() data up to.
   drivers/gpu/drm/i915/i915_drv.h:1193: warning: Incorrect use of kernel-doc format:                  * A monotonic timestamp for when the current aging tail pointer
   drivers/gpu/drm/i915/i915_drv.h:1199: warning: Incorrect use of kernel-doc format:                  * Although we can always read back the head pointer register,
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'pinned_ctx' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'specific_ctx_id' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'specific_ctx_id_mask' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'poll_check_timer' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'poll_wq' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'pollin' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'periodic' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'period_exponent' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'oa_buffer' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1129: warning: Incorrect use of kernel-doc format:          * The OA context specific information.
   drivers/gpu/drm/i915/i915_drv.h:1143: warning: Incorrect use of kernel-doc format:          * State of the OA buffer.
   drivers/gpu/drm/i915/i915_drv.h:1154: warning: Incorrect use of kernel-doc format:                  * Locks reads and writes to all head/tail state
   drivers/gpu/drm/i915/i915_drv.h:1176: warning: Incorrect use of kernel-doc format:                  * One 'aging' tail pointer and one 'aged' tail pointer ready to
   drivers/gpu/drm/i915/i915_drv.h:1188: warning: Incorrect use of kernel-doc format:                  * Index for the aged tail ready to read() data up to.
   drivers/gpu/drm/i915/i915_drv.h:1193: warning: Incorrect use of kernel-doc format:                  * A monotonic timestamp for when the current aging tail pointer
   drivers/gpu/drm/i915/i915_drv.h:1199: warning: Incorrect use of kernel-doc format:                  * Although we can always read back the head pointer register,
   drivers/gpu/drm/i915/i915_drv.h:1129: warning: Incorrect use of kernel-doc format:          * The OA context specific information.
   drivers/gpu/drm/i915/i915_drv.h:1143: warning: Incorrect use of kernel-doc format:          * State of the OA buffer.
   drivers/gpu/drm/i915/i915_drv.h:1154: warning: Incorrect use of kernel-doc format:                  * Locks reads and writes to all head/tail state
   drivers/gpu/drm/i915/i915_drv.h:1176: warning: Incorrect use of kernel-doc format:                  * One 'aging' tail pointer and one 'aged' tail pointer ready to
   drivers/gpu/drm/i915/i915_drv.h:1188: warning: Incorrect use of kernel-doc format:                  * Index for the aged tail ready to read() data up to.
   drivers/gpu/drm/i915/i915_drv.h:1193: warning: Incorrect use of kernel-doc format:                  * A monotonic timestamp for when the current aging tail pointer
   drivers/gpu/drm/i915/i915_drv.h:1199: warning: Incorrect use of kernel-doc format:                  * Although we can always read back the head pointer register,
   drivers/gpu/drm/mcde/mcde_drv.c:1: warning: 'ST-Ericsson MCDE DRM Driver' not found
   include/net/cfg80211.h:1185: warning: Function parameter or member 'txpwr' not described in 'station_parameters'
   include/net/mac80211.h:4056: warning: Function parameter or member 'sta_set_txpwr' not described in 'ieee80211_ops'
   include/net/mac80211.h:2018: warning: Function parameter or member 'txpwr' not described in 'ieee80211_sta'
   Documentation/admin-guide/perf/imx-ddr.rst:21: WARNING: Unexpected indentation.
   Documentation/admin-guide/perf/imx-ddr.rst:34: WARNING: Unexpected indentation.
   Documentation/admin-guide/perf/imx-ddr.rst:40: WARNING: Unexpected indentation.
   Documentation/admin-guide/perf/imx-ddr.rst:45: WARNING: Unexpected indentation.
   Documentation/admin-guide/perf/imx-ddr.rst:52: WARNING: Unexpected indentation.
   Documentation/admin-guide/xfs.rst:257: WARNING: Block quote ends without a blank line; unexpected unindent.
   Documentation/filesystems/ubifs-authentication.rst:94: WARNING: Inline interpreted text or phrase reference start-string without end-string.
   Documentation/usb/index.rst:5: WARNING: toctree contains reference to nonexisting document 'usb/rio'
   Documentation/usb/index.rst:5: WARNING: toctree contains reference to nonexisting document 'usb/wusb-design-overview'
   Documentation/usb/text_files.rst:22: WARNING: Include file 'Documentation/usb/wusb-cbaf' not found or reading it failed
   Documentation/trace/kprobetrace.rst:100: WARNING: Explicit markup ends without a blank line; unexpected unindent.
   WARNING: kernel-doc 'scripts/kernel-doc -rst -enable-lineno -function Reservation Object Overview drivers/dma-buf/reservation.c' failed with return code 1
   WARNING: kernel-doc 'scripts/kernel-doc -rst -enable-lineno -export drivers/dma-buf/reservation.c' failed with return code 2
   WARNING: kernel-doc 'scripts/kernel-doc -rst -enable-lineno -internal include/linux/reservation.h' failed with return code 2
   Documentation/translations/it_IT/process/maintainer-pgp-guide.rst:458: WARNING: Unknown target name: "nitrokey pro".
   Documentation/security/keys/core.rst:1110: WARNING: Inline emphasis start-string without end-string.
   Documentation/security/keys/core.rst:1110: WARNING: Inline emphasis start-string without end-string.
   Documentation/security/keys/core.rst:1108: WARNING: Inline emphasis start-string without end-string.
   Documentation/security/keys/core.rst:1108: WARNING: Inline emphasis start-string without end-string.
   Documentation/security/keys/core.rst:1108: WARNING: Inline emphasis start-string without end-string.
   include/uapi/linux/firewire-cdev.h:312: WARNING: Inline literal start-string without end-string.
   drivers/firewire/core-transaction.c:606: WARNING: Inline strong start-string without end-string.
   drivers/ata/libata-core.c:5945: WARNING: Unknown target name: "hw".
   drivers/message/fusion/mptbase.c:5057: WARNING: Definition list ends without a blank line; unexpected unindent.
   include/linux/regulator/driver.h:284: WARNING: Unknown target name: "regulator_regmap_x_voltage".
   include/linux/spi/spi.h:382: WARNING: Unexpected indentation.
   fs/seq_file.c:40: WARNING: Inline strong start-string without end-string.
   fs/seq_file.c:40: WARNING: Inline strong start-string without end-string.
   fs/seq_file.c:40: WARNING: Inline strong start-string without end-string.
   fs/seq_file.c:40: WARNING: Inline strong start-string without end-string.
   fs/posix_acl.c:636: WARNING: Inline emphasis start-string without end-string.
   fs/debugfs/inode.c:427: WARNING: Inline literal start-string without end-string.
   fs/debugfs/inode.c:506: WARNING: Inline literal start-string without end-string.
   fs/debugfs/inode.c:538: WARNING: Inline literal start-string without end-string.
   fs/debugfs/inode.c:631: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:424: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:430: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:469: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:475: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:514: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:520: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:560: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:566: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:608: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:614: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:875: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:881: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:928: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:934: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:1120: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:1126: WARNING: Inline literal start-string without end-string.
   Documentation/networking/device_drivers/pensando/ionic.rst:39: WARNING: Unexpected indentation.
   Documentation/networking/device_drivers/pensando/ionic.rst:43: WARNING: Unexpected indentation.
   Documentation/misc-devices/index.rst:14: WARNING: toctree contains reference to nonexisting document 'misc-devices/xilinx_sdfec'
   Documentation/driver-api/gpio/driver.rst:420: WARNING: Unexpected indentation.
   Documentation/driver-api/gpio/driver.rst:418: WARNING: Inline emphasis start-string without end-string.
   Documentation/driver-api/gpio/driver.rst:422: WARNING: Block quote ends without a blank line; unexpected unindent.

vim +124 include/drm/drm_fbconv_helper.h

87f9f686c7da49 Thomas Zimmermann 2019-10-14 @124  

:::::: The code at line 124 was first introduced by commit
:::::: 87f9f686c7da49f2b145d7c1073bb38319b31f99 drm/fbconv: Add modesetting infrastructure

:::::: TO: Thomas Zimmermann <tzimmermann@suse.de>
:::::: CC: 0day robot <lkp@intel.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 7279 bytes --]

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

* Re: [PATCH v2 12/15] drm/fbconv: Add helper documentation
@ 2019-10-15  8:40     ` kbuild test robot
  0 siblings, 0 replies; 77+ messages in thread
From: kbuild test robot @ 2019-10-15  8:40 UTC (permalink / raw)
  Cc: linux-fbdev, kbuild-all, Thomas Zimmermann, b.zolnierkie,
	airlied, gregkh, michel, corbet, malat, dri-devel, sean

[-- Attachment #1: Type: text/plain, Size: 24745 bytes --]

Hi Thomas,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[cannot apply to v5.4-rc3 next-20191014]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Thomas-Zimmermann/DRM-fbconv-helpers-for-converting-fbdev-drivers/20191015-152231
reproduce: make htmldocs

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   include/linux/skbuff.h:888: warning: Function parameter or member 'vlan_present' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'csum_complete_sw' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'csum_level' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'inner_protocol_type' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'remcsum_offload' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'sender_cpu' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'reserved_tailroom' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'inner_ipproto' not described in 'sk_buff'
   include/net/sock.h:233: warning: Function parameter or member 'skc_addrpair' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_portpair' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_ipv6only' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_net_refcnt' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_v6_daddr' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_v6_rcv_saddr' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_cookie' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_listener' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_tw_dr' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_rcv_wnd' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_tw_rcv_nxt' not described in 'sock_common'
   include/net/sock.h:515: warning: Function parameter or member 'sk_rx_skb_cache' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'sk_wq_raw' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'tcp_rtx_queue' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'sk_tx_skb_cache' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'sk_route_forced_caps' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'sk_txtime_report_errors' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'sk_validate_xmit_skb' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'sk_bpf_storage' not described in 'sock'
   include/net/sock.h:2439: warning: Function parameter or member 'tcp_rx_skb_cache_key' not described in 'DECLARE_STATIC_KEY_FALSE'
   include/net/sock.h:2439: warning: Excess function parameter 'sk' description in 'DECLARE_STATIC_KEY_FALSE'
   include/net/sock.h:2439: warning: Excess function parameter 'skb' description in 'DECLARE_STATIC_KEY_FALSE'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'gso_partial_features' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'l3mdev_ops' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'xfrmdev_ops' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'tlsdev_ops' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'name_assign_type' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'ieee802154_ptr' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'mpls_ptr' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'xdp_prog' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'gro_flush_timeout' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'nf_hooks_ingress' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member '____cacheline_aligned_in_smp' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'qdisc_hash' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'xps_cpus_map' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'xps_rxqs_map' not described in 'net_device'
   include/linux/phylink.h:56: warning: Function parameter or member '__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising' not described in 'phylink_link_state'
   include/linux/phylink.h:56: warning: Function parameter or member '__ETHTOOL_DECLARE_LINK_MODE_MASK(lp_advertising' not described in 'phylink_link_state'
   drivers/net/phy/phylink.c:595: warning: Function parameter or member 'config' not described in 'phylink_create'
   drivers/net/phy/phylink.c:595: warning: Excess function parameter 'ndev' description in 'phylink_create'
   lib/genalloc.c:1: warning: 'gen_pool_add_virt' not found
   lib/genalloc.c:1: warning: 'gen_pool_alloc' not found
   lib/genalloc.c:1: warning: 'gen_pool_free' not found
   lib/genalloc.c:1: warning: 'gen_pool_alloc_algo' not found
   include/linux/rculist.h:374: warning: Excess function parameter 'cond' description in 'list_for_each_entry_rcu'
   include/linux/rculist.h:651: warning: Excess function parameter 'cond' description in 'hlist_for_each_entry_rcu'
   mm/util.c:1: warning: 'get_user_pages_fast' not found
   drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c:335: warning: Excess function parameter 'dev' description in 'amdgpu_gem_prime_export'
   drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c:336: warning: Excess function parameter 'dev' description in 'amdgpu_gem_prime_export'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:142: warning: Function parameter or member 'blockable' not described in 'amdgpu_mn_read_lock'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:347: warning: cannot understand function prototype: 'struct amdgpu_vm_pt_cursor '
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:348: warning: cannot understand function prototype: 'struct amdgpu_vm_pt_cursor '
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:494: warning: Function parameter or member 'start' not described in 'amdgpu_vm_pt_first_dfs'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'adev' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'vm' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'start' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'cursor' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'entry' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:821: warning: Function parameter or member 'level' not described in 'amdgpu_vm_bo_param'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'params' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'bo' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'level' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'pe' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'addr' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'count' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'incr' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'flags' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:2821: warning: Function parameter or member 'pasid' not described in 'amdgpu_vm_make_compute'
   drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c:378: warning: Excess function parameter 'entry' description in 'amdgpu_irq_dispatch'
   drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c:379: warning: Function parameter or member 'ih' not described in 'amdgpu_irq_dispatch'
   drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c:379: warning: Excess function parameter 'entry' description in 'amdgpu_irq_dispatch'
   drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c:1: warning: no structured comments found
   drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c:1: warning: no structured comments found
   drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c:1: warning: 'pp_dpm_sclk pp_dpm_mclk pp_dpm_pcie' not found
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:132: warning: Incorrect use of kernel-doc format:          * @atomic_obj
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:238: warning: Incorrect use of kernel-doc format:          * gpu_info FW provided soc bounding box struct or 0 if not
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'atomic_obj' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'backlight_link' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'backlight_caps' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'freesync_module' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'fw_dmcu' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'dmcu_fw_version' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'soc_bounding_box' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c:1: warning: 'dm_crtc_high_irq' not found
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c:1: warning: 'dm_pflip_high_irq' not found
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c:1: warning: 'register_hpd_handlers' not found
   include/drm/drm_modeset_helper_vtables.h:1053: warning: Function parameter or member 'prepare_writeback_job' not described in 'drm_connector_helper_funcs'
   include/drm/drm_modeset_helper_vtables.h:1053: warning: Function parameter or member 'cleanup_writeback_job' not described in 'drm_connector_helper_funcs'
   include/drm/drm_atomic_state_helper.h:1: warning: no structured comments found
   include/drm/drm_gem_shmem_helper.h:87: warning: Function parameter or member 'madv' not described in 'drm_gem_shmem_object'
   include/drm/drm_gem_shmem_helper.h:87: warning: Function parameter or member 'madv_list' not described in 'drm_gem_shmem_object'
   drivers/gpu/drm/drm_fbconv_helper.c:370: warning: Excess function parameter 'fb_info' description in 'drm_fbconv_format_of_fb_var_screeninfo'
>> include/drm/drm_fbconv_helper.h:124: warning: Function parameter or member 'blit' not described in 'drm_fbconv_modeset'
>> drivers/gpu/drm/drm_fbconv_helper.c:371: warning: Function parameter or member 'fb_var' not described in 'drm_fbconv_format_of_fb_var_screeninfo'
   drivers/gpu/drm/drm_fbconv_helper.c:371: warning: Excess function parameter 'fb_info' description in 'drm_fbconv_format_of_fb_var_screeninfo'
   drivers/gpu/drm/i915/display/intel_dpll_mgr.h:158: warning: Enum value 'DPLL_ID_TGL_MGPLL5' not described in enum 'intel_dpll_id'
   drivers/gpu/drm/i915/display/intel_dpll_mgr.h:158: warning: Enum value 'DPLL_ID_TGL_MGPLL6' not described in enum 'intel_dpll_id'
   drivers/gpu/drm/i915/display/intel_dpll_mgr.h:158: warning: Excess enum value 'DPLL_ID_TGL_TCPLL5' description in 'intel_dpll_id'
   drivers/gpu/drm/i915/display/intel_dpll_mgr.h:158: warning: Excess enum value 'DPLL_ID_TGL_TCPLL6' description in 'intel_dpll_id'
   drivers/gpu/drm/i915/display/intel_dpll_mgr.h:342: warning: Function parameter or member 'wakeref' not described in 'intel_shared_dpll'
   Error: Cannot open file drivers/gpu/drm/i915/i915_gem_batch_pool.c
   Error: Cannot open file drivers/gpu/drm/i915/i915_gem_batch_pool.c
   Error: Cannot open file drivers/gpu/drm/i915/i915_gem_batch_pool.c
   drivers/gpu/drm/i915/i915_drv.h:1129: warning: Incorrect use of kernel-doc format:          * The OA context specific information.
   drivers/gpu/drm/i915/i915_drv.h:1143: warning: Incorrect use of kernel-doc format:          * State of the OA buffer.
   drivers/gpu/drm/i915/i915_drv.h:1154: warning: Incorrect use of kernel-doc format:                  * Locks reads and writes to all head/tail state
   drivers/gpu/drm/i915/i915_drv.h:1176: warning: Incorrect use of kernel-doc format:                  * One 'aging' tail pointer and one 'aged' tail pointer ready to
   drivers/gpu/drm/i915/i915_drv.h:1188: warning: Incorrect use of kernel-doc format:                  * Index for the aged tail ready to read() data up to.
   drivers/gpu/drm/i915/i915_drv.h:1193: warning: Incorrect use of kernel-doc format:                  * A monotonic timestamp for when the current aging tail pointer
   drivers/gpu/drm/i915/i915_drv.h:1199: warning: Incorrect use of kernel-doc format:                  * Although we can always read back the head pointer register,
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'pinned_ctx' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'specific_ctx_id' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'specific_ctx_id_mask' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'poll_check_timer' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'poll_wq' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'pollin' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'periodic' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'period_exponent' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'oa_buffer' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1129: warning: Incorrect use of kernel-doc format:          * The OA context specific information.
   drivers/gpu/drm/i915/i915_drv.h:1143: warning: Incorrect use of kernel-doc format:          * State of the OA buffer.
   drivers/gpu/drm/i915/i915_drv.h:1154: warning: Incorrect use of kernel-doc format:                  * Locks reads and writes to all head/tail state
   drivers/gpu/drm/i915/i915_drv.h:1176: warning: Incorrect use of kernel-doc format:                  * One 'aging' tail pointer and one 'aged' tail pointer ready to
   drivers/gpu/drm/i915/i915_drv.h:1188: warning: Incorrect use of kernel-doc format:                  * Index for the aged tail ready to read() data up to.
   drivers/gpu/drm/i915/i915_drv.h:1193: warning: Incorrect use of kernel-doc format:                  * A monotonic timestamp for when the current aging tail pointer
   drivers/gpu/drm/i915/i915_drv.h:1199: warning: Incorrect use of kernel-doc format:                  * Although we can always read back the head pointer register,
   drivers/gpu/drm/i915/i915_drv.h:1129: warning: Incorrect use of kernel-doc format:          * The OA context specific information.
   drivers/gpu/drm/i915/i915_drv.h:1143: warning: Incorrect use of kernel-doc format:          * State of the OA buffer.
   drivers/gpu/drm/i915/i915_drv.h:1154: warning: Incorrect use of kernel-doc format:                  * Locks reads and writes to all head/tail state
   drivers/gpu/drm/i915/i915_drv.h:1176: warning: Incorrect use of kernel-doc format:                  * One 'aging' tail pointer and one 'aged' tail pointer ready to
   drivers/gpu/drm/i915/i915_drv.h:1188: warning: Incorrect use of kernel-doc format:                  * Index for the aged tail ready to read() data up to.
   drivers/gpu/drm/i915/i915_drv.h:1193: warning: Incorrect use of kernel-doc format:                  * A monotonic timestamp for when the current aging tail pointer
   drivers/gpu/drm/i915/i915_drv.h:1199: warning: Incorrect use of kernel-doc format:                  * Although we can always read back the head pointer register,
   drivers/gpu/drm/mcde/mcde_drv.c:1: warning: 'ST-Ericsson MCDE DRM Driver' not found
   include/net/cfg80211.h:1185: warning: Function parameter or member 'txpwr' not described in 'station_parameters'
   include/net/mac80211.h:4056: warning: Function parameter or member 'sta_set_txpwr' not described in 'ieee80211_ops'
   include/net/mac80211.h:2018: warning: Function parameter or member 'txpwr' not described in 'ieee80211_sta'
   Documentation/admin-guide/perf/imx-ddr.rst:21: WARNING: Unexpected indentation.
   Documentation/admin-guide/perf/imx-ddr.rst:34: WARNING: Unexpected indentation.
   Documentation/admin-guide/perf/imx-ddr.rst:40: WARNING: Unexpected indentation.
   Documentation/admin-guide/perf/imx-ddr.rst:45: WARNING: Unexpected indentation.
   Documentation/admin-guide/perf/imx-ddr.rst:52: WARNING: Unexpected indentation.
   Documentation/admin-guide/xfs.rst:257: WARNING: Block quote ends without a blank line; unexpected unindent.
   Documentation/filesystems/ubifs-authentication.rst:94: WARNING: Inline interpreted text or phrase reference start-string without end-string.
   Documentation/usb/index.rst:5: WARNING: toctree contains reference to nonexisting document 'usb/rio'
   Documentation/usb/index.rst:5: WARNING: toctree contains reference to nonexisting document 'usb/wusb-design-overview'
   Documentation/usb/text_files.rst:22: WARNING: Include file 'Documentation/usb/wusb-cbaf' not found or reading it failed
   Documentation/trace/kprobetrace.rst:100: WARNING: Explicit markup ends without a blank line; unexpected unindent.
   WARNING: kernel-doc 'scripts/kernel-doc -rst -enable-lineno -function Reservation Object Overview drivers/dma-buf/reservation.c' failed with return code 1
   WARNING: kernel-doc 'scripts/kernel-doc -rst -enable-lineno -export drivers/dma-buf/reservation.c' failed with return code 2
   WARNING: kernel-doc 'scripts/kernel-doc -rst -enable-lineno -internal include/linux/reservation.h' failed with return code 2
   Documentation/translations/it_IT/process/maintainer-pgp-guide.rst:458: WARNING: Unknown target name: "nitrokey pro".
   Documentation/security/keys/core.rst:1110: WARNING: Inline emphasis start-string without end-string.
   Documentation/security/keys/core.rst:1110: WARNING: Inline emphasis start-string without end-string.
   Documentation/security/keys/core.rst:1108: WARNING: Inline emphasis start-string without end-string.
   Documentation/security/keys/core.rst:1108: WARNING: Inline emphasis start-string without end-string.
   Documentation/security/keys/core.rst:1108: WARNING: Inline emphasis start-string without end-string.
   include/uapi/linux/firewire-cdev.h:312: WARNING: Inline literal start-string without end-string.
   drivers/firewire/core-transaction.c:606: WARNING: Inline strong start-string without end-string.
   drivers/ata/libata-core.c:5945: WARNING: Unknown target name: "hw".
   drivers/message/fusion/mptbase.c:5057: WARNING: Definition list ends without a blank line; unexpected unindent.
   include/linux/regulator/driver.h:284: WARNING: Unknown target name: "regulator_regmap_x_voltage".
   include/linux/spi/spi.h:382: WARNING: Unexpected indentation.
   fs/seq_file.c:40: WARNING: Inline strong start-string without end-string.
   fs/seq_file.c:40: WARNING: Inline strong start-string without end-string.
   fs/seq_file.c:40: WARNING: Inline strong start-string without end-string.
   fs/seq_file.c:40: WARNING: Inline strong start-string without end-string.
   fs/posix_acl.c:636: WARNING: Inline emphasis start-string without end-string.
   fs/debugfs/inode.c:427: WARNING: Inline literal start-string without end-string.
   fs/debugfs/inode.c:506: WARNING: Inline literal start-string without end-string.
   fs/debugfs/inode.c:538: WARNING: Inline literal start-string without end-string.
   fs/debugfs/inode.c:631: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:424: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:430: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:469: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:475: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:514: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:520: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:560: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:566: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:608: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:614: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:875: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:881: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:928: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:934: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:1120: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:1126: WARNING: Inline literal start-string without end-string.
   Documentation/networking/device_drivers/pensando/ionic.rst:39: WARNING: Unexpected indentation.
   Documentation/networking/device_drivers/pensando/ionic.rst:43: WARNING: Unexpected indentation.
   Documentation/misc-devices/index.rst:14: WARNING: toctree contains reference to nonexisting document 'misc-devices/xilinx_sdfec'
   Documentation/driver-api/gpio/driver.rst:420: WARNING: Unexpected indentation.
   Documentation/driver-api/gpio/driver.rst:418: WARNING: Inline emphasis start-string without end-string.
   Documentation/driver-api/gpio/driver.rst:422: WARNING: Block quote ends without a blank line; unexpected unindent.

vim +124 include/drm/drm_fbconv_helper.h

87f9f686c7da49 Thomas Zimmermann 2019-10-14 @124  

:::::: The code at line 124 was first introduced by commit
:::::: 87f9f686c7da49f2b145d7c1073bb38319b31f99 drm/fbconv: Add modesetting infrastructure

:::::: TO: Thomas Zimmermann <tzimmermann@suse.de>
:::::: CC: 0day robot <lkp@intel.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 7279 bytes --]

[-- Attachment #3: Type: text/plain, Size: 159 bytes --]

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

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

* Re: [PATCH v2 12/15] drm/fbconv: Add helper documentation
@ 2019-10-15  8:40     ` kbuild test robot
  0 siblings, 0 replies; 77+ messages in thread
From: kbuild test robot @ 2019-10-15  8:40 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 24979 bytes --]

Hi Thomas,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[cannot apply to v5.4-rc3 next-20191014]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Thomas-Zimmermann/DRM-fbconv-helpers-for-converting-fbdev-drivers/20191015-152231
reproduce: make htmldocs

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   include/linux/skbuff.h:888: warning: Function parameter or member 'vlan_present' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'csum_complete_sw' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'csum_level' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'inner_protocol_type' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'remcsum_offload' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'sender_cpu' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'reserved_tailroom' not described in 'sk_buff'
   include/linux/skbuff.h:888: warning: Function parameter or member 'inner_ipproto' not described in 'sk_buff'
   include/net/sock.h:233: warning: Function parameter or member 'skc_addrpair' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_portpair' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_ipv6only' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_net_refcnt' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_v6_daddr' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_v6_rcv_saddr' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_cookie' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_listener' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_tw_dr' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_rcv_wnd' not described in 'sock_common'
   include/net/sock.h:233: warning: Function parameter or member 'skc_tw_rcv_nxt' not described in 'sock_common'
   include/net/sock.h:515: warning: Function parameter or member 'sk_rx_skb_cache' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'sk_wq_raw' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'tcp_rtx_queue' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'sk_tx_skb_cache' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'sk_route_forced_caps' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'sk_txtime_report_errors' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'sk_validate_xmit_skb' not described in 'sock'
   include/net/sock.h:515: warning: Function parameter or member 'sk_bpf_storage' not described in 'sock'
   include/net/sock.h:2439: warning: Function parameter or member 'tcp_rx_skb_cache_key' not described in 'DECLARE_STATIC_KEY_FALSE'
   include/net/sock.h:2439: warning: Excess function parameter 'sk' description in 'DECLARE_STATIC_KEY_FALSE'
   include/net/sock.h:2439: warning: Excess function parameter 'skb' description in 'DECLARE_STATIC_KEY_FALSE'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'gso_partial_features' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'l3mdev_ops' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'xfrmdev_ops' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'tlsdev_ops' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'name_assign_type' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'ieee802154_ptr' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'mpls_ptr' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'xdp_prog' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'gro_flush_timeout' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'nf_hooks_ingress' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member '____cacheline_aligned_in_smp' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'qdisc_hash' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'xps_cpus_map' not described in 'net_device'
   include/linux/netdevice.h:2053: warning: Function parameter or member 'xps_rxqs_map' not described in 'net_device'
   include/linux/phylink.h:56: warning: Function parameter or member '__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising' not described in 'phylink_link_state'
   include/linux/phylink.h:56: warning: Function parameter or member '__ETHTOOL_DECLARE_LINK_MODE_MASK(lp_advertising' not described in 'phylink_link_state'
   drivers/net/phy/phylink.c:595: warning: Function parameter or member 'config' not described in 'phylink_create'
   drivers/net/phy/phylink.c:595: warning: Excess function parameter 'ndev' description in 'phylink_create'
   lib/genalloc.c:1: warning: 'gen_pool_add_virt' not found
   lib/genalloc.c:1: warning: 'gen_pool_alloc' not found
   lib/genalloc.c:1: warning: 'gen_pool_free' not found
   lib/genalloc.c:1: warning: 'gen_pool_alloc_algo' not found
   include/linux/rculist.h:374: warning: Excess function parameter 'cond' description in 'list_for_each_entry_rcu'
   include/linux/rculist.h:651: warning: Excess function parameter 'cond' description in 'hlist_for_each_entry_rcu'
   mm/util.c:1: warning: 'get_user_pages_fast' not found
   drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c:335: warning: Excess function parameter 'dev' description in 'amdgpu_gem_prime_export'
   drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c:336: warning: Excess function parameter 'dev' description in 'amdgpu_gem_prime_export'
   drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c:142: warning: Function parameter or member 'blockable' not described in 'amdgpu_mn_read_lock'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:347: warning: cannot understand function prototype: 'struct amdgpu_vm_pt_cursor '
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:348: warning: cannot understand function prototype: 'struct amdgpu_vm_pt_cursor '
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:494: warning: Function parameter or member 'start' not described in 'amdgpu_vm_pt_first_dfs'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'adev' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'vm' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'start' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'cursor' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:546: warning: Function parameter or member 'entry' not described in 'for_each_amdgpu_vm_pt_dfs_safe'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:821: warning: Function parameter or member 'level' not described in 'amdgpu_vm_bo_param'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'params' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'bo' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'level' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'pe' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'addr' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'count' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'incr' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:1283: warning: Function parameter or member 'flags' not described in 'amdgpu_vm_update_flags'
   drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c:2821: warning: Function parameter or member 'pasid' not described in 'amdgpu_vm_make_compute'
   drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c:378: warning: Excess function parameter 'entry' description in 'amdgpu_irq_dispatch'
   drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c:379: warning: Function parameter or member 'ih' not described in 'amdgpu_irq_dispatch'
   drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c:379: warning: Excess function parameter 'entry' description in 'amdgpu_irq_dispatch'
   drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c:1: warning: no structured comments found
   drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c:1: warning: no structured comments found
   drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c:1: warning: 'pp_dpm_sclk pp_dpm_mclk pp_dpm_pcie' not found
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:132: warning: Incorrect use of kernel-doc format:          * @atomic_obj
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:238: warning: Incorrect use of kernel-doc format:          * gpu_info FW provided soc bounding box struct or 0 if not
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'atomic_obj' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'backlight_link' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'backlight_caps' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'freesync_module' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'fw_dmcu' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'dmcu_fw_version' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h:243: warning: Function parameter or member 'soc_bounding_box' not described in 'amdgpu_display_manager'
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c:1: warning: 'dm_crtc_high_irq' not found
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c:1: warning: 'dm_pflip_high_irq' not found
   drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c:1: warning: 'register_hpd_handlers' not found
   include/drm/drm_modeset_helper_vtables.h:1053: warning: Function parameter or member 'prepare_writeback_job' not described in 'drm_connector_helper_funcs'
   include/drm/drm_modeset_helper_vtables.h:1053: warning: Function parameter or member 'cleanup_writeback_job' not described in 'drm_connector_helper_funcs'
   include/drm/drm_atomic_state_helper.h:1: warning: no structured comments found
   include/drm/drm_gem_shmem_helper.h:87: warning: Function parameter or member 'madv' not described in 'drm_gem_shmem_object'
   include/drm/drm_gem_shmem_helper.h:87: warning: Function parameter or member 'madv_list' not described in 'drm_gem_shmem_object'
   drivers/gpu/drm/drm_fbconv_helper.c:370: warning: Excess function parameter 'fb_info' description in 'drm_fbconv_format_of_fb_var_screeninfo'
>> include/drm/drm_fbconv_helper.h:124: warning: Function parameter or member 'blit' not described in 'drm_fbconv_modeset'
>> drivers/gpu/drm/drm_fbconv_helper.c:371: warning: Function parameter or member 'fb_var' not described in 'drm_fbconv_format_of_fb_var_screeninfo'
   drivers/gpu/drm/drm_fbconv_helper.c:371: warning: Excess function parameter 'fb_info' description in 'drm_fbconv_format_of_fb_var_screeninfo'
   drivers/gpu/drm/i915/display/intel_dpll_mgr.h:158: warning: Enum value 'DPLL_ID_TGL_MGPLL5' not described in enum 'intel_dpll_id'
   drivers/gpu/drm/i915/display/intel_dpll_mgr.h:158: warning: Enum value 'DPLL_ID_TGL_MGPLL6' not described in enum 'intel_dpll_id'
   drivers/gpu/drm/i915/display/intel_dpll_mgr.h:158: warning: Excess enum value 'DPLL_ID_TGL_TCPLL5' description in 'intel_dpll_id'
   drivers/gpu/drm/i915/display/intel_dpll_mgr.h:158: warning: Excess enum value 'DPLL_ID_TGL_TCPLL6' description in 'intel_dpll_id'
   drivers/gpu/drm/i915/display/intel_dpll_mgr.h:342: warning: Function parameter or member 'wakeref' not described in 'intel_shared_dpll'
   Error: Cannot open file drivers/gpu/drm/i915/i915_gem_batch_pool.c
   Error: Cannot open file drivers/gpu/drm/i915/i915_gem_batch_pool.c
   Error: Cannot open file drivers/gpu/drm/i915/i915_gem_batch_pool.c
   drivers/gpu/drm/i915/i915_drv.h:1129: warning: Incorrect use of kernel-doc format:          * The OA context specific information.
   drivers/gpu/drm/i915/i915_drv.h:1143: warning: Incorrect use of kernel-doc format:          * State of the OA buffer.
   drivers/gpu/drm/i915/i915_drv.h:1154: warning: Incorrect use of kernel-doc format:                  * Locks reads and writes to all head/tail state
   drivers/gpu/drm/i915/i915_drv.h:1176: warning: Incorrect use of kernel-doc format:                  * One 'aging' tail pointer and one 'aged' tail pointer ready to
   drivers/gpu/drm/i915/i915_drv.h:1188: warning: Incorrect use of kernel-doc format:                  * Index for the aged tail ready to read() data up to.
   drivers/gpu/drm/i915/i915_drv.h:1193: warning: Incorrect use of kernel-doc format:                  * A monotonic timestamp for when the current aging tail pointer
   drivers/gpu/drm/i915/i915_drv.h:1199: warning: Incorrect use of kernel-doc format:                  * Although we can always read back the head pointer register,
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'pinned_ctx' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'specific_ctx_id' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'specific_ctx_id_mask' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'poll_check_timer' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'poll_wq' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'pollin' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'periodic' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'period_exponent' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1207: warning: Function parameter or member 'oa_buffer' not described in 'i915_perf_stream'
   drivers/gpu/drm/i915/i915_drv.h:1129: warning: Incorrect use of kernel-doc format:          * The OA context specific information.
   drivers/gpu/drm/i915/i915_drv.h:1143: warning: Incorrect use of kernel-doc format:          * State of the OA buffer.
   drivers/gpu/drm/i915/i915_drv.h:1154: warning: Incorrect use of kernel-doc format:                  * Locks reads and writes to all head/tail state
   drivers/gpu/drm/i915/i915_drv.h:1176: warning: Incorrect use of kernel-doc format:                  * One 'aging' tail pointer and one 'aged' tail pointer ready to
   drivers/gpu/drm/i915/i915_drv.h:1188: warning: Incorrect use of kernel-doc format:                  * Index for the aged tail ready to read() data up to.
   drivers/gpu/drm/i915/i915_drv.h:1193: warning: Incorrect use of kernel-doc format:                  * A monotonic timestamp for when the current aging tail pointer
   drivers/gpu/drm/i915/i915_drv.h:1199: warning: Incorrect use of kernel-doc format:                  * Although we can always read back the head pointer register,
   drivers/gpu/drm/i915/i915_drv.h:1129: warning: Incorrect use of kernel-doc format:          * The OA context specific information.
   drivers/gpu/drm/i915/i915_drv.h:1143: warning: Incorrect use of kernel-doc format:          * State of the OA buffer.
   drivers/gpu/drm/i915/i915_drv.h:1154: warning: Incorrect use of kernel-doc format:                  * Locks reads and writes to all head/tail state
   drivers/gpu/drm/i915/i915_drv.h:1176: warning: Incorrect use of kernel-doc format:                  * One 'aging' tail pointer and one 'aged' tail pointer ready to
   drivers/gpu/drm/i915/i915_drv.h:1188: warning: Incorrect use of kernel-doc format:                  * Index for the aged tail ready to read() data up to.
   drivers/gpu/drm/i915/i915_drv.h:1193: warning: Incorrect use of kernel-doc format:                  * A monotonic timestamp for when the current aging tail pointer
   drivers/gpu/drm/i915/i915_drv.h:1199: warning: Incorrect use of kernel-doc format:                  * Although we can always read back the head pointer register,
   drivers/gpu/drm/mcde/mcde_drv.c:1: warning: 'ST-Ericsson MCDE DRM Driver' not found
   include/net/cfg80211.h:1185: warning: Function parameter or member 'txpwr' not described in 'station_parameters'
   include/net/mac80211.h:4056: warning: Function parameter or member 'sta_set_txpwr' not described in 'ieee80211_ops'
   include/net/mac80211.h:2018: warning: Function parameter or member 'txpwr' not described in 'ieee80211_sta'
   Documentation/admin-guide/perf/imx-ddr.rst:21: WARNING: Unexpected indentation.
   Documentation/admin-guide/perf/imx-ddr.rst:34: WARNING: Unexpected indentation.
   Documentation/admin-guide/perf/imx-ddr.rst:40: WARNING: Unexpected indentation.
   Documentation/admin-guide/perf/imx-ddr.rst:45: WARNING: Unexpected indentation.
   Documentation/admin-guide/perf/imx-ddr.rst:52: WARNING: Unexpected indentation.
   Documentation/admin-guide/xfs.rst:257: WARNING: Block quote ends without a blank line; unexpected unindent.
   Documentation/filesystems/ubifs-authentication.rst:94: WARNING: Inline interpreted text or phrase reference start-string without end-string.
   Documentation/usb/index.rst:5: WARNING: toctree contains reference to nonexisting document 'usb/rio'
   Documentation/usb/index.rst:5: WARNING: toctree contains reference to nonexisting document 'usb/wusb-design-overview'
   Documentation/usb/text_files.rst:22: WARNING: Include file 'Documentation/usb/wusb-cbaf' not found or reading it failed
   Documentation/trace/kprobetrace.rst:100: WARNING: Explicit markup ends without a blank line; unexpected unindent.
   WARNING: kernel-doc 'scripts/kernel-doc -rst -enable-lineno -function Reservation Object Overview drivers/dma-buf/reservation.c' failed with return code 1
   WARNING: kernel-doc 'scripts/kernel-doc -rst -enable-lineno -export drivers/dma-buf/reservation.c' failed with return code 2
   WARNING: kernel-doc 'scripts/kernel-doc -rst -enable-lineno -internal include/linux/reservation.h' failed with return code 2
   Documentation/translations/it_IT/process/maintainer-pgp-guide.rst:458: WARNING: Unknown target name: "nitrokey pro".
   Documentation/security/keys/core.rst:1110: WARNING: Inline emphasis start-string without end-string.
   Documentation/security/keys/core.rst:1110: WARNING: Inline emphasis start-string without end-string.
   Documentation/security/keys/core.rst:1108: WARNING: Inline emphasis start-string without end-string.
   Documentation/security/keys/core.rst:1108: WARNING: Inline emphasis start-string without end-string.
   Documentation/security/keys/core.rst:1108: WARNING: Inline emphasis start-string without end-string.
   include/uapi/linux/firewire-cdev.h:312: WARNING: Inline literal start-string without end-string.
   drivers/firewire/core-transaction.c:606: WARNING: Inline strong start-string without end-string.
   drivers/ata/libata-core.c:5945: WARNING: Unknown target name: "hw".
   drivers/message/fusion/mptbase.c:5057: WARNING: Definition list ends without a blank line; unexpected unindent.
   include/linux/regulator/driver.h:284: WARNING: Unknown target name: "regulator_regmap_x_voltage".
   include/linux/spi/spi.h:382: WARNING: Unexpected indentation.
   fs/seq_file.c:40: WARNING: Inline strong start-string without end-string.
   fs/seq_file.c:40: WARNING: Inline strong start-string without end-string.
   fs/seq_file.c:40: WARNING: Inline strong start-string without end-string.
   fs/seq_file.c:40: WARNING: Inline strong start-string without end-string.
   fs/posix_acl.c:636: WARNING: Inline emphasis start-string without end-string.
   fs/debugfs/inode.c:427: WARNING: Inline literal start-string without end-string.
   fs/debugfs/inode.c:506: WARNING: Inline literal start-string without end-string.
   fs/debugfs/inode.c:538: WARNING: Inline literal start-string without end-string.
   fs/debugfs/inode.c:631: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:424: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:430: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:469: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:475: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:514: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:520: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:560: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:566: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:608: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:614: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:875: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:881: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:928: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:934: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:1120: WARNING: Inline literal start-string without end-string.
   fs/debugfs/file.c:1126: WARNING: Inline literal start-string without end-string.
   Documentation/networking/device_drivers/pensando/ionic.rst:39: WARNING: Unexpected indentation.
   Documentation/networking/device_drivers/pensando/ionic.rst:43: WARNING: Unexpected indentation.
   Documentation/misc-devices/index.rst:14: WARNING: toctree contains reference to nonexisting document 'misc-devices/xilinx_sdfec'
   Documentation/driver-api/gpio/driver.rst:420: WARNING: Unexpected indentation.
   Documentation/driver-api/gpio/driver.rst:418: WARNING: Inline emphasis start-string without end-string.
   Documentation/driver-api/gpio/driver.rst:422: WARNING: Block quote ends without a blank line; unexpected unindent.

vim +124 include/drm/drm_fbconv_helper.h

87f9f686c7da49 Thomas Zimmermann 2019-10-14 @124  

:::::: The code at line 124 was first introduced by commit
:::::: 87f9f686c7da49f2b145d7c1073bb38319b31f99 drm/fbconv: Add modesetting infrastructure

:::::: TO: Thomas Zimmermann <tzimmermann@suse.de>
:::::: CC: 0day robot <lkp@intel.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 7279 bytes --]

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

* Re: [PATCH v2 14/15] staging/mgakms: Import matroxfb driver source code
  2019-10-14 14:04 ` [PATCH v2 14/15] staging/mgakms: Import matroxfb driver source code Thomas Zimmermann
@ 2019-10-15 11:48     ` Ville Syrjälä
  0 siblings, 0 replies; 77+ messages in thread
From: Ville Syrjälä @ 2019-10-15 11:48 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: linux-fbdev, b.zolnierkie, airlied, gregkh, michel, corbet,
	malat, dri-devel, sean

On Mon, Oct 14, 2019 at 04:04:15PM +0200, Thomas Zimmermann wrote:
> Only code is being copied, no functional changes are made.
> 
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
>  drivers/staging/mgakms/g450_pll.c         |  539 +++++a

...

Personally I would start from scratch. In fact some years (*cough*
decade) ago I did just that and started writing a new driver for
matrox stuff. Unfortunately I ran out of steam after figuring out
most of the interesting hardware quirks and whatnot, so I never
finished it. The end result is that it still runs in userspace
but kinda looks like a kernel driver if you squint a bit.

Anyways, I just slapped a MIT license on it  dumped the whole
thing here:
https://gitlab.com/syrjala/mga
The development history was, shall we say, not really useful
so I just squashed it.

You, or someone else, might find it interesting. I think in
terms of hardware support it's a superset of any other driver,
apart from the blob.

-- 
Ville Syrjälä
syrjala@sci.fi
http://www.sci.fi/~syrjala/

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

* Re: [PATCH v2 14/15] staging/mgakms: Import matroxfb driver source code
@ 2019-10-15 11:48     ` Ville Syrjälä
  0 siblings, 0 replies; 77+ messages in thread
From: Ville Syrjälä @ 2019-10-15 11:48 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: linux-fbdev, b.zolnierkie, airlied, gregkh, michel, corbet,
	malat, dri-devel, sean

On Mon, Oct 14, 2019 at 04:04:15PM +0200, Thomas Zimmermann wrote:
> Only code is being copied, no functional changes are made.
> 
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> ---
>  drivers/staging/mgakms/g450_pll.c         |  539 +++++a

...

Personally I would start from scratch. In fact some years (*cough*
decade) ago I did just that and started writing a new driver for
matrox stuff. Unfortunately I ran out of steam after figuring out
most of the interesting hardware quirks and whatnot, so I never
finished it. The end result is that it still runs in userspace
but kinda looks like a kernel driver if you squint a bit.

Anyways, I just slapped a MIT license on it  dumped the whole
thing here:
https://gitlab.com/syrjala/mga
The development history was, shall we say, not really useful
so I just squashed it.

You, or someone else, might find it interesting. I think in
terms of hardware support it's a superset of any other driver,
apart from the blob.

-- 
Ville Syrjälä
syrjala@sci.fi
http://www.sci.fi/~syrjala/
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 14/15] staging/mgakms: Import matroxfb driver source code
  2019-10-15 11:48     ` Ville Syrjälä
@ 2019-10-15 12:46       ` Thomas Zimmermann
  -1 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-15 12:46 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel, corbet, gregkh, dri-devel,
	linux-fbdev


[-- Attachment #1.1: Type: text/plain, Size: 1885 bytes --]

Hi

Am 15.10.19 um 13:48 schrieb Ville Syrjälä:
> On Mon, Oct 14, 2019 at 04:04:15PM +0200, Thomas Zimmermann wrote:
>> Only code is being copied, no functional changes are made.
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> ---
>>  drivers/staging/mgakms/g450_pll.c         |  539 +++++a
> 
> ...
> 
> Personally I would start from scratch. In fact some years (*cough*
> decade) ago I did just that and started writing a new driver for
> matrox stuff. Unfortunately I ran out of steam after figuring out
> most of the interesting hardware quirks and whatnot, so I never
> finished it. The end result is that it still runs in userspace
> but kinda looks like a kernel driver if you squint a bit.
> 
> Anyways, I just slapped a MIT license on it  dumped the whole
> thing here:
> https://gitlab.com/syrjala/mga
> The development history was, shall we say, not really useful
> so I just squashed it.
> 
> You, or someone else, might find it interesting. I think in
> terms of hardware support it's a superset of any other driver,
> apart from the blob.
> 

Just to make this clear: I do not intend to port every single fbdev
driver to DRM. :)

I did, however, began to convert that Matrox driver. First, to see if
the approach does work in general; and because matroxfb is one of the
more complex drivers. If it can be converted, any other driver should be
convertible as well. I split up the driver code by HW generation and can
now refactor each generation on its own. I expect to end up with several
duplicated functions, which can be re-merged.

Maybe our repo can be helpful. Thanks for the link.

Best regards
Thomas

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH v2 14/15] staging/mgakms: Import matroxfb driver source code
@ 2019-10-15 12:46       ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-15 12:46 UTC (permalink / raw)
  To: airlied, daniel, maarten.lankhorst, mripard, sean, b.zolnierkie,
	ajax, ville.syrjala, malat, michel, corbet, gregkh, dri-devel,
	linux-fbdev


[-- Attachment #1.1.1: Type: text/plain, Size: 1885 bytes --]

Hi

Am 15.10.19 um 13:48 schrieb Ville Syrjälä:
> On Mon, Oct 14, 2019 at 04:04:15PM +0200, Thomas Zimmermann wrote:
>> Only code is being copied, no functional changes are made.
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
>> ---
>>  drivers/staging/mgakms/g450_pll.c         |  539 +++++a
> 
> ...
> 
> Personally I would start from scratch. In fact some years (*cough*
> decade) ago I did just that and started writing a new driver for
> matrox stuff. Unfortunately I ran out of steam after figuring out
> most of the interesting hardware quirks and whatnot, so I never
> finished it. The end result is that it still runs in userspace
> but kinda looks like a kernel driver if you squint a bit.
> 
> Anyways, I just slapped a MIT license on it  dumped the whole
> thing here:
> https://gitlab.com/syrjala/mga
> The development history was, shall we say, not really useful
> so I just squashed it.
> 
> You, or someone else, might find it interesting. I think in
> terms of hardware support it's a superset of any other driver,
> apart from the blob.
> 

Just to make this clear: I do not intend to port every single fbdev
driver to DRM. :)

I did, however, began to convert that Matrox driver. First, to see if
the approach does work in general; and because matroxfb is one of the
more complex drivers. If it can be converted, any other driver should be
convertible as well. I split up the driver code by HW generation and can
now refactor each generation on its own. I expect to end up with several
duplicated functions, which can be re-merged.

Maybe our repo can be helpful. Thanks for the link.

Best regards
Thomas

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

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

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

* Re: [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers
  2019-10-14 14:04 ` Thomas Zimmermann
@ 2019-10-15 14:33   ` Daniel Vetter
  -1 siblings, 0 replies; 77+ messages in thread
From: Daniel Vetter @ 2019-10-15 14:33 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: linux-fbdev, b.zolnierkie, airlied, gregkh, michel, corbet,
	malat, dri-devel, sean

Hi Thomas,

On Mon, Oct 14, 2019 at 04:04:01PM +0200, Thomas Zimmermann wrote:
> (was: DRM driver for fbdev devices)
> 
> This is version 2 of the fbdev conversion helpers. It's more or less a
> rewrite of the original patchset.
> 
> The fbdev subsystem is considered legacy and will probably be removed at
> some point. This would mean the loss of a signifanct number of drivers.
> Some of the affected hardware is not in use any longer, but some hardware
> is still around and provides good(-enough) framebuffers.
> 
> The fbconv helpers allow for running the current DRM stack on top of fbdev
> drivers. It's a set of functions that convert between fbdev interfaces and
> DRM interfaces. Based on SHMEM and simple KMS helpers, it only offers the
> basic functionality of a framebuffer, but should be compatible with most
> existing fbdev drivers.
> 
> A DRM driver using fbconv helpers consists of
> 
>   * DRM stub code that calls into fbconv helpers, and
>   * the original fbdev driver code.
> 
> The fbdev driver code has to be modified to register itself with the
> stub driver instead of the fbdev core framework. A tutorial on how to use
> the helpers is part of this patchset. The resulting driver hybrid can be
> refactored into a first-class DRM driver. The fbconv helpers contain a
> number of comments, labeled 'DRM porting note', which explain the required
> steps.
> 
> I tested the current patchset with the following drivers: atyfb, aty128fb,
> matroxfb, pm2fb, pm3fb, rivafb, s3fb, savagefb, sisfb, tdfxfb and tridentfb.
> With each, I was able to successfully start with fbcon enabled, run weston and
> X11. The drivers are available at [1]. For reference, the patchset includes
> the Matrox stub driver.

So I really don't want to rain on the parade here, since if you think this
is useful when converting fbdev drivers I'll buy that, and I'm all for
getting more modern drivers into drm.

But I have a bunch of concerns with the approach you're proposing here:

- we've tried staging for drm driver refactoring, it hurts. Separate tree
  plus the quick pace in refactoring create lots of pains. And for small
  drivers refacotoring before it's not buying you anything above
  refactoring in your own personal tree. And for big drivers we're fairly
  lenient with merging drivers that aren't fully polished yet, if there's
  a team serious enough with cleaning up the mess. I think even merging
  partial drivers directly under drivers/gpu (but behind CONFIG_BROKEN) is
  better than staging.

- we've had conversion helpers before (for the legacy kms -> atomic
  upgrade). They constantly broke, pretty much every release when someone
  wanted to use them they first had to fix them up again. I think having
  those helpers is good, but better to just have them in some branch
  somewhere where it's clear that they might not work anymore on latest
  upstream.

- especially for some of these simple fbdev drivers I feel like just
  typing a new driver from scratch might be simpler.

A few more concerns specifically for your mga example:

- We already have a mga driver. Might be better to integrate support for
  older mgas into that than have a parallel driver.

- Your helper is based on simple display pipe, and I think for these old
  mga chips (especially the dual pipe mga 450 and 550) simple display pipe
  helper is more a hindering detour than actual help. From a quick read
  through the code (especially all the custom ioctls) you definitely want
  separate TV-out connector to expose all the tv mode properties (instead
  of the custom ioctls).

- On the topic of ioctls, looks like we could add FBIOGET_VBLANK to our
  generic implementation in the fbdev helpers.

So here's my alternative proposal:

- You push this as a branch onto a gitlab repo (freedesktop.org or
  wherever you feel like).

- You add a gitlab CI target to autobuild the very nice kerneldoc you've
  created. Feel free to also do this with anything else you're familiar
  with, it's just I know gitlab and it's real simple to get a few docs
  autogenerated and published with it.

- We add a todo.rst patch linking to your branch and the docs and a few
  lines on how to best convert an fbdev driver over to kms/atomic.

And all the drivers would land the usual way, like any of the other
drivers we've added to drivers/gpu/drm over the past few years.

Thoughts?

Cheers, Daniel
> 
> v2:
> 	* rename to fbconv helpers
> 	* rewrite as helper library
> 	* switch over to simple KMS helpers
> 	* switch over to SHMEM
> 	* add documentation
> 
> [1] https://gitlab.freedesktop.org/tzimmermann/linux/commits/fbconv-plus-drivers
> 
> Thomas Zimmermann (15):
>   fbdev: Export fb_check_foreignness()
>   fbdev: Export FBPIXMAPSIZE
>   drm/simple-kms-helper: Add mode_fixup() to simple display pipe
>   drm: Add fbconv helper module
>   drm/fbconv: Add DRM <-> fbdev pixel-format conversion
>   drm/fbconv: Add mode conversion DRM <-> fbdev
>   drm/fbconv: Add modesetting infrastructure
>   drm/fbconv: Add plane-state check and update
>   drm/fbconv: Mode-setting pipeline enable / disable
>   drm/fbconv: Reimplement several fbdev interfaces
>   drm/fbconv: Add helpers for init and cleanup of fb_info structures
>   drm/fbconv: Add helper documentation
>   staging: Add mgakms driver
>   staging/mgakms: Import matroxfb driver source code
>   staging/mgakms: Update matroxfb driver code for DRM
> 
>  Documentation/gpu/drm-kms-helpers.rst     |   12 +
>  Documentation/gpu/todo.rst                |   15 +
>  drivers/gpu/drm/Kconfig                   |   11 +
>  drivers/gpu/drm/Makefile                  |    1 +
>  drivers/gpu/drm/drm_fbconv_helper.c       | 2126 +++++++++++++++++
>  drivers/gpu/drm/drm_simple_kms_helper.c   |   15 +
>  drivers/staging/Kconfig                   |    2 +
>  drivers/staging/Makefile                  |    1 +
>  drivers/staging/mgakms/Kconfig            |   18 +
>  drivers/staging/mgakms/Makefile           |   17 +
>  drivers/staging/mgakms/g450_pll.c         |  539 +++++
>  drivers/staging/mgakms/g450_pll.h         |   13 +
>  drivers/staging/mgakms/i2c-matroxfb.c     |  238 ++
>  drivers/staging/mgakms/matroxfb_DAC1064.c | 1082 +++++++++
>  drivers/staging/mgakms/matroxfb_DAC1064.h |  174 ++
>  drivers/staging/mgakms/matroxfb_Ti3026.c  |  746 ++++++
>  drivers/staging/mgakms/matroxfb_Ti3026.h  |   10 +
>  drivers/staging/mgakms/matroxfb_accel.c   |  519 +++++
>  drivers/staging/mgakms/matroxfb_accel.h   |    9 +
>  drivers/staging/mgakms/matroxfb_base.c    | 2592 +++++++++++++++++++++
>  drivers/staging/mgakms/matroxfb_base.h    |  700 ++++++
>  drivers/staging/mgakms/matroxfb_crtc2.h   |   35 +
>  drivers/staging/mgakms/matroxfb_g450.c    |  640 +++++
>  drivers/staging/mgakms/matroxfb_g450.h    |   10 +
>  drivers/staging/mgakms/matroxfb_maven.h   |   21 +
>  drivers/staging/mgakms/matroxfb_misc.c    |  815 +++++++
>  drivers/staging/mgakms/matroxfb_misc.h    |   22 +
>  drivers/staging/mgakms/mga_device.c       |   68 +
>  drivers/staging/mgakms/mga_device.h       |   30 +
>  drivers/staging/mgakms/mga_drv.c          |  129 +
>  drivers/staging/mgakms/mga_drv.h          |   14 +
>  drivers/video/fbdev/core/fbmem.c          |    5 +-
>  include/drm/drm_fbconv_helper.h           |  150 ++
>  include/drm/drm_simple_kms_helper.h       |   43 +
>  include/linux/fb.h                        |    3 +
>  35 files changed, 10822 insertions(+), 3 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_fbconv_helper.c
>  create mode 100644 drivers/staging/mgakms/Kconfig
>  create mode 100644 drivers/staging/mgakms/Makefile
>  create mode 100644 drivers/staging/mgakms/g450_pll.c
>  create mode 100644 drivers/staging/mgakms/g450_pll.h
>  create mode 100644 drivers/staging/mgakms/i2c-matroxfb.c
>  create mode 100644 drivers/staging/mgakms/matroxfb_DAC1064.c
>  create mode 100644 drivers/staging/mgakms/matroxfb_DAC1064.h
>  create mode 100644 drivers/staging/mgakms/matroxfb_Ti3026.c
>  create mode 100644 drivers/staging/mgakms/matroxfb_Ti3026.h
>  create mode 100644 drivers/staging/mgakms/matroxfb_accel.c
>  create mode 100644 drivers/staging/mgakms/matroxfb_accel.h
>  create mode 100644 drivers/staging/mgakms/matroxfb_base.c
>  create mode 100644 drivers/staging/mgakms/matroxfb_base.h
>  create mode 100644 drivers/staging/mgakms/matroxfb_crtc2.h
>  create mode 100644 drivers/staging/mgakms/matroxfb_g450.c
>  create mode 100644 drivers/staging/mgakms/matroxfb_g450.h
>  create mode 100644 drivers/staging/mgakms/matroxfb_maven.h
>  create mode 100644 drivers/staging/mgakms/matroxfb_misc.c
>  create mode 100644 drivers/staging/mgakms/matroxfb_misc.h
>  create mode 100644 drivers/staging/mgakms/mga_device.c
>  create mode 100644 drivers/staging/mgakms/mga_device.h
>  create mode 100644 drivers/staging/mgakms/mga_drv.c
>  create mode 100644 drivers/staging/mgakms/mga_drv.h
>  create mode 100644 include/drm/drm_fbconv_helper.h
> 
> --
> 2.23.0
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

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

* Re: [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers
@ 2019-10-15 14:33   ` Daniel Vetter
  0 siblings, 0 replies; 77+ messages in thread
From: Daniel Vetter @ 2019-10-15 14:33 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: linux-fbdev, b.zolnierkie, airlied, gregkh, michel, corbet,
	malat, dri-devel, sean

Hi Thomas,

On Mon, Oct 14, 2019 at 04:04:01PM +0200, Thomas Zimmermann wrote:
> (was: DRM driver for fbdev devices)
> 
> This is version 2 of the fbdev conversion helpers. It's more or less a
> rewrite of the original patchset.
> 
> The fbdev subsystem is considered legacy and will probably be removed at
> some point. This would mean the loss of a signifanct number of drivers.
> Some of the affected hardware is not in use any longer, but some hardware
> is still around and provides good(-enough) framebuffers.
> 
> The fbconv helpers allow for running the current DRM stack on top of fbdev
> drivers. It's a set of functions that convert between fbdev interfaces and
> DRM interfaces. Based on SHMEM and simple KMS helpers, it only offers the
> basic functionality of a framebuffer, but should be compatible with most
> existing fbdev drivers.
> 
> A DRM driver using fbconv helpers consists of
> 
>   * DRM stub code that calls into fbconv helpers, and
>   * the original fbdev driver code.
> 
> The fbdev driver code has to be modified to register itself with the
> stub driver instead of the fbdev core framework. A tutorial on how to use
> the helpers is part of this patchset. The resulting driver hybrid can be
> refactored into a first-class DRM driver. The fbconv helpers contain a
> number of comments, labeled 'DRM porting note', which explain the required
> steps.
> 
> I tested the current patchset with the following drivers: atyfb, aty128fb,
> matroxfb, pm2fb, pm3fb, rivafb, s3fb, savagefb, sisfb, tdfxfb and tridentfb.
> With each, I was able to successfully start with fbcon enabled, run weston and
> X11. The drivers are available at [1]. For reference, the patchset includes
> the Matrox stub driver.

So I really don't want to rain on the parade here, since if you think this
is useful when converting fbdev drivers I'll buy that, and I'm all for
getting more modern drivers into drm.

But I have a bunch of concerns with the approach you're proposing here:

- we've tried staging for drm driver refactoring, it hurts. Separate tree
  plus the quick pace in refactoring create lots of pains. And for small
  drivers refacotoring before it's not buying you anything above
  refactoring in your own personal tree. And for big drivers we're fairly
  lenient with merging drivers that aren't fully polished yet, if there's
  a team serious enough with cleaning up the mess. I think even merging
  partial drivers directly under drivers/gpu (but behind CONFIG_BROKEN) is
  better than staging.

- we've had conversion helpers before (for the legacy kms -> atomic
  upgrade). They constantly broke, pretty much every release when someone
  wanted to use them they first had to fix them up again. I think having
  those helpers is good, but better to just have them in some branch
  somewhere where it's clear that they might not work anymore on latest
  upstream.

- especially for some of these simple fbdev drivers I feel like just
  typing a new driver from scratch might be simpler.

A few more concerns specifically for your mga example:

- We already have a mga driver. Might be better to integrate support for
  older mgas into that than have a parallel driver.

- Your helper is based on simple display pipe, and I think for these old
  mga chips (especially the dual pipe mga 450 and 550) simple display pipe
  helper is more a hindering detour than actual help. From a quick read
  through the code (especially all the custom ioctls) you definitely want
  separate TV-out connector to expose all the tv mode properties (instead
  of the custom ioctls).

- On the topic of ioctls, looks like we could add FBIOGET_VBLANK to our
  generic implementation in the fbdev helpers.

So here's my alternative proposal:

- You push this as a branch onto a gitlab repo (freedesktop.org or
  wherever you feel like).

- You add a gitlab CI target to autobuild the very nice kerneldoc you've
  created. Feel free to also do this with anything else you're familiar
  with, it's just I know gitlab and it's real simple to get a few docs
  autogenerated and published with it.

- We add a todo.rst patch linking to your branch and the docs and a few
  lines on how to best convert an fbdev driver over to kms/atomic.

And all the drivers would land the usual way, like any of the other
drivers we've added to drivers/gpu/drm over the past few years.

Thoughts?

Cheers, Daniel
> 
> v2:
> 	* rename to fbconv helpers
> 	* rewrite as helper library
> 	* switch over to simple KMS helpers
> 	* switch over to SHMEM
> 	* add documentation
> 
> [1] https://gitlab.freedesktop.org/tzimmermann/linux/commits/fbconv-plus-drivers
> 
> Thomas Zimmermann (15):
>   fbdev: Export fb_check_foreignness()
>   fbdev: Export FBPIXMAPSIZE
>   drm/simple-kms-helper: Add mode_fixup() to simple display pipe
>   drm: Add fbconv helper module
>   drm/fbconv: Add DRM <-> fbdev pixel-format conversion
>   drm/fbconv: Add mode conversion DRM <-> fbdev
>   drm/fbconv: Add modesetting infrastructure
>   drm/fbconv: Add plane-state check and update
>   drm/fbconv: Mode-setting pipeline enable / disable
>   drm/fbconv: Reimplement several fbdev interfaces
>   drm/fbconv: Add helpers for init and cleanup of fb_info structures
>   drm/fbconv: Add helper documentation
>   staging: Add mgakms driver
>   staging/mgakms: Import matroxfb driver source code
>   staging/mgakms: Update matroxfb driver code for DRM
> 
>  Documentation/gpu/drm-kms-helpers.rst     |   12 +
>  Documentation/gpu/todo.rst                |   15 +
>  drivers/gpu/drm/Kconfig                   |   11 +
>  drivers/gpu/drm/Makefile                  |    1 +
>  drivers/gpu/drm/drm_fbconv_helper.c       | 2126 +++++++++++++++++
>  drivers/gpu/drm/drm_simple_kms_helper.c   |   15 +
>  drivers/staging/Kconfig                   |    2 +
>  drivers/staging/Makefile                  |    1 +
>  drivers/staging/mgakms/Kconfig            |   18 +
>  drivers/staging/mgakms/Makefile           |   17 +
>  drivers/staging/mgakms/g450_pll.c         |  539 +++++
>  drivers/staging/mgakms/g450_pll.h         |   13 +
>  drivers/staging/mgakms/i2c-matroxfb.c     |  238 ++
>  drivers/staging/mgakms/matroxfb_DAC1064.c | 1082 +++++++++
>  drivers/staging/mgakms/matroxfb_DAC1064.h |  174 ++
>  drivers/staging/mgakms/matroxfb_Ti3026.c  |  746 ++++++
>  drivers/staging/mgakms/matroxfb_Ti3026.h  |   10 +
>  drivers/staging/mgakms/matroxfb_accel.c   |  519 +++++
>  drivers/staging/mgakms/matroxfb_accel.h   |    9 +
>  drivers/staging/mgakms/matroxfb_base.c    | 2592 +++++++++++++++++++++
>  drivers/staging/mgakms/matroxfb_base.h    |  700 ++++++
>  drivers/staging/mgakms/matroxfb_crtc2.h   |   35 +
>  drivers/staging/mgakms/matroxfb_g450.c    |  640 +++++
>  drivers/staging/mgakms/matroxfb_g450.h    |   10 +
>  drivers/staging/mgakms/matroxfb_maven.h   |   21 +
>  drivers/staging/mgakms/matroxfb_misc.c    |  815 +++++++
>  drivers/staging/mgakms/matroxfb_misc.h    |   22 +
>  drivers/staging/mgakms/mga_device.c       |   68 +
>  drivers/staging/mgakms/mga_device.h       |   30 +
>  drivers/staging/mgakms/mga_drv.c          |  129 +
>  drivers/staging/mgakms/mga_drv.h          |   14 +
>  drivers/video/fbdev/core/fbmem.c          |    5 +-
>  include/drm/drm_fbconv_helper.h           |  150 ++
>  include/drm/drm_simple_kms_helper.h       |   43 +
>  include/linux/fb.h                        |    3 +
>  35 files changed, 10822 insertions(+), 3 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_fbconv_helper.c
>  create mode 100644 drivers/staging/mgakms/Kconfig
>  create mode 100644 drivers/staging/mgakms/Makefile
>  create mode 100644 drivers/staging/mgakms/g450_pll.c
>  create mode 100644 drivers/staging/mgakms/g450_pll.h
>  create mode 100644 drivers/staging/mgakms/i2c-matroxfb.c
>  create mode 100644 drivers/staging/mgakms/matroxfb_DAC1064.c
>  create mode 100644 drivers/staging/mgakms/matroxfb_DAC1064.h
>  create mode 100644 drivers/staging/mgakms/matroxfb_Ti3026.c
>  create mode 100644 drivers/staging/mgakms/matroxfb_Ti3026.h
>  create mode 100644 drivers/staging/mgakms/matroxfb_accel.c
>  create mode 100644 drivers/staging/mgakms/matroxfb_accel.h
>  create mode 100644 drivers/staging/mgakms/matroxfb_base.c
>  create mode 100644 drivers/staging/mgakms/matroxfb_base.h
>  create mode 100644 drivers/staging/mgakms/matroxfb_crtc2.h
>  create mode 100644 drivers/staging/mgakms/matroxfb_g450.c
>  create mode 100644 drivers/staging/mgakms/matroxfb_g450.h
>  create mode 100644 drivers/staging/mgakms/matroxfb_maven.h
>  create mode 100644 drivers/staging/mgakms/matroxfb_misc.c
>  create mode 100644 drivers/staging/mgakms/matroxfb_misc.h
>  create mode 100644 drivers/staging/mgakms/mga_device.c
>  create mode 100644 drivers/staging/mgakms/mga_device.h
>  create mode 100644 drivers/staging/mgakms/mga_drv.c
>  create mode 100644 drivers/staging/mgakms/mga_drv.h
>  create mode 100644 include/drm/drm_fbconv_helper.h
> 
> --
> 2.23.0
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers
  2019-10-15 14:33   ` Daniel Vetter
@ 2019-10-15 17:28     ` Thomas Zimmermann
  -1 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-15 17:28 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: linux-fbdev, b.zolnierkie, airlied, gregkh, michel, corbet,
	malat, dri-devel, sean


[-- Attachment #1.1: Type: text/plain, Size: 10549 bytes --]

Hi Daniel

Am 15.10.19 um 16:33 schrieb Daniel Vetter:
> Hi Thomas,
> 
> On Mon, Oct 14, 2019 at 04:04:01PM +0200, Thomas Zimmermann wrote:
>> (was: DRM driver for fbdev devices)
>>
>> This is version 2 of the fbdev conversion helpers. It's more or less a
>> rewrite of the original patchset.
>>
>> The fbdev subsystem is considered legacy and will probably be removed at
>> some point. This would mean the loss of a signifanct number of drivers.
>> Some of the affected hardware is not in use any longer, but some hardware
>> is still around and provides good(-enough) framebuffers.
>>
>> The fbconv helpers allow for running the current DRM stack on top of fbdev
>> drivers. It's a set of functions that convert between fbdev interfaces and
>> DRM interfaces. Based on SHMEM and simple KMS helpers, it only offers the
>> basic functionality of a framebuffer, but should be compatible with most
>> existing fbdev drivers.
>>
>> A DRM driver using fbconv helpers consists of
>>
>>   * DRM stub code that calls into fbconv helpers, and
>>   * the original fbdev driver code.
>>
>> The fbdev driver code has to be modified to register itself with the
>> stub driver instead of the fbdev core framework. A tutorial on how to use
>> the helpers is part of this patchset. The resulting driver hybrid can be
>> refactored into a first-class DRM driver. The fbconv helpers contain a
>> number of comments, labeled 'DRM porting note', which explain the required
>> steps.
>>
>> I tested the current patchset with the following drivers: atyfb, aty128fb,
>> matroxfb, pm2fb, pm3fb, rivafb, s3fb, savagefb, sisfb, tdfxfb and tridentfb.
>> With each, I was able to successfully start with fbcon enabled, run weston and
>> X11. The drivers are available at [1]. For reference, the patchset includes
>> the Matrox stub driver.
> 
> So I really don't want to rain on the parade here, since if you think this
> is useful when converting fbdev drivers I'll buy that, and I'm all for
> getting more modern drivers into drm.
> 
> But I have a bunch of concerns with the approach you're proposing here:
> 
> - we've tried staging for drm driver refactoring, it hurts. Separate tree
>   plus the quick pace in refactoring create lots of pains. And for small
>   drivers refacotoring before it's not buying you anything above
>   refactoring in your own personal tree. And for big drivers we're fairly
>   lenient with merging drivers that aren't fully polished yet, if there's
>   a team serious enough with cleaning up the mess. I think even merging
>   partial drivers directly under drivers/gpu (but behind CONFIG_BROKEN) is
>   better than staging.

I mostly put this into staging, because it's the kind of code you'd
expect there.

> - we've had conversion helpers before (for the legacy kms -> atomic
>   upgrade). They constantly broke, pretty much every release when someone
>   wanted to use them they first had to fix them up again. I think having
>   those helpers is good, but better to just have them in some branch
>   somewhere where it's clear that they might not work anymore on latest
>   upstream.
> 
> - especially for some of these simple fbdev drivers I feel like just
>   typing a new driver from scratch might be simpler.
> 
> A few more concerns specifically for your mga example:
> 
> - We already have a mga driver. Might be better to integrate support for
>   older mgas into that than have a parallel driver.

Two colleagues of mine, Takashi and Egbert, send a patch that added
support for desktop G200s to mgag200. [1] But it was rejected because
the devices are two old and not relevant any longer. If that opinion has
changed in the meantime, I wouldn't mind adding support for desktop GPUs
to the driver.

> - Your helper is based on simple display pipe, and I think for these old
>   mga chips (especially the dual pipe mga 450 and 550) simple display pipe
>   helper is more a hindering detour than actual help. From a quick read
>   through the code (especially all the custom ioctls) you definitely want
>   separate TV-out connector to expose all the tv mode properties (instead
>   of the custom ioctls).

Around the G100, there's something like a change in generation. Before,
devices had only a single output and less than 8 MiB of RAM. This works
well with GEM SHMEM and simple KMS. Afterwards, devices have 8 MiB or
more and multiple outputs. GEM VRAM and the full set of helpers fit this
much better. Maybe having 2 drivers that share common code (or 3 with
the Server Engine chipsets) makes most sense.

> 
> - On the topic of ioctls, looks like we could add FBIOGET_VBLANK to our
>   generic implementation in the fbdev helpers.
> 
> So here's my alternative proposal:
> 
> - You push this as a branch onto a gitlab repo (freedesktop.org or
>   wherever you feel like).
> 
> - You add a gitlab CI target to autobuild the very nice kerneldoc you've
>   created. Feel free to also do this with anything else you're familiar
>   with, it's just I know gitlab and it's real simple to get a few docs
>   autogenerated and published with it.
> 
> - We add a todo.rst patch linking to your branch and the docs and a few
>   lines on how to best convert an fbdev driver over to kms/atomic.

Yes we can do that.

Best regards
Thomas

[1] https://lists.freedesktop.org/archives/dri-devel/2017-July/147868.html

> 
> And all the drivers would land the usual way, like any of the other
> drivers we've added to drivers/gpu/drm over the past few years.
> 
> Thoughts?
> 
> Cheers, Daniel
>>
>> v2:
>> 	* rename to fbconv helpers
>> 	* rewrite as helper library
>> 	* switch over to simple KMS helpers
>> 	* switch over to SHMEM
>> 	* add documentation
>>
>> [1] https://gitlab.freedesktop.org/tzimmermann/linux/commits/fbconv-plus-drivers
>>
>> Thomas Zimmermann (15):
>>   fbdev: Export fb_check_foreignness()
>>   fbdev: Export FBPIXMAPSIZE
>>   drm/simple-kms-helper: Add mode_fixup() to simple display pipe
>>   drm: Add fbconv helper module
>>   drm/fbconv: Add DRM <-> fbdev pixel-format conversion
>>   drm/fbconv: Add mode conversion DRM <-> fbdev
>>   drm/fbconv: Add modesetting infrastructure
>>   drm/fbconv: Add plane-state check and update
>>   drm/fbconv: Mode-setting pipeline enable / disable
>>   drm/fbconv: Reimplement several fbdev interfaces
>>   drm/fbconv: Add helpers for init and cleanup of fb_info structures
>>   drm/fbconv: Add helper documentation
>>   staging: Add mgakms driver
>>   staging/mgakms: Import matroxfb driver source code
>>   staging/mgakms: Update matroxfb driver code for DRM
>>
>>  Documentation/gpu/drm-kms-helpers.rst     |   12 +
>>  Documentation/gpu/todo.rst                |   15 +
>>  drivers/gpu/drm/Kconfig                   |   11 +
>>  drivers/gpu/drm/Makefile                  |    1 +
>>  drivers/gpu/drm/drm_fbconv_helper.c       | 2126 +++++++++++++++++
>>  drivers/gpu/drm/drm_simple_kms_helper.c   |   15 +
>>  drivers/staging/Kconfig                   |    2 +
>>  drivers/staging/Makefile                  |    1 +
>>  drivers/staging/mgakms/Kconfig            |   18 +
>>  drivers/staging/mgakms/Makefile           |   17 +
>>  drivers/staging/mgakms/g450_pll.c         |  539 +++++
>>  drivers/staging/mgakms/g450_pll.h         |   13 +
>>  drivers/staging/mgakms/i2c-matroxfb.c     |  238 ++
>>  drivers/staging/mgakms/matroxfb_DAC1064.c | 1082 +++++++++
>>  drivers/staging/mgakms/matroxfb_DAC1064.h |  174 ++
>>  drivers/staging/mgakms/matroxfb_Ti3026.c  |  746 ++++++
>>  drivers/staging/mgakms/matroxfb_Ti3026.h  |   10 +
>>  drivers/staging/mgakms/matroxfb_accel.c   |  519 +++++
>>  drivers/staging/mgakms/matroxfb_accel.h   |    9 +
>>  drivers/staging/mgakms/matroxfb_base.c    | 2592 +++++++++++++++++++++
>>  drivers/staging/mgakms/matroxfb_base.h    |  700 ++++++
>>  drivers/staging/mgakms/matroxfb_crtc2.h   |   35 +
>>  drivers/staging/mgakms/matroxfb_g450.c    |  640 +++++
>>  drivers/staging/mgakms/matroxfb_g450.h    |   10 +
>>  drivers/staging/mgakms/matroxfb_maven.h   |   21 +
>>  drivers/staging/mgakms/matroxfb_misc.c    |  815 +++++++
>>  drivers/staging/mgakms/matroxfb_misc.h    |   22 +
>>  drivers/staging/mgakms/mga_device.c       |   68 +
>>  drivers/staging/mgakms/mga_device.h       |   30 +
>>  drivers/staging/mgakms/mga_drv.c          |  129 +
>>  drivers/staging/mgakms/mga_drv.h          |   14 +
>>  drivers/video/fbdev/core/fbmem.c          |    5 +-
>>  include/drm/drm_fbconv_helper.h           |  150 ++
>>  include/drm/drm_simple_kms_helper.h       |   43 +
>>  include/linux/fb.h                        |    3 +
>>  35 files changed, 10822 insertions(+), 3 deletions(-)
>>  create mode 100644 drivers/gpu/drm/drm_fbconv_helper.c
>>  create mode 100644 drivers/staging/mgakms/Kconfig
>>  create mode 100644 drivers/staging/mgakms/Makefile
>>  create mode 100644 drivers/staging/mgakms/g450_pll.c
>>  create mode 100644 drivers/staging/mgakms/g450_pll.h
>>  create mode 100644 drivers/staging/mgakms/i2c-matroxfb.c
>>  create mode 100644 drivers/staging/mgakms/matroxfb_DAC1064.c
>>  create mode 100644 drivers/staging/mgakms/matroxfb_DAC1064.h
>>  create mode 100644 drivers/staging/mgakms/matroxfb_Ti3026.c
>>  create mode 100644 drivers/staging/mgakms/matroxfb_Ti3026.h
>>  create mode 100644 drivers/staging/mgakms/matroxfb_accel.c
>>  create mode 100644 drivers/staging/mgakms/matroxfb_accel.h
>>  create mode 100644 drivers/staging/mgakms/matroxfb_base.c
>>  create mode 100644 drivers/staging/mgakms/matroxfb_base.h
>>  create mode 100644 drivers/staging/mgakms/matroxfb_crtc2.h
>>  create mode 100644 drivers/staging/mgakms/matroxfb_g450.c
>>  create mode 100644 drivers/staging/mgakms/matroxfb_g450.h
>>  create mode 100644 drivers/staging/mgakms/matroxfb_maven.h
>>  create mode 100644 drivers/staging/mgakms/matroxfb_misc.c
>>  create mode 100644 drivers/staging/mgakms/matroxfb_misc.h
>>  create mode 100644 drivers/staging/mgakms/mga_device.c
>>  create mode 100644 drivers/staging/mgakms/mga_device.h
>>  create mode 100644 drivers/staging/mgakms/mga_drv.c
>>  create mode 100644 drivers/staging/mgakms/mga_drv.h
>>  create mode 100644 include/drm/drm_fbconv_helper.h
>>
>> --
>> 2.23.0
>>
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers
@ 2019-10-15 17:28     ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2019-10-15 17:28 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: linux-fbdev, b.zolnierkie, airlied, gregkh, michel, corbet,
	malat, dri-devel, sean


[-- Attachment #1.1.1: Type: text/plain, Size: 10549 bytes --]

Hi Daniel

Am 15.10.19 um 16:33 schrieb Daniel Vetter:
> Hi Thomas,
> 
> On Mon, Oct 14, 2019 at 04:04:01PM +0200, Thomas Zimmermann wrote:
>> (was: DRM driver for fbdev devices)
>>
>> This is version 2 of the fbdev conversion helpers. It's more or less a
>> rewrite of the original patchset.
>>
>> The fbdev subsystem is considered legacy and will probably be removed at
>> some point. This would mean the loss of a signifanct number of drivers.
>> Some of the affected hardware is not in use any longer, but some hardware
>> is still around and provides good(-enough) framebuffers.
>>
>> The fbconv helpers allow for running the current DRM stack on top of fbdev
>> drivers. It's a set of functions that convert between fbdev interfaces and
>> DRM interfaces. Based on SHMEM and simple KMS helpers, it only offers the
>> basic functionality of a framebuffer, but should be compatible with most
>> existing fbdev drivers.
>>
>> A DRM driver using fbconv helpers consists of
>>
>>   * DRM stub code that calls into fbconv helpers, and
>>   * the original fbdev driver code.
>>
>> The fbdev driver code has to be modified to register itself with the
>> stub driver instead of the fbdev core framework. A tutorial on how to use
>> the helpers is part of this patchset. The resulting driver hybrid can be
>> refactored into a first-class DRM driver. The fbconv helpers contain a
>> number of comments, labeled 'DRM porting note', which explain the required
>> steps.
>>
>> I tested the current patchset with the following drivers: atyfb, aty128fb,
>> matroxfb, pm2fb, pm3fb, rivafb, s3fb, savagefb, sisfb, tdfxfb and tridentfb.
>> With each, I was able to successfully start with fbcon enabled, run weston and
>> X11. The drivers are available at [1]. For reference, the patchset includes
>> the Matrox stub driver.
> 
> So I really don't want to rain on the parade here, since if you think this
> is useful when converting fbdev drivers I'll buy that, and I'm all for
> getting more modern drivers into drm.
> 
> But I have a bunch of concerns with the approach you're proposing here:
> 
> - we've tried staging for drm driver refactoring, it hurts. Separate tree
>   plus the quick pace in refactoring create lots of pains. And for small
>   drivers refacotoring before it's not buying you anything above
>   refactoring in your own personal tree. And for big drivers we're fairly
>   lenient with merging drivers that aren't fully polished yet, if there's
>   a team serious enough with cleaning up the mess. I think even merging
>   partial drivers directly under drivers/gpu (but behind CONFIG_BROKEN) is
>   better than staging.

I mostly put this into staging, because it's the kind of code you'd
expect there.

> - we've had conversion helpers before (for the legacy kms -> atomic
>   upgrade). They constantly broke, pretty much every release when someone
>   wanted to use them they first had to fix them up again. I think having
>   those helpers is good, but better to just have them in some branch
>   somewhere where it's clear that they might not work anymore on latest
>   upstream.
> 
> - especially for some of these simple fbdev drivers I feel like just
>   typing a new driver from scratch might be simpler.
> 
> A few more concerns specifically for your mga example:
> 
> - We already have a mga driver. Might be better to integrate support for
>   older mgas into that than have a parallel driver.

Two colleagues of mine, Takashi and Egbert, send a patch that added
support for desktop G200s to mgag200. [1] But it was rejected because
the devices are two old and not relevant any longer. If that opinion has
changed in the meantime, I wouldn't mind adding support for desktop GPUs
to the driver.

> - Your helper is based on simple display pipe, and I think for these old
>   mga chips (especially the dual pipe mga 450 and 550) simple display pipe
>   helper is more a hindering detour than actual help. From a quick read
>   through the code (especially all the custom ioctls) you definitely want
>   separate TV-out connector to expose all the tv mode properties (instead
>   of the custom ioctls).

Around the G100, there's something like a change in generation. Before,
devices had only a single output and less than 8 MiB of RAM. This works
well with GEM SHMEM and simple KMS. Afterwards, devices have 8 MiB or
more and multiple outputs. GEM VRAM and the full set of helpers fit this
much better. Maybe having 2 drivers that share common code (or 3 with
the Server Engine chipsets) makes most sense.

> 
> - On the topic of ioctls, looks like we could add FBIOGET_VBLANK to our
>   generic implementation in the fbdev helpers.
> 
> So here's my alternative proposal:
> 
> - You push this as a branch onto a gitlab repo (freedesktop.org or
>   wherever you feel like).
> 
> - You add a gitlab CI target to autobuild the very nice kerneldoc you've
>   created. Feel free to also do this with anything else you're familiar
>   with, it's just I know gitlab and it's real simple to get a few docs
>   autogenerated and published with it.
> 
> - We add a todo.rst patch linking to your branch and the docs and a few
>   lines on how to best convert an fbdev driver over to kms/atomic.

Yes we can do that.

Best regards
Thomas

[1] https://lists.freedesktop.org/archives/dri-devel/2017-July/147868.html

> 
> And all the drivers would land the usual way, like any of the other
> drivers we've added to drivers/gpu/drm over the past few years.
> 
> Thoughts?
> 
> Cheers, Daniel
>>
>> v2:
>> 	* rename to fbconv helpers
>> 	* rewrite as helper library
>> 	* switch over to simple KMS helpers
>> 	* switch over to SHMEM
>> 	* add documentation
>>
>> [1] https://gitlab.freedesktop.org/tzimmermann/linux/commits/fbconv-plus-drivers
>>
>> Thomas Zimmermann (15):
>>   fbdev: Export fb_check_foreignness()
>>   fbdev: Export FBPIXMAPSIZE
>>   drm/simple-kms-helper: Add mode_fixup() to simple display pipe
>>   drm: Add fbconv helper module
>>   drm/fbconv: Add DRM <-> fbdev pixel-format conversion
>>   drm/fbconv: Add mode conversion DRM <-> fbdev
>>   drm/fbconv: Add modesetting infrastructure
>>   drm/fbconv: Add plane-state check and update
>>   drm/fbconv: Mode-setting pipeline enable / disable
>>   drm/fbconv: Reimplement several fbdev interfaces
>>   drm/fbconv: Add helpers for init and cleanup of fb_info structures
>>   drm/fbconv: Add helper documentation
>>   staging: Add mgakms driver
>>   staging/mgakms: Import matroxfb driver source code
>>   staging/mgakms: Update matroxfb driver code for DRM
>>
>>  Documentation/gpu/drm-kms-helpers.rst     |   12 +
>>  Documentation/gpu/todo.rst                |   15 +
>>  drivers/gpu/drm/Kconfig                   |   11 +
>>  drivers/gpu/drm/Makefile                  |    1 +
>>  drivers/gpu/drm/drm_fbconv_helper.c       | 2126 +++++++++++++++++
>>  drivers/gpu/drm/drm_simple_kms_helper.c   |   15 +
>>  drivers/staging/Kconfig                   |    2 +
>>  drivers/staging/Makefile                  |    1 +
>>  drivers/staging/mgakms/Kconfig            |   18 +
>>  drivers/staging/mgakms/Makefile           |   17 +
>>  drivers/staging/mgakms/g450_pll.c         |  539 +++++
>>  drivers/staging/mgakms/g450_pll.h         |   13 +
>>  drivers/staging/mgakms/i2c-matroxfb.c     |  238 ++
>>  drivers/staging/mgakms/matroxfb_DAC1064.c | 1082 +++++++++
>>  drivers/staging/mgakms/matroxfb_DAC1064.h |  174 ++
>>  drivers/staging/mgakms/matroxfb_Ti3026.c  |  746 ++++++
>>  drivers/staging/mgakms/matroxfb_Ti3026.h  |   10 +
>>  drivers/staging/mgakms/matroxfb_accel.c   |  519 +++++
>>  drivers/staging/mgakms/matroxfb_accel.h   |    9 +
>>  drivers/staging/mgakms/matroxfb_base.c    | 2592 +++++++++++++++++++++
>>  drivers/staging/mgakms/matroxfb_base.h    |  700 ++++++
>>  drivers/staging/mgakms/matroxfb_crtc2.h   |   35 +
>>  drivers/staging/mgakms/matroxfb_g450.c    |  640 +++++
>>  drivers/staging/mgakms/matroxfb_g450.h    |   10 +
>>  drivers/staging/mgakms/matroxfb_maven.h   |   21 +
>>  drivers/staging/mgakms/matroxfb_misc.c    |  815 +++++++
>>  drivers/staging/mgakms/matroxfb_misc.h    |   22 +
>>  drivers/staging/mgakms/mga_device.c       |   68 +
>>  drivers/staging/mgakms/mga_device.h       |   30 +
>>  drivers/staging/mgakms/mga_drv.c          |  129 +
>>  drivers/staging/mgakms/mga_drv.h          |   14 +
>>  drivers/video/fbdev/core/fbmem.c          |    5 +-
>>  include/drm/drm_fbconv_helper.h           |  150 ++
>>  include/drm/drm_simple_kms_helper.h       |   43 +
>>  include/linux/fb.h                        |    3 +
>>  35 files changed, 10822 insertions(+), 3 deletions(-)
>>  create mode 100644 drivers/gpu/drm/drm_fbconv_helper.c
>>  create mode 100644 drivers/staging/mgakms/Kconfig
>>  create mode 100644 drivers/staging/mgakms/Makefile
>>  create mode 100644 drivers/staging/mgakms/g450_pll.c
>>  create mode 100644 drivers/staging/mgakms/g450_pll.h
>>  create mode 100644 drivers/staging/mgakms/i2c-matroxfb.c
>>  create mode 100644 drivers/staging/mgakms/matroxfb_DAC1064.c
>>  create mode 100644 drivers/staging/mgakms/matroxfb_DAC1064.h
>>  create mode 100644 drivers/staging/mgakms/matroxfb_Ti3026.c
>>  create mode 100644 drivers/staging/mgakms/matroxfb_Ti3026.h
>>  create mode 100644 drivers/staging/mgakms/matroxfb_accel.c
>>  create mode 100644 drivers/staging/mgakms/matroxfb_accel.h
>>  create mode 100644 drivers/staging/mgakms/matroxfb_base.c
>>  create mode 100644 drivers/staging/mgakms/matroxfb_base.h
>>  create mode 100644 drivers/staging/mgakms/matroxfb_crtc2.h
>>  create mode 100644 drivers/staging/mgakms/matroxfb_g450.c
>>  create mode 100644 drivers/staging/mgakms/matroxfb_g450.h
>>  create mode 100644 drivers/staging/mgakms/matroxfb_maven.h
>>  create mode 100644 drivers/staging/mgakms/matroxfb_misc.c
>>  create mode 100644 drivers/staging/mgakms/matroxfb_misc.h
>>  create mode 100644 drivers/staging/mgakms/mga_device.c
>>  create mode 100644 drivers/staging/mgakms/mga_device.h
>>  create mode 100644 drivers/staging/mgakms/mga_drv.c
>>  create mode 100644 drivers/staging/mgakms/mga_drv.h
>>  create mode 100644 include/drm/drm_fbconv_helper.h
>>
>> --
>> 2.23.0
>>
> 

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Felix Imendörffer


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

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

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

* Re: [PATCH v2 08/15] drm/fbconv: Add plane-state check and update
  2019-10-14 14:04   ` Thomas Zimmermann
  (?)
@ 2019-10-15 17:28     ` kbuild test robot
  -1 siblings, 0 replies; 77+ messages in thread
From: kbuild test robot @ 2019-10-15 17:28 UTC (permalink / raw)
  Cc: linux-fbdev, kbuild-all, Thomas Zimmermann, b.zolnierkie,
	airlied, gregkh, michel, corbet, malat, dri-devel, sean

Hi Thomas,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[cannot apply to v5.4-rc3 next-20191014]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Thomas-Zimmermann/DRM-fbconv-helpers-for-converting-fbdev-drivers/20191015-152231
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.1-dirty
        make ARCH=x86_64 allmodconfig
        make C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__'

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)

>> drivers/gpu/drm/drm_fbconv_helper.c:981:39: sparse: sparse: incorrect type in argument 1 (different address spaces) @@    expected void [noderef] <asn:2> *dst @@    got n:2> *dst @@
>> drivers/gpu/drm/drm_fbconv_helper.c:981:39: sparse:    expected void [noderef] <asn:2> *dst
>> drivers/gpu/drm/drm_fbconv_helper.c:981:39: sparse:    got void *dst
   drivers/gpu/drm/drm_fbconv_helper.c:985:51: sparse: sparse: incorrect type in argument 1 (different address spaces) @@    expected void [noderef] <asn:2> *dst @@    got n:2> *dst @@
   drivers/gpu/drm/drm_fbconv_helper.c:985:51: sparse:    expected void [noderef] <asn:2> *dst
   drivers/gpu/drm/drm_fbconv_helper.c:985:51: sparse:    got void *dst
   drivers/gpu/drm/drm_fbconv_helper.c:990:51: sparse: sparse: incorrect type in argument 1 (different address spaces) @@    expected void [noderef] <asn:2> *dst @@    got n:2> *dst @@
   drivers/gpu/drm/drm_fbconv_helper.c:990:51: sparse:    expected void [noderef] <asn:2> *dst
   drivers/gpu/drm/drm_fbconv_helper.c:990:51: sparse:    got void *dst
>> drivers/gpu/drm/drm_fbconv_helper.c:1291:21: sparse: sparse: incorrect type in assignment (different address spaces) @@    expected void *screen_base @@    got char [noderef] <asvoid *screen_base @@
>> drivers/gpu/drm/drm_fbconv_helper.c:1291:21: sparse:    expected void *screen_base
>> drivers/gpu/drm/drm_fbconv_helper.c:1291:21: sparse:    got char [noderef] <asn:2> *screen_base
>> drivers/gpu/drm/drm_fbconv_helper.c:1294:29: sparse: sparse: incorrect type in assignment (different address spaces) @@    expected void *screen_base @@    got void [noderef] <asvoid *screen_base @@
   drivers/gpu/drm/drm_fbconv_helper.c:1294:29: sparse:    expected void *screen_base
>> drivers/gpu/drm/drm_fbconv_helper.c:1294:29: sparse:    got void [noderef] <asn:2> *
>> drivers/gpu/drm/drm_fbconv_helper.c:1318:25: sparse: sparse: incorrect type in argument 1 (different address spaces) @@    expected void volatile [noderef] <asn:2> *addr @@    got n:2> *addr @@
>> drivers/gpu/drm/drm_fbconv_helper.c:1318:25: sparse:    expected void volatile [noderef] <asn:2> *addr
>> drivers/gpu/drm/drm_fbconv_helper.c:1318:25: sparse:    got void *screen_base
   drivers/gpu/drm/drm_fbconv_helper.c:1346:38: sparse: sparse: incorrect type in argument 1 (different address spaces) @@    expected void volatile [noderef] <asn:2> *addr @@    got n:2> *addr @@
   drivers/gpu/drm/drm_fbconv_helper.c:1346:38: sparse:    expected void volatile [noderef] <asn:2> *addr
   drivers/gpu/drm/drm_fbconv_helper.c:1346:38: sparse:    got void *screen_base

vim +981 drivers/gpu/drm/drm_fbconv_helper.c

   956	
   957	/**
   958	 * drm_fbconv_blit_rect - copy an area of pixel data from a framebuffer
   959	 *	to the hardware buffer
   960	 * @dst:	the on-screen hardware buffer
   961	 * @vaddr:	the source buffer in kernel address space
   962	 * @fb:		the framebuffer of the source buffer
   963	 * @rect:	the area to copy
   964	 * Returns:
   965	 *	0 on success, or
   966	 *	a negative error code otherwise.
   967	 *
   968	 * This function copies the pixel data from a DRM framebuffer to a hardware
   969	 * buffer; doing necessary format conversion in the process. Not all
   970	 * combinations of source and destination formats are currently supported.
   971	 */
   972	int drm_fbconv_blit_rect(void *dst, void *vaddr, struct drm_framebuffer *fb,
   973				 struct drm_rect *rect)
   974	{
   975		struct drm_device *dev = fb->dev;
   976	
   977		if (!vaddr)
   978			return 0; /* no framebuffer set for plane; no error */
   979	
   980		if (dev->mode_config.preferred_depth = (fb->format->cpp[0] * 8))
 > 981			drm_fb_memcpy_dstclip(dst, vaddr, fb, rect);
   982	
   983		else if (fb->format->cpp[0] = 4 &&
   984			 dev->mode_config.preferred_depth = 16)
 > 985			drm_fb_xrgb8888_to_rgb565_dstclip(dst, fb->pitches[0],
   986							  vaddr, fb, rect, false);
   987	
   988		else if (fb->format->cpp[0] = 4 &&
   989			 dev->mode_config.preferred_depth = 24)
 > 990			drm_fb_xrgb8888_to_rgb888_dstclip(dst, fb->pitches[0],
   991							  vaddr, fb, rect);
   992	
   993		else {
   994			/* TODO: add the missing conversion */
   995			DRM_ERROR("fbconv: mismatching pixel formats\n");
   996			return -EINVAL;
   997		}
   998	
   999		return 0;
  1000	}
  1001	EXPORT_SYMBOL(drm_fbconv_blit_rect);
  1002	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

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

* Re: [PATCH v2 08/15] drm/fbconv: Add plane-state check and update
@ 2019-10-15 17:28     ` kbuild test robot
  0 siblings, 0 replies; 77+ messages in thread
From: kbuild test robot @ 2019-10-15 17:28 UTC (permalink / raw)
  Cc: linux-fbdev, kbuild-all, Thomas Zimmermann, b.zolnierkie,
	airlied, gregkh, michel, corbet, malat, dri-devel, sean

Hi Thomas,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[cannot apply to v5.4-rc3 next-20191014]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Thomas-Zimmermann/DRM-fbconv-helpers-for-converting-fbdev-drivers/20191015-152231
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.1-dirty
        make ARCH=x86_64 allmodconfig
        make C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__'

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)

>> drivers/gpu/drm/drm_fbconv_helper.c:981:39: sparse: sparse: incorrect type in argument 1 (different address spaces) @@    expected void [noderef] <asn:2> *dst @@    got n:2> *dst @@
>> drivers/gpu/drm/drm_fbconv_helper.c:981:39: sparse:    expected void [noderef] <asn:2> *dst
>> drivers/gpu/drm/drm_fbconv_helper.c:981:39: sparse:    got void *dst
   drivers/gpu/drm/drm_fbconv_helper.c:985:51: sparse: sparse: incorrect type in argument 1 (different address spaces) @@    expected void [noderef] <asn:2> *dst @@    got n:2> *dst @@
   drivers/gpu/drm/drm_fbconv_helper.c:985:51: sparse:    expected void [noderef] <asn:2> *dst
   drivers/gpu/drm/drm_fbconv_helper.c:985:51: sparse:    got void *dst
   drivers/gpu/drm/drm_fbconv_helper.c:990:51: sparse: sparse: incorrect type in argument 1 (different address spaces) @@    expected void [noderef] <asn:2> *dst @@    got n:2> *dst @@
   drivers/gpu/drm/drm_fbconv_helper.c:990:51: sparse:    expected void [noderef] <asn:2> *dst
   drivers/gpu/drm/drm_fbconv_helper.c:990:51: sparse:    got void *dst
>> drivers/gpu/drm/drm_fbconv_helper.c:1291:21: sparse: sparse: incorrect type in assignment (different address spaces) @@    expected void *screen_base @@    got char [noderef] <asvoid *screen_base @@
>> drivers/gpu/drm/drm_fbconv_helper.c:1291:21: sparse:    expected void *screen_base
>> drivers/gpu/drm/drm_fbconv_helper.c:1291:21: sparse:    got char [noderef] <asn:2> *screen_base
>> drivers/gpu/drm/drm_fbconv_helper.c:1294:29: sparse: sparse: incorrect type in assignment (different address spaces) @@    expected void *screen_base @@    got void [noderef] <asvoid *screen_base @@
   drivers/gpu/drm/drm_fbconv_helper.c:1294:29: sparse:    expected void *screen_base
>> drivers/gpu/drm/drm_fbconv_helper.c:1294:29: sparse:    got void [noderef] <asn:2> *
>> drivers/gpu/drm/drm_fbconv_helper.c:1318:25: sparse: sparse: incorrect type in argument 1 (different address spaces) @@    expected void volatile [noderef] <asn:2> *addr @@    got n:2> *addr @@
>> drivers/gpu/drm/drm_fbconv_helper.c:1318:25: sparse:    expected void volatile [noderef] <asn:2> *addr
>> drivers/gpu/drm/drm_fbconv_helper.c:1318:25: sparse:    got void *screen_base
   drivers/gpu/drm/drm_fbconv_helper.c:1346:38: sparse: sparse: incorrect type in argument 1 (different address spaces) @@    expected void volatile [noderef] <asn:2> *addr @@    got n:2> *addr @@
   drivers/gpu/drm/drm_fbconv_helper.c:1346:38: sparse:    expected void volatile [noderef] <asn:2> *addr
   drivers/gpu/drm/drm_fbconv_helper.c:1346:38: sparse:    got void *screen_base

vim +981 drivers/gpu/drm/drm_fbconv_helper.c

   956	
   957	/**
   958	 * drm_fbconv_blit_rect - copy an area of pixel data from a framebuffer
   959	 *	to the hardware buffer
   960	 * @dst:	the on-screen hardware buffer
   961	 * @vaddr:	the source buffer in kernel address space
   962	 * @fb:		the framebuffer of the source buffer
   963	 * @rect:	the area to copy
   964	 * Returns:
   965	 *	0 on success, or
   966	 *	a negative error code otherwise.
   967	 *
   968	 * This function copies the pixel data from a DRM framebuffer to a hardware
   969	 * buffer; doing necessary format conversion in the process. Not all
   970	 * combinations of source and destination formats are currently supported.
   971	 */
   972	int drm_fbconv_blit_rect(void *dst, void *vaddr, struct drm_framebuffer *fb,
   973				 struct drm_rect *rect)
   974	{
   975		struct drm_device *dev = fb->dev;
   976	
   977		if (!vaddr)
   978			return 0; /* no framebuffer set for plane; no error */
   979	
   980		if (dev->mode_config.preferred_depth == (fb->format->cpp[0] * 8))
 > 981			drm_fb_memcpy_dstclip(dst, vaddr, fb, rect);
   982	
   983		else if (fb->format->cpp[0] == 4 &&
   984			 dev->mode_config.preferred_depth == 16)
 > 985			drm_fb_xrgb8888_to_rgb565_dstclip(dst, fb->pitches[0],
   986							  vaddr, fb, rect, false);
   987	
   988		else if (fb->format->cpp[0] == 4 &&
   989			 dev->mode_config.preferred_depth == 24)
 > 990			drm_fb_xrgb8888_to_rgb888_dstclip(dst, fb->pitches[0],
   991							  vaddr, fb, rect);
   992	
   993		else {
   994			/* TODO: add the missing conversion */
   995			DRM_ERROR("fbconv: mismatching pixel formats\n");
   996			return -EINVAL;
   997		}
   998	
   999		return 0;
  1000	}
  1001	EXPORT_SYMBOL(drm_fbconv_blit_rect);
  1002	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 08/15] drm/fbconv: Add plane-state check and update
@ 2019-10-15 17:28     ` kbuild test robot
  0 siblings, 0 replies; 77+ messages in thread
From: kbuild test robot @ 2019-10-15 17:28 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 5464 bytes --]

Hi Thomas,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[cannot apply to v5.4-rc3 next-20191014]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Thomas-Zimmermann/DRM-fbconv-helpers-for-converting-fbdev-drivers/20191015-152231
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.1-dirty
        make ARCH=x86_64 allmodconfig
        make C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__'

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)

>> drivers/gpu/drm/drm_fbconv_helper.c:981:39: sparse: sparse: incorrect type in argument 1 (different address spaces) @@    expected void [noderef] <asn:2> *dst @@    got n:2> *dst @@
>> drivers/gpu/drm/drm_fbconv_helper.c:981:39: sparse:    expected void [noderef] <asn:2> *dst
>> drivers/gpu/drm/drm_fbconv_helper.c:981:39: sparse:    got void *dst
   drivers/gpu/drm/drm_fbconv_helper.c:985:51: sparse: sparse: incorrect type in argument 1 (different address spaces) @@    expected void [noderef] <asn:2> *dst @@    got n:2> *dst @@
   drivers/gpu/drm/drm_fbconv_helper.c:985:51: sparse:    expected void [noderef] <asn:2> *dst
   drivers/gpu/drm/drm_fbconv_helper.c:985:51: sparse:    got void *dst
   drivers/gpu/drm/drm_fbconv_helper.c:990:51: sparse: sparse: incorrect type in argument 1 (different address spaces) @@    expected void [noderef] <asn:2> *dst @@    got n:2> *dst @@
   drivers/gpu/drm/drm_fbconv_helper.c:990:51: sparse:    expected void [noderef] <asn:2> *dst
   drivers/gpu/drm/drm_fbconv_helper.c:990:51: sparse:    got void *dst
>> drivers/gpu/drm/drm_fbconv_helper.c:1291:21: sparse: sparse: incorrect type in assignment (different address spaces) @@    expected void *screen_base @@    got char [noderef] <asvoid *screen_base @@
>> drivers/gpu/drm/drm_fbconv_helper.c:1291:21: sparse:    expected void *screen_base
>> drivers/gpu/drm/drm_fbconv_helper.c:1291:21: sparse:    got char [noderef] <asn:2> *screen_base
>> drivers/gpu/drm/drm_fbconv_helper.c:1294:29: sparse: sparse: incorrect type in assignment (different address spaces) @@    expected void *screen_base @@    got void [noderef] <asvoid *screen_base @@
   drivers/gpu/drm/drm_fbconv_helper.c:1294:29: sparse:    expected void *screen_base
>> drivers/gpu/drm/drm_fbconv_helper.c:1294:29: sparse:    got void [noderef] <asn:2> *
>> drivers/gpu/drm/drm_fbconv_helper.c:1318:25: sparse: sparse: incorrect type in argument 1 (different address spaces) @@    expected void volatile [noderef] <asn:2> *addr @@    got n:2> *addr @@
>> drivers/gpu/drm/drm_fbconv_helper.c:1318:25: sparse:    expected void volatile [noderef] <asn:2> *addr
>> drivers/gpu/drm/drm_fbconv_helper.c:1318:25: sparse:    got void *screen_base
   drivers/gpu/drm/drm_fbconv_helper.c:1346:38: sparse: sparse: incorrect type in argument 1 (different address spaces) @@    expected void volatile [noderef] <asn:2> *addr @@    got n:2> *addr @@
   drivers/gpu/drm/drm_fbconv_helper.c:1346:38: sparse:    expected void volatile [noderef] <asn:2> *addr
   drivers/gpu/drm/drm_fbconv_helper.c:1346:38: sparse:    got void *screen_base

vim +981 drivers/gpu/drm/drm_fbconv_helper.c

   956	
   957	/**
   958	 * drm_fbconv_blit_rect - copy an area of pixel data from a framebuffer
   959	 *	to the hardware buffer
   960	 * @dst:	the on-screen hardware buffer
   961	 * @vaddr:	the source buffer in kernel address space
   962	 * @fb:		the framebuffer of the source buffer
   963	 * @rect:	the area to copy
   964	 * Returns:
   965	 *	0 on success, or
   966	 *	a negative error code otherwise.
   967	 *
   968	 * This function copies the pixel data from a DRM framebuffer to a hardware
   969	 * buffer; doing necessary format conversion in the process. Not all
   970	 * combinations of source and destination formats are currently supported.
   971	 */
   972	int drm_fbconv_blit_rect(void *dst, void *vaddr, struct drm_framebuffer *fb,
   973				 struct drm_rect *rect)
   974	{
   975		struct drm_device *dev = fb->dev;
   976	
   977		if (!vaddr)
   978			return 0; /* no framebuffer set for plane; no error */
   979	
   980		if (dev->mode_config.preferred_depth == (fb->format->cpp[0] * 8))
 > 981			drm_fb_memcpy_dstclip(dst, vaddr, fb, rect);
   982	
   983		else if (fb->format->cpp[0] == 4 &&
   984			 dev->mode_config.preferred_depth == 16)
 > 985			drm_fb_xrgb8888_to_rgb565_dstclip(dst, fb->pitches[0],
   986							  vaddr, fb, rect, false);
   987	
   988		else if (fb->format->cpp[0] == 4 &&
   989			 dev->mode_config.preferred_depth == 24)
 > 990			drm_fb_xrgb8888_to_rgb888_dstclip(dst, fb->pitches[0],
   991							  vaddr, fb, rect);
   992	
   993		else {
   994			/* TODO: add the missing conversion */
   995			DRM_ERROR("fbconv: mismatching pixel formats\n");
   996			return -EINVAL;
   997		}
   998	
   999		return 0;
  1000	}
  1001	EXPORT_SYMBOL(drm_fbconv_blit_rect);
  1002	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

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

* Re: [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers
  2019-10-15 17:28     ` Thomas Zimmermann
@ 2019-10-15 17:48       ` Daniel Vetter
  -1 siblings, 0 replies; 77+ messages in thread
From: Daniel Vetter @ 2019-10-15 17:48 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: Linux Fbdev development list, Bartlomiej Zolnierkiewicz,
	Dave Airlie, Greg KH, Michel Dänzer, Jonathan Corbet,
	Mathieu Malaterre, dri-devel, Sean Paul

On Tue, Oct 15, 2019 at 7:28 PM Thomas Zimmermann <tzimmermann@suse.de> wrote:
>
> Hi Daniel
>
> Am 15.10.19 um 16:33 schrieb Daniel Vetter:
> > Hi Thomas,
> >
> > On Mon, Oct 14, 2019 at 04:04:01PM +0200, Thomas Zimmermann wrote:
> >> (was: DRM driver for fbdev devices)
> >>
> >> This is version 2 of the fbdev conversion helpers. It's more or less a
> >> rewrite of the original patchset.
> >>
> >> The fbdev subsystem is considered legacy and will probably be removed at
> >> some point. This would mean the loss of a signifanct number of drivers.
> >> Some of the affected hardware is not in use any longer, but some hardware
> >> is still around and provides good(-enough) framebuffers.
> >>
> >> The fbconv helpers allow for running the current DRM stack on top of fbdev
> >> drivers. It's a set of functions that convert between fbdev interfaces and
> >> DRM interfaces. Based on SHMEM and simple KMS helpers, it only offers the
> >> basic functionality of a framebuffer, but should be compatible with most
> >> existing fbdev drivers.
> >>
> >> A DRM driver using fbconv helpers consists of
> >>
> >>   * DRM stub code that calls into fbconv helpers, and
> >>   * the original fbdev driver code.
> >>
> >> The fbdev driver code has to be modified to register itself with the
> >> stub driver instead of the fbdev core framework. A tutorial on how to use
> >> the helpers is part of this patchset. The resulting driver hybrid can be
> >> refactored into a first-class DRM driver. The fbconv helpers contain a
> >> number of comments, labeled 'DRM porting note', which explain the required
> >> steps.
> >>
> >> I tested the current patchset with the following drivers: atyfb, aty128fb,
> >> matroxfb, pm2fb, pm3fb, rivafb, s3fb, savagefb, sisfb, tdfxfb and tridentfb.
> >> With each, I was able to successfully start with fbcon enabled, run weston and
> >> X11. The drivers are available at [1]. For reference, the patchset includes
> >> the Matrox stub driver.
> >
> > So I really don't want to rain on the parade here, since if you think this
> > is useful when converting fbdev drivers I'll buy that, and I'm all for
> > getting more modern drivers into drm.
> >
> > But I have a bunch of concerns with the approach you're proposing here:
> >
> > - we've tried staging for drm driver refactoring, it hurts. Separate tree
> >   plus the quick pace in refactoring create lots of pains. And for small
> >   drivers refacotoring before it's not buying you anything above
> >   refactoring in your own personal tree. And for big drivers we're fairly
> >   lenient with merging drivers that aren't fully polished yet, if there's
> >   a team serious enough with cleaning up the mess. I think even merging
> >   partial drivers directly under drivers/gpu (but behind CONFIG_BROKEN) is
> >   better than staging.
>
> I mostly put this into staging, because it's the kind of code you'd
> expect there.

Yeah, except we tried, it's a real pain. Conclusion by everyone
involved is that staging doesn't work for the drm subsystem.

> > - we've had conversion helpers before (for the legacy kms -> atomic
> >   upgrade). They constantly broke, pretty much every release when someone
> >   wanted to use them they first had to fix them up again. I think having
> >   those helpers is good, but better to just have them in some branch
> >   somewhere where it's clear that they might not work anymore on latest
> >   upstream.
> >
> > - especially for some of these simple fbdev drivers I feel like just
> >   typing a new driver from scratch might be simpler.
> >
> > A few more concerns specifically for your mga example:
> >
> > - We already have a mga driver. Might be better to integrate support for
> >   older mgas into that than have a parallel driver.
>
> Two colleagues of mine, Takashi and Egbert, send a patch that added
> support for desktop G200s to mgag200. [1] But it was rejected because
> the devices are two old and not relevant any longer. If that opinion has
> changed in the meantime, I wouldn't mind adding support for desktop GPUs
> to the driver.

Hm that seems to have petered out inconclusive. I definitely think a
merged mga driver is better than 2 drm atomic kms drivers for roughly
the same hardware. I'm also assuming that at least for now no one
plans to resurrect the 3d acceleration support for these old chips.
But even then it's fairly easy to disable all that on the server
chips.

> > - Your helper is based on simple display pipe, and I think for these old
> >   mga chips (especially the dual pipe mga 450 and 550) simple display pipe
> >   helper is more a hindering detour than actual help. From a quick read
> >   through the code (especially all the custom ioctls) you definitely want
> >   separate TV-out connector to expose all the tv mode properties (instead
> >   of the custom ioctls).
>
> Around the G100, there's something like a change in generation. Before,
> devices had only a single output and less than 8 MiB of RAM. This works
> well with GEM SHMEM and simple KMS. Afterwards, devices have 8 MiB or
> more and multiple outputs. GEM VRAM and the full set of helpers fit this
> much better. Maybe having 2 drivers that share common code (or 3 with
> the Server Engine chipsets) makes most sense.

Yeah if that's the case maybe a mga100 and mga200g driver fits better.
Former based on simple display pipe.

You could also have them in one directory/kernel module, if there's
some low-level functions worth sharing (like clock programming), with
the low level driver probe either setting up the simple display based
mga100 support, or the fancier mga200 support using atomic directly.
If there's really no shared code at all, then separate kernel modules
sounds better.

> > - On the topic of ioctls, looks like we could add FBIOGET_VBLANK to our
> >   generic implementation in the fbdev helpers.
> >
> > So here's my alternative proposal:
> >
> > - You push this as a branch onto a gitlab repo (freedesktop.org or
> >   wherever you feel like).
> >
> > - You add a gitlab CI target to autobuild the very nice kerneldoc you've
> >   created. Feel free to also do this with anything else you're familiar
> >   with, it's just I know gitlab and it's real simple to get a few docs
> >   autogenerated and published with it.
> >
> > - We add a todo.rst patch linking to your branch and the docs and a few
> >   lines on how to best convert an fbdev driver over to kms/atomic.
>
> Yes we can do that.

Sounds like we have a rough plan?
-Daniel

>
> Best regards
> Thomas
>
> [1] https://lists.freedesktop.org/archives/dri-devel/2017-July/147868.html
>
> >
> > And all the drivers would land the usual way, like any of the other
> > drivers we've added to drivers/gpu/drm over the past few years.
> >
> > Thoughts?
> >
> > Cheers, Daniel
> >>
> >> v2:
> >>      * rename to fbconv helpers
> >>      * rewrite as helper library
> >>      * switch over to simple KMS helpers
> >>      * switch over to SHMEM
> >>      * add documentation
> >>
> >> [1] https://gitlab.freedesktop.org/tzimmermann/linux/commits/fbconv-plus-drivers
> >>
> >> Thomas Zimmermann (15):
> >>   fbdev: Export fb_check_foreignness()
> >>   fbdev: Export FBPIXMAPSIZE
> >>   drm/simple-kms-helper: Add mode_fixup() to simple display pipe
> >>   drm: Add fbconv helper module
> >>   drm/fbconv: Add DRM <-> fbdev pixel-format conversion
> >>   drm/fbconv: Add mode conversion DRM <-> fbdev
> >>   drm/fbconv: Add modesetting infrastructure
> >>   drm/fbconv: Add plane-state check and update
> >>   drm/fbconv: Mode-setting pipeline enable / disable
> >>   drm/fbconv: Reimplement several fbdev interfaces
> >>   drm/fbconv: Add helpers for init and cleanup of fb_info structures
> >>   drm/fbconv: Add helper documentation
> >>   staging: Add mgakms driver
> >>   staging/mgakms: Import matroxfb driver source code
> >>   staging/mgakms: Update matroxfb driver code for DRM
> >>
> >>  Documentation/gpu/drm-kms-helpers.rst     |   12 +
> >>  Documentation/gpu/todo.rst                |   15 +
> >>  drivers/gpu/drm/Kconfig                   |   11 +
> >>  drivers/gpu/drm/Makefile                  |    1 +
> >>  drivers/gpu/drm/drm_fbconv_helper.c       | 2126 +++++++++++++++++
> >>  drivers/gpu/drm/drm_simple_kms_helper.c   |   15 +
> >>  drivers/staging/Kconfig                   |    2 +
> >>  drivers/staging/Makefile                  |    1 +
> >>  drivers/staging/mgakms/Kconfig            |   18 +
> >>  drivers/staging/mgakms/Makefile           |   17 +
> >>  drivers/staging/mgakms/g450_pll.c         |  539 +++++
> >>  drivers/staging/mgakms/g450_pll.h         |   13 +
> >>  drivers/staging/mgakms/i2c-matroxfb.c     |  238 ++
> >>  drivers/staging/mgakms/matroxfb_DAC1064.c | 1082 +++++++++
> >>  drivers/staging/mgakms/matroxfb_DAC1064.h |  174 ++
> >>  drivers/staging/mgakms/matroxfb_Ti3026.c  |  746 ++++++
> >>  drivers/staging/mgakms/matroxfb_Ti3026.h  |   10 +
> >>  drivers/staging/mgakms/matroxfb_accel.c   |  519 +++++
> >>  drivers/staging/mgakms/matroxfb_accel.h   |    9 +
> >>  drivers/staging/mgakms/matroxfb_base.c    | 2592 +++++++++++++++++++++
> >>  drivers/staging/mgakms/matroxfb_base.h    |  700 ++++++
> >>  drivers/staging/mgakms/matroxfb_crtc2.h   |   35 +
> >>  drivers/staging/mgakms/matroxfb_g450.c    |  640 +++++
> >>  drivers/staging/mgakms/matroxfb_g450.h    |   10 +
> >>  drivers/staging/mgakms/matroxfb_maven.h   |   21 +
> >>  drivers/staging/mgakms/matroxfb_misc.c    |  815 +++++++
> >>  drivers/staging/mgakms/matroxfb_misc.h    |   22 +
> >>  drivers/staging/mgakms/mga_device.c       |   68 +
> >>  drivers/staging/mgakms/mga_device.h       |   30 +
> >>  drivers/staging/mgakms/mga_drv.c          |  129 +
> >>  drivers/staging/mgakms/mga_drv.h          |   14 +
> >>  drivers/video/fbdev/core/fbmem.c          |    5 +-
> >>  include/drm/drm_fbconv_helper.h           |  150 ++
> >>  include/drm/drm_simple_kms_helper.h       |   43 +
> >>  include/linux/fb.h                        |    3 +
> >>  35 files changed, 10822 insertions(+), 3 deletions(-)
> >>  create mode 100644 drivers/gpu/drm/drm_fbconv_helper.c
> >>  create mode 100644 drivers/staging/mgakms/Kconfig
> >>  create mode 100644 drivers/staging/mgakms/Makefile
> >>  create mode 100644 drivers/staging/mgakms/g450_pll.c
> >>  create mode 100644 drivers/staging/mgakms/g450_pll.h
> >>  create mode 100644 drivers/staging/mgakms/i2c-matroxfb.c
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_DAC1064.c
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_DAC1064.h
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_Ti3026.c
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_Ti3026.h
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_accel.c
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_accel.h
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_base.c
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_base.h
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_crtc2.h
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_g450.c
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_g450.h
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_maven.h
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_misc.c
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_misc.h
> >>  create mode 100644 drivers/staging/mgakms/mga_device.c
> >>  create mode 100644 drivers/staging/mgakms/mga_device.h
> >>  create mode 100644 drivers/staging/mgakms/mga_drv.c
> >>  create mode 100644 drivers/staging/mgakms/mga_drv.h
> >>  create mode 100644 include/drm/drm_fbconv_helper.h
> >>
> >> --
> >> 2.23.0
> >>
> >
>
> --
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Maxfeldstr. 5, 90409 Nürnberg, Germany
> (HRB 36809, AG Nürnberg)
> Geschäftsführer: Felix Imendörffer
>


-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* Re: [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers
@ 2019-10-15 17:48       ` Daniel Vetter
  0 siblings, 0 replies; 77+ messages in thread
From: Daniel Vetter @ 2019-10-15 17:48 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: Linux Fbdev development list, Bartlomiej Zolnierkiewicz,
	Dave Airlie, Greg KH, Michel Dänzer, Jonathan Corbet,
	Mathieu Malaterre, dri-devel, Sean Paul

On Tue, Oct 15, 2019 at 7:28 PM Thomas Zimmermann <tzimmermann@suse.de> wrote:
>
> Hi Daniel
>
> Am 15.10.19 um 16:33 schrieb Daniel Vetter:
> > Hi Thomas,
> >
> > On Mon, Oct 14, 2019 at 04:04:01PM +0200, Thomas Zimmermann wrote:
> >> (was: DRM driver for fbdev devices)
> >>
> >> This is version 2 of the fbdev conversion helpers. It's more or less a
> >> rewrite of the original patchset.
> >>
> >> The fbdev subsystem is considered legacy and will probably be removed at
> >> some point. This would mean the loss of a signifanct number of drivers.
> >> Some of the affected hardware is not in use any longer, but some hardware
> >> is still around and provides good(-enough) framebuffers.
> >>
> >> The fbconv helpers allow for running the current DRM stack on top of fbdev
> >> drivers. It's a set of functions that convert between fbdev interfaces and
> >> DRM interfaces. Based on SHMEM and simple KMS helpers, it only offers the
> >> basic functionality of a framebuffer, but should be compatible with most
> >> existing fbdev drivers.
> >>
> >> A DRM driver using fbconv helpers consists of
> >>
> >>   * DRM stub code that calls into fbconv helpers, and
> >>   * the original fbdev driver code.
> >>
> >> The fbdev driver code has to be modified to register itself with the
> >> stub driver instead of the fbdev core framework. A tutorial on how to use
> >> the helpers is part of this patchset. The resulting driver hybrid can be
> >> refactored into a first-class DRM driver. The fbconv helpers contain a
> >> number of comments, labeled 'DRM porting note', which explain the required
> >> steps.
> >>
> >> I tested the current patchset with the following drivers: atyfb, aty128fb,
> >> matroxfb, pm2fb, pm3fb, rivafb, s3fb, savagefb, sisfb, tdfxfb and tridentfb.
> >> With each, I was able to successfully start with fbcon enabled, run weston and
> >> X11. The drivers are available at [1]. For reference, the patchset includes
> >> the Matrox stub driver.
> >
> > So I really don't want to rain on the parade here, since if you think this
> > is useful when converting fbdev drivers I'll buy that, and I'm all for
> > getting more modern drivers into drm.
> >
> > But I have a bunch of concerns with the approach you're proposing here:
> >
> > - we've tried staging for drm driver refactoring, it hurts. Separate tree
> >   plus the quick pace in refactoring create lots of pains. And for small
> >   drivers refacotoring before it's not buying you anything above
> >   refactoring in your own personal tree. And for big drivers we're fairly
> >   lenient with merging drivers that aren't fully polished yet, if there's
> >   a team serious enough with cleaning up the mess. I think even merging
> >   partial drivers directly under drivers/gpu (but behind CONFIG_BROKEN) is
> >   better than staging.
>
> I mostly put this into staging, because it's the kind of code you'd
> expect there.

Yeah, except we tried, it's a real pain. Conclusion by everyone
involved is that staging doesn't work for the drm subsystem.

> > - we've had conversion helpers before (for the legacy kms -> atomic
> >   upgrade). They constantly broke, pretty much every release when someone
> >   wanted to use them they first had to fix them up again. I think having
> >   those helpers is good, but better to just have them in some branch
> >   somewhere where it's clear that they might not work anymore on latest
> >   upstream.
> >
> > - especially for some of these simple fbdev drivers I feel like just
> >   typing a new driver from scratch might be simpler.
> >
> > A few more concerns specifically for your mga example:
> >
> > - We already have a mga driver. Might be better to integrate support for
> >   older mgas into that than have a parallel driver.
>
> Two colleagues of mine, Takashi and Egbert, send a patch that added
> support for desktop G200s to mgag200. [1] But it was rejected because
> the devices are two old and not relevant any longer. If that opinion has
> changed in the meantime, I wouldn't mind adding support for desktop GPUs
> to the driver.

Hm that seems to have petered out inconclusive. I definitely think a
merged mga driver is better than 2 drm atomic kms drivers for roughly
the same hardware. I'm also assuming that at least for now no one
plans to resurrect the 3d acceleration support for these old chips.
But even then it's fairly easy to disable all that on the server
chips.

> > - Your helper is based on simple display pipe, and I think for these old
> >   mga chips (especially the dual pipe mga 450 and 550) simple display pipe
> >   helper is more a hindering detour than actual help. From a quick read
> >   through the code (especially all the custom ioctls) you definitely want
> >   separate TV-out connector to expose all the tv mode properties (instead
> >   of the custom ioctls).
>
> Around the G100, there's something like a change in generation. Before,
> devices had only a single output and less than 8 MiB of RAM. This works
> well with GEM SHMEM and simple KMS. Afterwards, devices have 8 MiB or
> more and multiple outputs. GEM VRAM and the full set of helpers fit this
> much better. Maybe having 2 drivers that share common code (or 3 with
> the Server Engine chipsets) makes most sense.

Yeah if that's the case maybe a mga100 and mga200g driver fits better.
Former based on simple display pipe.

You could also have them in one directory/kernel module, if there's
some low-level functions worth sharing (like clock programming), with
the low level driver probe either setting up the simple display based
mga100 support, or the fancier mga200 support using atomic directly.
If there's really no shared code at all, then separate kernel modules
sounds better.

> > - On the topic of ioctls, looks like we could add FBIOGET_VBLANK to our
> >   generic implementation in the fbdev helpers.
> >
> > So here's my alternative proposal:
> >
> > - You push this as a branch onto a gitlab repo (freedesktop.org or
> >   wherever you feel like).
> >
> > - You add a gitlab CI target to autobuild the very nice kerneldoc you've
> >   created. Feel free to also do this with anything else you're familiar
> >   with, it's just I know gitlab and it's real simple to get a few docs
> >   autogenerated and published with it.
> >
> > - We add a todo.rst patch linking to your branch and the docs and a few
> >   lines on how to best convert an fbdev driver over to kms/atomic.
>
> Yes we can do that.

Sounds like we have a rough plan?
-Daniel

>
> Best regards
> Thomas
>
> [1] https://lists.freedesktop.org/archives/dri-devel/2017-July/147868.html
>
> >
> > And all the drivers would land the usual way, like any of the other
> > drivers we've added to drivers/gpu/drm over the past few years.
> >
> > Thoughts?
> >
> > Cheers, Daniel
> >>
> >> v2:
> >>      * rename to fbconv helpers
> >>      * rewrite as helper library
> >>      * switch over to simple KMS helpers
> >>      * switch over to SHMEM
> >>      * add documentation
> >>
> >> [1] https://gitlab.freedesktop.org/tzimmermann/linux/commits/fbconv-plus-drivers
> >>
> >> Thomas Zimmermann (15):
> >>   fbdev: Export fb_check_foreignness()
> >>   fbdev: Export FBPIXMAPSIZE
> >>   drm/simple-kms-helper: Add mode_fixup() to simple display pipe
> >>   drm: Add fbconv helper module
> >>   drm/fbconv: Add DRM <-> fbdev pixel-format conversion
> >>   drm/fbconv: Add mode conversion DRM <-> fbdev
> >>   drm/fbconv: Add modesetting infrastructure
> >>   drm/fbconv: Add plane-state check and update
> >>   drm/fbconv: Mode-setting pipeline enable / disable
> >>   drm/fbconv: Reimplement several fbdev interfaces
> >>   drm/fbconv: Add helpers for init and cleanup of fb_info structures
> >>   drm/fbconv: Add helper documentation
> >>   staging: Add mgakms driver
> >>   staging/mgakms: Import matroxfb driver source code
> >>   staging/mgakms: Update matroxfb driver code for DRM
> >>
> >>  Documentation/gpu/drm-kms-helpers.rst     |   12 +
> >>  Documentation/gpu/todo.rst                |   15 +
> >>  drivers/gpu/drm/Kconfig                   |   11 +
> >>  drivers/gpu/drm/Makefile                  |    1 +
> >>  drivers/gpu/drm/drm_fbconv_helper.c       | 2126 +++++++++++++++++
> >>  drivers/gpu/drm/drm_simple_kms_helper.c   |   15 +
> >>  drivers/staging/Kconfig                   |    2 +
> >>  drivers/staging/Makefile                  |    1 +
> >>  drivers/staging/mgakms/Kconfig            |   18 +
> >>  drivers/staging/mgakms/Makefile           |   17 +
> >>  drivers/staging/mgakms/g450_pll.c         |  539 +++++
> >>  drivers/staging/mgakms/g450_pll.h         |   13 +
> >>  drivers/staging/mgakms/i2c-matroxfb.c     |  238 ++
> >>  drivers/staging/mgakms/matroxfb_DAC1064.c | 1082 +++++++++
> >>  drivers/staging/mgakms/matroxfb_DAC1064.h |  174 ++
> >>  drivers/staging/mgakms/matroxfb_Ti3026.c  |  746 ++++++
> >>  drivers/staging/mgakms/matroxfb_Ti3026.h  |   10 +
> >>  drivers/staging/mgakms/matroxfb_accel.c   |  519 +++++
> >>  drivers/staging/mgakms/matroxfb_accel.h   |    9 +
> >>  drivers/staging/mgakms/matroxfb_base.c    | 2592 +++++++++++++++++++++
> >>  drivers/staging/mgakms/matroxfb_base.h    |  700 ++++++
> >>  drivers/staging/mgakms/matroxfb_crtc2.h   |   35 +
> >>  drivers/staging/mgakms/matroxfb_g450.c    |  640 +++++
> >>  drivers/staging/mgakms/matroxfb_g450.h    |   10 +
> >>  drivers/staging/mgakms/matroxfb_maven.h   |   21 +
> >>  drivers/staging/mgakms/matroxfb_misc.c    |  815 +++++++
> >>  drivers/staging/mgakms/matroxfb_misc.h    |   22 +
> >>  drivers/staging/mgakms/mga_device.c       |   68 +
> >>  drivers/staging/mgakms/mga_device.h       |   30 +
> >>  drivers/staging/mgakms/mga_drv.c          |  129 +
> >>  drivers/staging/mgakms/mga_drv.h          |   14 +
> >>  drivers/video/fbdev/core/fbmem.c          |    5 +-
> >>  include/drm/drm_fbconv_helper.h           |  150 ++
> >>  include/drm/drm_simple_kms_helper.h       |   43 +
> >>  include/linux/fb.h                        |    3 +
> >>  35 files changed, 10822 insertions(+), 3 deletions(-)
> >>  create mode 100644 drivers/gpu/drm/drm_fbconv_helper.c
> >>  create mode 100644 drivers/staging/mgakms/Kconfig
> >>  create mode 100644 drivers/staging/mgakms/Makefile
> >>  create mode 100644 drivers/staging/mgakms/g450_pll.c
> >>  create mode 100644 drivers/staging/mgakms/g450_pll.h
> >>  create mode 100644 drivers/staging/mgakms/i2c-matroxfb.c
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_DAC1064.c
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_DAC1064.h
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_Ti3026.c
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_Ti3026.h
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_accel.c
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_accel.h
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_base.c
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_base.h
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_crtc2.h
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_g450.c
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_g450.h
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_maven.h
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_misc.c
> >>  create mode 100644 drivers/staging/mgakms/matroxfb_misc.h
> >>  create mode 100644 drivers/staging/mgakms/mga_device.c
> >>  create mode 100644 drivers/staging/mgakms/mga_device.h
> >>  create mode 100644 drivers/staging/mgakms/mga_drv.c
> >>  create mode 100644 drivers/staging/mgakms/mga_drv.h
> >>  create mode 100644 include/drm/drm_fbconv_helper.h
> >>
> >> --
> >> 2.23.0
> >>
> >
>
> --
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Maxfeldstr. 5, 90409 Nürnberg, Germany
> (HRB 36809, AG Nürnberg)
> Geschäftsführer: Felix Imendörffer
>


-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers
  2019-10-15 17:48       ` Daniel Vetter
@ 2019-10-15 18:05         ` Greg KH
  -1 siblings, 0 replies; 77+ messages in thread
From: Greg KH @ 2019-10-15 18:05 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Linux Fbdev development list, Bartlomiej Zolnierkiewicz,
	Dave Airlie, Michel Dänzer, Jonathan Corbet,
	Mathieu Malaterre, dri-devel, Thomas Zimmermann, Sean Paul

On Tue, Oct 15, 2019 at 07:48:29PM +0200, Daniel Vetter wrote:
> On Tue, Oct 15, 2019 at 7:28 PM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> >
> > Hi Daniel
> >
> > Am 15.10.19 um 16:33 schrieb Daniel Vetter:
> > > Hi Thomas,
> > >
> > > On Mon, Oct 14, 2019 at 04:04:01PM +0200, Thomas Zimmermann wrote:
> > >> (was: DRM driver for fbdev devices)
> > >>
> > >> This is version 2 of the fbdev conversion helpers. It's more or less a
> > >> rewrite of the original patchset.
> > >>
> > >> The fbdev subsystem is considered legacy and will probably be removed at
> > >> some point. This would mean the loss of a signifanct number of drivers.
> > >> Some of the affected hardware is not in use any longer, but some hardware
> > >> is still around and provides good(-enough) framebuffers.
> > >>
> > >> The fbconv helpers allow for running the current DRM stack on top of fbdev
> > >> drivers. It's a set of functions that convert between fbdev interfaces and
> > >> DRM interfaces. Based on SHMEM and simple KMS helpers, it only offers the
> > >> basic functionality of a framebuffer, but should be compatible with most
> > >> existing fbdev drivers.
> > >>
> > >> A DRM driver using fbconv helpers consists of
> > >>
> > >>   * DRM stub code that calls into fbconv helpers, and
> > >>   * the original fbdev driver code.
> > >>
> > >> The fbdev driver code has to be modified to register itself with the
> > >> stub driver instead of the fbdev core framework. A tutorial on how to use
> > >> the helpers is part of this patchset. The resulting driver hybrid can be
> > >> refactored into a first-class DRM driver. The fbconv helpers contain a
> > >> number of comments, labeled 'DRM porting note', which explain the required
> > >> steps.
> > >>
> > >> I tested the current patchset with the following drivers: atyfb, aty128fb,
> > >> matroxfb, pm2fb, pm3fb, rivafb, s3fb, savagefb, sisfb, tdfxfb and tridentfb.
> > >> With each, I was able to successfully start with fbcon enabled, run weston and
> > >> X11. The drivers are available at [1]. For reference, the patchset includes
> > >> the Matrox stub driver.
> > >
> > > So I really don't want to rain on the parade here, since if you think this
> > > is useful when converting fbdev drivers I'll buy that, and I'm all for
> > > getting more modern drivers into drm.
> > >
> > > But I have a bunch of concerns with the approach you're proposing here:
> > >
> > > - we've tried staging for drm driver refactoring, it hurts. Separate tree
> > >   plus the quick pace in refactoring create lots of pains. And for small
> > >   drivers refacotoring before it's not buying you anything above
> > >   refactoring in your own personal tree. And for big drivers we're fairly
> > >   lenient with merging drivers that aren't fully polished yet, if there's
> > >   a team serious enough with cleaning up the mess. I think even merging
> > >   partial drivers directly under drivers/gpu (but behind CONFIG_BROKEN) is
> > >   better than staging.
> >
> > I mostly put this into staging, because it's the kind of code you'd
> > expect there.
> 
> Yeah, except we tried, it's a real pain. Conclusion by everyone
> involved is that staging doesn't work for the drm subsystem.

As the staging maintainer, I too agree with this.  No drm drivers/code
in staging please.

thanks,

greg k-h

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

* Re: [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers
@ 2019-10-15 18:05         ` Greg KH
  0 siblings, 0 replies; 77+ messages in thread
From: Greg KH @ 2019-10-15 18:05 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Linux Fbdev development list, Bartlomiej Zolnierkiewicz,
	Dave Airlie, Michel Dänzer, Jonathan Corbet,
	Mathieu Malaterre, dri-devel, Thomas Zimmermann, Sean Paul

On Tue, Oct 15, 2019 at 07:48:29PM +0200, Daniel Vetter wrote:
> On Tue, Oct 15, 2019 at 7:28 PM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> >
> > Hi Daniel
> >
> > Am 15.10.19 um 16:33 schrieb Daniel Vetter:
> > > Hi Thomas,
> > >
> > > On Mon, Oct 14, 2019 at 04:04:01PM +0200, Thomas Zimmermann wrote:
> > >> (was: DRM driver for fbdev devices)
> > >>
> > >> This is version 2 of the fbdev conversion helpers. It's more or less a
> > >> rewrite of the original patchset.
> > >>
> > >> The fbdev subsystem is considered legacy and will probably be removed at
> > >> some point. This would mean the loss of a signifanct number of drivers.
> > >> Some of the affected hardware is not in use any longer, but some hardware
> > >> is still around and provides good(-enough) framebuffers.
> > >>
> > >> The fbconv helpers allow for running the current DRM stack on top of fbdev
> > >> drivers. It's a set of functions that convert between fbdev interfaces and
> > >> DRM interfaces. Based on SHMEM and simple KMS helpers, it only offers the
> > >> basic functionality of a framebuffer, but should be compatible with most
> > >> existing fbdev drivers.
> > >>
> > >> A DRM driver using fbconv helpers consists of
> > >>
> > >>   * DRM stub code that calls into fbconv helpers, and
> > >>   * the original fbdev driver code.
> > >>
> > >> The fbdev driver code has to be modified to register itself with the
> > >> stub driver instead of the fbdev core framework. A tutorial on how to use
> > >> the helpers is part of this patchset. The resulting driver hybrid can be
> > >> refactored into a first-class DRM driver. The fbconv helpers contain a
> > >> number of comments, labeled 'DRM porting note', which explain the required
> > >> steps.
> > >>
> > >> I tested the current patchset with the following drivers: atyfb, aty128fb,
> > >> matroxfb, pm2fb, pm3fb, rivafb, s3fb, savagefb, sisfb, tdfxfb and tridentfb.
> > >> With each, I was able to successfully start with fbcon enabled, run weston and
> > >> X11. The drivers are available at [1]. For reference, the patchset includes
> > >> the Matrox stub driver.
> > >
> > > So I really don't want to rain on the parade here, since if you think this
> > > is useful when converting fbdev drivers I'll buy that, and I'm all for
> > > getting more modern drivers into drm.
> > >
> > > But I have a bunch of concerns with the approach you're proposing here:
> > >
> > > - we've tried staging for drm driver refactoring, it hurts. Separate tree
> > >   plus the quick pace in refactoring create lots of pains. And for small
> > >   drivers refacotoring before it's not buying you anything above
> > >   refactoring in your own personal tree. And for big drivers we're fairly
> > >   lenient with merging drivers that aren't fully polished yet, if there's
> > >   a team serious enough with cleaning up the mess. I think even merging
> > >   partial drivers directly under drivers/gpu (but behind CONFIG_BROKEN) is
> > >   better than staging.
> >
> > I mostly put this into staging, because it's the kind of code you'd
> > expect there.
> 
> Yeah, except we tried, it's a real pain. Conclusion by everyone
> involved is that staging doesn't work for the drm subsystem.

As the staging maintainer, I too agree with this.  No drm drivers/code
in staging please.

thanks,

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

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

* Re: [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers
  2019-10-15 17:48       ` Daniel Vetter
@ 2019-10-15 18:13         ` Ville Syrjälä
  -1 siblings, 0 replies; 77+ messages in thread
From: Ville Syrjälä @ 2019-10-15 18:13 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Linux Fbdev development list, Bartlomiej Zolnierkiewicz,
	Dave Airlie, Greg KH, Michel Dänzer, Jonathan Corbet,
	Mathieu Malaterre, dri-devel, Thomas Zimmermann, Sean Paul

On Tue, Oct 15, 2019 at 07:48:29PM +0200, Daniel Vetter wrote:
> On Tue, Oct 15, 2019 at 7:28 PM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> >
> > Hi Daniel
> >
> > Am 15.10.19 um 16:33 schrieb Daniel Vetter:
> > > Hi Thomas,
> > >
> > > On Mon, Oct 14, 2019 at 04:04:01PM +0200, Thomas Zimmermann wrote:
> > >> (was: DRM driver for fbdev devices)
> > >>
> > >> This is version 2 of the fbdev conversion helpers. It's more or less a
> > >> rewrite of the original patchset.
> > >>
> > >> The fbdev subsystem is considered legacy and will probably be removed at
> > >> some point. This would mean the loss of a signifanct number of drivers.
> > >> Some of the affected hardware is not in use any longer, but some hardware
> > >> is still around and provides good(-enough) framebuffers.
> > >>
> > >> The fbconv helpers allow for running the current DRM stack on top of fbdev
> > >> drivers. It's a set of functions that convert between fbdev interfaces and
> > >> DRM interfaces. Based on SHMEM and simple KMS helpers, it only offers the
> > >> basic functionality of a framebuffer, but should be compatible with most
> > >> existing fbdev drivers.
> > >>
> > >> A DRM driver using fbconv helpers consists of
> > >>
> > >>   * DRM stub code that calls into fbconv helpers, and
> > >>   * the original fbdev driver code.
> > >>
> > >> The fbdev driver code has to be modified to register itself with the
> > >> stub driver instead of the fbdev core framework. A tutorial on how to use
> > >> the helpers is part of this patchset. The resulting driver hybrid can be
> > >> refactored into a first-class DRM driver. The fbconv helpers contain a
> > >> number of comments, labeled 'DRM porting note', which explain the required
> > >> steps.
> > >>
> > >> I tested the current patchset with the following drivers: atyfb, aty128fb,
> > >> matroxfb, pm2fb, pm3fb, rivafb, s3fb, savagefb, sisfb, tdfxfb and tridentfb.
> > >> With each, I was able to successfully start with fbcon enabled, run weston and
> > >> X11. The drivers are available at [1]. For reference, the patchset includes
> > >> the Matrox stub driver.
> > >
> > > So I really don't want to rain on the parade here, since if you think this
> > > is useful when converting fbdev drivers I'll buy that, and I'm all for
> > > getting more modern drivers into drm.
> > >
> > > But I have a bunch of concerns with the approach you're proposing here:
> > >
> > > - we've tried staging for drm driver refactoring, it hurts. Separate tree
> > >   plus the quick pace in refactoring create lots of pains. And for small
> > >   drivers refacotoring before it's not buying you anything above
> > >   refactoring in your own personal tree. And for big drivers we're fairly
> > >   lenient with merging drivers that aren't fully polished yet, if there's
> > >   a team serious enough with cleaning up the mess. I think even merging
> > >   partial drivers directly under drivers/gpu (but behind CONFIG_BROKEN) is
> > >   better than staging.
> >
> > I mostly put this into staging, because it's the kind of code you'd
> > expect there.
> 
> Yeah, except we tried, it's a real pain. Conclusion by everyone
> involved is that staging doesn't work for the drm subsystem.
> 
> > > - we've had conversion helpers before (for the legacy kms -> atomic
> > >   upgrade). They constantly broke, pretty much every release when someone
> > >   wanted to use them they first had to fix them up again. I think having
> > >   those helpers is good, but better to just have them in some branch
> > >   somewhere where it's clear that they might not work anymore on latest
> > >   upstream.
> > >
> > > - especially for some of these simple fbdev drivers I feel like just
> > >   typing a new driver from scratch might be simpler.
> > >
> > > A few more concerns specifically for your mga example:
> > >
> > > - We already have a mga driver. Might be better to integrate support for
> > >   older mgas into that than have a parallel driver.
> >
> > Two colleagues of mine, Takashi and Egbert, send a patch that added
> > support for desktop G200s to mgag200. [1] But it was rejected because
> > the devices are two old and not relevant any longer. If that opinion has
> > changed in the meantime, I wouldn't mind adding support for desktop GPUs
> > to the driver.
> 
> Hm that seems to have petered out inconclusive. I definitely think a
> merged mga driver is better than 2 drm atomic kms drivers for roughly
> the same hardware. I'm also assuming that at least for now no one
> plans to resurrect the 3d acceleration support for these old chips.
> But even then it's fairly easy to disable all that on the server
> chips.
> 
> > > - Your helper is based on simple display pipe, and I think for these old
> > >   mga chips (especially the dual pipe mga 450 and 550) simple display pipe
> > >   helper is more a hindering detour than actual help. From a quick read
> > >   through the code (especially all the custom ioctls) you definitely want
> > >   separate TV-out connector to expose all the tv mode properties (instead
> > >   of the custom ioctls).
> >
> > Around the G100, there's something like a change in generation. Before,
> > devices had only a single output and less than 8 MiB of RAM. This works
> > well with GEM SHMEM and simple KMS. Afterwards, devices have 8 MiB or
> > more and multiple outputs. GEM VRAM and the full set of helpers fit this
> > much better. Maybe having 2 drivers that share common code (or 3 with
> > the Server Engine chipsets) makes most sense.
> 
> Yeah if that's the case maybe a mga100 and mga200g driver fits better.
> Former based on simple display pipe.

The display hardware differences are quite minimal from 
1064SG to G200. G400 did add the second CRTC but essentially
nothing else changed from G200 display. G450/G550 changed
the PLLS around a bit just for the heck of it, and integrated 
the TMDS transmitter and TV encoder. And then they did even
more PLL madness with the different G200 server chip variants.

So IMO from display hw POV G100 vs. G200 split doesn't really
make sense.

And if you go to the effort of supporting dual head on G400+ then
the single head case on earlier platforms is just the same as the
single head "trivial" case on G400+, so totally different drivers
doesn't make sense there either. Also not all G400 cards have
the TVO/TMDS chip present in which case you can only use a
single head anyway (it's almost identical to a G200 card at
that point, assuming you drive the single output with the
primary CRTC).

-- 
Ville Syrjälä
Intel

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

* Re: [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers
@ 2019-10-15 18:13         ` Ville Syrjälä
  0 siblings, 0 replies; 77+ messages in thread
From: Ville Syrjälä @ 2019-10-15 18:13 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Linux Fbdev development list, Bartlomiej Zolnierkiewicz,
	Dave Airlie, Greg KH, Michel Dänzer, Jonathan Corbet,
	Mathieu Malaterre, dri-devel, Thomas Zimmermann, Sean Paul

On Tue, Oct 15, 2019 at 07:48:29PM +0200, Daniel Vetter wrote:
> On Tue, Oct 15, 2019 at 7:28 PM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> >
> > Hi Daniel
> >
> > Am 15.10.19 um 16:33 schrieb Daniel Vetter:
> > > Hi Thomas,
> > >
> > > On Mon, Oct 14, 2019 at 04:04:01PM +0200, Thomas Zimmermann wrote:
> > >> (was: DRM driver for fbdev devices)
> > >>
> > >> This is version 2 of the fbdev conversion helpers. It's more or less a
> > >> rewrite of the original patchset.
> > >>
> > >> The fbdev subsystem is considered legacy and will probably be removed at
> > >> some point. This would mean the loss of a signifanct number of drivers.
> > >> Some of the affected hardware is not in use any longer, but some hardware
> > >> is still around and provides good(-enough) framebuffers.
> > >>
> > >> The fbconv helpers allow for running the current DRM stack on top of fbdev
> > >> drivers. It's a set of functions that convert between fbdev interfaces and
> > >> DRM interfaces. Based on SHMEM and simple KMS helpers, it only offers the
> > >> basic functionality of a framebuffer, but should be compatible with most
> > >> existing fbdev drivers.
> > >>
> > >> A DRM driver using fbconv helpers consists of
> > >>
> > >>   * DRM stub code that calls into fbconv helpers, and
> > >>   * the original fbdev driver code.
> > >>
> > >> The fbdev driver code has to be modified to register itself with the
> > >> stub driver instead of the fbdev core framework. A tutorial on how to use
> > >> the helpers is part of this patchset. The resulting driver hybrid can be
> > >> refactored into a first-class DRM driver. The fbconv helpers contain a
> > >> number of comments, labeled 'DRM porting note', which explain the required
> > >> steps.
> > >>
> > >> I tested the current patchset with the following drivers: atyfb, aty128fb,
> > >> matroxfb, pm2fb, pm3fb, rivafb, s3fb, savagefb, sisfb, tdfxfb and tridentfb.
> > >> With each, I was able to successfully start with fbcon enabled, run weston and
> > >> X11. The drivers are available at [1]. For reference, the patchset includes
> > >> the Matrox stub driver.
> > >
> > > So I really don't want to rain on the parade here, since if you think this
> > > is useful when converting fbdev drivers I'll buy that, and I'm all for
> > > getting more modern drivers into drm.
> > >
> > > But I have a bunch of concerns with the approach you're proposing here:
> > >
> > > - we've tried staging for drm driver refactoring, it hurts. Separate tree
> > >   plus the quick pace in refactoring create lots of pains. And for small
> > >   drivers refacotoring before it's not buying you anything above
> > >   refactoring in your own personal tree. And for big drivers we're fairly
> > >   lenient with merging drivers that aren't fully polished yet, if there's
> > >   a team serious enough with cleaning up the mess. I think even merging
> > >   partial drivers directly under drivers/gpu (but behind CONFIG_BROKEN) is
> > >   better than staging.
> >
> > I mostly put this into staging, because it's the kind of code you'd
> > expect there.
> 
> Yeah, except we tried, it's a real pain. Conclusion by everyone
> involved is that staging doesn't work for the drm subsystem.
> 
> > > - we've had conversion helpers before (for the legacy kms -> atomic
> > >   upgrade). They constantly broke, pretty much every release when someone
> > >   wanted to use them they first had to fix them up again. I think having
> > >   those helpers is good, but better to just have them in some branch
> > >   somewhere where it's clear that they might not work anymore on latest
> > >   upstream.
> > >
> > > - especially for some of these simple fbdev drivers I feel like just
> > >   typing a new driver from scratch might be simpler.
> > >
> > > A few more concerns specifically for your mga example:
> > >
> > > - We already have a mga driver. Might be better to integrate support for
> > >   older mgas into that than have a parallel driver.
> >
> > Two colleagues of mine, Takashi and Egbert, send a patch that added
> > support for desktop G200s to mgag200. [1] But it was rejected because
> > the devices are two old and not relevant any longer. If that opinion has
> > changed in the meantime, I wouldn't mind adding support for desktop GPUs
> > to the driver.
> 
> Hm that seems to have petered out inconclusive. I definitely think a
> merged mga driver is better than 2 drm atomic kms drivers for roughly
> the same hardware. I'm also assuming that at least for now no one
> plans to resurrect the 3d acceleration support for these old chips.
> But even then it's fairly easy to disable all that on the server
> chips.
> 
> > > - Your helper is based on simple display pipe, and I think for these old
> > >   mga chips (especially the dual pipe mga 450 and 550) simple display pipe
> > >   helper is more a hindering detour than actual help. From a quick read
> > >   through the code (especially all the custom ioctls) you definitely want
> > >   separate TV-out connector to expose all the tv mode properties (instead
> > >   of the custom ioctls).
> >
> > Around the G100, there's something like a change in generation. Before,
> > devices had only a single output and less than 8 MiB of RAM. This works
> > well with GEM SHMEM and simple KMS. Afterwards, devices have 8 MiB or
> > more and multiple outputs. GEM VRAM and the full set of helpers fit this
> > much better. Maybe having 2 drivers that share common code (or 3 with
> > the Server Engine chipsets) makes most sense.
> 
> Yeah if that's the case maybe a mga100 and mga200g driver fits better.
> Former based on simple display pipe.

The display hardware differences are quite minimal from 
1064SG to G200. G400 did add the second CRTC but essentially
nothing else changed from G200 display. G450/G550 changed
the PLLS around a bit just for the heck of it, and integrated 
the TMDS transmitter and TV encoder. And then they did even
more PLL madness with the different G200 server chip variants.

So IMO from display hw POV G100 vs. G200 split doesn't really
make sense.

And if you go to the effort of supporting dual head on G400+ then
the single head case on earlier platforms is just the same as the
single head "trivial" case on G400+, so totally different drivers
doesn't make sense there either. Also not all G400 cards have
the TVO/TMDS chip present in which case you can only use a
single head anyway (it's almost identical to a G200 card at
that point, assuming you drive the single output with the
primary CRTC).

-- 
Ville Syrjälä
Intel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers
  2019-10-15 18:13         ` Ville Syrjälä
@ 2019-10-15 18:28           ` Ville Syrjälä
  -1 siblings, 0 replies; 77+ messages in thread
From: Ville Syrjälä @ 2019-10-15 18:28 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Linux Fbdev development list, Bartlomiej Zolnierkiewicz,
	Dave Airlie, Greg KH, Michel Dänzer, Jonathan Corbet,
	Mathieu Malaterre, dri-devel, Thomas Zimmermann, Sean Paul

On Tue, Oct 15, 2019 at 09:13:37PM +0300, Ville Syrjälä wrote:
> On Tue, Oct 15, 2019 at 07:48:29PM +0200, Daniel Vetter wrote:
> > On Tue, Oct 15, 2019 at 7:28 PM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> > >
> > > Hi Daniel
> > >
> > > Am 15.10.19 um 16:33 schrieb Daniel Vetter:
> > > > Hi Thomas,
> > > >
> > > > On Mon, Oct 14, 2019 at 04:04:01PM +0200, Thomas Zimmermann wrote:
> > > >> (was: DRM driver for fbdev devices)
> > > >>
> > > >> This is version 2 of the fbdev conversion helpers. It's more or less a
> > > >> rewrite of the original patchset.
> > > >>
> > > >> The fbdev subsystem is considered legacy and will probably be removed at
> > > >> some point. This would mean the loss of a signifanct number of drivers.
> > > >> Some of the affected hardware is not in use any longer, but some hardware
> > > >> is still around and provides good(-enough) framebuffers.
> > > >>
> > > >> The fbconv helpers allow for running the current DRM stack on top of fbdev
> > > >> drivers. It's a set of functions that convert between fbdev interfaces and
> > > >> DRM interfaces. Based on SHMEM and simple KMS helpers, it only offers the
> > > >> basic functionality of a framebuffer, but should be compatible with most
> > > >> existing fbdev drivers.
> > > >>
> > > >> A DRM driver using fbconv helpers consists of
> > > >>
> > > >>   * DRM stub code that calls into fbconv helpers, and
> > > >>   * the original fbdev driver code.
> > > >>
> > > >> The fbdev driver code has to be modified to register itself with the
> > > >> stub driver instead of the fbdev core framework. A tutorial on how to use
> > > >> the helpers is part of this patchset. The resulting driver hybrid can be
> > > >> refactored into a first-class DRM driver. The fbconv helpers contain a
> > > >> number of comments, labeled 'DRM porting note', which explain the required
> > > >> steps.
> > > >>
> > > >> I tested the current patchset with the following drivers: atyfb, aty128fb,
> > > >> matroxfb, pm2fb, pm3fb, rivafb, s3fb, savagefb, sisfb, tdfxfb and tridentfb.
> > > >> With each, I was able to successfully start with fbcon enabled, run weston and
> > > >> X11. The drivers are available at [1]. For reference, the patchset includes
> > > >> the Matrox stub driver.
> > > >
> > > > So I really don't want to rain on the parade here, since if you think this
> > > > is useful when converting fbdev drivers I'll buy that, and I'm all for
> > > > getting more modern drivers into drm.
> > > >
> > > > But I have a bunch of concerns with the approach you're proposing here:
> > > >
> > > > - we've tried staging for drm driver refactoring, it hurts. Separate tree
> > > >   plus the quick pace in refactoring create lots of pains. And for small
> > > >   drivers refacotoring before it's not buying you anything above
> > > >   refactoring in your own personal tree. And for big drivers we're fairly
> > > >   lenient with merging drivers that aren't fully polished yet, if there's
> > > >   a team serious enough with cleaning up the mess. I think even merging
> > > >   partial drivers directly under drivers/gpu (but behind CONFIG_BROKEN) is
> > > >   better than staging.
> > >
> > > I mostly put this into staging, because it's the kind of code you'd
> > > expect there.
> > 
> > Yeah, except we tried, it's a real pain. Conclusion by everyone
> > involved is that staging doesn't work for the drm subsystem.
> > 
> > > > - we've had conversion helpers before (for the legacy kms -> atomic
> > > >   upgrade). They constantly broke, pretty much every release when someone
> > > >   wanted to use them they first had to fix them up again. I think having
> > > >   those helpers is good, but better to just have them in some branch
> > > >   somewhere where it's clear that they might not work anymore on latest
> > > >   upstream.
> > > >
> > > > - especially for some of these simple fbdev drivers I feel like just
> > > >   typing a new driver from scratch might be simpler.
> > > >
> > > > A few more concerns specifically for your mga example:
> > > >
> > > > - We already have a mga driver. Might be better to integrate support for
> > > >   older mgas into that than have a parallel driver.
> > >
> > > Two colleagues of mine, Takashi and Egbert, send a patch that added
> > > support for desktop G200s to mgag200. [1] But it was rejected because
> > > the devices are two old and not relevant any longer. If that opinion has
> > > changed in the meantime, I wouldn't mind adding support for desktop GPUs
> > > to the driver.
> > 
> > Hm that seems to have petered out inconclusive. I definitely think a
> > merged mga driver is better than 2 drm atomic kms drivers for roughly
> > the same hardware. I'm also assuming that at least for now no one
> > plans to resurrect the 3d acceleration support for these old chips.
> > But even then it's fairly easy to disable all that on the server
> > chips.
> > 
> > > > - Your helper is based on simple display pipe, and I think for these old
> > > >   mga chips (especially the dual pipe mga 450 and 550) simple display pipe
> > > >   helper is more a hindering detour than actual help. From a quick read
> > > >   through the code (especially all the custom ioctls) you definitely want
> > > >   separate TV-out connector to expose all the tv mode properties (instead
> > > >   of the custom ioctls).
> > >
> > > Around the G100, there's something like a change in generation. Before,
> > > devices had only a single output and less than 8 MiB of RAM. This works
> > > well with GEM SHMEM and simple KMS. Afterwards, devices have 8 MiB or
> > > more and multiple outputs. GEM VRAM and the full set of helpers fit this
> > > much better. Maybe having 2 drivers that share common code (or 3 with
> > > the Server Engine chipsets) makes most sense.
> > 
> > Yeah if that's the case maybe a mga100 and mga200g driver fits better.
> > Former based on simple display pipe.
> 
> The display hardware differences are quite minimal from 
> 1064SG to G200. G400 did add the second CRTC but essentially
> nothing else changed from G200 display. G450/G550 changed
> the PLLS around a bit just for the heck of it, and integrated 
> the TMDS transmitter and TV encoder. And then they did even
> more PLL madness with the different G200 server chip variants.
> 
> So IMO from display hw POV G100 vs. G200 split doesn't really
> make sense.

Ah, I did forget that G100 and earlier don't support the
cursor 16 color mode that G200+ have. So I guess there is a
little bit of a difference there.

-- 
Ville Syrjälä
Intel

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

* Re: [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers
@ 2019-10-15 18:28           ` Ville Syrjälä
  0 siblings, 0 replies; 77+ messages in thread
From: Ville Syrjälä @ 2019-10-15 18:28 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Linux Fbdev development list, Bartlomiej Zolnierkiewicz,
	Dave Airlie, Greg KH, Michel Dänzer, Jonathan Corbet,
	Mathieu Malaterre, dri-devel, Thomas Zimmermann, Sean Paul

On Tue, Oct 15, 2019 at 09:13:37PM +0300, Ville Syrjälä wrote:
> On Tue, Oct 15, 2019 at 07:48:29PM +0200, Daniel Vetter wrote:
> > On Tue, Oct 15, 2019 at 7:28 PM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> > >
> > > Hi Daniel
> > >
> > > Am 15.10.19 um 16:33 schrieb Daniel Vetter:
> > > > Hi Thomas,
> > > >
> > > > On Mon, Oct 14, 2019 at 04:04:01PM +0200, Thomas Zimmermann wrote:
> > > >> (was: DRM driver for fbdev devices)
> > > >>
> > > >> This is version 2 of the fbdev conversion helpers. It's more or less a
> > > >> rewrite of the original patchset.
> > > >>
> > > >> The fbdev subsystem is considered legacy and will probably be removed at
> > > >> some point. This would mean the loss of a signifanct number of drivers.
> > > >> Some of the affected hardware is not in use any longer, but some hardware
> > > >> is still around and provides good(-enough) framebuffers.
> > > >>
> > > >> The fbconv helpers allow for running the current DRM stack on top of fbdev
> > > >> drivers. It's a set of functions that convert between fbdev interfaces and
> > > >> DRM interfaces. Based on SHMEM and simple KMS helpers, it only offers the
> > > >> basic functionality of a framebuffer, but should be compatible with most
> > > >> existing fbdev drivers.
> > > >>
> > > >> A DRM driver using fbconv helpers consists of
> > > >>
> > > >>   * DRM stub code that calls into fbconv helpers, and
> > > >>   * the original fbdev driver code.
> > > >>
> > > >> The fbdev driver code has to be modified to register itself with the
> > > >> stub driver instead of the fbdev core framework. A tutorial on how to use
> > > >> the helpers is part of this patchset. The resulting driver hybrid can be
> > > >> refactored into a first-class DRM driver. The fbconv helpers contain a
> > > >> number of comments, labeled 'DRM porting note', which explain the required
> > > >> steps.
> > > >>
> > > >> I tested the current patchset with the following drivers: atyfb, aty128fb,
> > > >> matroxfb, pm2fb, pm3fb, rivafb, s3fb, savagefb, sisfb, tdfxfb and tridentfb.
> > > >> With each, I was able to successfully start with fbcon enabled, run weston and
> > > >> X11. The drivers are available at [1]. For reference, the patchset includes
> > > >> the Matrox stub driver.
> > > >
> > > > So I really don't want to rain on the parade here, since if you think this
> > > > is useful when converting fbdev drivers I'll buy that, and I'm all for
> > > > getting more modern drivers into drm.
> > > >
> > > > But I have a bunch of concerns with the approach you're proposing here:
> > > >
> > > > - we've tried staging for drm driver refactoring, it hurts. Separate tree
> > > >   plus the quick pace in refactoring create lots of pains. And for small
> > > >   drivers refacotoring before it's not buying you anything above
> > > >   refactoring in your own personal tree. And for big drivers we're fairly
> > > >   lenient with merging drivers that aren't fully polished yet, if there's
> > > >   a team serious enough with cleaning up the mess. I think even merging
> > > >   partial drivers directly under drivers/gpu (but behind CONFIG_BROKEN) is
> > > >   better than staging.
> > >
> > > I mostly put this into staging, because it's the kind of code you'd
> > > expect there.
> > 
> > Yeah, except we tried, it's a real pain. Conclusion by everyone
> > involved is that staging doesn't work for the drm subsystem.
> > 
> > > > - we've had conversion helpers before (for the legacy kms -> atomic
> > > >   upgrade). They constantly broke, pretty much every release when someone
> > > >   wanted to use them they first had to fix them up again. I think having
> > > >   those helpers is good, but better to just have them in some branch
> > > >   somewhere where it's clear that they might not work anymore on latest
> > > >   upstream.
> > > >
> > > > - especially for some of these simple fbdev drivers I feel like just
> > > >   typing a new driver from scratch might be simpler.
> > > >
> > > > A few more concerns specifically for your mga example:
> > > >
> > > > - We already have a mga driver. Might be better to integrate support for
> > > >   older mgas into that than have a parallel driver.
> > >
> > > Two colleagues of mine, Takashi and Egbert, send a patch that added
> > > support for desktop G200s to mgag200. [1] But it was rejected because
> > > the devices are two old and not relevant any longer. If that opinion has
> > > changed in the meantime, I wouldn't mind adding support for desktop GPUs
> > > to the driver.
> > 
> > Hm that seems to have petered out inconclusive. I definitely think a
> > merged mga driver is better than 2 drm atomic kms drivers for roughly
> > the same hardware. I'm also assuming that at least for now no one
> > plans to resurrect the 3d acceleration support for these old chips.
> > But even then it's fairly easy to disable all that on the server
> > chips.
> > 
> > > > - Your helper is based on simple display pipe, and I think for these old
> > > >   mga chips (especially the dual pipe mga 450 and 550) simple display pipe
> > > >   helper is more a hindering detour than actual help. From a quick read
> > > >   through the code (especially all the custom ioctls) you definitely want
> > > >   separate TV-out connector to expose all the tv mode properties (instead
> > > >   of the custom ioctls).
> > >
> > > Around the G100, there's something like a change in generation. Before,
> > > devices had only a single output and less than 8 MiB of RAM. This works
> > > well with GEM SHMEM and simple KMS. Afterwards, devices have 8 MiB or
> > > more and multiple outputs. GEM VRAM and the full set of helpers fit this
> > > much better. Maybe having 2 drivers that share common code (or 3 with
> > > the Server Engine chipsets) makes most sense.
> > 
> > Yeah if that's the case maybe a mga100 and mga200g driver fits better.
> > Former based on simple display pipe.
> 
> The display hardware differences are quite minimal from 
> 1064SG to G200. G400 did add the second CRTC but essentially
> nothing else changed from G200 display. G450/G550 changed
> the PLLS around a bit just for the heck of it, and integrated 
> the TMDS transmitter and TV encoder. And then they did even
> more PLL madness with the different G200 server chip variants.
> 
> So IMO from display hw POV G100 vs. G200 split doesn't really
> make sense.

Ah, I did forget that G100 and earlier don't support the
cursor 16 color mode that G200+ have. So I guess there is a
little bit of a difference there.

-- 
Ville Syrjälä
Intel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 15/15] staging/mgakms: Update matroxfb driver code for DRM
  2019-10-14 14:04   ` Thomas Zimmermann
@ 2019-10-17 16:04     ` kbuild test robot
  -1 siblings, 0 replies; 77+ messages in thread
From: kbuild test robot @ 2019-10-17 16:04 UTC (permalink / raw)
  Cc: linux-fbdev, kbuild-all, Thomas Zimmermann, b.zolnierkie,
	airlied, gregkh, michel, corbet, malat, dri-devel, sean

[-- Attachment #1: Type: text/plain, Size: 8355 bytes --]

Hi Thomas,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[cannot apply to v5.4-rc3 next-20191017]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Thomas-Zimmermann/DRM-fbconv-helpers-for-converting-fbdev-drivers/20191015-152231
config: x86_64-allyesconfig (attached as .config)
compiler: gcc-7 (Debian 7.4.0-13) 7.4.0
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   ld: drivers/staging/mgakms/g450_pll.o: in function `__crc_g450_mnp2f':
   (*ABS*+0x456b8a98): multiple definition of `__crc_g450_mnp2f'
   ld: drivers/staging/mgakms/g450_pll.o: in function `__crc_matroxfb_g450_setclk':
   (*ABS*+0x4da4fa96): multiple definition of `__crc_matroxfb_g450_setclk'
   ld: drivers/staging/mgakms/g450_pll.o: in function `matroxfb_g450_setclk':
>> (.text+0x5b0): multiple definition of `matroxfb_g450_setclk'; drivers/video/fbdev/matrox/g450_pll.o:(.text+0x5b0): first defined here
   ld: drivers/staging/mgakms/g450_pll.o: in function `g450_mnp2f':
>> (.text+0x0): multiple definition of `g450_mnp2f'; drivers/video/fbdev/matrox/g450_pll.o:(.text+0x0): first defined here
   ld: drivers/staging/mgakms/g450_pll.o: in function `matroxfb_g450_setpll_cond':
>> (.text+0x230): multiple definition of `matroxfb_g450_setpll_cond'; drivers/video/fbdev/matrox/g450_pll.o:(.text+0x230): first defined here
   ld: drivers/staging/mgakms/g450_pll.o: in function `__crc_matroxfb_g450_setpll_cond':
   (*ABS*+0xc16eb42d): multiple definition of `__crc_matroxfb_g450_setpll_cond'
   ld: drivers/staging/mgakms/matroxfb_accel.o: in function `matrox_cfbX_init':
>> (.text+0x0): multiple definition of `matrox_cfbX_init'; drivers/video/fbdev/matrox/matroxfb_accel.o:(.text+0x0): first defined here
   ld: drivers/staging/mgakms/matroxfb_accel.o: in function `__crc_matrox_cfbX_init':
   (*ABS*+0xad1ca004): multiple definition of `__crc_matrox_cfbX_init'
   ld: drivers/staging/mgakms/matroxfb_base.o: in function `__crc_matroxfb_enable_irq':
   (*ABS*+0x2f4ea06b): multiple definition of `__crc_matroxfb_enable_irq'
   ld: drivers/staging/mgakms/matroxfb_base.o: in function `__crc_matroxfb_register_driver':
   (*ABS*+0x9eefe8ea): multiple definition of `__crc_matroxfb_register_driver'
   ld: drivers/staging/mgakms/matroxfb_base.o: in function `matroxfb_enable_irq':
>> (.text+0x3d70): multiple definition of `matroxfb_enable_irq'; drivers/video/fbdev/matrox/matroxfb_base.o:(.text+0x3d40): first defined here
   ld: drivers/staging/mgakms/matroxfb_base.o: in function `__crc_matroxfb_unregister_driver':
   (*ABS*+0xe6ed497): multiple definition of `__crc_matroxfb_unregister_driver'
   ld: drivers/staging/mgakms/matroxfb_base.o: in function `matroxfb_register_driver':
>> (.text+0x7e0): multiple definition of `matroxfb_register_driver'; drivers/video/fbdev/matrox/matroxfb_base.o:(.text+0x7e0): first defined here
   ld: drivers/staging/mgakms/matroxfb_base.o: in function `matroxfb_wait_for_sync':
>> (.text+0x41b0): multiple definition of `matroxfb_wait_for_sync'; drivers/video/fbdev/matrox/matroxfb_base.o:(.text+0x4180): first defined here
   ld: drivers/staging/mgakms/matroxfb_base.o: in function `__crc_matroxfb_wait_for_sync':
   (*ABS*+0xf264a0a8): multiple definition of `__crc_matroxfb_wait_for_sync'
   ld: drivers/staging/mgakms/matroxfb_base.o: in function `matroxfb_unregister_driver':
>> (.text+0x950): multiple definition of `matroxfb_unregister_driver'; drivers/video/fbdev/matrox/matroxfb_base.o:(.text+0x950): first defined here
>> ld: drivers/staging/mgakms/matroxfb_DAC1064.o:(.data+0x0): multiple definition of `matrox_G100'; drivers/video/fbdev/matrox/matroxfb_DAC1064.o:(.data+0x0): first defined here
   ld: drivers/staging/mgakms/matroxfb_DAC1064.o: in function `__crc_DAC1064_global_init':
   (*ABS*+0x279aabee): multiple definition of `__crc_DAC1064_global_init'
   ld: drivers/staging/mgakms/matroxfb_DAC1064.o: in function `__crc_DAC1064_global_restore':
   (*ABS*+0xb0a182ca): multiple definition of `__crc_DAC1064_global_restore'
>> ld: drivers/staging/mgakms/matroxfb_DAC1064.o:(.data+0x40): multiple definition of `matrox_mystique'; drivers/video/fbdev/matrox/matroxfb_DAC1064.o:(.data+0x40): first defined here
   ld: drivers/staging/mgakms/matroxfb_DAC1064.o: in function `__crc_matrox_mystique':
   (*ABS*+0x82a67894): multiple definition of `__crc_matrox_mystique'
   ld: drivers/staging/mgakms/matroxfb_DAC1064.o: in function `DAC1064_global_restore':
>> (.text+0x0): multiple definition of `DAC1064_global_restore'; drivers/video/fbdev/matrox/matroxfb_DAC1064.o:(.text+0x0): first defined here
   ld: drivers/staging/mgakms/matroxfb_DAC1064.o: in function `__crc_matrox_G100':
   (*ABS*+0x1efba743): multiple definition of `__crc_matrox_G100'
   ld: drivers/staging/mgakms/matroxfb_DAC1064.o: in function `DAC1064_global_init':
>> (.text+0x130): multiple definition of `DAC1064_global_init'; drivers/video/fbdev/matrox/matroxfb_DAC1064.o:(.text+0x130): first defined here
   ld: drivers/staging/mgakms/matroxfb_g450.o: in function `__crc_matroxfb_g450_connect':
   (*ABS*+0xb554d1f9): multiple definition of `__crc_matroxfb_g450_connect'
   ld: drivers/staging/mgakms/matroxfb_g450.o: in function `__crc_matroxfb_g450_shutdown':
   (*ABS*+0xfef8ad0b): multiple definition of `__crc_matroxfb_g450_shutdown'
   ld: drivers/staging/mgakms/matroxfb_g450.o: in function `matroxfb_g450_shutdown':
>> (.text+0x2c0): multiple definition of `matroxfb_g450_shutdown'; drivers/video/fbdev/matrox/matroxfb_g450.o:(.text+0x2c0): first defined here
   ld: drivers/staging/mgakms/matroxfb_g450.o: in function `matroxfb_g450_connect':
>> (.text+0x130): multiple definition of `matroxfb_g450_connect'; drivers/video/fbdev/matrox/matroxfb_g450.o:(.text+0x130): first defined here
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `__crc_matroxfb_DAC_in':
   (*ABS*+0xa94ac221): multiple definition of `__crc_matroxfb_DAC_in'
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `__crc_matroxfb_DAC_out':
   (*ABS*+0x7b927ef5): multiple definition of `__crc_matroxfb_DAC_out'
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `matroxfb_PLL_calcclock':
>> (.text+0x260): multiple definition of `matroxfb_PLL_calcclock'; drivers/video/fbdev/matrox/matroxfb_misc.o:(.text+0x260): first defined here
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `matroxfb_DAC_in':
>> (.text+0x50): multiple definition of `matroxfb_DAC_in'; drivers/video/fbdev/matrox/matroxfb_misc.o:(.text+0x50): first defined here
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `matroxfb_DAC_out':
>> (.text+0x0): multiple definition of `matroxfb_DAC_out'; drivers/video/fbdev/matrox/matroxfb_misc.o:(.text+0x0): first defined here
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `matroxfb_vgaHWinit':
>> (.text+0x500): multiple definition of `matroxfb_vgaHWinit'; drivers/video/fbdev/matrox/matroxfb_misc.o:(.text+0x500): first defined here
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `__crc_matroxfb_vgaHWinit':
   (*ABS*+0x880c2f5e): multiple definition of `__crc_matroxfb_vgaHWinit'
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `matroxfb_vgaHWrestore':
>> (.text+0xd50): multiple definition of `matroxfb_vgaHWrestore'; drivers/video/fbdev/matrox/matroxfb_misc.o:(.text+0xd50): first defined here
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `__crc_matroxfb_read_pins':
   (*ABS*+0x10a9907b): multiple definition of `__crc_matroxfb_read_pins'
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `matroxfb_read_pins':
>> (.text+0x13d0): multiple definition of `matroxfb_read_pins'; drivers/video/fbdev/matrox/matroxfb_misc.o:(.text+0x13d0): first defined here
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `matroxfb_var2my':

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 70189 bytes --]

[-- Attachment #3: Type: text/plain, Size: 159 bytes --]

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

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

* Re: [PATCH v2 15/15] staging/mgakms: Update matroxfb driver code for DRM
@ 2019-10-17 16:04     ` kbuild test robot
  0 siblings, 0 replies; 77+ messages in thread
From: kbuild test robot @ 2019-10-17 16:04 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 8456 bytes --]

Hi Thomas,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[cannot apply to v5.4-rc3 next-20191017]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Thomas-Zimmermann/DRM-fbconv-helpers-for-converting-fbdev-drivers/20191015-152231
config: x86_64-allyesconfig (attached as .config)
compiler: gcc-7 (Debian 7.4.0-13) 7.4.0
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   ld: drivers/staging/mgakms/g450_pll.o: in function `__crc_g450_mnp2f':
   (*ABS*+0x456b8a98): multiple definition of `__crc_g450_mnp2f'
   ld: drivers/staging/mgakms/g450_pll.o: in function `__crc_matroxfb_g450_setclk':
   (*ABS*+0x4da4fa96): multiple definition of `__crc_matroxfb_g450_setclk'
   ld: drivers/staging/mgakms/g450_pll.o: in function `matroxfb_g450_setclk':
>> (.text+0x5b0): multiple definition of `matroxfb_g450_setclk'; drivers/video/fbdev/matrox/g450_pll.o:(.text+0x5b0): first defined here
   ld: drivers/staging/mgakms/g450_pll.o: in function `g450_mnp2f':
>> (.text+0x0): multiple definition of `g450_mnp2f'; drivers/video/fbdev/matrox/g450_pll.o:(.text+0x0): first defined here
   ld: drivers/staging/mgakms/g450_pll.o: in function `matroxfb_g450_setpll_cond':
>> (.text+0x230): multiple definition of `matroxfb_g450_setpll_cond'; drivers/video/fbdev/matrox/g450_pll.o:(.text+0x230): first defined here
   ld: drivers/staging/mgakms/g450_pll.o: in function `__crc_matroxfb_g450_setpll_cond':
   (*ABS*+0xc16eb42d): multiple definition of `__crc_matroxfb_g450_setpll_cond'
   ld: drivers/staging/mgakms/matroxfb_accel.o: in function `matrox_cfbX_init':
>> (.text+0x0): multiple definition of `matrox_cfbX_init'; drivers/video/fbdev/matrox/matroxfb_accel.o:(.text+0x0): first defined here
   ld: drivers/staging/mgakms/matroxfb_accel.o: in function `__crc_matrox_cfbX_init':
   (*ABS*+0xad1ca004): multiple definition of `__crc_matrox_cfbX_init'
   ld: drivers/staging/mgakms/matroxfb_base.o: in function `__crc_matroxfb_enable_irq':
   (*ABS*+0x2f4ea06b): multiple definition of `__crc_matroxfb_enable_irq'
   ld: drivers/staging/mgakms/matroxfb_base.o: in function `__crc_matroxfb_register_driver':
   (*ABS*+0x9eefe8ea): multiple definition of `__crc_matroxfb_register_driver'
   ld: drivers/staging/mgakms/matroxfb_base.o: in function `matroxfb_enable_irq':
>> (.text+0x3d70): multiple definition of `matroxfb_enable_irq'; drivers/video/fbdev/matrox/matroxfb_base.o:(.text+0x3d40): first defined here
   ld: drivers/staging/mgakms/matroxfb_base.o: in function `__crc_matroxfb_unregister_driver':
   (*ABS*+0xe6ed497): multiple definition of `__crc_matroxfb_unregister_driver'
   ld: drivers/staging/mgakms/matroxfb_base.o: in function `matroxfb_register_driver':
>> (.text+0x7e0): multiple definition of `matroxfb_register_driver'; drivers/video/fbdev/matrox/matroxfb_base.o:(.text+0x7e0): first defined here
   ld: drivers/staging/mgakms/matroxfb_base.o: in function `matroxfb_wait_for_sync':
>> (.text+0x41b0): multiple definition of `matroxfb_wait_for_sync'; drivers/video/fbdev/matrox/matroxfb_base.o:(.text+0x4180): first defined here
   ld: drivers/staging/mgakms/matroxfb_base.o: in function `__crc_matroxfb_wait_for_sync':
   (*ABS*+0xf264a0a8): multiple definition of `__crc_matroxfb_wait_for_sync'
   ld: drivers/staging/mgakms/matroxfb_base.o: in function `matroxfb_unregister_driver':
>> (.text+0x950): multiple definition of `matroxfb_unregister_driver'; drivers/video/fbdev/matrox/matroxfb_base.o:(.text+0x950): first defined here
>> ld: drivers/staging/mgakms/matroxfb_DAC1064.o:(.data+0x0): multiple definition of `matrox_G100'; drivers/video/fbdev/matrox/matroxfb_DAC1064.o:(.data+0x0): first defined here
   ld: drivers/staging/mgakms/matroxfb_DAC1064.o: in function `__crc_DAC1064_global_init':
   (*ABS*+0x279aabee): multiple definition of `__crc_DAC1064_global_init'
   ld: drivers/staging/mgakms/matroxfb_DAC1064.o: in function `__crc_DAC1064_global_restore':
   (*ABS*+0xb0a182ca): multiple definition of `__crc_DAC1064_global_restore'
>> ld: drivers/staging/mgakms/matroxfb_DAC1064.o:(.data+0x40): multiple definition of `matrox_mystique'; drivers/video/fbdev/matrox/matroxfb_DAC1064.o:(.data+0x40): first defined here
   ld: drivers/staging/mgakms/matroxfb_DAC1064.o: in function `__crc_matrox_mystique':
   (*ABS*+0x82a67894): multiple definition of `__crc_matrox_mystique'
   ld: drivers/staging/mgakms/matroxfb_DAC1064.o: in function `DAC1064_global_restore':
>> (.text+0x0): multiple definition of `DAC1064_global_restore'; drivers/video/fbdev/matrox/matroxfb_DAC1064.o:(.text+0x0): first defined here
   ld: drivers/staging/mgakms/matroxfb_DAC1064.o: in function `__crc_matrox_G100':
   (*ABS*+0x1efba743): multiple definition of `__crc_matrox_G100'
   ld: drivers/staging/mgakms/matroxfb_DAC1064.o: in function `DAC1064_global_init':
>> (.text+0x130): multiple definition of `DAC1064_global_init'; drivers/video/fbdev/matrox/matroxfb_DAC1064.o:(.text+0x130): first defined here
   ld: drivers/staging/mgakms/matroxfb_g450.o: in function `__crc_matroxfb_g450_connect':
   (*ABS*+0xb554d1f9): multiple definition of `__crc_matroxfb_g450_connect'
   ld: drivers/staging/mgakms/matroxfb_g450.o: in function `__crc_matroxfb_g450_shutdown':
   (*ABS*+0xfef8ad0b): multiple definition of `__crc_matroxfb_g450_shutdown'
   ld: drivers/staging/mgakms/matroxfb_g450.o: in function `matroxfb_g450_shutdown':
>> (.text+0x2c0): multiple definition of `matroxfb_g450_shutdown'; drivers/video/fbdev/matrox/matroxfb_g450.o:(.text+0x2c0): first defined here
   ld: drivers/staging/mgakms/matroxfb_g450.o: in function `matroxfb_g450_connect':
>> (.text+0x130): multiple definition of `matroxfb_g450_connect'; drivers/video/fbdev/matrox/matroxfb_g450.o:(.text+0x130): first defined here
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `__crc_matroxfb_DAC_in':
   (*ABS*+0xa94ac221): multiple definition of `__crc_matroxfb_DAC_in'
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `__crc_matroxfb_DAC_out':
   (*ABS*+0x7b927ef5): multiple definition of `__crc_matroxfb_DAC_out'
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `matroxfb_PLL_calcclock':
>> (.text+0x260): multiple definition of `matroxfb_PLL_calcclock'; drivers/video/fbdev/matrox/matroxfb_misc.o:(.text+0x260): first defined here
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `matroxfb_DAC_in':
>> (.text+0x50): multiple definition of `matroxfb_DAC_in'; drivers/video/fbdev/matrox/matroxfb_misc.o:(.text+0x50): first defined here
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `matroxfb_DAC_out':
>> (.text+0x0): multiple definition of `matroxfb_DAC_out'; drivers/video/fbdev/matrox/matroxfb_misc.o:(.text+0x0): first defined here
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `matroxfb_vgaHWinit':
>> (.text+0x500): multiple definition of `matroxfb_vgaHWinit'; drivers/video/fbdev/matrox/matroxfb_misc.o:(.text+0x500): first defined here
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `__crc_matroxfb_vgaHWinit':
   (*ABS*+0x880c2f5e): multiple definition of `__crc_matroxfb_vgaHWinit'
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `matroxfb_vgaHWrestore':
>> (.text+0xd50): multiple definition of `matroxfb_vgaHWrestore'; drivers/video/fbdev/matrox/matroxfb_misc.o:(.text+0xd50): first defined here
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `__crc_matroxfb_read_pins':
   (*ABS*+0x10a9907b): multiple definition of `__crc_matroxfb_read_pins'
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `matroxfb_read_pins':
>> (.text+0x13d0): multiple definition of `matroxfb_read_pins'; drivers/video/fbdev/matrox/matroxfb_misc.o:(.text+0x13d0): first defined here
   ld: drivers/staging/mgakms/matroxfb_misc.o: in function `matroxfb_var2my':

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 70189 bytes --]

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

* Re: [PATCH v2 15/15] staging/mgakms: Update matroxfb driver code for DRM
  2019-10-14 14:04   ` Thomas Zimmermann
  (?)
@ 2019-10-17 16:19     ` kbuild test robot
  -1 siblings, 0 replies; 77+ messages in thread
From: kbuild test robot @ 2019-10-17 16:19 UTC (permalink / raw)
  Cc: linux-fbdev, kbuild-all, Thomas Zimmermann, b.zolnierkie,
	airlied, gregkh, michel, corbet, malat, dri-devel, sean

[-- Attachment #1: Type: text/plain, Size: 5338 bytes --]

Hi Thomas,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[cannot apply to v5.4-rc3 next-20191014]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Thomas-Zimmermann/DRM-fbconv-helpers-for-converting-fbdev-drivers/20191015-152231
config: arm64-allyesconfig (attached as .config)
compiler: aarch64-linux-gcc (GCC) 7.4.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.4.0 make.cross ARCH=arm64 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/staging/mgakms/g450_pll.o: In function `__crc_g450_mnp2f':
>> g450_pll.c:(*ABS*+0x3559243b): multiple definition of `__crc_g450_mnp2f'
   drivers/staging/mgakms/g450_pll.o: In function `__crc_matroxfb_g450_setclk':
>> g450_pll.c:(*ABS*+0xb4e884b9): multiple definition of `__crc_matroxfb_g450_setclk'
   drivers/staging/mgakms/g450_pll.o: In function `matroxfb_g450_setclk':
>> g450_pll.c:(.text+0x1fe8): multiple definition of `matroxfb_g450_setclk'
   drivers/video/fbdev/matrox/g450_pll.o:g450_pll.c:(.text+0x1fe8): first defined here
   drivers/staging/mgakms/g450_pll.o: In function `g450_mnp2f':
>> g450_pll.c:(.text+0x0): multiple definition of `g450_mnp2f'
   drivers/video/fbdev/matrox/g450_pll.o:g450_pll.c:(.text+0x0): first defined here
   drivers/staging/mgakms/g450_pll.o: In function `matroxfb_g450_setpll_cond':
>> g450_pll.c:(.text+0x258): multiple definition of `matroxfb_g450_setpll_cond'
   drivers/video/fbdev/matrox/g450_pll.o:g450_pll.c:(.text+0x258): first defined here
   drivers/staging/mgakms/g450_pll.o: In function `__crc_matroxfb_g450_setpll_cond':
>> g450_pll.c:(*ABS*+0x92a49e90): multiple definition of `__crc_matroxfb_g450_setpll_cond'
   drivers/staging/mgakms/matroxfb_accel.o: In function `matrox_cfbX_init':
>> matroxfb_accel.c:(.text+0x78): multiple definition of `matrox_cfbX_init'
   drivers/video/fbdev/matrox/matroxfb_accel.o:matroxfb_accel.c:(.text+0x78): first defined here
   drivers/staging/mgakms/matroxfb_accel.o: In function `__crc_matrox_cfbX_init':
>> matroxfb_accel.c:(*ABS*+0x30cc4dd3): multiple definition of `__crc_matrox_cfbX_init'
   drivers/staging/mgakms/matroxfb_base.o: In function `__crc_matroxfb_enable_irq':
>> matroxfb_base.c:(*ABS*+0xcf34e848): multiple definition of `__crc_matroxfb_enable_irq'
   drivers/staging/mgakms/matroxfb_base.o: In function `__crc_matroxfb_register_driver':
>> matroxfb_base.c:(*ABS*+0x1294ef50): multiple definition of `__crc_matroxfb_register_driver'
   drivers/staging/mgakms/matroxfb_base.o: In function `matroxfb_enable_irq':
>> matroxfb_base.c:(.text+0x1130): multiple definition of `matroxfb_enable_irq'
   drivers/video/fbdev/matrox/matroxfb_base.o:matroxfb_base.c:(.text+0x1108): first defined here
   drivers/staging/mgakms/matroxfb_base.o: In function `__crc_matroxfb_unregister_driver':
>> matroxfb_base.c:(*ABS*+0x6a5fc443): multiple definition of `__crc_matroxfb_unregister_driver'
   drivers/staging/mgakms/matroxfb_base.o: In function `matroxfb_register_driver':
>> matroxfb_base.c:(.text+0x3e8): multiple definition of `matroxfb_register_driver'
   drivers/video/fbdev/matrox/matroxfb_base.o:matroxfb_base.c:(.text+0x3c8): first defined here
   drivers/staging/mgakms/matroxfb_base.o: In function `matroxfb_wait_for_sync':
>> matroxfb_base.c:(.text+0x13a0): multiple definition of `matroxfb_wait_for_sync'
   drivers/video/fbdev/matrox/matroxfb_base.o:matroxfb_base.c:(.text+0x1378): first defined here
   drivers/staging/mgakms/matroxfb_base.o: In function `__crc_matroxfb_wait_for_sync':
>> matroxfb_base.c:(*ABS*+0x299ca154): multiple definition of `__crc_matroxfb_wait_for_sync'
   drivers/staging/mgakms/matroxfb_base.o: In function `matroxfb_unregister_driver':
>> matroxfb_base.c:(.text+0x540): multiple definition of `matroxfb_unregister_driver'
   drivers/video/fbdev/matrox/matroxfb_base.o:matroxfb_base.c:(.text+0x520): first defined here
>> drivers/staging/mgakms/matroxfb_DAC1064.o:(.data+0xc0): multiple definition of `matrox_G100'
   drivers/video/fbdev/matrox/matroxfb_DAC1064.o:(.data+0xc0): first defined here
   drivers/staging/mgakms/matroxfb_DAC1064.o: In function `__crc_DAC1064_global_init':
>> matroxfb_DAC1064.c:(*ABS*+0xd101267): multiple definition of `__crc_DAC1064_global_init'
   drivers/staging/mgakms/matroxfb_DAC1064.o: In function `__crc_DAC1064_global_restore':
>> matroxfb_DAC1064.c:(*ABS*+0xf73a4dac): multiple definition of `__crc_DAC1064_global_restore'
>> drivers/staging/mgakms/matroxfb_DAC1064.o:(.data+0x100): multiple definition of `matrox_mystique'
   drivers/video/fbdev/matrox/matroxfb_DAC1064.o:(.data+0x100): first defined here
   drivers/staging/mgakms/matroxfb_DAC1064.o: In function `__crc_matrox_mystique':

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 67227 bytes --]

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

* Re: [PATCH v2 15/15] staging/mgakms: Update matroxfb driver code for DRM
@ 2019-10-17 16:19     ` kbuild test robot
  0 siblings, 0 replies; 77+ messages in thread
From: kbuild test robot @ 2019-10-17 16:19 UTC (permalink / raw)
  Cc: linux-fbdev, kbuild-all, Thomas Zimmermann, b.zolnierkie,
	airlied, gregkh, michel, corbet, malat, dri-devel, sean

[-- Attachment #1: Type: text/plain, Size: 5338 bytes --]

Hi Thomas,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[cannot apply to v5.4-rc3 next-20191014]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Thomas-Zimmermann/DRM-fbconv-helpers-for-converting-fbdev-drivers/20191015-152231
config: arm64-allyesconfig (attached as .config)
compiler: aarch64-linux-gcc (GCC) 7.4.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.4.0 make.cross ARCH=arm64 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/staging/mgakms/g450_pll.o: In function `__crc_g450_mnp2f':
>> g450_pll.c:(*ABS*+0x3559243b): multiple definition of `__crc_g450_mnp2f'
   drivers/staging/mgakms/g450_pll.o: In function `__crc_matroxfb_g450_setclk':
>> g450_pll.c:(*ABS*+0xb4e884b9): multiple definition of `__crc_matroxfb_g450_setclk'
   drivers/staging/mgakms/g450_pll.o: In function `matroxfb_g450_setclk':
>> g450_pll.c:(.text+0x1fe8): multiple definition of `matroxfb_g450_setclk'
   drivers/video/fbdev/matrox/g450_pll.o:g450_pll.c:(.text+0x1fe8): first defined here
   drivers/staging/mgakms/g450_pll.o: In function `g450_mnp2f':
>> g450_pll.c:(.text+0x0): multiple definition of `g450_mnp2f'
   drivers/video/fbdev/matrox/g450_pll.o:g450_pll.c:(.text+0x0): first defined here
   drivers/staging/mgakms/g450_pll.o: In function `matroxfb_g450_setpll_cond':
>> g450_pll.c:(.text+0x258): multiple definition of `matroxfb_g450_setpll_cond'
   drivers/video/fbdev/matrox/g450_pll.o:g450_pll.c:(.text+0x258): first defined here
   drivers/staging/mgakms/g450_pll.o: In function `__crc_matroxfb_g450_setpll_cond':
>> g450_pll.c:(*ABS*+0x92a49e90): multiple definition of `__crc_matroxfb_g450_setpll_cond'
   drivers/staging/mgakms/matroxfb_accel.o: In function `matrox_cfbX_init':
>> matroxfb_accel.c:(.text+0x78): multiple definition of `matrox_cfbX_init'
   drivers/video/fbdev/matrox/matroxfb_accel.o:matroxfb_accel.c:(.text+0x78): first defined here
   drivers/staging/mgakms/matroxfb_accel.o: In function `__crc_matrox_cfbX_init':
>> matroxfb_accel.c:(*ABS*+0x30cc4dd3): multiple definition of `__crc_matrox_cfbX_init'
   drivers/staging/mgakms/matroxfb_base.o: In function `__crc_matroxfb_enable_irq':
>> matroxfb_base.c:(*ABS*+0xcf34e848): multiple definition of `__crc_matroxfb_enable_irq'
   drivers/staging/mgakms/matroxfb_base.o: In function `__crc_matroxfb_register_driver':
>> matroxfb_base.c:(*ABS*+0x1294ef50): multiple definition of `__crc_matroxfb_register_driver'
   drivers/staging/mgakms/matroxfb_base.o: In function `matroxfb_enable_irq':
>> matroxfb_base.c:(.text+0x1130): multiple definition of `matroxfb_enable_irq'
   drivers/video/fbdev/matrox/matroxfb_base.o:matroxfb_base.c:(.text+0x1108): first defined here
   drivers/staging/mgakms/matroxfb_base.o: In function `__crc_matroxfb_unregister_driver':
>> matroxfb_base.c:(*ABS*+0x6a5fc443): multiple definition of `__crc_matroxfb_unregister_driver'
   drivers/staging/mgakms/matroxfb_base.o: In function `matroxfb_register_driver':
>> matroxfb_base.c:(.text+0x3e8): multiple definition of `matroxfb_register_driver'
   drivers/video/fbdev/matrox/matroxfb_base.o:matroxfb_base.c:(.text+0x3c8): first defined here
   drivers/staging/mgakms/matroxfb_base.o: In function `matroxfb_wait_for_sync':
>> matroxfb_base.c:(.text+0x13a0): multiple definition of `matroxfb_wait_for_sync'
   drivers/video/fbdev/matrox/matroxfb_base.o:matroxfb_base.c:(.text+0x1378): first defined here
   drivers/staging/mgakms/matroxfb_base.o: In function `__crc_matroxfb_wait_for_sync':
>> matroxfb_base.c:(*ABS*+0x299ca154): multiple definition of `__crc_matroxfb_wait_for_sync'
   drivers/staging/mgakms/matroxfb_base.o: In function `matroxfb_unregister_driver':
>> matroxfb_base.c:(.text+0x540): multiple definition of `matroxfb_unregister_driver'
   drivers/video/fbdev/matrox/matroxfb_base.o:matroxfb_base.c:(.text+0x520): first defined here
>> drivers/staging/mgakms/matroxfb_DAC1064.o:(.data+0xc0): multiple definition of `matrox_G100'
   drivers/video/fbdev/matrox/matroxfb_DAC1064.o:(.data+0xc0): first defined here
   drivers/staging/mgakms/matroxfb_DAC1064.o: In function `__crc_DAC1064_global_init':
>> matroxfb_DAC1064.c:(*ABS*+0xd101267): multiple definition of `__crc_DAC1064_global_init'
   drivers/staging/mgakms/matroxfb_DAC1064.o: In function `__crc_DAC1064_global_restore':
>> matroxfb_DAC1064.c:(*ABS*+0xf73a4dac): multiple definition of `__crc_DAC1064_global_restore'
>> drivers/staging/mgakms/matroxfb_DAC1064.o:(.data+0x100): multiple definition of `matrox_mystique'
   drivers/video/fbdev/matrox/matroxfb_DAC1064.o:(.data+0x100): first defined here
   drivers/staging/mgakms/matroxfb_DAC1064.o: In function `__crc_matrox_mystique':

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 67227 bytes --]

[-- Attachment #3: Type: text/plain, Size: 159 bytes --]

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

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

* Re: [PATCH v2 15/15] staging/mgakms: Update matroxfb driver code for DRM
@ 2019-10-17 16:19     ` kbuild test robot
  0 siblings, 0 replies; 77+ messages in thread
From: kbuild test robot @ 2019-10-17 16:19 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 5415 bytes --]

Hi Thomas,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[cannot apply to v5.4-rc3 next-20191014]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/Thomas-Zimmermann/DRM-fbconv-helpers-for-converting-fbdev-drivers/20191015-152231
config: arm64-allyesconfig (attached as .config)
compiler: aarch64-linux-gcc (GCC) 7.4.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.4.0 make.cross ARCH=arm64 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/staging/mgakms/g450_pll.o: In function `__crc_g450_mnp2f':
>> g450_pll.c:(*ABS*+0x3559243b): multiple definition of `__crc_g450_mnp2f'
   drivers/staging/mgakms/g450_pll.o: In function `__crc_matroxfb_g450_setclk':
>> g450_pll.c:(*ABS*+0xb4e884b9): multiple definition of `__crc_matroxfb_g450_setclk'
   drivers/staging/mgakms/g450_pll.o: In function `matroxfb_g450_setclk':
>> g450_pll.c:(.text+0x1fe8): multiple definition of `matroxfb_g450_setclk'
   drivers/video/fbdev/matrox/g450_pll.o:g450_pll.c:(.text+0x1fe8): first defined here
   drivers/staging/mgakms/g450_pll.o: In function `g450_mnp2f':
>> g450_pll.c:(.text+0x0): multiple definition of `g450_mnp2f'
   drivers/video/fbdev/matrox/g450_pll.o:g450_pll.c:(.text+0x0): first defined here
   drivers/staging/mgakms/g450_pll.o: In function `matroxfb_g450_setpll_cond':
>> g450_pll.c:(.text+0x258): multiple definition of `matroxfb_g450_setpll_cond'
   drivers/video/fbdev/matrox/g450_pll.o:g450_pll.c:(.text+0x258): first defined here
   drivers/staging/mgakms/g450_pll.o: In function `__crc_matroxfb_g450_setpll_cond':
>> g450_pll.c:(*ABS*+0x92a49e90): multiple definition of `__crc_matroxfb_g450_setpll_cond'
   drivers/staging/mgakms/matroxfb_accel.o: In function `matrox_cfbX_init':
>> matroxfb_accel.c:(.text+0x78): multiple definition of `matrox_cfbX_init'
   drivers/video/fbdev/matrox/matroxfb_accel.o:matroxfb_accel.c:(.text+0x78): first defined here
   drivers/staging/mgakms/matroxfb_accel.o: In function `__crc_matrox_cfbX_init':
>> matroxfb_accel.c:(*ABS*+0x30cc4dd3): multiple definition of `__crc_matrox_cfbX_init'
   drivers/staging/mgakms/matroxfb_base.o: In function `__crc_matroxfb_enable_irq':
>> matroxfb_base.c:(*ABS*+0xcf34e848): multiple definition of `__crc_matroxfb_enable_irq'
   drivers/staging/mgakms/matroxfb_base.o: In function `__crc_matroxfb_register_driver':
>> matroxfb_base.c:(*ABS*+0x1294ef50): multiple definition of `__crc_matroxfb_register_driver'
   drivers/staging/mgakms/matroxfb_base.o: In function `matroxfb_enable_irq':
>> matroxfb_base.c:(.text+0x1130): multiple definition of `matroxfb_enable_irq'
   drivers/video/fbdev/matrox/matroxfb_base.o:matroxfb_base.c:(.text+0x1108): first defined here
   drivers/staging/mgakms/matroxfb_base.o: In function `__crc_matroxfb_unregister_driver':
>> matroxfb_base.c:(*ABS*+0x6a5fc443): multiple definition of `__crc_matroxfb_unregister_driver'
   drivers/staging/mgakms/matroxfb_base.o: In function `matroxfb_register_driver':
>> matroxfb_base.c:(.text+0x3e8): multiple definition of `matroxfb_register_driver'
   drivers/video/fbdev/matrox/matroxfb_base.o:matroxfb_base.c:(.text+0x3c8): first defined here
   drivers/staging/mgakms/matroxfb_base.o: In function `matroxfb_wait_for_sync':
>> matroxfb_base.c:(.text+0x13a0): multiple definition of `matroxfb_wait_for_sync'
   drivers/video/fbdev/matrox/matroxfb_base.o:matroxfb_base.c:(.text+0x1378): first defined here
   drivers/staging/mgakms/matroxfb_base.o: In function `__crc_matroxfb_wait_for_sync':
>> matroxfb_base.c:(*ABS*+0x299ca154): multiple definition of `__crc_matroxfb_wait_for_sync'
   drivers/staging/mgakms/matroxfb_base.o: In function `matroxfb_unregister_driver':
>> matroxfb_base.c:(.text+0x540): multiple definition of `matroxfb_unregister_driver'
   drivers/video/fbdev/matrox/matroxfb_base.o:matroxfb_base.c:(.text+0x520): first defined here
>> drivers/staging/mgakms/matroxfb_DAC1064.o:(.data+0xc0): multiple definition of `matrox_G100'
   drivers/video/fbdev/matrox/matroxfb_DAC1064.o:(.data+0xc0): first defined here
   drivers/staging/mgakms/matroxfb_DAC1064.o: In function `__crc_DAC1064_global_init':
>> matroxfb_DAC1064.c:(*ABS*+0xd101267): multiple definition of `__crc_DAC1064_global_init'
   drivers/staging/mgakms/matroxfb_DAC1064.o: In function `__crc_DAC1064_global_restore':
>> matroxfb_DAC1064.c:(*ABS*+0xf73a4dac): multiple definition of `__crc_DAC1064_global_restore'
>> drivers/staging/mgakms/matroxfb_DAC1064.o:(.data+0x100): multiple definition of `matrox_mystique'
   drivers/video/fbdev/matrox/matroxfb_DAC1064.o:(.data+0x100): first defined here
   drivers/staging/mgakms/matroxfb_DAC1064.o: In function `__crc_matrox_mystique':

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 67227 bytes --]

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

* Re: [PATCH v2 09/15] drm/fbconv: Mode-setting pipeline enable / disable
  2019-10-14 14:04   ` Thomas Zimmermann
@ 2022-05-28 20:17     ` Geert Uytterhoeven
  -1 siblings, 0 replies; 77+ messages in thread
From: Geert Uytterhoeven @ 2022-05-28 20:17 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: David Airlie, Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Sean Paul, Bartlomiej Zolnierkiewicz, ajax,
	Ville Syrjälä,
	Mathieu Malaterre, michel, Jonathan Corbet, Greg KH,
	DRI Development, Linux Fbdev development list

Hi Thomas,

On Mon, Oct 14, 2019 at 4:05 PM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> The display mode is set by converting the DRM display mode to an
> fb_info state and handling it to the fbdev driver's fb_setvar()
> function. This also requires a color depth, which we take from the
> value of struct drm_mode_config.preferred_depth
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>

> --- a/drivers/gpu/drm/drm_fbconv_helper.c
> +++ b/drivers/gpu/drm/drm_fbconv_helper.c
> @@ -919,6 +919,24 @@ static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
>         return 0;
>  }
>
> +static int drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
> +       struct fb_var_screeninfo *fb_var, struct drm_simple_display_pipe *pipe)
> +{
> +       struct drm_plane *primary = pipe->crtc.primary;
> +       struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
> +
> +       if (primary && primary->state && primary->state->fb)
> +               return drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
> +                       fb_var, primary->state->fb,
> +                       modeset->fb_info->fix.smem_len);
> +
> +       fb_var->xres_virtual = fb_var->xres;
> +       fb_var->yres_virtual = fb_var->yres;
> +       fb_var->bits_per_pixel = modeset->dev->mode_config.preferred_depth;

This looks wrong to me: IMHO bits_per_pixel should be derived from
the fourcc format of the _new_ mode to be set...

> +
> +       return 0;
> +}
> +
>  /**
>   * drm_fbconv_simple_display_pipe_mode_valid - default implementation for
>   *     struct drm_simple_display_pipe_funcs.mode_valid
> @@ -950,6 +968,28 @@ bool drm_fbconv_simple_display_pipe_mode_fixup(
>         struct drm_crtc *crtc, const struct drm_display_mode *mode,
>         struct drm_display_mode *adjusted_mode)
>  {
> +       struct drm_simple_display_pipe *pipe =
> +               container_of(crtc, struct drm_simple_display_pipe, crtc);
> +       struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
> +       struct fb_var_screeninfo fb_var;
> +       int ret;
> +
> +       if (!modeset->fb_info->fbops->fb_check_var)
> +               return true;
> +
> +       drm_fbconv_init_fb_var_screeninfo_from_mode(&fb_var, mode);
> +
> +       ret = drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
> +               &fb_var, &modeset->pipe);
> +       if (ret)
> +               return true;
> +
> +       ret = modeset->fb_info->fbops->fb_check_var(&fb_var, modeset->fb_info);

... hence this fails if the requested mode is valid with the new
fourcc format, but invalid with the old (but preferred) depth.
E.g. due to bandwidth limitations, a high-resolution mode is valid
with a low color depth, while a high color depth is limited to lower
resolutions.

Unfortunately we do not know the new fourcc format here, as both
drm_simple_display_pipe_funcs.mode_{valid,fixup}() are passed
the mode (from drm_mode_set.mode), but not the new format (from
drm_mode_set.fb->format).

Am I missing something? Is the new format available in some other way?
Thanks!

> +       if (ret < 0)
> +               return false;
> +
> +       drm_mode_update_from_fb_var_screeninfo(adjusted_mode, &fb_var);
> +
>         return true;
>  }
>  EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_mode_fixup);

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [PATCH v2 09/15] drm/fbconv: Mode-setting pipeline enable / disable
@ 2022-05-28 20:17     ` Geert Uytterhoeven
  0 siblings, 0 replies; 77+ messages in thread
From: Geert Uytterhoeven @ 2022-05-28 20:17 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: Linux Fbdev development list, Bartlomiej Zolnierkiewicz,
	David Airlie, Greg KH, michel, Jonathan Corbet,
	Mathieu Malaterre, DRI Development, Sean Paul

Hi Thomas,

On Mon, Oct 14, 2019 at 4:05 PM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> The display mode is set by converting the DRM display mode to an
> fb_info state and handling it to the fbdev driver's fb_setvar()
> function. This also requires a color depth, which we take from the
> value of struct drm_mode_config.preferred_depth
>
> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>

> --- a/drivers/gpu/drm/drm_fbconv_helper.c
> +++ b/drivers/gpu/drm/drm_fbconv_helper.c
> @@ -919,6 +919,24 @@ static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
>         return 0;
>  }
>
> +static int drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
> +       struct fb_var_screeninfo *fb_var, struct drm_simple_display_pipe *pipe)
> +{
> +       struct drm_plane *primary = pipe->crtc.primary;
> +       struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
> +
> +       if (primary && primary->state && primary->state->fb)
> +               return drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
> +                       fb_var, primary->state->fb,
> +                       modeset->fb_info->fix.smem_len);
> +
> +       fb_var->xres_virtual = fb_var->xres;
> +       fb_var->yres_virtual = fb_var->yres;
> +       fb_var->bits_per_pixel = modeset->dev->mode_config.preferred_depth;

This looks wrong to me: IMHO bits_per_pixel should be derived from
the fourcc format of the _new_ mode to be set...

> +
> +       return 0;
> +}
> +
>  /**
>   * drm_fbconv_simple_display_pipe_mode_valid - default implementation for
>   *     struct drm_simple_display_pipe_funcs.mode_valid
> @@ -950,6 +968,28 @@ bool drm_fbconv_simple_display_pipe_mode_fixup(
>         struct drm_crtc *crtc, const struct drm_display_mode *mode,
>         struct drm_display_mode *adjusted_mode)
>  {
> +       struct drm_simple_display_pipe *pipe =
> +               container_of(crtc, struct drm_simple_display_pipe, crtc);
> +       struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
> +       struct fb_var_screeninfo fb_var;
> +       int ret;
> +
> +       if (!modeset->fb_info->fbops->fb_check_var)
> +               return true;
> +
> +       drm_fbconv_init_fb_var_screeninfo_from_mode(&fb_var, mode);
> +
> +       ret = drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
> +               &fb_var, &modeset->pipe);
> +       if (ret)
> +               return true;
> +
> +       ret = modeset->fb_info->fbops->fb_check_var(&fb_var, modeset->fb_info);

... hence this fails if the requested mode is valid with the new
fourcc format, but invalid with the old (but preferred) depth.
E.g. due to bandwidth limitations, a high-resolution mode is valid
with a low color depth, while a high color depth is limited to lower
resolutions.

Unfortunately we do not know the new fourcc format here, as both
drm_simple_display_pipe_funcs.mode_{valid,fixup}() are passed
the mode (from drm_mode_set.mode), but not the new format (from
drm_mode_set.fb->format).

Am I missing something? Is the new format available in some other way?
Thanks!

> +       if (ret < 0)
> +               return false;
> +
> +       drm_mode_update_from_fb_var_screeninfo(adjusted_mode, &fb_var);
> +
>         return true;
>  }
>  EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_mode_fixup);

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [PATCH v2 09/15] drm/fbconv: Mode-setting pipeline enable / disable
  2022-05-28 20:17     ` Geert Uytterhoeven
@ 2022-05-30  7:47       ` Thomas Zimmermann
  -1 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2022-05-30  7:47 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: David Airlie, Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Sean Paul, Bartlomiej Zolnierkiewicz, ajax,
	Ville Syrjälä,
	Mathieu Malaterre, michel, Jonathan Corbet, Greg KH,
	DRI Development, Linux Fbdev development list


[-- Attachment #1.1: Type: text/plain, Size: 4683 bytes --]

Hi Geert,

first of all, thanks for looking at the patch.

Am 28.05.22 um 22:17 schrieb Geert Uytterhoeven:
> Hi Thomas,
> 
> On Mon, Oct 14, 2019 at 4:05 PM Thomas Zimmermann <tzimmermann@suse.de> wrote:
>> The display mode is set by converting the DRM display mode to an
>> fb_info state and handling it to the fbdev driver's fb_setvar()
>> function. This also requires a color depth, which we take from the
>> value of struct drm_mode_config.preferred_depth
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> 
>> --- a/drivers/gpu/drm/drm_fbconv_helper.c
>> +++ b/drivers/gpu/drm/drm_fbconv_helper.c
>> @@ -919,6 +919,24 @@ static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
>>          return 0;
>>   }
>>
>> +static int drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
>> +       struct fb_var_screeninfo *fb_var, struct drm_simple_display_pipe *pipe)
>> +{
>> +       struct drm_plane *primary = pipe->crtc.primary;
>> +       struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
>> +
>> +       if (primary && primary->state && primary->state->fb)
>> +               return drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
>> +                       fb_var, primary->state->fb,
>> +                       modeset->fb_info->fix.smem_len);
>> +
>> +       fb_var->xres_virtual = fb_var->xres;
>> +       fb_var->yres_virtual = fb_var->yres;
>> +       fb_var->bits_per_pixel = modeset->dev->mode_config.preferred_depth;
> 
> This looks wrong to me: IMHO bits_per_pixel should be derived from
> the fourcc format of the _new_ mode to be set...

Indeed, this appears to be wrong.

> 
>> +
>> +       return 0;
>> +}
>> +
>>   /**
>>    * drm_fbconv_simple_display_pipe_mode_valid - default implementation for
>>    *     struct drm_simple_display_pipe_funcs.mode_valid
>> @@ -950,6 +968,28 @@ bool drm_fbconv_simple_display_pipe_mode_fixup(
>>          struct drm_crtc *crtc, const struct drm_display_mode *mode,
>>          struct drm_display_mode *adjusted_mode)
>>   {
>> +       struct drm_simple_display_pipe *pipe =
>> +               container_of(crtc, struct drm_simple_display_pipe, crtc);
>> +       struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
>> +       struct fb_var_screeninfo fb_var;
>> +       int ret;
>> +
>> +       if (!modeset->fb_info->fbops->fb_check_var)
>> +               return true;
>> +
>> +       drm_fbconv_init_fb_var_screeninfo_from_mode(&fb_var, mode);
>> +
>> +       ret = drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
>> +               &fb_var, &modeset->pipe);
>> +       if (ret)
>> +               return true;
>> +
>> +       ret = modeset->fb_info->fbops->fb_check_var(&fb_var, modeset->fb_info);
> 
> ... hence this fails if the requested mode is valid with the new
> fourcc format, but invalid with the old (but preferred) depth.
> E.g. due to bandwidth limitations, a high-resolution mode is valid
> with a low color depth, while a high color depth is limited to lower
> resolutions.

I tested the helpers with various fbdev drivers and modified them until 
all of these drivers produced at least some output. I'm not surprised 
that there are still bugs.

> 
> Unfortunately we do not know the new fourcc format here, as both
> drm_simple_display_pipe_funcs.mode_{valid,fixup}() are passed
> the mode (from drm_mode_set.mode), but not the new format (from
> drm_mode_set.fb->format).
> 
> Am I missing something? Is the new format available in some other way?

We can always get the format from the new plane state of 
modeset->pipe->plane. We'd have this in the atomic_check call. And it 
appears that drm_fbconv_simple_display_pipe_check() is a better place 
for this code anyway.

Best regards
Thomas

> Thanks!
> 
>> +       if (ret < 0)
>> +               return false;
>> +
>> +       drm_mode_update_from_fb_var_screeninfo(adjusted_mode, &fb_var);
>> +
>>          return true;
>>   }
>>   EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_mode_fixup);
> 
> Gr{oetje,eeting}s,
> 
>                          Geert
> 
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
> 
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
>                                  -- Linus Torvalds

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

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

* Re: [PATCH v2 09/15] drm/fbconv: Mode-setting pipeline enable / disable
@ 2022-05-30  7:47       ` Thomas Zimmermann
  0 siblings, 0 replies; 77+ messages in thread
From: Thomas Zimmermann @ 2022-05-30  7:47 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Linux Fbdev development list, Bartlomiej Zolnierkiewicz,
	David Airlie, Greg KH, michel, Jonathan Corbet,
	Mathieu Malaterre, DRI Development, Sean Paul


[-- Attachment #1.1: Type: text/plain, Size: 4683 bytes --]

Hi Geert,

first of all, thanks for looking at the patch.

Am 28.05.22 um 22:17 schrieb Geert Uytterhoeven:
> Hi Thomas,
> 
> On Mon, Oct 14, 2019 at 4:05 PM Thomas Zimmermann <tzimmermann@suse.de> wrote:
>> The display mode is set by converting the DRM display mode to an
>> fb_info state and handling it to the fbdev driver's fb_setvar()
>> function. This also requires a color depth, which we take from the
>> value of struct drm_mode_config.preferred_depth
>>
>> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> 
>> --- a/drivers/gpu/drm/drm_fbconv_helper.c
>> +++ b/drivers/gpu/drm/drm_fbconv_helper.c
>> @@ -919,6 +919,24 @@ static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
>>          return 0;
>>   }
>>
>> +static int drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
>> +       struct fb_var_screeninfo *fb_var, struct drm_simple_display_pipe *pipe)
>> +{
>> +       struct drm_plane *primary = pipe->crtc.primary;
>> +       struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
>> +
>> +       if (primary && primary->state && primary->state->fb)
>> +               return drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
>> +                       fb_var, primary->state->fb,
>> +                       modeset->fb_info->fix.smem_len);
>> +
>> +       fb_var->xres_virtual = fb_var->xres;
>> +       fb_var->yres_virtual = fb_var->yres;
>> +       fb_var->bits_per_pixel = modeset->dev->mode_config.preferred_depth;
> 
> This looks wrong to me: IMHO bits_per_pixel should be derived from
> the fourcc format of the _new_ mode to be set...

Indeed, this appears to be wrong.

> 
>> +
>> +       return 0;
>> +}
>> +
>>   /**
>>    * drm_fbconv_simple_display_pipe_mode_valid - default implementation for
>>    *     struct drm_simple_display_pipe_funcs.mode_valid
>> @@ -950,6 +968,28 @@ bool drm_fbconv_simple_display_pipe_mode_fixup(
>>          struct drm_crtc *crtc, const struct drm_display_mode *mode,
>>          struct drm_display_mode *adjusted_mode)
>>   {
>> +       struct drm_simple_display_pipe *pipe =
>> +               container_of(crtc, struct drm_simple_display_pipe, crtc);
>> +       struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
>> +       struct fb_var_screeninfo fb_var;
>> +       int ret;
>> +
>> +       if (!modeset->fb_info->fbops->fb_check_var)
>> +               return true;
>> +
>> +       drm_fbconv_init_fb_var_screeninfo_from_mode(&fb_var, mode);
>> +
>> +       ret = drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
>> +               &fb_var, &modeset->pipe);
>> +       if (ret)
>> +               return true;
>> +
>> +       ret = modeset->fb_info->fbops->fb_check_var(&fb_var, modeset->fb_info);
> 
> ... hence this fails if the requested mode is valid with the new
> fourcc format, but invalid with the old (but preferred) depth.
> E.g. due to bandwidth limitations, a high-resolution mode is valid
> with a low color depth, while a high color depth is limited to lower
> resolutions.

I tested the helpers with various fbdev drivers and modified them until 
all of these drivers produced at least some output. I'm not surprised 
that there are still bugs.

> 
> Unfortunately we do not know the new fourcc format here, as both
> drm_simple_display_pipe_funcs.mode_{valid,fixup}() are passed
> the mode (from drm_mode_set.mode), but not the new format (from
> drm_mode_set.fb->format).
> 
> Am I missing something? Is the new format available in some other way?

We can always get the format from the new plane state of 
modeset->pipe->plane. We'd have this in the atomic_check call. And it 
appears that drm_fbconv_simple_display_pipe_check() is a better place 
for this code anyway.

Best regards
Thomas

> Thanks!
> 
>> +       if (ret < 0)
>> +               return false;
>> +
>> +       drm_mode_update_from_fb_var_screeninfo(adjusted_mode, &fb_var);
>> +
>>          return true;
>>   }
>>   EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_mode_fixup);
> 
> Gr{oetje,eeting}s,
> 
>                          Geert
> 
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
> 
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
>                                  -- Linus Torvalds

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 840 bytes --]

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

* Re: [PATCH v2 09/15] drm/fbconv: Mode-setting pipeline enable / disable
  2022-05-30  7:47       ` Thomas Zimmermann
@ 2022-05-30  8:34         ` Geert Uytterhoeven
  -1 siblings, 0 replies; 77+ messages in thread
From: Geert Uytterhoeven @ 2022-05-30  8:34 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: Linux Fbdev development list, Bartlomiej Zolnierkiewicz,
	David Airlie, Greg KH, michel, Jonathan Corbet,
	Mathieu Malaterre, DRI Development, Sean Paul

Hi Thomas,

On Mon, May 30, 2022 at 9:47 AM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> first of all, thanks for looking at the patch.

Thank you, your patch series helped a lot.

> Am 28.05.22 um 22:17 schrieb Geert Uytterhoeven:
> > On Mon, Oct 14, 2019 at 4:05 PM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> >> The display mode is set by converting the DRM display mode to an
> >> fb_info state and handling it to the fbdev driver's fb_setvar()
> >> function. This also requires a color depth, which we take from the
> >> value of struct drm_mode_config.preferred_depth
> >>
> >> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> >
> >> --- a/drivers/gpu/drm/drm_fbconv_helper.c
> >> +++ b/drivers/gpu/drm/drm_fbconv_helper.c
> >> @@ -919,6 +919,24 @@ static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
> >>          return 0;
> >>   }
> >>
> >> +static int drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
> >> +       struct fb_var_screeninfo *fb_var, struct drm_simple_display_pipe *pipe)
> >> +{
> >> +       struct drm_plane *primary = pipe->crtc.primary;
> >> +       struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
> >> +
> >> +       if (primary && primary->state && primary->state->fb)
> >> +               return drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
> >> +                       fb_var, primary->state->fb,
> >> +                       modeset->fb_info->fix.smem_len);
> >> +
> >> +       fb_var->xres_virtual = fb_var->xres;
> >> +       fb_var->yres_virtual = fb_var->yres;
> >> +       fb_var->bits_per_pixel = modeset->dev->mode_config.preferred_depth;
> >
> > This looks wrong to me: IMHO bits_per_pixel should be derived from
> > the fourcc format of the _new_ mode to be set...
>
> Indeed, this appears to be wrong.

OK.

>
> >
> >> +
> >> +       return 0;
> >> +}
> >> +
> >>   /**
> >>    * drm_fbconv_simple_display_pipe_mode_valid - default implementation for
> >>    *     struct drm_simple_display_pipe_funcs.mode_valid
> >> @@ -950,6 +968,28 @@ bool drm_fbconv_simple_display_pipe_mode_fixup(
> >>          struct drm_crtc *crtc, const struct drm_display_mode *mode,
> >>          struct drm_display_mode *adjusted_mode)
> >>   {
> >> +       struct drm_simple_display_pipe *pipe =
> >> +               container_of(crtc, struct drm_simple_display_pipe, crtc);
> >> +       struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
> >> +       struct fb_var_screeninfo fb_var;
> >> +       int ret;
> >> +
> >> +       if (!modeset->fb_info->fbops->fb_check_var)
> >> +               return true;
> >> +
> >> +       drm_fbconv_init_fb_var_screeninfo_from_mode(&fb_var, mode);
> >> +
> >> +       ret = drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
> >> +               &fb_var, &modeset->pipe);
> >> +       if (ret)
> >> +               return true;
> >> +
> >> +       ret = modeset->fb_info->fbops->fb_check_var(&fb_var, modeset->fb_info);
> >
> > ... hence this fails if the requested mode is valid with the new
> > fourcc format, but invalid with the old (but preferred) depth.
> > E.g. due to bandwidth limitations, a high-resolution mode is valid
> > with a low color depth, while a high color depth is limited to lower
> > resolutions.
>
> I tested the helpers with various fbdev drivers and modified them until
> all of these drivers produced at least some output. I'm not surprised
> that there are still bugs.

As usual, the devil is in the details ;-)

The other issue I was facing are the non-rounding KHZ2PICOS() and
PICOS2KHZ() macros, and the numerous back-and-forth conversions:
a valid pixclock in kHz is converted to a valid pixclock in ps,
and accepted.  The returned pixclock in ps is slightly different,
and converted to an invalid pixclock in kHz, hence rejected in the
next iteration (remember: fb_ops.fb_check_var() should only round up
values to match, never round down)...

> > Unfortunately we do not know the new fourcc format here, as both
> > drm_simple_display_pipe_funcs.mode_{valid,fixup}() are passed
> > the mode (from drm_mode_set.mode), but not the new format (from
> > drm_mode_set.fb->format).
> >
> > Am I missing something? Is the new format available in some other way?
>
> We can always get the format from the new plane state of
> modeset->pipe->plane. We'd have this in the atomic_check call. And it
> appears that drm_fbconv_simple_display_pipe_check() is a better place
> for this code anyway.

Thanks, I'll give that a try!

Anyway, I finally made some progress with KMS-style mode-setting inside
my ataridrm driver. Before, I relied solely on initial fbdev-style
mode-setting in the probe function.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [PATCH v2 09/15] drm/fbconv: Mode-setting pipeline enable / disable
@ 2022-05-30  8:34         ` Geert Uytterhoeven
  0 siblings, 0 replies; 77+ messages in thread
From: Geert Uytterhoeven @ 2022-05-30  8:34 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: David Airlie, Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Sean Paul, Bartlomiej Zolnierkiewicz, ajax,
	Ville Syrjälä,
	Mathieu Malaterre, michel, Jonathan Corbet, Greg KH,
	DRI Development, Linux Fbdev development list

Hi Thomas,

On Mon, May 30, 2022 at 9:47 AM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> first of all, thanks for looking at the patch.

Thank you, your patch series helped a lot.

> Am 28.05.22 um 22:17 schrieb Geert Uytterhoeven:
> > On Mon, Oct 14, 2019 at 4:05 PM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> >> The display mode is set by converting the DRM display mode to an
> >> fb_info state and handling it to the fbdev driver's fb_setvar()
> >> function. This also requires a color depth, which we take from the
> >> value of struct drm_mode_config.preferred_depth
> >>
> >> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> >
> >> --- a/drivers/gpu/drm/drm_fbconv_helper.c
> >> +++ b/drivers/gpu/drm/drm_fbconv_helper.c
> >> @@ -919,6 +919,24 @@ static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
> >>          return 0;
> >>   }
> >>
> >> +static int drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
> >> +       struct fb_var_screeninfo *fb_var, struct drm_simple_display_pipe *pipe)
> >> +{
> >> +       struct drm_plane *primary = pipe->crtc.primary;
> >> +       struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
> >> +
> >> +       if (primary && primary->state && primary->state->fb)
> >> +               return drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
> >> +                       fb_var, primary->state->fb,
> >> +                       modeset->fb_info->fix.smem_len);
> >> +
> >> +       fb_var->xres_virtual = fb_var->xres;
> >> +       fb_var->yres_virtual = fb_var->yres;
> >> +       fb_var->bits_per_pixel = modeset->dev->mode_config.preferred_depth;
> >
> > This looks wrong to me: IMHO bits_per_pixel should be derived from
> > the fourcc format of the _new_ mode to be set...
>
> Indeed, this appears to be wrong.

OK.

>
> >
> >> +
> >> +       return 0;
> >> +}
> >> +
> >>   /**
> >>    * drm_fbconv_simple_display_pipe_mode_valid - default implementation for
> >>    *     struct drm_simple_display_pipe_funcs.mode_valid
> >> @@ -950,6 +968,28 @@ bool drm_fbconv_simple_display_pipe_mode_fixup(
> >>          struct drm_crtc *crtc, const struct drm_display_mode *mode,
> >>          struct drm_display_mode *adjusted_mode)
> >>   {
> >> +       struct drm_simple_display_pipe *pipe =
> >> +               container_of(crtc, struct drm_simple_display_pipe, crtc);
> >> +       struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
> >> +       struct fb_var_screeninfo fb_var;
> >> +       int ret;
> >> +
> >> +       if (!modeset->fb_info->fbops->fb_check_var)
> >> +               return true;
> >> +
> >> +       drm_fbconv_init_fb_var_screeninfo_from_mode(&fb_var, mode);
> >> +
> >> +       ret = drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
> >> +               &fb_var, &modeset->pipe);
> >> +       if (ret)
> >> +               return true;
> >> +
> >> +       ret = modeset->fb_info->fbops->fb_check_var(&fb_var, modeset->fb_info);
> >
> > ... hence this fails if the requested mode is valid with the new
> > fourcc format, but invalid with the old (but preferred) depth.
> > E.g. due to bandwidth limitations, a high-resolution mode is valid
> > with a low color depth, while a high color depth is limited to lower
> > resolutions.
>
> I tested the helpers with various fbdev drivers and modified them until
> all of these drivers produced at least some output. I'm not surprised
> that there are still bugs.

As usual, the devil is in the details ;-)

The other issue I was facing are the non-rounding KHZ2PICOS() and
PICOS2KHZ() macros, and the numerous back-and-forth conversions:
a valid pixclock in kHz is converted to a valid pixclock in ps,
and accepted.  The returned pixclock in ps is slightly different,
and converted to an invalid pixclock in kHz, hence rejected in the
next iteration (remember: fb_ops.fb_check_var() should only round up
values to match, never round down)...

> > Unfortunately we do not know the new fourcc format here, as both
> > drm_simple_display_pipe_funcs.mode_{valid,fixup}() are passed
> > the mode (from drm_mode_set.mode), but not the new format (from
> > drm_mode_set.fb->format).
> >
> > Am I missing something? Is the new format available in some other way?
>
> We can always get the format from the new plane state of
> modeset->pipe->plane. We'd have this in the atomic_check call. And it
> appears that drm_fbconv_simple_display_pipe_check() is a better place
> for this code anyway.

Thanks, I'll give that a try!

Anyway, I finally made some progress with KMS-style mode-setting inside
my ataridrm driver. Before, I relied solely on initial fbdev-style
mode-setting in the probe function.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [PATCH v2 09/15] drm/fbconv: Mode-setting pipeline enable / disable
  2022-05-30  8:34         ` Geert Uytterhoeven
@ 2022-07-01 20:01           ` Geert Uytterhoeven
  -1 siblings, 0 replies; 77+ messages in thread
From: Geert Uytterhoeven @ 2022-07-01 20:01 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: David Airlie, Daniel Vetter, Maarten Lankhorst, Maxime Ripard,
	Sean Paul, ajax, Ville Syrjälä,
	Mathieu Malaterre, michel, Jonathan Corbet, Greg KH,
	DRI Development, Linux Fbdev development list

Hi Thomas,

On Mon, May 30, 2022 at 10:34 AM Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
> On Mon, May 30, 2022 at 9:47 AM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> > Am 28.05.22 um 22:17 schrieb Geert Uytterhoeven:
> > > On Mon, Oct 14, 2019 at 4:05 PM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> > >> The display mode is set by converting the DRM display mode to an
> > >> fb_info state and handling it to the fbdev driver's fb_setvar()
> > >> function. This also requires a color depth, which we take from the
> > >> value of struct drm_mode_config.preferred_depth
> > >>
> > >> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> > >
> > >> --- a/drivers/gpu/drm/drm_fbconv_helper.c
> > >> +++ b/drivers/gpu/drm/drm_fbconv_helper.c
> > >> @@ -919,6 +919,24 @@ static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
> > >>          return 0;
> > >>   }
> > >>
> > >> +static int drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
> > >> +       struct fb_var_screeninfo *fb_var, struct drm_simple_display_pipe *pipe)
> > >> +{
> > >> +       struct drm_plane *primary = pipe->crtc.primary;
> > >> +       struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
> > >> +
> > >> +       if (primary && primary->state && primary->state->fb)
> > >> +               return drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
> > >> +                       fb_var, primary->state->fb,
> > >> +                       modeset->fb_info->fix.smem_len);
> > >> +
> > >> +       fb_var->xres_virtual = fb_var->xres;
> > >> +       fb_var->yres_virtual = fb_var->yres;
> > >> +       fb_var->bits_per_pixel = modeset->dev->mode_config.preferred_depth;
> > >
> > > This looks wrong to me: IMHO bits_per_pixel should be derived from
> > > the fourcc format of the _new_ mode to be set...
> >
> > Indeed, this appears to be wrong.
>
> OK.
>
> >
> > >
> > >> +
> > >> +       return 0;
> > >> +}
> > >> +
> > >>   /**
> > >>    * drm_fbconv_simple_display_pipe_mode_valid - default implementation for
> > >>    *     struct drm_simple_display_pipe_funcs.mode_valid
> > >> @@ -950,6 +968,28 @@ bool drm_fbconv_simple_display_pipe_mode_fixup(
> > >>          struct drm_crtc *crtc, const struct drm_display_mode *mode,
> > >>          struct drm_display_mode *adjusted_mode)
> > >>   {
> > >> +       struct drm_simple_display_pipe *pipe =
> > >> +               container_of(crtc, struct drm_simple_display_pipe, crtc);
> > >> +       struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
> > >> +       struct fb_var_screeninfo fb_var;
> > >> +       int ret;
> > >> +
> > >> +       if (!modeset->fb_info->fbops->fb_check_var)
> > >> +               return true;
> > >> +
> > >> +       drm_fbconv_init_fb_var_screeninfo_from_mode(&fb_var, mode);
> > >> +
> > >> +       ret = drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
> > >> +               &fb_var, &modeset->pipe);
> > >> +       if (ret)
> > >> +               return true;
> > >> +
> > >> +       ret = modeset->fb_info->fbops->fb_check_var(&fb_var, modeset->fb_info);
> > >
> > > ... hence this fails if the requested mode is valid with the new
> > > fourcc format, but invalid with the old (but preferred) depth.
> > > E.g. due to bandwidth limitations, a high-resolution mode is valid
> > > with a low color depth, while a high color depth is limited to lower
> > > resolutions.

> > > Unfortunately we do not know the new fourcc format here, as both
> > > drm_simple_display_pipe_funcs.mode_{valid,fixup}() are passed
> > > the mode (from drm_mode_set.mode), but not the new format (from
> > > drm_mode_set.fb->format).
> > >
> > > Am I missing something? Is the new format available in some other way?
> >
> > We can always get the format from the new plane state of
> > modeset->pipe->plane. We'd have this in the atomic_check call. And it
> > appears that drm_fbconv_simple_display_pipe_check() is a better place
> > for this code anyway.
>
> Thanks, I'll give that a try!

Getting the format from the new plane state of pipe->plane doesn't
work, as pipe->plane.state->fb = NULL.
But it is indeed available in the drm_simple_display_pipe_funcs.check()
callback, so that seems to work...

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [PATCH v2 09/15] drm/fbconv: Mode-setting pipeline enable / disable
@ 2022-07-01 20:01           ` Geert Uytterhoeven
  0 siblings, 0 replies; 77+ messages in thread
From: Geert Uytterhoeven @ 2022-07-01 20:01 UTC (permalink / raw)
  To: Thomas Zimmermann
  Cc: Linux Fbdev development list, Jonathan Corbet, David Airlie,
	Greg KH, michel, Mathieu Malaterre, DRI Development, Sean Paul

Hi Thomas,

On Mon, May 30, 2022 at 10:34 AM Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
> On Mon, May 30, 2022 at 9:47 AM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> > Am 28.05.22 um 22:17 schrieb Geert Uytterhoeven:
> > > On Mon, Oct 14, 2019 at 4:05 PM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> > >> The display mode is set by converting the DRM display mode to an
> > >> fb_info state and handling it to the fbdev driver's fb_setvar()
> > >> function. This also requires a color depth, which we take from the
> > >> value of struct drm_mode_config.preferred_depth
> > >>
> > >> Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
> > >
> > >> --- a/drivers/gpu/drm/drm_fbconv_helper.c
> > >> +++ b/drivers/gpu/drm/drm_fbconv_helper.c
> > >> @@ -919,6 +919,24 @@ static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
> > >>          return 0;
> > >>   }
> > >>
> > >> +static int drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
> > >> +       struct fb_var_screeninfo *fb_var, struct drm_simple_display_pipe *pipe)
> > >> +{
> > >> +       struct drm_plane *primary = pipe->crtc.primary;
> > >> +       struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
> > >> +
> > >> +       if (primary && primary->state && primary->state->fb)
> > >> +               return drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
> > >> +                       fb_var, primary->state->fb,
> > >> +                       modeset->fb_info->fix.smem_len);
> > >> +
> > >> +       fb_var->xres_virtual = fb_var->xres;
> > >> +       fb_var->yres_virtual = fb_var->yres;
> > >> +       fb_var->bits_per_pixel = modeset->dev->mode_config.preferred_depth;
> > >
> > > This looks wrong to me: IMHO bits_per_pixel should be derived from
> > > the fourcc format of the _new_ mode to be set...
> >
> > Indeed, this appears to be wrong.
>
> OK.
>
> >
> > >
> > >> +
> > >> +       return 0;
> > >> +}
> > >> +
> > >>   /**
> > >>    * drm_fbconv_simple_display_pipe_mode_valid - default implementation for
> > >>    *     struct drm_simple_display_pipe_funcs.mode_valid
> > >> @@ -950,6 +968,28 @@ bool drm_fbconv_simple_display_pipe_mode_fixup(
> > >>          struct drm_crtc *crtc, const struct drm_display_mode *mode,
> > >>          struct drm_display_mode *adjusted_mode)
> > >>   {
> > >> +       struct drm_simple_display_pipe *pipe =
> > >> +               container_of(crtc, struct drm_simple_display_pipe, crtc);
> > >> +       struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
> > >> +       struct fb_var_screeninfo fb_var;
> > >> +       int ret;
> > >> +
> > >> +       if (!modeset->fb_info->fbops->fb_check_var)
> > >> +               return true;
> > >> +
> > >> +       drm_fbconv_init_fb_var_screeninfo_from_mode(&fb_var, mode);
> > >> +
> > >> +       ret = drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
> > >> +               &fb_var, &modeset->pipe);
> > >> +       if (ret)
> > >> +               return true;
> > >> +
> > >> +       ret = modeset->fb_info->fbops->fb_check_var(&fb_var, modeset->fb_info);
> > >
> > > ... hence this fails if the requested mode is valid with the new
> > > fourcc format, but invalid with the old (but preferred) depth.
> > > E.g. due to bandwidth limitations, a high-resolution mode is valid
> > > with a low color depth, while a high color depth is limited to lower
> > > resolutions.

> > > Unfortunately we do not know the new fourcc format here, as both
> > > drm_simple_display_pipe_funcs.mode_{valid,fixup}() are passed
> > > the mode (from drm_mode_set.mode), but not the new format (from
> > > drm_mode_set.fb->format).
> > >
> > > Am I missing something? Is the new format available in some other way?
> >
> > We can always get the format from the new plane state of
> > modeset->pipe->plane. We'd have this in the atomic_check call. And it
> > appears that drm_fbconv_simple_display_pipe_check() is a better place
> > for this code anyway.
>
> Thanks, I'll give that a try!

Getting the format from the new plane state of pipe->plane doesn't
work, as pipe->plane.state->fb = NULL.
But it is indeed available in the drm_simple_display_pipe_funcs.check()
callback, so that seems to work...

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

end of thread, other threads:[~2022-07-01 20:02 UTC | newest]

Thread overview: 77+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-14 14:04 [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers Thomas Zimmermann
2019-10-14 14:04 ` Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 01/15] fbdev: Export fb_check_foreignness() Thomas Zimmermann
2019-10-14 14:04   ` Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 02/15] fbdev: Export FBPIXMAPSIZE Thomas Zimmermann
2019-10-14 14:04   ` Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 03/15] drm/simple-kms-helper: Add mode_fixup() to simple display pipe Thomas Zimmermann
2019-10-14 14:04   ` Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 04/15] drm: Add fbconv helper module Thomas Zimmermann
2019-10-14 14:04   ` Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 05/15] drm/fbconv: Add DRM <-> fbdev pixel-format conversion Thomas Zimmermann
2019-10-14 14:04   ` Thomas Zimmermann
2019-10-14 20:30   ` Sam Ravnborg
2019-10-14 20:30     ` Sam Ravnborg
2019-10-15  5:48     ` Thomas Zimmermann
2019-10-15  5:48       ` Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 06/15] drm/fbconv: Add mode conversion DRM <-> fbdev Thomas Zimmermann
2019-10-14 14:04   ` Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 07/15] drm/fbconv: Add modesetting infrastructure Thomas Zimmermann
2019-10-14 14:04   ` Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 08/15] drm/fbconv: Add plane-state check and update Thomas Zimmermann
2019-10-14 14:04   ` Thomas Zimmermann
2019-10-15  8:30   ` kbuild test robot
2019-10-15  8:30     ` kbuild test robot
2019-10-15  8:30     ` kbuild test robot
2019-10-15 17:28   ` kbuild test robot
2019-10-15 17:28     ` kbuild test robot
2019-10-15 17:28     ` kbuild test robot
2019-10-14 14:04 ` [PATCH v2 09/15] drm/fbconv: Mode-setting pipeline enable / disable Thomas Zimmermann
2019-10-14 14:04   ` Thomas Zimmermann
2022-05-28 20:17   ` Geert Uytterhoeven
2022-05-28 20:17     ` Geert Uytterhoeven
2022-05-30  7:47     ` Thomas Zimmermann
2022-05-30  7:47       ` Thomas Zimmermann
2022-05-30  8:34       ` Geert Uytterhoeven
2022-05-30  8:34         ` Geert Uytterhoeven
2022-07-01 20:01         ` Geert Uytterhoeven
2022-07-01 20:01           ` Geert Uytterhoeven
2019-10-14 14:04 ` [PATCH v2 10/15] drm/fbconv: Reimplement several fbdev interfaces Thomas Zimmermann
2019-10-14 14:04   ` Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 11/15] drm/fbconv: Add helpers for init and cleanup of fb_info structures Thomas Zimmermann
2019-10-14 14:04   ` Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 12/15] drm/fbconv: Add helper documentation Thomas Zimmermann
2019-10-14 14:04   ` Thomas Zimmermann
2019-10-15  8:40   ` kbuild test robot
2019-10-15  8:40     ` kbuild test robot
2019-10-15  8:40     ` kbuild test robot
2019-10-14 14:04 ` [PATCH v2 13/15] staging: Add mgakms driver Thomas Zimmermann
2019-10-14 14:04   ` Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 14/15] staging/mgakms: Import matroxfb driver source code Thomas Zimmermann
2019-10-15 11:48   ` Ville Syrjälä
2019-10-15 11:48     ` Ville Syrjälä
2019-10-15 12:46     ` Thomas Zimmermann
2019-10-15 12:46       ` Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 15/15] staging/mgakms: Update matroxfb driver code for DRM Thomas Zimmermann
2019-10-14 14:04   ` Thomas Zimmermann
2019-10-17 16:04   ` kbuild test robot
2019-10-17 16:04     ` kbuild test robot
2019-10-17 16:19   ` kbuild test robot
2019-10-17 16:19     ` kbuild test robot
2019-10-17 16:19     ` kbuild test robot
2019-10-14 20:36 ` [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers Sam Ravnborg
2019-10-14 20:36   ` Sam Ravnborg
2019-10-15  6:11   ` Thomas Zimmermann
2019-10-15  6:11     ` Thomas Zimmermann
2019-10-15 14:33 ` Daniel Vetter
2019-10-15 14:33   ` Daniel Vetter
2019-10-15 17:28   ` Thomas Zimmermann
2019-10-15 17:28     ` Thomas Zimmermann
2019-10-15 17:48     ` Daniel Vetter
2019-10-15 17:48       ` Daniel Vetter
2019-10-15 18:05       ` Greg KH
2019-10-15 18:05         ` Greg KH
2019-10-15 18:13       ` Ville Syrjälä
2019-10-15 18:13         ` Ville Syrjälä
2019-10-15 18:28         ` Ville Syrjälä
2019-10-15 18:28           ` Ville Syrjälä

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