drm/glint: initial CRTC work

Signed-off-by: Matt Turner <mattst88@gmail.com>
diff --git a/drivers/gpu/drm/glint/Makefile b/drivers/gpu/drm/glint/Makefile
index 867349d..c6bc2bd 100644
--- a/drivers/gpu/drm/glint/Makefile
+++ b/drivers/gpu/drm/glint/Makefile
@@ -3,6 +3,7 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 ccflags-y := -Iinclude/drm
-glint-y   := glint_display.o glint_device.o glint_drv.o glint_irq.o glint_kms.o
+glint-y   := glint_crtc.o glint_display.o glint_device.o glint_drv.o \
+	glint_irq.o glint_kms.o
 
 obj-$(CONFIG_DRM_GLINT) += glint.o
diff --git a/drivers/gpu/drm/glint/glint.h b/drivers/gpu/drm/glint/glint.h
index 51c8f2c..e4fda71 100644
--- a/drivers/gpu/drm/glint/glint.h
+++ b/drivers/gpu/drm/glint/glint.h
@@ -2,6 +2,7 @@
 #define __GLINT_H__
 
 #include "glint_family.h"
+#include "glint_mode.h"
 
 struct glint_mc {
 	resource_size_t			aper_size;
@@ -21,6 +22,9 @@
 	void				*rmmio;
 
 	struct glint_mc			mc;
+	struct glint_mode_info		mode_info;
+
+	int				num_crtc;
 };
 
 #endif				/* __GLINT_H__ */
diff --git a/drivers/gpu/drm/glint/glint_crtc.c b/drivers/gpu/drm/glint/glint_crtc.c
new file mode 100644
index 0000000..126a0e8
--- /dev/null
+++ b/drivers/gpu/drm/glint/glint_crtc.c
@@ -0,0 +1,88 @@
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc_helper.h"
+
+#include <video/pm3fb.h>
+
+#include "glint.h"
+#include "glint_drv.h"
+#include "glint_mode.h"
+
+static void glint_crtc_load_lut(struct drm_crtc *crtc)
+{
+	struct glint_crtc *glint_crtc = to_glint_crtc(crtc);
+	struct drm_device *dev = crtc->dev;
+	struct glint_device *gdev = dev->dev_private;
+	int i;
+
+	if (!crtc->enabled)
+		return;
+
+	for (i = 0; i < 256; i++) {
+		WREG8(PM3RD_PaletteWriteAddress, i);
+		WREG8(PM3RD_PaletteData, glint_crtc->lut_r[i]);
+		WREG8(PM3RD_PaletteData, glint_crtc->lut_b[i]);
+		WREG8(PM3RD_PaletteData, glint_crtc->lut_g[i]);
+	}
+}
+
+static void glint_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
+				  u16 *blue, uint32_t size)
+{
+	struct glint_crtc *glint_crtc = to_glint_crtc(crtc);
+	int i;
+
+	if (size != 256) {
+		return;
+	}
+
+	for (i = 0; i < 256; i++) {
+		glint_crtc->lut_r[i] = red[i];
+		glint_crtc->lut_g[i] = green[i];
+		glint_crtc->lut_b[i] = blue[i];
+	}
+	glint_crtc_load_lut(crtc);
+}
+
+static void glint_crtc_destroy(struct drm_crtc *crtc)
+{
+	struct glint_crtc *glint_crtc = to_glint_crtc(crtc);
+
+	drm_crtc_cleanup(crtc);
+	kfree(glint_crtc);
+}
+
+static const struct drm_crtc_funcs glint_crtc_funcs = {
+	/*
+	.cursor_set = glint_crtc_cursor_set,
+	.cursor_move = glint_crtc_cursor_move,
+	*/
+	.cursor_set = NULL,
+	.cursor_move = NULL,
+	.gamma_set = glint_crtc_gamma_set,
+	.set_config = drm_crtc_helper_set_config,
+	.destroy = glint_crtc_destroy,
+};
+
+void glint_crtc_init(struct drm_device *dev, int index)
+{
+	struct glint_device *gdev = dev->dev_private;
+	struct glint_crtc *glint_crtc;
+	int i;
+
+	glint_crtc = kzalloc(sizeof(struct glint_crtc) + (GLINTFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL);
+	if (glint_crtc == NULL)
+		return;
+
+	drm_crtc_init(dev, &glint_crtc->base, &glint_crtc_funcs);
+
+	drm_mode_crtc_set_gamma_size(&glint_crtc->base, 256);
+	glint_crtc->crtc_id = index;
+	gdev->mode_info.crtcs[index] = glint_crtc;
+
+	for (i = 0; i < 256; i++) {
+		glint_crtc->lut_r[i] = i;
+		glint_crtc->lut_g[i] = i;
+		glint_crtc->lut_b[i] = i;
+	}
+}
diff --git a/drivers/gpu/drm/glint/glint_device.c b/drivers/gpu/drm/glint/glint_device.c
index 2cf207a..125df20 100644
--- a/drivers/gpu/drm/glint/glint_device.c
+++ b/drivers/gpu/drm/glint/glint_device.c
@@ -83,6 +83,7 @@
 	gdev->ddev = ddev;
 	gdev->pdev = pdev;
 	gdev->flags = flags;
+	gdev->num_crtc = 2;
 
 	/* Registers mapping */
 	/* TODO: block userspace mapping of io register */
diff --git a/drivers/gpu/drm/glint/glint_display.c b/drivers/gpu/drm/glint/glint_display.c
index 174e269..a8061ea 100644
--- a/drivers/gpu/drm/glint/glint_display.c
+++ b/drivers/gpu/drm/glint/glint_display.c
@@ -1,13 +1,34 @@
 #include "drmP.h"
 #include "drm.h"
+#include "drm_crtc_helper.h"
 
 #include "glint.h"
+#include "glint_drv.h"
 
 int glint_modeset_init(struct glint_device *gdev)
 {
+	int i;
+
+	drm_mode_config_init(gdev->ddev);
+	gdev->mode_info.mode_config_initialized = true;
+
+	gdev->ddev->mode_config.max_width = GLINT_MAX_FB_WIDTH;
+	gdev->ddev->mode_config.max_height = GLINT_MAX_FB_HEIGHT;
+
+	gdev->ddev->mode_config.fb_base = gdev->mc.aper_base;
+
+	/* allocate crtcs */
+	for (i = 0; i < gdev->num_crtc; i++) {
+		glint_crtc_init(gdev->ddev, i);
+	}
+
 	return 0;
 }
 
 void glint_modeset_fini(struct glint_device *gdev)
 {
+	if (gdev->mode_info.mode_config_initialized) {
+		drm_mode_config_cleanup(gdev->ddev);
+		gdev->mode_info.mode_config_initialized = false;
+	}
 }
diff --git a/drivers/gpu/drm/glint/glint_drv.h b/drivers/gpu/drm/glint/glint_drv.h
index b3f7d55..5c419f7 100644
--- a/drivers/gpu/drm/glint/glint_drv.h
+++ b/drivers/gpu/drm/glint/glint_drv.h
@@ -14,6 +14,10 @@
 #define GLINT_INFO(fmt, arg...) DRM_INFO(DRIVER_NAME ": " fmt, ##arg)
 #define GLINT_ERROR(fmt, arg...) DRM_ERROR(DRIVER_NAME ": " fmt, ##arg)
 
+#define GLINTFB_CONN_LIMIT 4
+
+#define RREG8(reg) ioread8(((void __iomem *)gdev->rmmio) + (reg))
+#define WREG8(reg, v) iowrite8(v, ((void __iomem *)gdev->rmmio) + (reg))
 #define RREG32(reg) ioread32(((void __iomem *)gdev->rmmio) + (reg))
 #define WREG32(reg, v) iowrite32(v, ((void __iomem *)gdev->rmmio) + (reg))
 
@@ -21,6 +25,9 @@
 
 #include "glint.h"
 
+				/* glint_crtc.c */
+void glint_crtc_init(struct drm_device *dev, int index);
+
 				/* glint_device.c */
 int glint_device_init(struct glint_device *gdev,
 		      struct drm_device *ddev,
diff --git a/drivers/gpu/drm/glint/glint_mode.h b/drivers/gpu/drm/glint/glint_mode.h
new file mode 100644
index 0000000..151bc44
--- /dev/null
+++ b/drivers/gpu/drm/glint/glint_mode.h
@@ -0,0 +1,24 @@
+#ifndef __GLINT_MODE_H__
+#define __GLINT_MODE_H__
+
+#include "drmP.h"
+#include "drm.h"
+
+#define GLINT_MAX_FB_HEIGHT 4096
+#define GLINT_MAX_FB_WIDTH 4096
+
+#define to_glint_crtc(x) container_of(x, struct glint_crtc, base)
+
+struct glint_crtc {
+	struct drm_crtc			base;
+	u8				lut_r[256], lut_g[256], lut_b[256];
+	int				crtc_id;
+	bool				enabled;
+};
+
+struct glint_mode_info {
+	bool				mode_config_initialized;
+	struct glint_crtc		*crtcs[2]; /* FIXME: how many CRTCs? */
+};
+
+#endif				/* __GLINT_MODE_H__ */