aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/gpu/drm/mgag200
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/mgag200')
-rw-r--r--drivers/gpu/drm/mgag200/Makefile4
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_bmc.c99
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.c21
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.h208
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_g200.c254
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_g200eh.c277
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_g200eh3.c181
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_g200er.c315
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_g200ev.c316
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_g200ew3.c192
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_g200se.c431
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_g200wb.c326
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mode.c726
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_pll.c997
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_reg.h2
15 files changed, 2761 insertions, 1588 deletions
diff --git a/drivers/gpu/drm/mgag200/Makefile b/drivers/gpu/drm/mgag200/Makefile
index 89558549c3af..182e224c460d 100644
--- a/drivers/gpu/drm/mgag200/Makefile
+++ b/drivers/gpu/drm/mgag200/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
mgag200-y := \
+ mgag200_bmc.o \
mgag200_drv.o \
mgag200_g200.o \
mgag200_g200eh.o \
@@ -10,7 +11,6 @@ mgag200-y := \
mgag200_g200se.o \
mgag200_g200wb.o \
mgag200_i2c.o \
- mgag200_mode.o \
- mgag200_pll.o
+ mgag200_mode.o
obj-$(CONFIG_DRM_MGAG200) += mgag200.o
diff --git a/drivers/gpu/drm/mgag200/mgag200_bmc.c b/drivers/gpu/drm/mgag200/mgag200_bmc.c
new file mode 100644
index 000000000000..2ba2e3c5086a
--- /dev/null
+++ b/drivers/gpu/drm/mgag200/mgag200_bmc.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/delay.h>
+
+#include "mgag200_drv.h"
+
+void mgag200_bmc_disable_vidrst(struct mga_device *mdev)
+{
+ u8 tmp;
+ int iter_max;
+
+ /*
+ * 1 - The first step is to inform the BMC of an upcoming mode
+ * change. We are putting the misc<0> to output.
+ */
+
+ WREG8(DAC_INDEX, MGA1064_GEN_IO_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= 0x10;
+ WREG_DAC(MGA1064_GEN_IO_CTL, tmp);
+
+ /* we are putting a 1 on the misc<0> line */
+ WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA);
+ tmp = RREG8(DAC_DATA);
+ tmp |= 0x10;
+ WREG_DAC(MGA1064_GEN_IO_DATA, tmp);
+
+ /*
+ * 2- Second step to mask any further scan request. This is
+ * done by asserting the remfreqmsk bit (XSPAREREG<7>)
+ */
+
+ WREG8(DAC_INDEX, MGA1064_SPAREREG);
+ tmp = RREG8(DAC_DATA);
+ tmp |= 0x80;
+ WREG_DAC(MGA1064_SPAREREG, tmp);
+
+ /*
+ * 3a- The third step is to verify if there is an active scan.
+ * We are waiting for a 0 on remhsyncsts <XSPAREREG<0>).
+ */
+ iter_max = 300;
+ while (!(tmp & 0x1) && iter_max) {
+ WREG8(DAC_INDEX, MGA1064_SPAREREG);
+ tmp = RREG8(DAC_DATA);
+ udelay(1000);
+ iter_max--;
+ }
+
+ /*
+ * 3b- This step occurs only if the remove is actually
+ * scanning. We are waiting for the end of the frame which is
+ * a 1 on remvsyncsts (XSPAREREG<1>)
+ */
+ if (iter_max) {
+ iter_max = 300;
+ while ((tmp & 0x2) && iter_max) {
+ WREG8(DAC_INDEX, MGA1064_SPAREREG);
+ tmp = RREG8(DAC_DATA);
+ udelay(1000);
+ iter_max--;
+ }
+ }
+}
+
+void mgag200_bmc_enable_vidrst(struct mga_device *mdev)
+{
+ u8 tmp;
+
+ /* Ensure that the vrsten and hrsten are set */
+ WREG8(MGAREG_CRTCEXT_INDEX, 1);
+ tmp = RREG8(MGAREG_CRTCEXT_DATA);
+ WREG8(MGAREG_CRTCEXT_DATA, tmp | 0x88);
+
+ /* Assert rstlvl2 */
+ WREG8(DAC_INDEX, MGA1064_REMHEADCTL2);
+ tmp = RREG8(DAC_DATA);
+ tmp |= 0x8;
+ WREG8(DAC_DATA, tmp);
+
+ udelay(10);
+
+ /* Deassert rstlvl2 */
+ tmp &= ~0x08;
+ WREG8(DAC_INDEX, MGA1064_REMHEADCTL2);
+ WREG8(DAC_DATA, tmp);
+
+ /* Remove mask of scan request */
+ WREG8(DAC_INDEX, MGA1064_SPAREREG);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~0x80;
+ WREG8(DAC_DATA, tmp);
+
+ /* Put back a 0 on the misc<0> line */
+ WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~0x10;
+ WREG_DAC(MGA1064_GEN_IO_DATA, tmp);
+}
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c
index a222bf76804f..ece6cd102dbb 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.c
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -155,15 +155,16 @@ int mgag200_device_preinit(struct mga_device *mdev)
return 0;
}
-int mgag200_device_init(struct mga_device *mdev, enum mga_type type,
- const struct mgag200_device_info *info)
+int mgag200_device_init(struct mga_device *mdev,
+ const struct mgag200_device_info *info,
+ const struct mgag200_device_funcs *funcs)
{
struct drm_device *dev = &mdev->base;
u8 crtcext3, misc;
int ret;
mdev->info = info;
- mdev->type = type;
+ mdev->funcs = funcs;
ret = drmm_mutex_init(dev, &mdev->rmmio_lock);
if (ret)
@@ -226,29 +227,29 @@ mgag200_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
switch (type) {
case G200_PCI:
case G200_AGP:
- mdev = mgag200_g200_device_create(pdev, &mgag200_driver, type);
+ mdev = mgag200_g200_device_create(pdev, &mgag200_driver);
break;
case G200_SE_A:
case G200_SE_B:
mdev = mgag200_g200se_device_create(pdev, &mgag200_driver, type);
break;
case G200_WB:
- mdev = mgag200_g200wb_device_create(pdev, &mgag200_driver, type);
+ mdev = mgag200_g200wb_device_create(pdev, &mgag200_driver);
break;
case G200_EV:
- mdev = mgag200_g200ev_device_create(pdev, &mgag200_driver, type);
+ mdev = mgag200_g200ev_device_create(pdev, &mgag200_driver);
break;
case G200_EH:
- mdev = mgag200_g200eh_device_create(pdev, &mgag200_driver, type);
+ mdev = mgag200_g200eh_device_create(pdev, &mgag200_driver);
break;
case G200_EH3:
- mdev = mgag200_g200eh3_device_create(pdev, &mgag200_driver, type);
+ mdev = mgag200_g200eh3_device_create(pdev, &mgag200_driver);
break;
case G200_ER:
- mdev = mgag200_g200er_device_create(pdev, &mgag200_driver, type);
+ mdev = mgag200_g200er_device_create(pdev, &mgag200_driver);
break;
case G200_EW3:
- mdev = mgag200_g200ew3_device_create(pdev, &mgag200_driver, type);
+ mdev = mgag200_g200ew3_device_create(pdev, &mgag200_driver);
break;
default:
dev_err(&pdev->dev, "Device type %d is unsupported\n", type);
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h
index 301c4ab46539..f0c2349404b4 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -15,11 +15,13 @@
#include <video/vga.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
#include <drm/drm_encoder.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem.h>
#include <drm/drm_gem_shmem_helper.h>
-#include <drm/drm_simple_kms_helper.h>
+#include <drm/drm_plane.h>
#include "mgag200_reg.h"
@@ -123,11 +125,39 @@
#define MGA_MISC_OUT 0x1fc2
#define MGA_MISC_IN 0x1fcc
+/*
+ * TODO: This is a pretty large set of default values for all kinds of
+ * settings. It should be split and set in the various DRM helpers,
+ * such as the CRTC reset or atomic_enable helpers. The PLL values
+ * probably belong to each model's PLL code.
+ */
+#define MGAG200_DAC_DEFAULT(xvrefctrl, xpixclkctrl, xmiscctrl, xsyspllm, xsysplln, xsyspllp) \
+ /* 0x00: */ 0, 0, 0, 0, 0, 0, 0x00, 0, \
+ /* 0x08: */ 0, 0, 0, 0, 0, 0, 0, 0, \
+ /* 0x10: */ 0, 0, 0, 0, 0, 0, 0, 0, \
+ /* 0x18: */ (xvrefctrl), \
+ /* 0x19: */ 0, \
+ /* 0x1a: */ (xpixclkctrl), \
+ /* 0x1b: */ 0xff, 0xbf, 0x20, \
+ /* 0x1e: */ (xmiscctrl), \
+ /* 0x1f: */ 0x20, \
+ /* 0x20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ /* 0x28: */ 0x00, 0x00, 0x00, 0x00, \
+ /* 0x2c: */ (xsyspllm), \
+ /* 0x2d: */ (xsysplln), \
+ /* 0x2e: */ (xsyspllp), \
+ /* 0x2f: */ 0x40, \
+ /* 0x30: */ 0x00, 0xb0, 0x00, 0xc2, 0x34, 0x14, 0x02, 0x83, \
+ /* 0x38: */ 0x00, 0x93, 0x00, 0x77, 0x00, 0x00, 0x00, 0x3a, \
+ /* 0x40: */ 0, 0, 0, 0, 0, 0, 0, 0, \
+ /* 0x48: */ 0, 0, 0, 0, 0, 0, 0, 0 \
+
+#define MGAG200_LUT_SIZE 256
+
#define MGAG200_MAX_FB_HEIGHT 4096
#define MGAG200_MAX_FB_WIDTH 4096
struct mga_device;
-struct mgag200_pll;
/*
* Stores parameters for programming the PLLs
@@ -146,20 +176,12 @@ struct mgag200_pll_values {
unsigned int s;
};
-struct mgag200_pll_funcs {
- int (*compute)(struct mgag200_pll *pll, long clock, struct mgag200_pll_values *pllc);
- void (*update)(struct mgag200_pll *pll, const struct mgag200_pll_values *pllc);
-};
-
-struct mgag200_pll {
- struct mga_device *mdev;
-
- const struct mgag200_pll_funcs *funcs;
-};
-
struct mgag200_crtc_state {
struct drm_crtc_state base;
+ /* Primary-plane format; required for modesetting and color mgmt. */
+ const struct drm_format_info *format;
+
struct mgag200_pll_values pixpllc;
};
@@ -188,8 +210,6 @@ enum mga_type {
G200_EW3,
};
-#define IS_G200_SE(mdev) (mdev->type == G200_SE_A || mdev->type == G200_SE_B)
-
struct mgag200_device_info {
u16 max_hdisplay;
u16 max_vdisplay;
@@ -230,10 +250,39 @@ struct mgag200_device_info {
.bug_no_startadd = (_bug_no_startadd), \
}
+struct mgag200_device_funcs {
+ /*
+ * Disables an external reset source (i.e., BMC) before programming
+ * a new display mode.
+ */
+ void (*disable_vidrst)(struct mga_device *mdev);
+
+ /*
+ * Enables an external reset source (i.e., BMC) after programming
+ * a new display mode.
+ */
+ void (*enable_vidrst)(struct mga_device *mdev);
+
+ /*
+ * Validate that the given state can be programmed into PIXPLLC. On
+ * success, the calculated parameters should be stored in the CRTC's
+ * state in struct @mgag200_crtc_state.pixpllc.
+ */
+ int (*pixpllc_atomic_check)(struct drm_crtc *crtc, struct drm_atomic_state *new_state);
+
+ /*
+ * Program PIXPLLC from the CRTC state. The parameters should have been
+ * stored in struct @mgag200_crtc_state.pixpllc by the corresponding
+ * implementation of @pixpllc_atomic_check.
+ */
+ void (*pixpllc_atomic_update)(struct drm_crtc *crtc, struct drm_atomic_state *old_state);
+};
+
struct mga_device {
struct drm_device base;
const struct mgag200_device_info *info;
+ const struct mgag200_device_funcs *funcs;
struct resource *rmmio_res;
void __iomem *rmmio;
@@ -243,12 +292,11 @@ struct mga_device {
void __iomem *vram;
resource_size_t vram_available;
- enum mga_type type;
-
- struct mgag200_pll pixpll;
+ struct drm_plane primary_plane;
+ struct drm_crtc crtc;
+ struct drm_encoder encoder;
struct mga_i2c_chan i2c;
struct drm_connector connector;
- struct drm_simple_display_pipe display_pipe;
};
static inline struct mga_device *to_mga_device(struct drm_device *dev)
@@ -287,35 +335,113 @@ int mgag200_init_pci_options(struct pci_dev *pdev, u32 option, u32 option2);
resource_size_t mgag200_probe_vram(void __iomem *mem, resource_size_t size);
resource_size_t mgag200_device_probe_vram(struct mga_device *mdev);
int mgag200_device_preinit(struct mga_device *mdev);
-int mgag200_device_init(struct mga_device *mdev, enum mga_type type,
- const struct mgag200_device_info *info);
+int mgag200_device_init(struct mga_device *mdev,
+ const struct mgag200_device_info *info,
+ const struct mgag200_device_funcs *funcs);
/* mgag200_<device type>.c */
-struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
- enum mga_type type);
+struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct drm_driver *drv);
struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
enum mga_type type);
-struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
- enum mga_type type);
-struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
- enum mga_type type);
-struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
- enum mga_type type);
-struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
- enum mga_type type);
-struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
- enum mga_type type);
-struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
- enum mga_type type);
+void mgag200_g200wb_init_registers(struct mga_device *mdev);
+void mgag200_g200wb_pixpllc_atomic_update(struct drm_crtc *crtc, struct drm_atomic_state *old_state);
+struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv);
+struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv);
+void mgag200_g200eh_init_registers(struct mga_device *mdev);
+void mgag200_g200eh_pixpllc_atomic_update(struct drm_crtc *crtc, struct drm_atomic_state *old_state);
+struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev,
+ const struct drm_driver *drv);
+struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev,
+ const struct drm_driver *drv);
+struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev,
+ const struct drm_driver *drv);
+struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev,
+ const struct drm_driver *drv);
- /* mgag200_mode.c */
-resource_size_t mgag200_device_probe_vram(struct mga_device *mdev);
-int mgag200_modeset_init(struct mga_device *mdev, resource_size_t vram_fb_available);
+/*
+ * mgag200_mode.c
+ */
+
+struct drm_crtc;
+struct drm_crtc_state;
+struct drm_display_mode;
+struct drm_plane;
+struct drm_atomic_state;
+
+extern const uint32_t mgag200_primary_plane_formats[];
+extern const size_t mgag200_primary_plane_formats_size;
+extern const uint64_t mgag200_primary_plane_fmtmods[];
+
+int mgag200_primary_plane_helper_atomic_check(struct drm_plane *plane,
+ struct drm_atomic_state *new_state);
+void mgag200_primary_plane_helper_atomic_update(struct drm_plane *plane,
+ struct drm_atomic_state *old_state);
+void mgag200_primary_plane_helper_atomic_disable(struct drm_plane *plane,
+ struct drm_atomic_state *old_state);
+#define MGAG200_PRIMARY_PLANE_HELPER_FUNCS \
+ DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, \
+ .atomic_check = mgag200_primary_plane_helper_atomic_check, \
+ .atomic_update = mgag200_primary_plane_helper_atomic_update, \
+ .atomic_disable = mgag200_primary_plane_helper_atomic_disable
+
+#define MGAG200_PRIMARY_PLANE_FUNCS \
+ .update_plane = drm_atomic_helper_update_plane, \
+ .disable_plane = drm_atomic_helper_disable_plane, \
+ .destroy = drm_plane_cleanup, \
+ DRM_GEM_SHADOW_PLANE_FUNCS
+
+enum drm_mode_status mgag200_crtc_helper_mode_valid(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode);
+int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state);
+void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *old_state);
+void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *old_state);
+void mgag200_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *old_state);
+
+#define MGAG200_CRTC_HELPER_FUNCS \
+ .mode_valid = mgag200_crtc_helper_mode_valid, \
+ .atomic_check = mgag200_crtc_helper_atomic_check, \
+ .atomic_flush = mgag200_crtc_helper_atomic_flush, \
+ .atomic_enable = mgag200_crtc_helper_atomic_enable, \
+ .atomic_disable = mgag200_crtc_helper_atomic_disable
+
+void mgag200_crtc_reset(struct drm_crtc *crtc);
+struct drm_crtc_state *mgag200_crtc_atomic_duplicate_state(struct drm_crtc *crtc);
+void mgag200_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state);
+
+#define MGAG200_CRTC_FUNCS \
+ .reset = mgag200_crtc_reset, \
+ .destroy = drm_crtc_cleanup, \
+ .set_config = drm_atomic_helper_set_config, \
+ .page_flip = drm_atomic_helper_page_flip, \
+ .atomic_duplicate_state = mgag200_crtc_atomic_duplicate_state, \
+ .atomic_destroy_state = mgag200_crtc_atomic_destroy_state
+
+#define MGAG200_DAC_ENCODER_FUNCS \
+ .destroy = drm_encoder_cleanup
+
+int mgag200_vga_connector_helper_get_modes(struct drm_connector *connector);
+
+#define MGAG200_VGA_CONNECTOR_HELPER_FUNCS \
+ .get_modes = mgag200_vga_connector_helper_get_modes
+
+#define MGAG200_VGA_CONNECTOR_FUNCS \
+ .reset = drm_atomic_helper_connector_reset, \
+ .fill_modes = drm_helper_probe_single_connector_modes, \
+ .destroy = drm_connector_cleanup, \
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, \
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state
+
+void mgag200_set_mode_regs(struct mga_device *mdev, const struct drm_display_mode *mode);
+void mgag200_set_format_regs(struct mga_device *mdev, const struct drm_format_info *format);
+void mgag200_enable_display(struct mga_device *mdev);
+void mgag200_init_registers(struct mga_device *mdev);
+int mgag200_mode_config_init(struct mga_device *mdev, resource_size_t vram_available);
+
+ /* mgag200_bmc.c */
+void mgag200_bmc_disable_vidrst(struct mga_device *mdev);
+void mgag200_bmc_enable_vidrst(struct mga_device *mdev);
/* mgag200_i2c.c */
int mgag200_i2c_init(struct mga_device *mdev, struct mga_i2c_chan *i2c);
- /* mgag200_pll.c */
-int mgag200_pixpll_init(struct mgag200_pll *pixpll, struct mga_device *mdev);
-
#endif /* __MGAG200_DRV_H__ */
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200.c b/drivers/gpu/drm/mgag200/mgag200_g200.c
index 674385921b7f..bf5d7fe525a3 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200.c
@@ -3,7 +3,11 @@
#include <linux/pci.h>
#include <linux/vmalloc.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_probe_helper.h>
#include "mgag200_drv.h"
@@ -30,6 +34,235 @@ static int mgag200_g200_init_pci_options(struct pci_dev *pdev)
return mgag200_init_pci_options(pdev, option, 0x00008000);
}
+static void mgag200_g200_init_registers(struct mgag200_g200_device *g200)
+{
+ static const u8 dacvalue[] = {
+ MGAG200_DAC_DEFAULT(0x00, 0xc9, 0x1f,
+ 0x04, 0x2d, 0x19)
+ };
+
+ struct mga_device *mdev = &g200->base;
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(dacvalue); ++i) {
+ if ((i <= 0x17) ||
+ (i == 0x1b) ||
+ (i == 0x1c) ||
+ ((i >= 0x1f) && (i <= 0x29)) ||
+ ((i >= 0x30) && (i <= 0x37)))
+ continue;
+ WREG_DAC(i, dacvalue[i]);
+ }
+
+ mgag200_init_registers(mdev);
+}
+
+/*
+ * PIXPLLC
+ */
+
+static int mgag200_g200_pixpllc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state)
+{
+ static const int post_div_max = 7;
+ static const int in_div_min = 1;
+ static const int in_div_max = 6;
+ static const int feed_div_min = 7;
+ static const int feed_div_max = 127;
+
+ struct drm_device *dev = crtc->dev;
+ struct mgag200_g200_device *g200 = to_mgag200_g200_device(dev);
+ struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+ struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+ long clock = new_crtc_state->mode.clock;
+ struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
+ u8 testp, testm, testn;
+ u8 n = 0, m = 0, p, s;
+ long f_vco;
+ long computed;
+ long delta, tmp_delta;
+ long ref_clk = g200->ref_clk;
+ long p_clk_min = g200->pclk_min;
+ long p_clk_max = g200->pclk_max;
+
+ if (clock > p_clk_max) {
+ drm_err(dev, "Pixel Clock %ld too high\n", clock);
+ return -EINVAL;
+ }
+
+ if (clock < p_clk_min >> 3)
+ clock = p_clk_min >> 3;
+
+ f_vco = clock;
+ for (testp = 0;
+ testp <= post_div_max && f_vco < p_clk_min;
+ testp = (testp << 1) + 1, f_vco <<= 1)
+ ;
+ p = testp + 1;
+
+ delta = clock;
+
+ for (testm = in_div_min; testm <= in_div_max; testm++) {
+ for (testn = feed_div_min; testn <= feed_div_max; testn++) {
+ computed = ref_clk * (testn + 1) / (testm + 1);
+ if (computed < f_vco)
+ tmp_delta = f_vco - computed;
+ else
+ tmp_delta = computed - f_vco;
+ if (tmp_delta < delta) {
+ delta = tmp_delta;
+ m = testm + 1;
+ n = testn + 1;
+ }
+ }
+ }
+ f_vco = ref_clk * n / m;
+ if (f_vco < 100000)
+ s = 0;
+ else if (f_vco < 140000)
+ s = 1;
+ else if (f_vco < 180000)
+ s = 2;
+ else
+ s = 3;
+
+ drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n",
+ clock, f_vco, m, n, p, s);
+
+ pixpllc->m = m;
+ pixpllc->n = n;
+ pixpllc->p = p;
+ pixpllc->s = s;
+
+ return 0;
+}
+
+static void mgag200_g200_pixpllc_atomic_update(struct drm_crtc *crtc,
+ struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = to_mga_device(dev);
+ struct drm_crtc_state *crtc_state = crtc->state;
+ struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
+ struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
+ unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
+ u8 xpixpllcm, xpixpllcn, xpixpllcp;
+
+ pixpllcm = pixpllc->m - 1;
+ pixpllcn = pixpllc->n - 1;
+ pixpllcp = pixpllc->p - 1;
+ pixpllcs = pixpllc->s;
+
+ xpixpllcm = pixpllcm;
+ xpixpllcn = pixpllcn;
+ xpixpllcp = (pixpllcs << 3) | pixpllcp;
+
+ WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
+
+ WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
+ WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
+ WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
+}
+
+/*
+ * Mode-setting pipeline
+ */
+
+static const struct drm_plane_helper_funcs mgag200_g200_primary_plane_helper_funcs = {
+ MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
+};
+
+static const struct drm_plane_funcs mgag200_g200_primary_plane_funcs = {
+ MGAG200_PRIMARY_PLANE_FUNCS,
+};
+
+static const struct drm_crtc_helper_funcs mgag200_g200_crtc_helper_funcs = {
+ MGAG200_CRTC_HELPER_FUNCS,
+};
+
+static const struct drm_crtc_funcs mgag200_g200_crtc_funcs = {
+ MGAG200_CRTC_FUNCS,
+};
+
+static const struct drm_encoder_funcs mgag200_g200_dac_encoder_funcs = {
+ MGAG200_DAC_ENCODER_FUNCS,
+};
+
+static const struct drm_connector_helper_funcs mgag200_g200_vga_connector_helper_funcs = {
+ MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
+};
+
+static const struct drm_connector_funcs mgag200_g200_vga_connector_funcs = {
+ MGAG200_VGA_CONNECTOR_FUNCS,
+};
+
+static int mgag200_g200_pipeline_init(struct mga_device *mdev)
+{
+ struct drm_device *dev = &mdev->base;
+ struct drm_plane *primary_plane = &mdev->primary_plane;
+ struct drm_crtc *crtc = &mdev->crtc;
+ struct drm_encoder *encoder = &mdev->encoder;
+ struct mga_i2c_chan *i2c = &mdev->i2c;
+ struct drm_connector *connector = &mdev->connector;
+ int ret;
+
+ ret = drm_universal_plane_init(dev, primary_plane, 0,
+ &mgag200_g200_primary_plane_funcs,
+ mgag200_primary_plane_formats,
+ mgag200_primary_plane_formats_size,
+ mgag200_primary_plane_fmtmods,
+ DRM_PLANE_TYPE_PRIMARY, NULL);
+ if (ret) {
+ drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
+ return ret;
+ }
+ drm_plane_helper_add(primary_plane, &mgag200_g200_primary_plane_helper_funcs);
+ drm_plane_enable_fb_damage_clips(primary_plane);
+
+ ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
+ &mgag200_g200_crtc_funcs, NULL);
+ if (ret) {
+ drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
+ return ret;
+ }
+ drm_crtc_helper_add(crtc, &mgag200_g200_crtc_helper_funcs);
+
+ /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
+ drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
+ drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
+
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
+ ret = drm_encoder_init(dev, encoder, &mgag200_g200_dac_encoder_funcs,
+ DRM_MODE_ENCODER_DAC, NULL);
+ if (ret) {
+ drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = mgag200_i2c_init(mdev, i2c);
+ if (ret) {
+ drm_err(dev, "failed to add DDC bus: %d\n", ret);
+ return ret;
+ }
+
+ ret = drm_connector_init_with_ddc(dev, connector,
+ &mgag200_g200_vga_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA,
+ &i2c->adapter);
+ if (ret) {
+ drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
+ return ret;
+ }
+ drm_connector_helper_add(connector, &mgag200_g200_vga_connector_helper_funcs);
+
+ ret = drm_connector_attach_encoder(connector, encoder);
+ if (ret) {
+ drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
/*
* DRM Device
*/
@@ -160,8 +393,12 @@ out:
pci_unmap_rom(pdev, rom);
}
-struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
- enum mga_type type)
+static const struct mgag200_device_funcs mgag200_g200_device_funcs = {
+ .pixpllc_atomic_check = mgag200_g200_pixpllc_atomic_check,
+ .pixpllc_atomic_update = mgag200_g200_pixpllc_atomic_update,
+};
+
+struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct drm_driver *drv)
{
struct mgag200_g200_device *g200;
struct mga_device *mdev;
@@ -187,15 +424,24 @@ struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct
mgag200_g200_init_refclk(g200);
- ret = mgag200_device_init(mdev, type, &mgag200_g200_device_info);
+ ret = mgag200_device_init(mdev, &mgag200_g200_device_info,
+ &mgag200_g200_device_funcs);
if (ret)
return ERR_PTR(ret);
+ mgag200_g200_init_registers(g200);
+
vram_available = mgag200_device_probe_vram(mdev);
- ret = mgag200_modeset_init(mdev, vram_available);
+ ret = mgag200_mode_config_init(mdev, vram_available);
if (ret)
return ERR_PTR(ret);
+ ret = mgag200_g200_pipeline_init(mdev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ drm_mode_config_reset(dev);
+
return mdev;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh.c b/drivers/gpu/drm/mgag200/mgag200_g200eh.c
index 1b9a22728744..fad62453a91d 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200eh.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200eh.c
@@ -1,11 +1,267 @@
// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/delay.h>
#include <linux/pci.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_probe_helper.h>
#include "mgag200_drv.h"
+void mgag200_g200eh_init_registers(struct mga_device *mdev)
+{
+ static const u8 dacvalue[] = {
+ MGAG200_DAC_DEFAULT(0x00, 0xc9,
+ MGA1064_MISC_CTL_VGA8 | MGA1064_MISC_CTL_DAC_RAM_CS,
+ 0x00, 0x00, 0x00)
+ };
+
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {
+ if ((i <= 0x17) ||
+ (i == 0x1b) ||
+ (i == 0x1c) ||
+ ((i >= 0x1f) && (i <= 0x29)) ||
+ ((i >= 0x30) && (i <= 0x37)) ||
+ ((i >= 0x44) && (i <= 0x4e)))
+ continue;
+ WREG_DAC(i, dacvalue[i]);
+ }
+
+ mgag200_init_registers(mdev);
+}
+
+/*
+ * PIXPLLC
+ */
+
+static int mgag200_g200eh_pixpllc_atomic_check(struct drm_crtc *crtc,
+ struct drm_atomic_state *new_state)
+{
+ static const unsigned int vcomax = 800000;
+ static const unsigned int vcomin = 400000;
+ static const unsigned int pllreffreq = 33333;
+
+ struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+ struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+ long clock = new_crtc_state->mode.clock;
+ struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
+ unsigned int delta, tmpdelta;
+ unsigned int testp, testm, testn;
+ unsigned int p, m, n, s;
+ unsigned int computed;
+
+ m = n = p = s = 0;
+ delta = 0xffffffff;
+
+ for (testp = 16; testp > 0; testp >>= 1) {
+ if (clock * testp > vcomax)
+ continue;
+ if (clock * testp < vcomin)
+ continue;
+
+ for (testm = 1; testm < 33; testm++) {
+ for (testn = 17; testn < 257; testn++) {
+ computed = (pllreffreq * testn) / (testm * testp);
+ if (computed > clock)
+ tmpdelta = computed - clock;
+ else
+ tmpdelta = clock - computed;
+ if (tmpdelta < delta) {
+ delta = tmpdelta;
+ n = testn;
+ m = testm;
+ p = testp;
+ }
+ }
+ }
+ }
+
+ pixpllc->m = m;
+ pixpllc->n = n;
+ pixpllc->p = p;
+ pixpllc->s = s;
+
+ return 0;
+}
+
+void mgag200_g200eh_pixpllc_atomic_update(struct drm_crtc *crtc,
+ struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = to_mga_device(dev);
+ struct drm_crtc_state *crtc_state = crtc->state;
+ struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
+ struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
+ unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
+ u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
+ int i, j, tmpcount, vcount;
+ bool pll_locked = false;
+
+ pixpllcm = pixpllc->m - 1;
+ pixpllcn = pixpllc->n - 1;
+ pixpllcp = pixpllc->p - 1;
+ pixpllcs = pixpllc->s;
+
+ xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm;
+ xpixpllcn = pixpllcn;
+ xpixpllcp = (pixpllcs << 3) | pixpllcp;
+
+ WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
+
+ for (i = 0; i <= 32 && pll_locked == false; i++) {
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
+ WREG8(DAC_DATA, tmp);
+
+ tmp = RREG8(MGAREG_MEM_MISC_READ);
+ tmp |= 0x3 << 2;
+ WREG8(MGAREG_MEM_MISC_WRITE, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
+ WREG8(DAC_DATA, tmp);
+
+ udelay(500);
+
+ WREG_DAC(MGA1064_EH_PIX_PLLC_M, xpixpllcm);
+ WREG_DAC(MGA1064_EH_PIX_PLLC_N, xpixpllcn);
+ WREG_DAC(MGA1064_EH_PIX_PLLC_P, xpixpllcp);
+
+ udelay(500);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
+ tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
+ WREG8(DAC_DATA, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
+ tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
+ WREG8(DAC_DATA, tmp);
+
+ vcount = RREG8(MGAREG_VCOUNT);
+
+ for (j = 0; j < 30 && pll_locked == false; j++) {
+ tmpcount = RREG8(MGAREG_VCOUNT);
+ if (tmpcount < vcount)
+ vcount = 0;
+ if ((tmpcount - vcount) > 2)
+ pll_locked = true;
+ else
+ udelay(5);
+ }
+ }
+}
+
+/*
+ * Mode-setting pipeline
+ */
+
+static const struct drm_plane_helper_funcs mgag200_g200eh_primary_plane_helper_funcs = {
+ MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
+};
+
+static const struct drm_plane_funcs mgag200_g200eh_primary_plane_funcs = {
+ MGAG200_PRIMARY_PLANE_FUNCS,
+};
+
+static const struct drm_crtc_helper_funcs mgag200_g200eh_crtc_helper_funcs = {
+ MGAG200_CRTC_HELPER_FUNCS,
+};
+
+static const struct drm_crtc_funcs mgag200_g200eh_crtc_funcs = {
+ MGAG200_CRTC_FUNCS,
+};
+
+static const struct drm_encoder_funcs mgag200_g200eh_dac_encoder_funcs = {
+ MGAG200_DAC_ENCODER_FUNCS,
+};
+
+static const struct drm_connector_helper_funcs mgag200_g200eh_vga_connector_helper_funcs = {
+ MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
+};
+
+static const struct drm_connector_funcs mgag200_g200eh_vga_connector_funcs = {
+ MGAG200_VGA_CONNECTOR_FUNCS,
+};
+
+static int mgag200_g200eh_pipeline_init(struct mga_device *mdev)
+{
+ struct drm_device *dev = &mdev->base;
+ struct drm_plane *primary_plane = &mdev->primary_plane;
+ struct drm_crtc *crtc = &mdev->crtc;
+ struct drm_encoder *encoder = &mdev->encoder;
+ struct mga_i2c_chan *i2c = &mdev->i2c;
+ struct drm_connector *connector = &mdev->connector;
+ int ret;
+
+ ret = drm_universal_plane_init(dev, primary_plane, 0,
+ &mgag200_g200eh_primary_plane_funcs,
+ mgag200_primary_plane_formats,
+ mgag200_primary_plane_formats_size,
+ mgag200_primary_plane_fmtmods,
+ DRM_PLANE_TYPE_PRIMARY, NULL);
+ if (ret) {
+ drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
+ return ret;
+ }
+ drm_plane_helper_add(primary_plane, &mgag200_g200eh_primary_plane_helper_funcs);
+ drm_plane_enable_fb_damage_clips(primary_plane);
+
+ ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
+ &mgag200_g200eh_crtc_funcs, NULL);
+ if (ret) {
+ drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
+ return ret;
+ }
+ drm_crtc_helper_add(crtc, &mgag200_g200eh_crtc_helper_funcs);
+
+ /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
+ drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
+ drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
+
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
+ ret = drm_encoder_init(dev, encoder, &mgag200_g200eh_dac_encoder_funcs,
+ DRM_MODE_ENCODER_DAC, NULL);
+ if (ret) {
+ drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = mgag200_i2c_init(mdev, i2c);
+ if (ret) {
+ drm_err(dev, "failed to add DDC bus: %d\n", ret);
+ return ret;
+ }
+
+ ret = drm_connector_init_with_ddc(dev, connector,
+ &mgag200_g200eh_vga_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA,
+ &i2c->adapter);
+ if (ret) {
+ drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
+ return ret;
+ }
+ drm_connector_helper_add(connector, &mgag200_g200eh_vga_connector_helper_funcs);
+
+ ret = drm_connector_attach_encoder(connector, encoder);
+ if (ret) {
+ drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
/*
* DRM device
*/
@@ -13,8 +269,12 @@
static const struct mgag200_device_info mgag200_g200eh_device_info =
MGAG200_DEVICE_INFO_INIT(2048, 2048, 37500, false, 1, 0, false);
-struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
- enum mga_type type)
+static const struct mgag200_device_funcs mgag200_g200eh_device_funcs = {
+ .pixpllc_atomic_check = mgag200_g200eh_pixpllc_atomic_check,
+ .pixpllc_atomic_update = mgag200_g200eh_pixpllc_atomic_update,
+};
+
+struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv)
{
struct mga_device *mdev;
struct drm_device *dev;
@@ -36,15 +296,24 @@ struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const stru
if (ret)
return ERR_PTR(ret);
- ret = mgag200_device_init(mdev, type, &mgag200_g200eh_device_info);
+ ret = mgag200_device_init(mdev, &mgag200_g200eh_device_info,
+ &mgag200_g200eh_device_funcs);
if (ret)
return ERR_PTR(ret);
+ mgag200_g200eh_init_registers(mdev);
+
vram_available = mgag200_device_probe_vram(mdev);
- ret = mgag200_modeset_init(mdev, vram_available);
+ ret = mgag200_mode_config_init(mdev, vram_available);
if (ret)
return ERR_PTR(ret);
+ ret = mgag200_g200eh_pipeline_init(mdev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ drm_mode_config_reset(dev);
+
return mdev;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c
index 438cda1b14c9..0f7d8112cd49 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200eh3.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200eh3.c
@@ -2,20 +2,184 @@
#include <linux/pci.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_probe_helper.h>
#include "mgag200_drv.h"
/*
+ * PIXPLLC
+ */
+
+static int mgag200_g200eh3_pixpllc_atomic_check(struct drm_crtc *crtc,
+ struct drm_atomic_state *new_state)
+{
+ static const unsigned int vcomax = 3000000;
+ static const unsigned int vcomin = 1500000;
+ static const unsigned int pllreffreq = 25000;
+
+ struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+ struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+ long clock = new_crtc_state->mode.clock;
+ struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
+ unsigned int delta, tmpdelta;
+ unsigned int testp, testm, testn;
+ unsigned int p, m, n, s;
+ unsigned int computed;
+
+ m = n = p = s = 0;
+ delta = 0xffffffff;
+ testp = 0;
+
+ for (testm = 150; testm >= 6; testm--) {
+ if (clock * testm > vcomax)
+ continue;
+ if (clock * testm < vcomin)
+ continue;
+ for (testn = 120; testn >= 60; testn--) {
+ computed = (pllreffreq * testn) / testm;
+ if (computed > clock)
+ tmpdelta = computed - clock;
+ else
+ tmpdelta = clock - computed;
+ if (tmpdelta < delta) {
+ delta = tmpdelta;
+ n = testn + 1;
+ m = testm + 1;
+ p = testp + 1;
+ }
+ if (delta == 0)
+ break;
+ }
+ if (delta == 0)
+ break;
+ }
+
+ pixpllc->m = m;
+ pixpllc->n = n;
+ pixpllc->p = p;
+ pixpllc->s = s;
+
+ return 0;
+}
+
+/*
+ * Mode-setting pipeline
+ */
+
+static const struct drm_plane_helper_funcs mgag200_g200eh3_primary_plane_helper_funcs = {
+ MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
+};
+
+static const struct drm_plane_funcs mgag200_g200eh3_primary_plane_funcs = {
+ MGAG200_PRIMARY_PLANE_FUNCS,
+};
+
+static const struct drm_crtc_helper_funcs mgag200_g200eh3_crtc_helper_funcs = {
+ MGAG200_CRTC_HELPER_FUNCS,
+};
+
+static const struct drm_crtc_funcs mgag200_g200eh3_crtc_funcs = {
+ MGAG200_CRTC_FUNCS,
+};
+
+static const struct drm_encoder_funcs mgag200_g200eh3_dac_encoder_funcs = {
+ MGAG200_DAC_ENCODER_FUNCS,
+};
+
+static const struct drm_connector_helper_funcs mgag200_g200eh3_vga_connector_helper_funcs = {
+ MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
+};
+
+static const struct drm_connector_funcs mgag200_g200eh3_vga_connector_funcs = {
+ MGAG200_VGA_CONNECTOR_FUNCS,
+};
+
+static int mgag200_g200eh3_pipeline_init(struct mga_device *mdev)
+{
+ struct drm_device *dev = &mdev->base;
+ struct drm_plane *primary_plane = &mdev->primary_plane;
+ struct drm_crtc *crtc = &mdev->crtc;
+ struct drm_encoder *encoder = &mdev->encoder;
+ struct mga_i2c_chan *i2c = &mdev->i2c;
+ struct drm_connector *connector = &mdev->connector;
+ int ret;
+
+ ret = drm_universal_plane_init(dev, primary_plane, 0,
+ &mgag200_g200eh3_primary_plane_funcs,
+ mgag200_primary_plane_formats,
+ mgag200_primary_plane_formats_size,
+ mgag200_primary_plane_fmtmods,
+ DRM_PLANE_TYPE_PRIMARY, NULL);
+ if (ret) {
+ drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
+ return ret;
+ }
+ drm_plane_helper_add(primary_plane, &mgag200_g200eh3_primary_plane_helper_funcs);
+ drm_plane_enable_fb_damage_clips(primary_plane);
+
+ ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
+ &mgag200_g200eh3_crtc_funcs, NULL);
+ if (ret) {
+ drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
+ return ret;
+ }
+ drm_crtc_helper_add(crtc, &mgag200_g200eh3_crtc_helper_funcs);
+
+ /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
+ drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
+ drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
+
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
+ ret = drm_encoder_init(dev, encoder, &mgag200_g200eh3_dac_encoder_funcs,
+ DRM_MODE_ENCODER_DAC, NULL);
+ if (ret) {
+ drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = mgag200_i2c_init(mdev, i2c);
+ if (ret) {
+ drm_err(dev, "failed to add DDC bus: %d\n", ret);
+ return ret;
+ }
+
+ ret = drm_connector_init_with_ddc(dev, connector,
+ &mgag200_g200eh3_vga_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA,
+ &i2c->adapter);
+ if (ret) {
+ drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
+ return ret;
+ }
+ drm_connector_helper_add(connector, &mgag200_g200eh3_vga_connector_helper_funcs);
+
+ ret = drm_connector_attach_encoder(connector, encoder);
+ if (ret) {
+ drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
* DRM device
*/
static const struct mgag200_device_info mgag200_g200eh3_device_info =
MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false, 1, 0, false);
+static const struct mgag200_device_funcs mgag200_g200eh3_device_funcs = {
+ .pixpllc_atomic_check = mgag200_g200eh3_pixpllc_atomic_check,
+ .pixpllc_atomic_update = mgag200_g200eh_pixpllc_atomic_update, // same as G200EH
+};
+
struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev,
- const struct drm_driver *drv,
- enum mga_type type)
+ const struct drm_driver *drv)
{
struct mga_device *mdev;
struct drm_device *dev;
@@ -37,15 +201,24 @@ struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev,
if (ret)
return ERR_PTR(ret);
- ret = mgag200_device_init(mdev, type, &mgag200_g200eh3_device_info);
+ ret = mgag200_device_init(mdev, &mgag200_g200eh3_device_info,
+ &mgag200_g200eh3_device_funcs);
if (ret)
return ERR_PTR(ret);
+ mgag200_g200eh_init_registers(mdev); // same as G200EH
+
vram_available = mgag200_device_probe_vram(mdev);
- ret = mgag200_modeset_init(mdev, vram_available);
+ ret = mgag200_mode_config_init(mdev, vram_available);
if (ret)
return ERR_PTR(ret);
+ ret = mgag200_g200eh3_pipeline_init(mdev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ drm_mode_config_reset(dev);
+
return mdev;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200er.c b/drivers/gpu/drm/mgag200/mgag200_g200er.c
index 0790d4e6463d..bce267e0f7de 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200er.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200er.c
@@ -1,11 +1,305 @@
// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/delay.h>
#include <linux/pci.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_probe_helper.h>
#include "mgag200_drv.h"
+static void mgag200_g200er_init_registers(struct mga_device *mdev)
+{
+ static const u8 dacvalue[] = {
+ MGAG200_DAC_DEFAULT(0x00, 0xc9, 0x1f, 0x00, 0x00, 0x00)
+ };
+
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {
+ if ((i <= 0x17) ||
+ (i == 0x1b) ||
+ (i == 0x1c) ||
+ ((i >= 0x1f) && (i <= 0x29)) ||
+ ((i >= 0x30) && (i <= 0x37)))
+ continue;
+ WREG_DAC(i, dacvalue[i]);
+ }
+
+ WREG_DAC(0x90, 0); /* G200ER specific */
+
+ mgag200_init_registers(mdev);
+
+ WREG_ECRT(0x24, 0x5); /* G200ER specific */
+}
+
+static void mgag200_g200er_reset_tagfifo(struct mga_device *mdev)
+{
+ static const uint32_t RESET_FLAG = 0x00200000; /* undocumented magic value */
+ u32 memctl;
+
+ memctl = RREG32(MGAREG_MEMCTL);
+
+ memctl |= RESET_FLAG;
+ WREG32(MGAREG_MEMCTL, memctl);
+
+ udelay(1000);
+
+ memctl &= ~RESET_FLAG;
+ WREG32(MGAREG_MEMCTL, memctl);
+}
+
+/*
+ * PIXPLLC
+ */
+
+static int mgag200_g200er_pixpllc_atomic_check(struct drm_crtc *crtc,
+ struct drm_atomic_state *new_state)
+{
+ static const unsigned int vcomax = 1488000;
+ static const unsigned int vcomin = 1056000;
+ static const unsigned int pllreffreq = 48000;
+ static const unsigned int m_div_val[] = { 1, 2, 4, 8 };
+
+ struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+ struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+ long clock = new_crtc_state->mode.clock;
+ struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
+ unsigned int delta, tmpdelta;
+ int testr, testn, testm, testo;
+ unsigned int p, m, n, s;
+ unsigned int computed, vco;
+
+ m = n = p = s = 0;
+ delta = 0xffffffff;
+
+ for (testr = 0; testr < 4; testr++) {
+ if (delta == 0)
+ break;
+ for (testn = 5; testn < 129; testn++) {
+ if (delta == 0)
+ break;
+ for (testm = 3; testm >= 0; testm--) {
+ if (delta == 0)
+ break;
+ for (testo = 5; testo < 33; testo++) {
+ vco = pllreffreq * (testn + 1) /
+ (testr + 1);
+ if (vco < vcomin)
+ continue;
+ if (vco > vcomax)
+ continue;
+ computed = vco / (m_div_val[testm] * (testo + 1));
+ if (computed > clock)
+ tmpdelta = computed - clock;
+ else
+ tmpdelta = clock - computed;
+ if (tmpdelta < delta) {
+ delta = tmpdelta;
+ m = (testm | (testo << 3)) + 1;
+ n = testn + 1;
+ p = testr + 1;
+ s = testr;
+ }
+ }
+ }
+ }
+ }
+
+ pixpllc->m = m;
+ pixpllc->n = n;
+ pixpllc->p = p;
+ pixpllc->s = s;
+
+ return 0;
+}
+
+static void mgag200_g200er_pixpllc_atomic_update(struct drm_crtc *crtc,
+ struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = to_mga_device(dev);
+ struct drm_crtc_state *crtc_state = crtc->state;
+ struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
+ struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
+ unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
+ u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
+
+ pixpllcm = pixpllc->m - 1;
+ pixpllcn = pixpllc->n - 1;
+ pixpllcp = pixpllc->p - 1;
+ pixpllcs = pixpllc->s;
+
+ xpixpllcm = pixpllcm;
+ xpixpllcn = pixpllcn;
+ xpixpllcp = (pixpllcs << 3) | pixpllcp;
+
+ WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
+ WREG8(DAC_DATA, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= MGA1064_REMHEADCTL_CLKDIS;
+ WREG8(DAC_DATA, tmp);
+
+ tmp = RREG8(MGAREG_MEM_MISC_READ);
+ tmp |= (0x3<<2) | 0xc0;
+ WREG8(MGAREG_MEM_MISC_WRITE, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
+ tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
+ WREG8(DAC_DATA, tmp);
+
+ udelay(500);
+
+ WREG_DAC(MGA1064_ER_PIX_PLLC_N, xpixpllcn);
+ WREG_DAC(MGA1064_ER_PIX_PLLC_M, xpixpllcm);
+ WREG_DAC(MGA1064_ER_PIX_PLLC_P, xpixpllcp);
+
+ udelay(50);
+}
+
+/*
+ * Mode-setting pipeline
+ */
+
+static const struct drm_plane_helper_funcs mgag200_g200er_primary_plane_helper_funcs = {
+ MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
+};
+
+static const struct drm_plane_funcs mgag200_g200er_primary_plane_funcs = {
+ MGAG200_PRIMARY_PLANE_FUNCS,
+};
+
+static void mgag200_g200er_crtc_helper_atomic_enable(struct drm_crtc *crtc,
+ struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = to_mga_device(dev);
+ const struct mgag200_device_funcs *funcs = mdev->funcs;
+ struct drm_crtc_state *crtc_state = crtc->state;
+ struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
+ struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
+ const struct drm_format_info *format = mgag200_crtc_state->format;
+
+ if (funcs->disable_vidrst)
+ funcs->disable_vidrst(mdev);
+
+ mgag200_set_format_regs(mdev, format);
+ mgag200_set_mode_regs(mdev, adjusted_mode);
+
+ if (funcs->pixpllc_atomic_update)
+ funcs->pixpllc_atomic_update(crtc, old_state);
+
+ mgag200_g200er_reset_tagfifo(mdev);
+
+ mgag200_enable_display(mdev);
+
+ if (funcs->enable_vidrst)
+ funcs->enable_vidrst(mdev);
+}
+
+static const struct drm_crtc_helper_funcs mgag200_g200er_crtc_helper_funcs = {
+ .mode_valid = mgag200_crtc_helper_mode_valid,
+ .atomic_check = mgag200_crtc_helper_atomic_check,
+ .atomic_flush = mgag200_crtc_helper_atomic_flush,
+ .atomic_enable = mgag200_g200er_crtc_helper_atomic_enable,
+ .atomic_disable = mgag200_crtc_helper_atomic_disable
+};
+
+static const struct drm_crtc_funcs mgag200_g200er_crtc_funcs = {
+ MGAG200_CRTC_FUNCS,
+};
+
+static const struct drm_encoder_funcs mgag200_g200er_dac_encoder_funcs = {
+ MGAG200_DAC_ENCODER_FUNCS,
+};
+
+static const struct drm_connector_helper_funcs mgag200_g200er_vga_connector_helper_funcs = {
+ MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
+};
+
+static const struct drm_connector_funcs mgag200_g200er_vga_connector_funcs = {
+ MGAG200_VGA_CONNECTOR_FUNCS,
+};
+
+static int mgag200_g200er_pipeline_init(struct mga_device *mdev)
+{
+ struct drm_device *dev = &mdev->base;
+ struct drm_plane *primary_plane = &mdev->primary_plane;
+ struct drm_crtc *crtc = &mdev->crtc;
+ struct drm_encoder *encoder = &mdev->encoder;
+ struct mga_i2c_chan *i2c = &mdev->i2c;
+ struct drm_connector *connector = &mdev->connector;
+ int ret;
+
+ ret = drm_universal_plane_init(dev, primary_plane, 0,
+ &mgag200_g200er_primary_plane_funcs,
+ mgag200_primary_plane_formats,
+ mgag200_primary_plane_formats_size,
+ mgag200_primary_plane_fmtmods,
+ DRM_PLANE_TYPE_PRIMARY, NULL);
+ if (ret) {
+ drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
+ return ret;
+ }
+ drm_plane_helper_add(primary_plane, &mgag200_g200er_primary_plane_helper_funcs);
+ drm_plane_enable_fb_damage_clips(primary_plane);
+
+ ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
+ &mgag200_g200er_crtc_funcs, NULL);
+ if (ret) {
+ drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
+ return ret;
+ }
+ drm_crtc_helper_add(crtc, &mgag200_g200er_crtc_helper_funcs);
+
+ /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
+ drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
+ drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
+
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
+ ret = drm_encoder_init(dev, encoder, &mgag200_g200er_dac_encoder_funcs,
+ DRM_MODE_ENCODER_DAC, NULL);
+ if (ret) {
+ drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = mgag200_i2c_init(mdev, i2c);
+ if (ret) {
+ drm_err(dev, "failed to add DDC bus: %d\n", ret);
+ return ret;
+ }
+
+ ret = drm_connector_init_with_ddc(dev, connector,
+ &mgag200_g200er_vga_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA,
+ &i2c->adapter);
+ if (ret) {
+ drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
+ return ret;
+ }
+ drm_connector_helper_add(connector, &mgag200_g200er_vga_connector_helper_funcs);
+
+ ret = drm_connector_attach_encoder(connector, encoder);
+ if (ret) {
+ drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
/*
* DRM device
*/
@@ -13,8 +307,12 @@
static const struct mgag200_device_info mgag200_g200er_device_info =
MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 1, 0, false);
-struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
- enum mga_type type)
+static const struct mgag200_device_funcs mgag200_g200er_device_funcs = {
+ .pixpllc_atomic_check = mgag200_g200er_pixpllc_atomic_check,
+ .pixpllc_atomic_update = mgag200_g200er_pixpllc_atomic_update,
+};
+
+struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv)
{
struct mga_device *mdev;
struct drm_device *dev;
@@ -32,15 +330,24 @@ struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const stru
if (ret)
return ERR_PTR(ret);
- ret = mgag200_device_init(mdev, type, &mgag200_g200er_device_info);
+ ret = mgag200_device_init(mdev, &mgag200_g200er_device_info,
+ &mgag200_g200er_device_funcs);
if (ret)
return ERR_PTR(ret);
+ mgag200_g200er_init_registers(mdev);
+
vram_available = mgag200_device_probe_vram(mdev);
- ret = mgag200_modeset_init(mdev, vram_available);
+ ret = mgag200_mode_config_init(mdev, vram_available);
if (ret)
return ERR_PTR(ret);
+ ret = mgag200_g200er_pipeline_init(mdev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ drm_mode_config_reset(dev);
+
return mdev;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ev.c b/drivers/gpu/drm/mgag200/mgag200_g200ev.c
index 5353422d0eef..ac957f42abe1 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200ev.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200ev.c
@@ -1,11 +1,306 @@
// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/delay.h>
#include <linux/pci.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_probe_helper.h>
#include "mgag200_drv.h"
+static void mgag200_g200ev_init_registers(struct mga_device *mdev)
+{
+ static const u8 dacvalue[] = {
+ MGAG200_DAC_DEFAULT(0x00,
+ MGA1064_PIX_CLK_CTL_SEL_PLL,
+ MGA1064_MISC_CTL_VGA8 | MGA1064_MISC_CTL_DAC_RAM_CS,
+ 0x00, 0x00, 0x00)
+ };
+
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {
+ if ((i <= 0x17) ||
+ (i == 0x1b) ||
+ (i == 0x1c) ||
+ ((i >= 0x1f) && (i <= 0x29)) ||
+ ((i >= 0x30) && (i <= 0x37)) ||
+ ((i >= 0x44) && (i <= 0x4e)))
+ continue;
+ WREG_DAC(i, dacvalue[i]);
+ }
+
+ mgag200_init_registers(mdev);
+}
+
+static void mgag200_g200ev_set_hiprilvl(struct mga_device *mdev)
+{
+ WREG_ECRT(0x06, 0x00);
+}
+
+/*
+ * PIXPLLC
+ */
+
+static int mgag200_g200ev_pixpllc_atomic_check(struct drm_crtc *crtc,
+ struct drm_atomic_state *new_state)
+{
+ static const unsigned int vcomax = 550000;
+ static const unsigned int vcomin = 150000;
+ static const unsigned int pllreffreq = 50000;
+
+ struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+ struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+ long clock = new_crtc_state->mode.clock;
+ struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
+ unsigned int delta, tmpdelta;
+ unsigned int testp, testm, testn;
+ unsigned int p, m, n, s;
+ unsigned int computed;
+
+ m = n = p = s = 0;
+ delta = 0xffffffff;
+
+ for (testp = 16; testp > 0; testp--) {
+ if (clock * testp > vcomax)
+ continue;
+ if (clock * testp < vcomin)
+ continue;
+
+ for (testn = 1; testn < 257; testn++) {
+ for (testm = 1; testm < 17; testm++) {
+ computed = (pllreffreq * testn) /
+ (testm * testp);
+ if (computed > clock)
+ tmpdelta = computed - clock;
+ else
+ tmpdelta = clock - computed;
+ if (tmpdelta < delta) {
+ delta = tmpdelta;
+ n = testn;
+ m = testm;
+ p = testp;
+ }
+ }
+ }
+ }
+
+ pixpllc->m = m;
+ pixpllc->n = n;
+ pixpllc->p = p;
+ pixpllc->s = s;
+
+ return 0;
+}
+
+static void mgag200_g200ev_pixpllc_atomic_update(struct drm_crtc *crtc,
+ struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = to_mga_device(dev);
+ struct drm_crtc_state *crtc_state = crtc->state;
+ struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
+ struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
+ unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
+ u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
+
+ pixpllcm = pixpllc->m - 1;
+ pixpllcn = pixpllc->n - 1;
+ pixpllcp = pixpllc->p - 1;
+ pixpllcs = pixpllc->s;
+
+ xpixpllcm = pixpllcm;
+ xpixpllcn = pixpllcn;
+ xpixpllcp = (pixpllcs << 3) | pixpllcp;
+
+ WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
+ WREG8(DAC_DATA, tmp);
+
+ tmp = RREG8(MGAREG_MEM_MISC_READ);
+ tmp |= 0x3 << 2;
+ WREG8(MGAREG_MEM_MISC_WRITE, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);
+ tmp = RREG8(DAC_DATA);
+ WREG8(DAC_DATA, tmp & ~0x40);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
+ WREG8(DAC_DATA, tmp);
+
+ WREG_DAC(MGA1064_EV_PIX_PLLC_M, xpixpllcm);
+ WREG_DAC(MGA1064_EV_PIX_PLLC_N, xpixpllcn);
+ WREG_DAC(MGA1064_EV_PIX_PLLC_P, xpixpllcp);
+
+ udelay(50);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
+ WREG8(DAC_DATA, tmp);
+
+ udelay(500);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
+ tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
+ WREG8(DAC_DATA, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);
+ tmp = RREG8(DAC_DATA);
+ WREG8(DAC_DATA, tmp | 0x40);
+
+ tmp = RREG8(MGAREG_MEM_MISC_READ);
+ tmp |= (0x3 << 2);
+ WREG8(MGAREG_MEM_MISC_WRITE, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
+ WREG8(DAC_DATA, tmp);
+}
+
+/*
+ * Mode-setting pipeline
+ */
+
+static const struct drm_plane_helper_funcs mgag200_g200ev_primary_plane_helper_funcs = {
+ MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
+};
+
+static const struct drm_plane_funcs mgag200_g200ev_primary_plane_funcs = {
+ MGAG200_PRIMARY_PLANE_FUNCS,
+};
+
+static void mgag200_g200ev_crtc_helper_atomic_enable(struct drm_crtc *crtc,
+ struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = to_mga_device(dev);
+ const struct mgag200_device_funcs *funcs = mdev->funcs;
+ struct drm_crtc_state *crtc_state = crtc->state;
+ struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
+ struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
+ const struct drm_format_info *format = mgag200_crtc_state->format;
+
+ if (funcs->disable_vidrst)
+ funcs->disable_vidrst(mdev);
+
+ mgag200_set_format_regs(mdev, format);
+ mgag200_set_mode_regs(mdev, adjusted_mode);
+
+ if (funcs->pixpllc_atomic_update)
+ funcs->pixpllc_atomic_update(crtc, old_state);
+
+ mgag200_g200ev_set_hiprilvl(mdev);
+
+ mgag200_enable_display(mdev);
+
+ if (funcs->enable_vidrst)
+ funcs->enable_vidrst(mdev);
+}
+
+static const struct drm_crtc_helper_funcs mgag200_g200ev_crtc_helper_funcs = {
+ .mode_valid = mgag200_crtc_helper_mode_valid,
+ .atomic_check = mgag200_crtc_helper_atomic_check,
+ .atomic_flush = mgag200_crtc_helper_atomic_flush,
+ .atomic_enable = mgag200_g200ev_crtc_helper_atomic_enable,
+ .atomic_disable = mgag200_crtc_helper_atomic_disable
+};
+
+static const struct drm_crtc_funcs mgag200_g200ev_crtc_funcs = {
+ MGAG200_CRTC_FUNCS,
+};
+
+static const struct drm_encoder_funcs mgag200_g200ev_dac_encoder_funcs = {
+ MGAG200_DAC_ENCODER_FUNCS,
+};
+
+static const struct drm_connector_helper_funcs mgag200_g200ev_vga_connector_helper_funcs = {
+ MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
+};
+
+static const struct drm_connector_funcs mgag200_g200ev_vga_connector_funcs = {
+ MGAG200_VGA_CONNECTOR_FUNCS,
+};
+
+static int mgag200_g200ev_pipeline_init(struct mga_device *mdev)
+{
+ struct drm_device *dev = &mdev->base;
+ struct drm_plane *primary_plane = &mdev->primary_plane;
+ struct drm_crtc *crtc = &mdev->crtc;
+ struct drm_encoder *encoder = &mdev->encoder;
+ struct mga_i2c_chan *i2c = &mdev->i2c;
+ struct drm_connector *connector = &mdev->connector;
+ int ret;
+
+ ret = drm_universal_plane_init(dev, primary_plane, 0,
+ &mgag200_g200ev_primary_plane_funcs,
+ mgag200_primary_plane_formats,
+ mgag200_primary_plane_formats_size,
+ mgag200_primary_plane_fmtmods,
+ DRM_PLANE_TYPE_PRIMARY, NULL);
+ if (ret) {
+ drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
+ return ret;
+ }
+ drm_plane_helper_add(primary_plane, &mgag200_g200ev_primary_plane_helper_funcs);
+ drm_plane_enable_fb_damage_clips(primary_plane);
+
+ ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
+ &mgag200_g200ev_crtc_funcs, NULL);
+ if (ret) {
+ drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
+ return ret;
+ }
+ drm_crtc_helper_add(crtc, &mgag200_g200ev_crtc_helper_funcs);
+
+ /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
+ drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
+ drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
+
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
+ ret = drm_encoder_init(dev, encoder, &mgag200_g200ev_dac_encoder_funcs,
+ DRM_MODE_ENCODER_DAC, NULL);
+ if (ret) {
+ drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = mgag200_i2c_init(mdev, i2c);
+ if (ret) {
+ drm_err(dev, "failed to add DDC bus: %d\n", ret);
+ return ret;
+ }
+
+ ret = drm_connector_init_with_ddc(dev, connector,
+ &mgag200_g200ev_vga_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA,
+ &i2c->adapter);
+ if (ret) {
+ drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
+ return ret;
+ }
+ drm_connector_helper_add(connector, &mgag200_g200ev_vga_connector_helper_funcs);
+
+ ret = drm_connector_attach_encoder(connector, encoder);
+ if (ret) {
+ drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
/*
* DRM device
*/
@@ -13,8 +308,12 @@
static const struct mgag200_device_info mgag200_g200ev_device_info =
MGAG200_DEVICE_INFO_INIT(2048, 2048, 32700, false, 0, 1, false);
-struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
- enum mga_type type)
+static const struct mgag200_device_funcs mgag200_g200ev_device_funcs = {
+ .pixpllc_atomic_check = mgag200_g200ev_pixpllc_atomic_check,
+ .pixpllc_atomic_update = mgag200_g200ev_pixpllc_atomic_update,
+};
+
+struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv)
{
struct mga_device *mdev;
struct drm_device *dev;
@@ -36,15 +335,24 @@ struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const stru
if (ret)
return ERR_PTR(ret);
- ret = mgag200_device_init(mdev, type, &mgag200_g200ev_device_info);
+ ret = mgag200_device_init(mdev, &mgag200_g200ev_device_info,
+ &mgag200_g200ev_device_funcs);
if (ret)
return ERR_PTR(ret);
+ mgag200_g200ev_init_registers(mdev);
+
vram_available = mgag200_device_probe_vram(mdev);
- ret = mgag200_modeset_init(mdev, vram_available);
+ ret = mgag200_mode_config_init(mdev, vram_available);
if (ret)
return ERR_PTR(ret);
+ ret = mgag200_g200ev_pipeline_init(mdev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ drm_mode_config_reset(dev);
+
return mdev;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c
index 3bfc1324cf78..170934414d7d 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200ew3.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200ew3.c
@@ -2,10 +2,179 @@
#include <linux/pci.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_probe_helper.h>
#include "mgag200_drv.h"
+static void mgag200_g200ew3_init_registers(struct mga_device *mdev)
+{
+ mgag200_g200wb_init_registers(mdev); // same as G200WB
+
+ WREG_ECRT(0x34, 0x5); // G200EW3 specific
+}
+
+/*
+ * PIXPLLC
+ */
+
+static int mgag200_g200ew3_pixpllc_atomic_check(struct drm_crtc *crtc,
+ struct drm_atomic_state *new_state)
+{
+ static const unsigned int vcomax = 800000;
+ static const unsigned int vcomin = 400000;
+ static const unsigned int pllreffreq = 25000;
+
+ struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+ struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+ long clock = new_crtc_state->mode.clock;
+ struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
+ unsigned int delta, tmpdelta;
+ unsigned int testp, testm, testn, testp2;
+ unsigned int p, m, n, s;
+ unsigned int computed;
+
+ m = n = p = s = 0;
+ delta = 0xffffffff;
+
+ for (testp = 1; testp < 8; testp++) {
+ for (testp2 = 1; testp2 < 8; testp2++) {
+ if (testp < testp2)
+ continue;
+ if ((clock * testp * testp2) > vcomax)
+ continue;
+ if ((clock * testp * testp2) < vcomin)
+ continue;
+ for (testm = 1; testm < 26; testm++) {
+ for (testn = 32; testn < 2048 ; testn++) {
+ computed = (pllreffreq * testn) / (testm * testp * testp2);
+ if (computed > clock)
+ tmpdelta = computed - clock;
+ else
+ tmpdelta = clock - computed;
+ if (tmpdelta < delta) {
+ delta = tmpdelta;
+ m = testm + 1;
+ n = testn + 1;
+ p = testp + 1;
+ s = testp2;
+ }
+ }
+ }
+ }
+ }
+
+ pixpllc->m = m;
+ pixpllc->n = n;
+ pixpllc->p = p;
+ pixpllc->s = s;
+
+ return 0;
+}
+
+/*
+ * Mode-setting pipeline
+ */
+
+static const struct drm_plane_helper_funcs mgag200_g200ew3_primary_plane_helper_funcs = {
+ MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
+};
+
+static const struct drm_plane_funcs mgag200_g200ew3_primary_plane_funcs = {
+ MGAG200_PRIMARY_PLANE_FUNCS,
+};
+
+static const struct drm_crtc_helper_funcs mgag200_g200ew3_crtc_helper_funcs = {
+ MGAG200_CRTC_HELPER_FUNCS,
+};
+
+static const struct drm_crtc_funcs mgag200_g200ew3_crtc_funcs = {
+ MGAG200_CRTC_FUNCS,
+};
+
+static const struct drm_encoder_funcs mgag200_g200ew3_dac_encoder_funcs = {
+ MGAG200_DAC_ENCODER_FUNCS,
+};
+
+static const struct drm_connector_helper_funcs mgag200_g200ew3_vga_connector_helper_funcs = {
+ MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
+};
+
+static const struct drm_connector_funcs mgag200_g200ew3_vga_connector_funcs = {
+ MGAG200_VGA_CONNECTOR_FUNCS,
+};
+
+static int mgag200_g200ew3_pipeline_init(struct mga_device *mdev)
+{
+ struct drm_device *dev = &mdev->base;
+ struct drm_plane *primary_plane = &mdev->primary_plane;
+ struct drm_crtc *crtc = &mdev->crtc;
+ struct drm_encoder *encoder = &mdev->encoder;
+ struct mga_i2c_chan *i2c = &mdev->i2c;
+ struct drm_connector *connector = &mdev->connector;
+ int ret;
+
+ ret = drm_universal_plane_init(dev, primary_plane, 0,
+ &mgag200_g200ew3_primary_plane_funcs,
+ mgag200_primary_plane_formats,
+ mgag200_primary_plane_formats_size,
+ mgag200_primary_plane_fmtmods,
+ DRM_PLANE_TYPE_PRIMARY, NULL);
+ if (ret) {
+ drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
+ return ret;
+ }
+ drm_plane_helper_add(primary_plane, &mgag200_g200ew3_primary_plane_helper_funcs);
+ drm_plane_enable_fb_damage_clips(primary_plane);
+
+ ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
+ &mgag200_g200ew3_crtc_funcs, NULL);
+ if (ret) {
+ drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
+ return ret;
+ }
+ drm_crtc_helper_add(crtc, &mgag200_g200ew3_crtc_helper_funcs);
+
+ /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
+ drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
+ drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
+
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
+ ret = drm_encoder_init(dev, encoder, &mgag200_g200ew3_dac_encoder_funcs,
+ DRM_MODE_ENCODER_DAC, NULL);
+ if (ret) {
+ drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = mgag200_i2c_init(mdev, i2c);
+ if (ret) {
+ drm_err(dev, "failed to add DDC bus: %d\n", ret);
+ return ret;
+ }
+
+ ret = drm_connector_init_with_ddc(dev, connector,
+ &mgag200_g200ew3_vga_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA,
+ &i2c->adapter);
+ if (ret) {
+ drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
+ return ret;
+ }
+ drm_connector_helper_add(connector, &mgag200_g200ew3_vga_connector_helper_funcs);
+
+ ret = drm_connector_attach_encoder(connector, encoder);
+ if (ret) {
+ drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
/*
* DRM device
*/
@@ -13,6 +182,13 @@
static const struct mgag200_device_info mgag200_g200ew3_device_info =
MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, true, 0, 1, false);
+static const struct mgag200_device_funcs mgag200_g200ew3_device_funcs = {
+ .disable_vidrst = mgag200_bmc_disable_vidrst,
+ .enable_vidrst = mgag200_bmc_enable_vidrst,
+ .pixpllc_atomic_check = mgag200_g200ew3_pixpllc_atomic_check,
+ .pixpllc_atomic_update = mgag200_g200wb_pixpllc_atomic_update, // same as G200WB
+};
+
static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev)
{
resource_size_t vram_size = resource_size(mdev->vram_res);
@@ -23,8 +199,7 @@ static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev
}
struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev,
- const struct drm_driver *drv,
- enum mga_type type)
+ const struct drm_driver *drv)
{
struct mga_device *mdev;
struct drm_device *dev;
@@ -46,15 +221,24 @@ struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev,
if (ret)
return ERR_PTR(ret);
- ret = mgag200_device_init(mdev, type, &mgag200_g200ew3_device_info);
+ ret = mgag200_device_init(mdev, &mgag200_g200ew3_device_info,
+ &mgag200_g200ew3_device_funcs);
if (ret)
return ERR_PTR(ret);
+ mgag200_g200ew3_init_registers(mdev);
+
vram_available = mgag200_g200ew3_device_probe_vram(mdev);
- ret = mgag200_modeset_init(mdev, vram_available);
+ ret = mgag200_mode_config_init(mdev, vram_available);
if (ret)
return ERR_PTR(ret);
+ ret = mgag200_g200ew3_pipeline_init(mdev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ drm_mode_config_reset(dev);
+
return mdev;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200se.c b/drivers/gpu/drm/mgag200/mgag200_g200se.c
index 0a3e66695e22..be389ed91cbd 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200se.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200se.c
@@ -1,8 +1,13 @@
// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/delay.h>
#include <linux/pci.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_probe_helper.h>
#include "mgag200_drv.h"
@@ -28,6 +33,404 @@ static int mgag200_g200se_init_pci_options(struct pci_dev *pdev)
return mgag200_init_pci_options(pdev, option, 0x00008000);
}
+static void mgag200_g200se_init_registers(struct mgag200_g200se_device *g200se)
+{
+ static const u8 dacvalue[] = {
+ MGAG200_DAC_DEFAULT(0x03,
+ MGA1064_PIX_CLK_CTL_SEL_PLL,
+ MGA1064_MISC_CTL_DAC_EN |
+ MGA1064_MISC_CTL_VGA8 |
+ MGA1064_MISC_CTL_DAC_RAM_CS,
+ 0x00, 0x00, 0x00)
+ };
+
+ struct mga_device *mdev = &g200se->base;
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {
+ if ((i <= 0x17) ||
+ (i == 0x1b) ||
+ (i == 0x1c) ||
+ ((i >= 0x1f) && (i <= 0x29)) ||
+ ((i == 0x2c) || (i == 0x2d) || (i == 0x2e)) ||
+ ((i >= 0x30) && (i <= 0x37)))
+ continue;
+ WREG_DAC(i, dacvalue[i]);
+ }
+
+ mgag200_init_registers(mdev);
+}
+
+static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev,
+ const struct drm_display_mode *mode,
+ const struct drm_format_info *format)
+{
+ struct mgag200_g200se_device *g200se = to_mgag200_g200se_device(&mdev->base);
+ unsigned int hiprilvl;
+ u8 crtcext6;
+
+ if (g200se->unique_rev_id >= 0x04) {
+ hiprilvl = 0;
+ } else if (g200se->unique_rev_id >= 0x02) {
+ unsigned int bpp;
+ unsigned long mb;
+
+ if (format->cpp[0] * 8 > 16)
+ bpp = 32;
+ else if (format->cpp[0] * 8 > 8)
+ bpp = 16;
+ else
+ bpp = 8;
+
+ mb = (mode->clock * bpp) / 1000;
+ if (mb > 3100)
+ hiprilvl = 0;
+ else if (mb > 2600)
+ hiprilvl = 1;
+ else if (mb > 1900)
+ hiprilvl = 2;
+ else if (mb > 1160)
+ hiprilvl = 3;
+ else if (mb > 440)
+ hiprilvl = 4;
+ else
+ hiprilvl = 5;
+
+ } else if (g200se->unique_rev_id >= 0x01) {
+ hiprilvl = 3;
+ } else {
+ hiprilvl = 4;
+ }
+
+ crtcext6 = hiprilvl; /* implicitly sets maxhipri to 0 */
+
+ WREG_ECRT(0x06, crtcext6);
+}
+
+/*
+ * PIXPLLC
+ */
+
+static int mgag200_g200se_00_pixpllc_atomic_check(struct drm_crtc *crtc,
+ struct drm_atomic_state *new_state)
+{
+ static const unsigned int vcomax = 320000;
+ static const unsigned int vcomin = 160000;
+ static const unsigned int pllreffreq = 25000;
+
+ struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+ struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+ long clock = new_crtc_state->mode.clock;
+ struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
+ unsigned int delta, tmpdelta, permitteddelta;
+ unsigned int testp, testm, testn;
+ unsigned int p, m, n, s;
+ unsigned int computed;
+
+ m = n = p = s = 0;
+ delta = 0xffffffff;
+ permitteddelta = clock * 5 / 1000;
+
+ for (testp = 8; testp > 0; testp /= 2) {
+ if (clock * testp > vcomax)
+ continue;
+ if (clock * testp < vcomin)
+ continue;
+
+ for (testn = 17; testn < 256; testn++) {
+ for (testm = 1; testm < 32; testm++) {
+ computed = (pllreffreq * testn) / (testm * testp);
+ if (computed > clock)
+ tmpdelta = computed - clock;
+ else
+ tmpdelta = clock - computed;
+ if (tmpdelta < delta) {
+ delta = tmpdelta;
+ m = testm;
+ n = testn;
+ p = testp;
+ }
+ }
+ }
+ }
+
+ if (delta > permitteddelta) {
+ pr_warn("PLL delta too large\n");
+ return -EINVAL;
+ }
+
+ pixpllc->m = m;
+ pixpllc->n = n;
+ pixpllc->p = p;
+ pixpllc->s = s;
+
+ return 0;
+}
+
+static void mgag200_g200se_00_pixpllc_atomic_update(struct drm_crtc *crtc,
+ struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = to_mga_device(dev);
+ struct drm_crtc_state *crtc_state = crtc->state;
+ struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
+ struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
+ unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
+ u8 xpixpllcm, xpixpllcn, xpixpllcp;
+
+ pixpllcm = pixpllc->m - 1;
+ pixpllcn = pixpllc->n - 1;
+ pixpllcp = pixpllc->p - 1;
+ pixpllcs = pixpllc->s;
+
+ xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1);
+ xpixpllcn = pixpllcn;
+ xpixpllcp = (pixpllcs << 3) | pixpllcp;
+
+ WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
+
+ WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
+ WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
+ WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
+}
+
+static int mgag200_g200se_04_pixpllc_atomic_check(struct drm_crtc *crtc,
+ struct drm_atomic_state *new_state)
+{
+ static const unsigned int vcomax = 1600000;
+ static const unsigned int vcomin = 800000;
+ static const unsigned int pllreffreq = 25000;
+ static const unsigned int pvalues_e4[] = {16, 14, 12, 10, 8, 6, 4, 2, 1};
+
+ struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+ struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+ long clock = new_crtc_state->mode.clock;
+ struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
+ unsigned int delta, tmpdelta, permitteddelta;
+ unsigned int testp, testm, testn;
+ unsigned int p, m, n, s;
+ unsigned int computed;
+ unsigned int fvv;
+ unsigned int i;
+
+ m = n = p = s = 0;
+ delta = 0xffffffff;
+
+ if (clock < 25000)
+ clock = 25000;
+ clock = clock * 2;
+
+ /* Permited delta is 0.5% as VESA Specification */
+ permitteddelta = clock * 5 / 1000;
+
+ for (i = 0 ; i < ARRAY_SIZE(pvalues_e4); i++) {
+ testp = pvalues_e4[i];
+
+ if ((clock * testp) > vcomax)
+ continue;
+ if ((clock * testp) < vcomin)
+ continue;
+
+ for (testn = 50; testn <= 256; testn++) {
+ for (testm = 1; testm <= 32; testm++) {
+ computed = (pllreffreq * testn) / (testm * testp);
+ if (computed > clock)
+ tmpdelta = computed - clock;
+ else
+ tmpdelta = clock - computed;
+
+ if (tmpdelta < delta) {
+ delta = tmpdelta;
+ m = testm;
+ n = testn;
+ p = testp;
+ }
+ }
+ }
+ }
+
+ fvv = pllreffreq * n / m;
+ fvv = (fvv - 800000) / 50000;
+ if (fvv > 15)
+ fvv = 15;
+ s = fvv << 1;
+
+ if (delta > permitteddelta) {
+ pr_warn("PLL delta too large\n");
+ return -EINVAL;
+ }
+
+ pixpllc->m = m;
+ pixpllc->n = n;
+ pixpllc->p = p;
+ pixpllc->s = s;
+
+ return 0;
+}
+
+static void mgag200_g200se_04_pixpllc_atomic_update(struct drm_crtc *crtc,
+ struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = to_mga_device(dev);
+ struct drm_crtc_state *crtc_state = crtc->state;
+ struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
+ struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
+ unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
+ u8 xpixpllcm, xpixpllcn, xpixpllcp;
+
+ pixpllcm = pixpllc->m - 1;
+ pixpllcn = pixpllc->n - 1;
+ pixpllcp = pixpllc->p - 1;
+ pixpllcs = pixpllc->s;
+
+ xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1);
+ xpixpllcn = pixpllcn;
+ xpixpllcp = (pixpllcs << 3) | pixpllcp;
+
+ WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
+
+ WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
+ WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
+ WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
+
+ WREG_DAC(0x1a, 0x09);
+ msleep(20);
+ WREG_DAC(0x1a, 0x01);
+}
+
+/*
+ * Mode-setting pipeline
+ */
+
+static const struct drm_plane_helper_funcs mgag200_g200se_primary_plane_helper_funcs = {
+ MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
+};
+
+static const struct drm_plane_funcs mgag200_g200se_primary_plane_funcs = {
+ MGAG200_PRIMARY_PLANE_FUNCS,
+};
+
+static void mgag200_g200se_crtc_helper_atomic_enable(struct drm_crtc *crtc,
+ struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = to_mga_device(dev);
+ const struct mgag200_device_funcs *funcs = mdev->funcs;
+ struct drm_crtc_state *crtc_state = crtc->state;
+ struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
+ struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
+ const struct drm_format_info *format = mgag200_crtc_state->format;
+
+ if (funcs->disable_vidrst)
+ funcs->disable_vidrst(mdev);
+
+ mgag200_set_format_regs(mdev, format);
+ mgag200_set_mode_regs(mdev, adjusted_mode);
+
+ if (funcs->pixpllc_atomic_update)
+ funcs->pixpllc_atomic_update(crtc, old_state);
+
+ mgag200_g200se_set_hiprilvl(mdev, adjusted_mode, format);
+
+ mgag200_enable_display(mdev);
+
+ if (funcs->enable_vidrst)
+ funcs->enable_vidrst(mdev);
+}
+
+static const struct drm_crtc_helper_funcs mgag200_g200se_crtc_helper_funcs = {
+ .mode_valid = mgag200_crtc_helper_mode_valid,
+ .atomic_check = mgag200_crtc_helper_atomic_check,
+ .atomic_flush = mgag200_crtc_helper_atomic_flush,
+ .atomic_enable = mgag200_g200se_crtc_helper_atomic_enable,
+ .atomic_disable = mgag200_crtc_helper_atomic_disable
+};
+
+static const struct drm_crtc_funcs mgag200_g200se_crtc_funcs = {
+ MGAG200_CRTC_FUNCS,
+};
+
+static const struct drm_encoder_funcs mgag200_g200se_dac_encoder_funcs = {
+ MGAG200_DAC_ENCODER_FUNCS,
+};
+
+static const struct drm_connector_helper_funcs mgag200_g200se_vga_connector_helper_funcs = {
+ MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
+};
+
+static const struct drm_connector_funcs mgag200_g200se_vga_connector_funcs = {
+ MGAG200_VGA_CONNECTOR_FUNCS,
+};
+
+static int mgag200_g200se_pipeline_init(struct mga_device *mdev)
+{
+ struct drm_device *dev = &mdev->base;
+ struct drm_plane *primary_plane = &mdev->primary_plane;
+ struct drm_crtc *crtc = &mdev->crtc;
+ struct drm_encoder *encoder = &mdev->encoder;
+ struct mga_i2c_chan *i2c = &mdev->i2c;
+ struct drm_connector *connector = &mdev->connector;
+ int ret;
+
+ ret = drm_universal_plane_init(dev, primary_plane, 0,
+ &mgag200_g200se_primary_plane_funcs,
+ mgag200_primary_plane_formats,
+ mgag200_primary_plane_formats_size,
+ mgag200_primary_plane_fmtmods,
+ DRM_PLANE_TYPE_PRIMARY, NULL);
+ if (ret) {
+ drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
+ return ret;
+ }
+ drm_plane_helper_add(primary_plane, &mgag200_g200se_primary_plane_helper_funcs);
+ drm_plane_enable_fb_damage_clips(primary_plane);
+
+ ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
+ &mgag200_g200se_crtc_funcs, NULL);
+ if (ret) {
+ drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
+ return ret;
+ }
+ drm_crtc_helper_add(crtc, &mgag200_g200se_crtc_helper_funcs);
+
+ /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
+ drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
+ drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
+
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
+ ret = drm_encoder_init(dev, encoder, &mgag200_g200se_dac_encoder_funcs,
+ DRM_MODE_ENCODER_DAC, NULL);
+ if (ret) {
+ drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = mgag200_i2c_init(mdev, i2c);
+ if (ret) {
+ drm_err(dev, "failed to add DDC bus: %d\n", ret);
+ return ret;
+ }
+
+ ret = drm_connector_init_with_ddc(dev, connector,
+ &mgag200_g200se_vga_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA,
+ &i2c->adapter);
+ if (ret) {
+ drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
+ return ret;
+ }
+ drm_connector_helper_add(connector, &mgag200_g200se_vga_connector_helper_funcs);
+
+ ret = drm_connector_attach_encoder(connector, encoder);
+ if (ret) {
+ drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
/*
* DRM device
*/
@@ -65,11 +468,22 @@ static int mgag200_g200se_init_unique_rev_id(struct mgag200_g200se_device *g200s
return 0;
}
+static const struct mgag200_device_funcs mgag200_g200se_00_device_funcs = {
+ .pixpllc_atomic_check = mgag200_g200se_00_pixpllc_atomic_check,
+ .pixpllc_atomic_update = mgag200_g200se_00_pixpllc_atomic_update,
+};
+
+static const struct mgag200_device_funcs mgag200_g200se_04_device_funcs = {
+ .pixpllc_atomic_check = mgag200_g200se_04_pixpllc_atomic_check,
+ .pixpllc_atomic_update = mgag200_g200se_04_pixpllc_atomic_update,
+};
+
struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
enum mga_type type)
{
struct mgag200_g200se_device *g200se;
const struct mgag200_device_info *info;
+ const struct mgag200_device_funcs *funcs;
struct mga_device *mdev;
struct drm_device *dev;
resource_size_t vram_available;
@@ -116,15 +530,28 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru
return ERR_PTR(-EINVAL);
}
- ret = mgag200_device_init(mdev, type, info);
+ if (g200se->unique_rev_id >= 0x04)
+ funcs = &mgag200_g200se_04_device_funcs;
+ else
+ funcs = &mgag200_g200se_00_device_funcs;
+
+ ret = mgag200_device_init(mdev, info, funcs);
if (ret)
return ERR_PTR(ret);
+ mgag200_g200se_init_registers(g200se);
+
vram_available = mgag200_device_probe_vram(mdev);
- ret = mgag200_modeset_init(mdev, vram_available);
+ ret = mgag200_mode_config_init(mdev, vram_available);
if (ret)
return ERR_PTR(ret);
+ ret = mgag200_g200se_pipeline_init(mdev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ drm_mode_config_reset(dev);
+
return mdev;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_g200wb.c b/drivers/gpu/drm/mgag200/mgag200_g200wb.c
index c8450ac8eaec..9baa727ac6f9 100644
--- a/drivers/gpu/drm/mgag200/mgag200_g200wb.c
+++ b/drivers/gpu/drm/mgag200/mgag200_g200wb.c
@@ -1,11 +1,314 @@
// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/delay.h>
#include <linux/pci.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_probe_helper.h>
#include "mgag200_drv.h"
+void mgag200_g200wb_init_registers(struct mga_device *mdev)
+{
+ static const u8 dacvalue[] = {
+ MGAG200_DAC_DEFAULT(0x07, 0xc9, 0x1f, 0x00, 0x00, 0x00)
+ };
+
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {
+ if ((i <= 0x17) ||
+ (i == 0x1b) ||
+ (i == 0x1c) ||
+ ((i >= 0x1f) && (i <= 0x29)) ||
+ ((i >= 0x30) && (i <= 0x37)) ||
+ ((i >= 0x44) && (i <= 0x4e)))
+ continue;
+ WREG_DAC(i, dacvalue[i]);
+ }
+
+ mgag200_init_registers(mdev);
+}
+
+/*
+ * PIXPLLC
+ */
+
+static int mgag200_g200wb_pixpllc_atomic_check(struct drm_crtc *crtc,
+ struct drm_atomic_state *new_state)
+{
+ static const unsigned int vcomax = 550000;
+ static const unsigned int vcomin = 150000;
+ static const unsigned int pllreffreq = 48000;
+
+ struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+ struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+ long clock = new_crtc_state->mode.clock;
+ struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
+ unsigned int delta, tmpdelta;
+ unsigned int testp, testm, testn;
+ unsigned int p, m, n, s;
+ unsigned int computed;
+
+ m = n = p = s = 0;
+ delta = 0xffffffff;
+
+ for (testp = 1; testp < 9; testp++) {
+ if (clock * testp > vcomax)
+ continue;
+ if (clock * testp < vcomin)
+ continue;
+
+ for (testm = 1; testm < 17; testm++) {
+ for (testn = 1; testn < 151; testn++) {
+ computed = (pllreffreq * testn) / (testm * testp);
+ if (computed > clock)
+ tmpdelta = computed - clock;
+ else
+ tmpdelta = clock - computed;
+ if (tmpdelta < delta) {
+ delta = tmpdelta;
+ n = testn;
+ m = testm;
+ p = testp;
+ s = 0;
+ }
+ }
+ }
+ }
+
+ pixpllc->m = m;
+ pixpllc->n = n;
+ pixpllc->p = p;
+ pixpllc->s = s;
+
+ return 0;
+}
+
+void mgag200_g200wb_pixpllc_atomic_update(struct drm_crtc *crtc,
+ struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = to_mga_device(dev);
+ struct drm_crtc_state *crtc_state = crtc->state;
+ struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
+ struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
+ bool pll_locked = false;
+ unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
+ u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
+ int i, j, tmpcount, vcount;
+
+ pixpllcm = pixpllc->m - 1;
+ pixpllcn = pixpllc->n - 1;
+ pixpllcp = pixpllc->p - 1;
+ pixpllcs = pixpllc->s;
+
+ xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm;
+ xpixpllcn = pixpllcn;
+ xpixpllcp = ((pixpllcn & GENMASK(10, 9)) >> 3) | (pixpllcs << 3) | pixpllcp;
+
+ WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
+
+ for (i = 0; i <= 32 && pll_locked == false; i++) {
+ if (i > 0) {
+ WREG8(MGAREG_CRTC_INDEX, 0x1e);
+ tmp = RREG8(MGAREG_CRTC_DATA);
+ if (tmp < 0xff)
+ WREG8(MGAREG_CRTC_DATA, tmp+1);
+ }
+
+ /* set pixclkdis to 1 */
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
+ WREG8(DAC_DATA, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= MGA1064_REMHEADCTL_CLKDIS;
+ WREG8(DAC_DATA, tmp);
+
+ /* select PLL Set C */
+ tmp = RREG8(MGAREG_MEM_MISC_READ);
+ tmp |= 0x3 << 2;
+ WREG8(MGAREG_MEM_MISC_WRITE, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80;
+ WREG8(DAC_DATA, tmp);
+
+ udelay(500);
+
+ /* reset the PLL */
+ WREG8(DAC_INDEX, MGA1064_VREF_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~0x04;
+ WREG8(DAC_DATA, tmp);
+
+ udelay(50);
+
+ /* program pixel pll register */
+ WREG_DAC(MGA1064_WB_PIX_PLLC_N, xpixpllcn);
+ WREG_DAC(MGA1064_WB_PIX_PLLC_M, xpixpllcm);
+ WREG_DAC(MGA1064_WB_PIX_PLLC_P, xpixpllcp);
+
+ udelay(50);
+
+ /* turn pll on */
+ WREG8(DAC_INDEX, MGA1064_VREF_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= 0x04;
+ WREG_DAC(MGA1064_VREF_CTL, tmp);
+
+ udelay(500);
+
+ /* select the pixel pll */
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
+ tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
+ WREG8(DAC_DATA, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_REMHEADCTL_CLKSL_MSK;
+ tmp |= MGA1064_REMHEADCTL_CLKSL_PLL;
+ WREG8(DAC_DATA, tmp);
+
+ /* reset dotclock rate bit */
+ WREG8(MGAREG_SEQ_INDEX, 1);
+ tmp = RREG8(MGAREG_SEQ_DATA);
+ tmp &= ~0x8;
+ WREG8(MGAREG_SEQ_DATA, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
+ WREG8(DAC_DATA, tmp);
+
+ vcount = RREG8(MGAREG_VCOUNT);
+
+ for (j = 0; j < 30 && pll_locked == false; j++) {
+ tmpcount = RREG8(MGAREG_VCOUNT);
+ if (tmpcount < vcount)
+ vcount = 0;
+ if ((tmpcount - vcount) > 2)
+ pll_locked = true;
+ else
+ udelay(5);
+ }
+ }
+
+ WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_REMHEADCTL_CLKDIS;
+ WREG_DAC(MGA1064_REMHEADCTL, tmp);
+}
+
+/*
+ * Mode-setting pipeline
+ */
+
+static const struct drm_plane_helper_funcs mgag200_g200wb_primary_plane_helper_funcs = {
+ MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
+};
+
+static const struct drm_plane_funcs mgag200_g200wb_primary_plane_funcs = {
+ MGAG200_PRIMARY_PLANE_FUNCS,
+};
+
+static const struct drm_crtc_helper_funcs mgag200_g200wb_crtc_helper_funcs = {
+ MGAG200_CRTC_HELPER_FUNCS,
+};
+
+static const struct drm_crtc_funcs mgag200_g200wb_crtc_funcs = {
+ MGAG200_CRTC_FUNCS,
+};
+
+static const struct drm_encoder_funcs mgag200_g200wb_dac_encoder_funcs = {
+ MGAG200_DAC_ENCODER_FUNCS,
+};
+
+static const struct drm_connector_helper_funcs mgag200_g200wb_vga_connector_helper_funcs = {
+ MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
+};
+
+static const struct drm_connector_funcs mgag200_g200wb_vga_connector_funcs = {
+ MGAG200_VGA_CONNECTOR_FUNCS,
+};
+
+static int mgag200_g200wb_pipeline_init(struct mga_device *mdev)
+{
+ struct drm_device *dev = &mdev->base;
+ struct drm_plane *primary_plane = &mdev->primary_plane;
+ struct drm_crtc *crtc = &mdev->crtc;
+ struct drm_encoder *encoder = &mdev->encoder;
+ struct mga_i2c_chan *i2c = &mdev->i2c;
+ struct drm_connector *connector = &mdev->connector;
+ int ret;
+
+ ret = drm_universal_plane_init(dev, primary_plane, 0,
+ &mgag200_g200wb_primary_plane_funcs,
+ mgag200_primary_plane_formats,
+ mgag200_primary_plane_formats_size,
+ mgag200_primary_plane_fmtmods,
+ DRM_PLANE_TYPE_PRIMARY, NULL);
+ if (ret) {
+ drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
+ return ret;
+ }
+ drm_plane_helper_add(primary_plane, &mgag200_g200wb_primary_plane_helper_funcs);
+ drm_plane_enable_fb_damage_clips(primary_plane);
+
+ ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
+ &mgag200_g200wb_crtc_funcs, NULL);
+ if (ret) {
+ drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
+ return ret;
+ }
+ drm_crtc_helper_add(crtc, &mgag200_g200wb_crtc_helper_funcs);
+
+ /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
+ drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
+ drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
+
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
+ ret = drm_encoder_init(dev, encoder, &mgag200_g200wb_dac_encoder_funcs,
+ DRM_MODE_ENCODER_DAC, NULL);
+ if (ret) {
+ drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = mgag200_i2c_init(mdev, i2c);
+ if (ret) {
+ drm_err(dev, "failed to add DDC bus: %d\n", ret);
+ return ret;
+ }
+
+ ret = drm_connector_init_with_ddc(dev, connector,
+ &mgag200_g200wb_vga_connector_funcs,
+ DRM_MODE_CONNECTOR_VGA,
+ &i2c->adapter);
+ if (ret) {
+ drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
+ return ret;
+ }
+ drm_connector_helper_add(connector, &mgag200_g200wb_vga_connector_helper_funcs);
+
+ ret = drm_connector_attach_encoder(connector, encoder);
+ if (ret) {
+ drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
/*
* DRM device
*/
@@ -13,8 +316,14 @@
static const struct mgag200_device_info mgag200_g200wb_device_info =
MGAG200_DEVICE_INFO_INIT(1280, 1024, 31877, true, 0, 1, false);
-struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
- enum mga_type type)
+static const struct mgag200_device_funcs mgag200_g200wb_device_funcs = {
+ .disable_vidrst = mgag200_bmc_disable_vidrst,
+ .enable_vidrst = mgag200_bmc_enable_vidrst,
+ .pixpllc_atomic_check = mgag200_g200wb_pixpllc_atomic_check,
+ .pixpllc_atomic_update = mgag200_g200wb_pixpllc_atomic_update,
+};
+
+struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv)
{
struct mga_device *mdev;
struct drm_device *dev;
@@ -36,15 +345,24 @@ struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const stru
if (ret)
return ERR_PTR(ret);
- ret = mgag200_device_init(mdev, type, &mgag200_g200wb_device_info);
+ ret = mgag200_device_init(mdev, &mgag200_g200wb_device_info,
+ &mgag200_g200wb_device_funcs);
if (ret)
return ERR_PTR(ret);
+ mgag200_g200wb_init_registers(mdev);
+
vram_available = mgag200_device_probe_vram(mdev);
- ret = mgag200_modeset_init(mdev, vram_available);
+ ret = mgag200_mode_config_init(mdev, vram_available);
if (ret)
return ERR_PTR(ret);
+ ret = mgag200_g200wb_pipeline_init(mdev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ drm_mode_config_reset(dev);
+
return mdev;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 225cca2ed60e..bbab2549243a 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -11,24 +11,19 @@
#include <linux/delay.h>
#include <linux/iosys-map.h>
+#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_atomic_state_helper.h>
-#include <drm/drm_crtc_helper.h>
#include <drm/drm_damage_helper.h>
#include <drm/drm_format_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
-#include <drm/drm_plane_helper.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
#include "mgag200_drv.h"
-#define MGAG200_LUT_SIZE 256
-
/*
* This file contains setup code for the CRTC.
*/
@@ -132,95 +127,6 @@ static inline void mga_wait_busy(struct mga_device *mdev)
} while ((status & 0x01) && time_before(jiffies, timeout));
}
-static void mgag200_g200wb_hold_bmc(struct mga_device *mdev)
-{
- u8 tmp;
- int iter_max;
-
- /* 1- The first step is to warn the BMC of an upcoming mode change.
- * We are putting the misc<0> to output.*/
-
- WREG8(DAC_INDEX, MGA1064_GEN_IO_CTL);
- tmp = RREG8(DAC_DATA);
- tmp |= 0x10;
- WREG_DAC(MGA1064_GEN_IO_CTL, tmp);
-
- /* we are putting a 1 on the misc<0> line */
- WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA);
- tmp = RREG8(DAC_DATA);
- tmp |= 0x10;
- WREG_DAC(MGA1064_GEN_IO_DATA, tmp);
-
- /* 2- Second step to mask and further scan request
- * This will be done by asserting the remfreqmsk bit (XSPAREREG<7>)
- */
- WREG8(DAC_INDEX, MGA1064_SPAREREG);
- tmp = RREG8(DAC_DATA);
- tmp |= 0x80;
- WREG_DAC(MGA1064_SPAREREG, tmp);
-
- /* 3a- the third step is to verifu if there is an active scan
- * We are searching for a 0 on remhsyncsts <XSPAREREG<0>)
- */
- iter_max = 300;
- while (!(tmp & 0x1) && iter_max) {
- WREG8(DAC_INDEX, MGA1064_SPAREREG);
- tmp = RREG8(DAC_DATA);
- udelay(1000);
- iter_max--;
- }
-
- /* 3b- this step occurs only if the remove is actually scanning
- * we are waiting for the end of the frame which is a 1 on
- * remvsyncsts (XSPAREREG<1>)
- */
- if (iter_max) {
- iter_max = 300;
- while ((tmp & 0x2) && iter_max) {
- WREG8(DAC_INDEX, MGA1064_SPAREREG);
- tmp = RREG8(DAC_DATA);
- udelay(1000);
- iter_max--;
- }
- }
-}
-
-static void mgag200_g200wb_release_bmc(struct mga_device *mdev)
-{
- u8 tmp;
-
- /* 1- The first step is to ensure that the vrsten and hrsten are set */
- WREG8(MGAREG_CRTCEXT_INDEX, 1);
- tmp = RREG8(MGAREG_CRTCEXT_DATA);
- WREG8(MGAREG_CRTCEXT_DATA, tmp | 0x88);
-
- /* 2- second step is to assert the rstlvl2 */
- WREG8(DAC_INDEX, MGA1064_REMHEADCTL2);
- tmp = RREG8(DAC_DATA);
- tmp |= 0x8;
- WREG8(DAC_DATA, tmp);
-
- /* wait 10 us */
- udelay(10);
-
- /* 3- deassert rstlvl2 */
- tmp &= ~0x08;
- WREG8(DAC_INDEX, MGA1064_REMHEADCTL2);
- WREG8(DAC_DATA, tmp);
-
- /* 4- remove mask of scan request */
- WREG8(DAC_INDEX, MGA1064_SPAREREG);
- tmp = RREG8(DAC_DATA);
- tmp &= ~0x80;
- WREG8(DAC_DATA, tmp);
-
- /* 5- put back a 0 on the misc<0> line */
- WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA);
- tmp = RREG8(DAC_DATA);
- tmp &= ~0x10;
- WREG_DAC(MGA1064_GEN_IO_DATA, tmp);
-}
-
/*
* This is how the framebuffer base address is stored in g200 cards:
* * Assume @offset is the gpu_addr variable of the framebuffer object
@@ -267,86 +173,10 @@ static void mgag200_set_startadd(struct mga_device *mdev,
WREG_ECRT(0x00, crtcext0);
}
-static void mgag200_set_dac_regs(struct mga_device *mdev)
-{
- size_t i;
- u8 dacvalue[] = {
- /* 0x00: */ 0, 0, 0, 0, 0, 0, 0x00, 0,
- /* 0x08: */ 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x10: */ 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x18: */ 0x00, 0, 0xC9, 0xFF, 0xBF, 0x20, 0x1F, 0x20,
- /* 0x20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* 0x28: */ 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x40,
- /* 0x30: */ 0x00, 0xB0, 0x00, 0xC2, 0x34, 0x14, 0x02, 0x83,
- /* 0x38: */ 0x00, 0x93, 0x00, 0x77, 0x00, 0x00, 0x00, 0x3A,
- /* 0x40: */ 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x48: */ 0, 0, 0, 0, 0, 0, 0, 0
- };
-
- switch (mdev->type) {
- case G200_PCI:
- case G200_AGP:
- dacvalue[MGA1064_SYS_PLL_M] = 0x04;
- dacvalue[MGA1064_SYS_PLL_N] = 0x2D;
- dacvalue[MGA1064_SYS_PLL_P] = 0x19;
- break;
- case G200_SE_A:
- case G200_SE_B:
- dacvalue[MGA1064_VREF_CTL] = 0x03;
- dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL;
- dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_DAC_EN |
- MGA1064_MISC_CTL_VGA8 |
- MGA1064_MISC_CTL_DAC_RAM_CS;
- break;
- case G200_WB:
- case G200_EW3:
- dacvalue[MGA1064_VREF_CTL] = 0x07;
- break;
- case G200_EV:
- dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL;
- dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 |
- MGA1064_MISC_CTL_DAC_RAM_CS;
- break;
- case G200_EH:
- case G200_EH3:
- dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 |
- MGA1064_MISC_CTL_DAC_RAM_CS;
- break;
- case G200_ER:
- break;
- }
-
- for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {
- if ((i <= 0x17) ||
- (i == 0x1b) ||
- (i == 0x1c) ||
- ((i >= 0x1f) && (i <= 0x29)) ||
- ((i >= 0x30) && (i <= 0x37)))
- continue;
- if (IS_G200_SE(mdev) &&
- ((i == 0x2c) || (i == 0x2d) || (i == 0x2e)))
- continue;
- if ((mdev->type == G200_EV ||
- mdev->type == G200_WB ||
- mdev->type == G200_EH ||
- mdev->type == G200_EW3 ||
- mdev->type == G200_EH3) &&
- (i >= 0x44) && (i <= 0x4e))
- continue;
-
- WREG_DAC(i, dacvalue[i]);
- }
-
- if (mdev->type == G200_ER)
- WREG_DAC(0x90, 0);
-}
-
-static void mgag200_init_regs(struct mga_device *mdev)
+void mgag200_init_registers(struct mga_device *mdev)
{
u8 crtc11, misc;
- mgag200_set_dac_regs(mdev);
-
WREG_SEQ(2, 0x0f);
WREG_SEQ(3, 0x00);
WREG_SEQ(4, 0x0e);
@@ -364,19 +194,12 @@ static void mgag200_init_regs(struct mga_device *mdev)
MGAREG_CRTC11_VINTCLR);
WREG_CRT(0x11, crtc11);
- if (mdev->type == G200_ER)
- WREG_ECRT(0x24, 0x5);
-
- if (mdev->type == G200_EW3)
- WREG_ECRT(0x34, 0x5);
-
misc = RREG8(MGA_MISC_IN);
misc |= MGAREG_MISC_IOADSEL;
WREG8(MGA_MISC_OUT, misc);
}
-static void mgag200_set_mode_regs(struct mga_device *mdev,
- const struct drm_display_mode *mode)
+void mgag200_set_mode_regs(struct mga_device *mdev, const struct drm_display_mode *mode)
{
const struct mgag200_device_info *info = mdev->info;
unsigned int hdisplay, hsyncstart, hsyncend, htotal;
@@ -500,11 +323,9 @@ static void mgag200_set_offset(struct mga_device *mdev,
WREG_ECRT(0x00, crtcext0);
}
-static void mgag200_set_format_regs(struct mga_device *mdev,
- const struct drm_framebuffer *fb)
+void mgag200_set_format_regs(struct mga_device *mdev, const struct drm_format_info *format)
{
struct drm_device *dev = &mdev->base;
- const struct drm_format_info *format = fb->format;
unsigned int bpp, bppshift, scale;
u8 crtcext3, xmulctrl;
@@ -565,76 +386,9 @@ static void mgag200_set_format_regs(struct mga_device *mdev,
WREG_ECRT(3, crtcext3);
}
-static void mgag200_g200er_reset_tagfifo(struct mga_device *mdev)
+void mgag200_enable_display(struct mga_device *mdev)
{
- static uint32_t RESET_FLAG = 0x00200000; /* undocumented magic value */
- u32 memctl;
-
- memctl = RREG32(MGAREG_MEMCTL);
-
- memctl |= RESET_FLAG;
- WREG32(MGAREG_MEMCTL, memctl);
-
- udelay(1000);
-
- memctl &= ~RESET_FLAG;
- WREG32(MGAREG_MEMCTL, memctl);
-}
-
-static void mgag200_g200se_set_hiprilvl(struct mga_device *mdev,
- const struct drm_display_mode *mode,
- const struct drm_framebuffer *fb)
-{
- struct mgag200_g200se_device *g200se = to_mgag200_g200se_device(&mdev->base);
- unsigned int hiprilvl;
- u8 crtcext6;
-
- if (g200se->unique_rev_id >= 0x04) {
- hiprilvl = 0;
- } else if (g200se->unique_rev_id >= 0x02) {
- unsigned int bpp;
- unsigned long mb;
-
- if (fb->format->cpp[0] * 8 > 16)
- bpp = 32;
- else if (fb->format->cpp[0] * 8 > 8)
- bpp = 16;
- else
- bpp = 8;
-
- mb = (mode->clock * bpp) / 1000;
- if (mb > 3100)
- hiprilvl = 0;
- else if (mb > 2600)
- hiprilvl = 1;
- else if (mb > 1900)
- hiprilvl = 2;
- else if (mb > 1160)
- hiprilvl = 3;
- else if (mb > 440)
- hiprilvl = 4;
- else
- hiprilvl = 5;
-
- } else if (g200se->unique_rev_id >= 0x01) {
- hiprilvl = 3;
- } else {
- hiprilvl = 4;
- }
-
- crtcext6 = hiprilvl; /* implicitly sets maxhipri to 0 */
-
- WREG_ECRT(0x06, crtcext6);
-}
-
-static void mgag200_g200ev_set_hiprilvl(struct mga_device *mdev)
-{
- WREG_ECRT(0x06, 0x00);
-}
-
-static void mgag200_enable_display(struct mga_device *mdev)
-{
- u8 seq0, seq1, crtcext1;
+ u8 seq0, crtcext1;
RREG_SEQ(0x00, seq0);
seq0 |= MGAREG_SEQ0_SYNCRST |
@@ -648,12 +402,6 @@ static void mgag200_enable_display(struct mga_device *mdev)
mga_wait_vsync(mdev);
mga_wait_busy(mdev);
- RREG_SEQ(0x01, seq1);
- seq1 &= ~MGAREG_SEQ1_SCROFF;
- WREG_SEQ(0x01, seq1);
-
- msleep(20);
-
RREG_ECRT(0x01, crtcext1);
crtcext1 &= ~MGAREG_CRTCEXT1_VSYNCOFF;
crtcext1 &= ~MGAREG_CRTCEXT1_HSYNCOFF;
@@ -662,7 +410,7 @@ static void mgag200_enable_display(struct mga_device *mdev)
static void mgag200_disable_display(struct mga_device *mdev)
{
- u8 seq0, seq1, crtcext1;
+ u8 seq0, crtcext1;
RREG_SEQ(0x00, seq0);
seq0 &= ~MGAREG_SEQ0_SYNCRST;
@@ -675,59 +423,127 @@ static void mgag200_disable_display(struct mga_device *mdev)
mga_wait_vsync(mdev);
mga_wait_busy(mdev);
- RREG_SEQ(0x01, seq1);
- seq1 |= MGAREG_SEQ1_SCROFF;
- WREG_SEQ(0x01, seq1);
-
- msleep(20);
-
RREG_ECRT(0x01, crtcext1);
crtcext1 |= MGAREG_CRTCEXT1_VSYNCOFF |
MGAREG_CRTCEXT1_HSYNCOFF;
WREG_ECRT(0x01, crtcext1);
}
+static void mgag200_handle_damage(struct mga_device *mdev, const struct iosys_map *vmap,
+ struct drm_framebuffer *fb, struct drm_rect *clip)
+{
+ struct iosys_map dst = IOSYS_MAP_INIT_VADDR_IOMEM(mdev->vram);
+
+ iosys_map_incr(&dst, drm_fb_clip_offset(fb->pitches[0], fb->format, clip));
+ drm_fb_memcpy(&dst, fb->pitches, vmap, fb, clip);
+}
+
/*
- * Connector
+ * Primary plane
*/
-static int mgag200_vga_connector_helper_get_modes(struct drm_connector *connector)
+const uint32_t mgag200_primary_plane_formats[] = {
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_RGB888,
+};
+
+const size_t mgag200_primary_plane_formats_size = ARRAY_SIZE(mgag200_primary_plane_formats);
+
+const uint64_t mgag200_primary_plane_fmtmods[] = {
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID
+};
+
+int mgag200_primary_plane_helper_atomic_check(struct drm_plane *plane,
+ struct drm_atomic_state *new_state)
{
- struct mga_device *mdev = to_mga_device(connector->dev);
+ struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane);
+ struct drm_framebuffer *new_fb = new_plane_state->fb;
+ struct drm_framebuffer *fb = NULL;
+ struct drm_crtc *new_crtc = new_plane_state->crtc;
+ struct drm_crtc_state *new_crtc_state = NULL;
+ struct mgag200_crtc_state *new_mgag200_crtc_state;
int ret;
- /*
- * Protect access to I/O registers from concurrent modesetting
- * by acquiring the I/O-register lock.
- */
- mutex_lock(&mdev->rmmio_lock);
- ret = drm_connector_helper_get_modes_from_ddc(connector);
- mutex_unlock(&mdev->rmmio_lock);
+ if (new_crtc)
+ new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_crtc);
- return ret;
+ ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,
+ DRM_PLANE_NO_SCALING,
+ DRM_PLANE_NO_SCALING,
+ false, true);
+ if (ret)
+ return ret;
+ else if (!new_plane_state->visible)
+ return 0;
+
+ if (plane->state)
+ fb = plane->state->fb;
+
+ if (!fb || (fb->format != new_fb->format))
+ new_crtc_state->mode_changed = true; /* update PLL settings */
+
+ new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
+ new_mgag200_crtc_state->format = new_fb->format;
+
+ return 0;
}
-static const struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = {
- .get_modes = mgag200_vga_connector_helper_get_modes,
-};
+void mgag200_primary_plane_helper_atomic_update(struct drm_plane *plane,
+ struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = plane->dev;
+ struct mga_device *mdev = to_mga_device(dev);
+ struct drm_plane_state *plane_state = plane->state;
+ struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(old_state, plane);
+ struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
+ struct drm_framebuffer *fb = plane_state->fb;
+ struct drm_atomic_helper_damage_iter iter;
+ struct drm_rect damage;
+ u8 seq1;
-static const struct drm_connector_funcs mga_vga_connector_funcs = {
- .reset = drm_atomic_helper_connector_reset,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = drm_connector_cleanup,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
+ if (!fb)
+ return;
+
+ drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
+ drm_atomic_for_each_plane_damage(&iter, &damage) {
+ mgag200_handle_damage(mdev, shadow_plane_state->data, fb, &damage);
+ }
+
+ /* Always scanout image at VRAM offset 0 */
+ mgag200_set_startadd(mdev, (u32)0);
+ mgag200_set_offset(mdev, fb);
+
+ if (!old_plane_state->crtc && plane_state->crtc) { // enabling
+ RREG_SEQ(0x01, seq1);
+ seq1 &= ~MGAREG_SEQ1_SCROFF;
+ WREG_SEQ(0x01, seq1);
+ msleep(20);
+ }
+}
+
+void mgag200_primary_plane_helper_atomic_disable(struct drm_plane *plane,
+ struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = plane->dev;
+ struct mga_device *mdev = to_mga_device(dev);
+ u8 seq1;
+
+ RREG_SEQ(0x01, seq1);
+ seq1 |= MGAREG_SEQ1_SCROFF;
+ WREG_SEQ(0x01, seq1);
+ msleep(20);
+}
/*
- * Simple Display Pipe
+ * CRTC
*/
-static enum drm_mode_status
-mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
- const struct drm_display_mode *mode)
+enum drm_mode_status mgag200_crtc_helper_mode_valid(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode)
{
- struct mga_device *mdev = to_mga_device(pipe->crtc.dev);
+ struct mga_device *mdev = to_mga_device(crtc->dev);
const struct mgag200_device_info *info = mdev->info;
/*
@@ -754,167 +570,112 @@ mgag200_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
return MODE_OK;
}
-static void
-mgag200_handle_damage(struct mga_device *mdev, struct drm_framebuffer *fb,
- struct drm_rect *clip, const struct iosys_map *map)
-{
- void __iomem *dst = mdev->vram;
- void *vmap = map->vaddr; /* TODO: Use mapping abstraction properly */
-
- dst += drm_fb_clip_offset(fb->pitches[0], fb->format, clip);
- drm_fb_memcpy_toio(dst, fb->pitches[0], vmap, fb, clip);
-}
-
-static void
-mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
- struct drm_crtc_state *crtc_state,
- struct drm_plane_state *plane_state)
+int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state)
{
- struct drm_crtc *crtc = &pipe->crtc;
struct drm_device *dev = crtc->dev;
struct mga_device *mdev = to_mga_device(dev);
- struct mgag200_pll *pixpll = &mdev->pixpll;
- struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
- struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
- struct drm_framebuffer *fb = plane_state->fb;
- struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
- struct drm_rect fullscreen = {
- .x1 = 0,
- .x2 = fb->width,
- .y1 = 0,
- .y2 = fb->height,
- };
-
- /*
- * Concurrent operations could possibly trigger a call to
- * drm_connector_helper_funcs.get_modes by trying to read the
- * display modes. Protect access to I/O registers by acquiring
- * the I/O-register lock.
- */
- mutex_lock(&mdev->rmmio_lock);
-
- if (mdev->type == G200_WB || mdev->type == G200_EW3)
- mgag200_g200wb_hold_bmc(mdev);
-
- mgag200_set_format_regs(mdev, fb);
- mgag200_set_mode_regs(mdev, adjusted_mode);
-
- pixpll->funcs->update(pixpll, &mgag200_crtc_state->pixpllc);
-
- if (mdev->type == G200_ER)
- mgag200_g200er_reset_tagfifo(mdev);
-
- if (IS_G200_SE(mdev))
- mgag200_g200se_set_hiprilvl(mdev, adjusted_mode, fb);
- else if (mdev->type == G200_EV)
- mgag200_g200ev_set_hiprilvl(mdev);
-
- if (mdev->type == G200_WB || mdev->type == G200_EW3)
- mgag200_g200wb_release_bmc(mdev);
+ const struct mgag200_device_funcs *funcs = mdev->funcs;
+ struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
+ struct drm_property_blob *new_gamma_lut = new_crtc_state->gamma_lut;
+ int ret;
- if (crtc_state->gamma_lut)
- mgag200_crtc_set_gamma(mdev, fb->format, crtc_state->gamma_lut->data);
- else
- mgag200_crtc_set_gamma_linear(mdev, fb->format);
+ ret = drm_atomic_helper_check_crtc_state(new_crtc_state, false);
+ if (ret)
+ return ret;
- mgag200_enable_display(mdev);
+ if (!new_crtc_state->enable)
+ return 0;
- mgag200_handle_damage(mdev, fb, &fullscreen, &shadow_plane_state->data[0]);
+ if (new_crtc_state->mode_changed) {
+ if (funcs->pixpllc_atomic_check) {
+ ret = funcs->pixpllc_atomic_check(crtc, new_state);
+ if (ret)
+ return ret;
+ }
+ }
- /* Always scanout image at VRAM offset 0 */
- mgag200_set_startadd(mdev, (u32)0);
- mgag200_set_offset(mdev, fb);
+ if (new_crtc_state->color_mgmt_changed && new_gamma_lut) {
+ if (new_gamma_lut->length != MGAG200_LUT_SIZE * sizeof(struct drm_color_lut)) {
+ drm_dbg(dev, "Wrong size for gamma_lut %zu\n", new_gamma_lut->length);
+ return -EINVAL;
+ }
+ }
- mutex_unlock(&mdev->rmmio_lock);
+ return drm_atomic_add_affected_planes(new_state, crtc);
}
-static void
-mgag200_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
+void mgag200_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *old_state)
{
- struct drm_crtc *crtc = &pipe->crtc;
- struct mga_device *mdev = to_mga_device(crtc->dev);
+ struct drm_crtc_state *crtc_state = crtc->state;
+ struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = to_mga_device(dev);
- mgag200_disable_display(mdev);
+ if (crtc_state->enable && crtc_state->color_mgmt_changed) {
+ const struct drm_format_info *format = mgag200_crtc_state->format;
+
+ if (crtc_state->gamma_lut)
+ mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut->data);
+ else
+ mgag200_crtc_set_gamma_linear(mdev, format);
+ }
}
-static int
-mgag200_simple_display_pipe_check(struct drm_simple_display_pipe *pipe,
- struct drm_plane_state *plane_state,
- struct drm_crtc_state *crtc_state)
+void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *old_state)
{
- struct drm_plane *plane = plane_state->plane;
- struct drm_device *dev = plane->dev;
+ struct drm_device *dev = crtc->dev;
struct mga_device *mdev = to_mga_device(dev);
- struct mgag200_pll *pixpll = &mdev->pixpll;
+ const struct mgag200_device_funcs *funcs = mdev->funcs;
+ struct drm_crtc_state *crtc_state = crtc->state;
+ struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
- struct drm_framebuffer *new_fb = plane_state->fb;
- struct drm_framebuffer *fb = NULL;
- int ret;
+ const struct drm_format_info *format = mgag200_crtc_state->format;
- if (!new_fb)
- return 0;
+ if (funcs->disable_vidrst)
+ funcs->disable_vidrst(mdev);
- if (plane->state)
- fb = plane->state->fb;
+ mgag200_set_format_regs(mdev, format);
+ mgag200_set_mode_regs(mdev, adjusted_mode);
- if (!fb || (fb->format != new_fb->format))
- crtc_state->mode_changed = true; /* update PLL settings */
+ if (funcs->pixpllc_atomic_update)
+ funcs->pixpllc_atomic_update(crtc, old_state);
- if (crtc_state->mode_changed) {
- ret = pixpll->funcs->compute(pixpll, crtc_state->mode.clock,
- &mgag200_crtc_state->pixpllc);
- if (ret)
- return ret;
- }
+ mgag200_enable_display(mdev);
- if (crtc_state->color_mgmt_changed && crtc_state->gamma_lut) {
- if (crtc_state->gamma_lut->length !=
- MGAG200_LUT_SIZE * sizeof(struct drm_color_lut)) {
- drm_err(dev, "Wrong size for gamma_lut %zu\n",
- crtc_state->gamma_lut->length);
- return -EINVAL;
- }
- }
- return 0;
+ if (funcs->enable_vidrst)
+ funcs->enable_vidrst(mdev);
}
-static void
-mgag200_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
- struct drm_plane_state *old_state)
+void mgag200_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *old_state)
{
- struct drm_plane *plane = &pipe->plane;
- struct drm_crtc *crtc = &pipe->crtc;
- struct drm_device *dev = plane->dev;
- struct mga_device *mdev = to_mga_device(dev);
- struct drm_plane_state *state = plane->state;
- struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state);
- struct drm_framebuffer *fb = state->fb;
- struct drm_rect damage;
- struct drm_atomic_helper_damage_iter iter;
+ struct mga_device *mdev = to_mga_device(crtc->dev);
+ const struct mgag200_device_funcs *funcs = mdev->funcs;
- if (!fb)
- return;
+ if (funcs->disable_vidrst)
+ funcs->disable_vidrst(mdev);
- mutex_lock(&mdev->rmmio_lock);
+ mgag200_disable_display(mdev);
- if (crtc->state->color_mgmt_changed && crtc->state->gamma_lut)
- mgag200_crtc_set_gamma(mdev, fb->format, crtc->state->gamma_lut->data);
+ if (funcs->enable_vidrst)
+ funcs->enable_vidrst(mdev);
+}
- drm_atomic_helper_damage_iter_init(&iter, old_state, state);
- drm_atomic_for_each_plane_damage(&iter, &damage) {
- mgag200_handle_damage(mdev, fb, &damage, &shadow_plane_state->data[0]);
- }
- /* Always scanout image at VRAM offset 0 */
- mgag200_set_startadd(mdev, (u32)0);
- mgag200_set_offset(mdev, fb);
+void mgag200_crtc_reset(struct drm_crtc *crtc)
+{
+ struct mgag200_crtc_state *mgag200_crtc_state;
- mutex_unlock(&mdev->rmmio_lock);
+ if (crtc->state)
+ crtc->funcs->atomic_destroy_state(crtc, crtc->state);
+
+ mgag200_crtc_state = kzalloc(sizeof(*mgag200_crtc_state), GFP_KERNEL);
+ if (mgag200_crtc_state)
+ __drm_atomic_helper_crtc_reset(crtc, &mgag200_crtc_state->base);
+ else
+ __drm_atomic_helper_crtc_reset(crtc, NULL);
}
-static struct drm_crtc_state *
-mgag200_simple_display_pipe_duplicate_crtc_state(struct drm_simple_display_pipe *pipe)
+struct drm_crtc_state *mgag200_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
{
- struct drm_crtc *crtc = &pipe->crtc;
struct drm_crtc_state *crtc_state = crtc->state;
struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
struct mgag200_crtc_state *new_mgag200_crtc_state;
@@ -927,14 +688,14 @@ mgag200_simple_display_pipe_duplicate_crtc_state(struct drm_simple_display_pipe
return NULL;
__drm_atomic_helper_crtc_duplicate_state(crtc, &new_mgag200_crtc_state->base);
+ new_mgag200_crtc_state->format = mgag200_crtc_state->format;
memcpy(&new_mgag200_crtc_state->pixpllc, &mgag200_crtc_state->pixpllc,
sizeof(new_mgag200_crtc_state->pixpllc));
return &new_mgag200_crtc_state->base;
}
-static void mgag200_simple_display_pipe_destroy_crtc_state(struct drm_simple_display_pipe *pipe,
- struct drm_crtc_state *crtc_state)
+void mgag200_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state)
{
struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
@@ -942,50 +703,49 @@ static void mgag200_simple_display_pipe_destroy_crtc_state(struct drm_simple_dis
kfree(mgag200_crtc_state);
}
-static void mgag200_simple_display_pipe_reset_crtc(struct drm_simple_display_pipe *pipe)
+/*
+ * Connector
+ */
+
+int mgag200_vga_connector_helper_get_modes(struct drm_connector *connector)
{
- struct drm_crtc *crtc = &pipe->crtc;
- struct mgag200_crtc_state *mgag200_crtc_state;
+ struct mga_device *mdev = to_mga_device(connector->dev);
+ int ret;
- if (crtc->state) {
- mgag200_simple_display_pipe_destroy_crtc_state(pipe, crtc->state);
- crtc->state = NULL; /* must be set to NULL here */
- }
+ /*
+ * Protect access to I/O registers from concurrent modesetting
+ * by acquiring the I/O-register lock.
+ */
+ mutex_lock(&mdev->rmmio_lock);
+ ret = drm_connector_helper_get_modes_from_ddc(connector);
+ mutex_unlock(&mdev->rmmio_lock);
- mgag200_crtc_state = kzalloc(sizeof(*mgag200_crtc_state), GFP_KERNEL);
- if (!mgag200_crtc_state)
- return;
- __drm_atomic_helper_crtc_reset(crtc, &mgag200_crtc_state->base);
+ return ret;
}
-static const struct drm_simple_display_pipe_funcs
-mgag200_simple_display_pipe_funcs = {
- .mode_valid = mgag200_simple_display_pipe_mode_valid,
- .enable = mgag200_simple_display_pipe_enable,
- .disable = mgag200_simple_display_pipe_disable,
- .check = mgag200_simple_display_pipe_check,
- .update = mgag200_simple_display_pipe_update,
- .reset_crtc = mgag200_simple_display_pipe_reset_crtc,
- .duplicate_crtc_state = mgag200_simple_display_pipe_duplicate_crtc_state,
- .destroy_crtc_state = mgag200_simple_display_pipe_destroy_crtc_state,
- DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS,
-};
-
-static const uint32_t mgag200_simple_display_pipe_formats[] = {
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_RGB565,
- DRM_FORMAT_RGB888,
-};
-
-static const uint64_t mgag200_simple_display_pipe_fmtmods[] = {
- DRM_FORMAT_MOD_LINEAR,
- DRM_FORMAT_MOD_INVALID
-};
-
/*
* Mode config
*/
+static void mgag200_mode_config_helper_atomic_commit_tail(struct drm_atomic_state *state)
+{
+ struct mga_device *mdev = to_mga_device(state->dev);
+
+ /*
+ * Concurrent operations could possibly trigger a call to
+ * drm_connector_helper_funcs.get_modes by trying to read the
+ * display modes. Protect access to I/O registers by acquiring
+ * the I/O-register lock.
+ */
+ mutex_lock(&mdev->rmmio_lock);
+ drm_atomic_helper_commit_tail(state);
+ mutex_unlock(&mdev->rmmio_lock);
+}
+
+static const struct drm_mode_config_helper_funcs mgag200_mode_config_helper_funcs = {
+ .atomic_commit_tail = mgag200_mode_config_helper_atomic_commit_tail,
+};
+
/* Calculates a mode's required memory bandwidth (in KiB/sec). */
static uint32_t mgag200_calculate_mode_bandwidth(const struct drm_display_mode *mode,
unsigned int bits_per_pixel)
@@ -1048,23 +808,16 @@ static const struct drm_mode_config_funcs mgag200_mode_config_funcs = {
.atomic_commit = drm_atomic_helper_commit,
};
-int mgag200_modeset_init(struct mga_device *mdev, resource_size_t vram_available)
+int mgag200_mode_config_init(struct mga_device *mdev, resource_size_t vram_available)
{
struct drm_device *dev = &mdev->base;
- struct mga_i2c_chan *i2c = &mdev->i2c;
- struct drm_connector *connector = &mdev->connector;
- struct drm_simple_display_pipe *pipe = &mdev->display_pipe;
- size_t format_count = ARRAY_SIZE(mgag200_simple_display_pipe_formats);
int ret;
- mgag200_init_regs(mdev);
-
mdev->vram_available = vram_available;
ret = drmm_mode_config_init(dev);
if (ret) {
- drm_err(dev, "drmm_mode_config_init() failed, error %d\n",
- ret);
+ drm_err(dev, "drmm_mode_config_init() failed: %d\n", ret);
return ret;
}
@@ -1073,48 +826,7 @@ int mgag200_modeset_init(struct mga_device *mdev, resource_size_t vram_available
dev->mode_config.preferred_depth = 24;
dev->mode_config.fb_base = mdev->vram_res->start;
dev->mode_config.funcs = &mgag200_mode_config_funcs;
-
- ret = mgag200_i2c_init(mdev, i2c);
- if (ret) {
- drm_err(dev, "failed to add DDC bus: %d\n", ret);
- return ret;
- }
-
- ret = drm_connector_init_with_ddc(dev, connector,
- &mga_vga_connector_funcs,
- DRM_MODE_CONNECTOR_VGA,
- &i2c->adapter);
- if (ret) {
- drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
- return ret;
- }
- drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs);
-
- ret = mgag200_pixpll_init(&mdev->pixpll, mdev);
- if (ret)
- return ret;
-
- ret = drm_simple_display_pipe_init(dev, pipe,
- &mgag200_simple_display_pipe_funcs,
- mgag200_simple_display_pipe_formats,
- format_count,
- mgag200_simple_display_pipe_fmtmods,
- connector);
- if (ret) {
- drm_err(dev,
- "drm_simple_display_pipe_init() failed, error %d\n",
- ret);
- return ret;
- }
-
- drm_plane_enable_fb_damage_clips(&pipe->plane);
-
- /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
- drm_mode_crtc_set_gamma_size(&pipe->crtc, MGAG200_LUT_SIZE);
-
- drm_crtc_enable_color_mgmt(&pipe->crtc, 0, false, MGAG200_LUT_SIZE);
-
- drm_mode_config_reset(dev);
+ dev->mode_config.helper_private = &mgag200_mode_config_helper_funcs;
return 0;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_pll.c b/drivers/gpu/drm/mgag200/mgag200_pll.c
deleted file mode 100644
index 8065ca5d8de9..000000000000
--- a/drivers/gpu/drm/mgag200/mgag200_pll.c
+++ /dev/null
@@ -1,997 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-#include <linux/delay.h>
-
-#include "mgag200_drv.h"
-
-/*
- * G200
- */
-
-static int mgag200_pixpll_compute_g200(struct mgag200_pll *pixpll, long clock,
- struct mgag200_pll_values *pixpllc)
-{
- struct mga_device *mdev = pixpll->mdev;
- struct drm_device *dev = &mdev->base;
- struct mgag200_g200_device *g200 = to_mgag200_g200_device(dev);
- const int post_div_max = 7;
- const int in_div_min = 1;
- const int in_div_max = 6;
- const int feed_div_min = 7;
- const int feed_div_max = 127;
- u8 testp, testm, testn;
- u8 n = 0, m = 0, p, s;
- long f_vco;
- long computed;
- long delta, tmp_delta;
- long ref_clk = g200->ref_clk;
- long p_clk_min = g200->pclk_min;
- long p_clk_max = g200->pclk_max;
-
- if (clock > p_clk_max) {
- drm_err(dev, "Pixel Clock %ld too high\n", clock);
- return -EINVAL;
- }
-
- if (clock < p_clk_min >> 3)
- clock = p_clk_min >> 3;
-
- f_vco = clock;
- for (testp = 0;
- testp <= post_div_max && f_vco < p_clk_min;
- testp = (testp << 1) + 1, f_vco <<= 1)
- ;
- p = testp + 1;
-
- delta = clock;
-
- for (testm = in_div_min; testm <= in_div_max; testm++) {
- for (testn = feed_div_min; testn <= feed_div_max; testn++) {
- computed = ref_clk * (testn + 1) / (testm + 1);
- if (computed < f_vco)
- tmp_delta = f_vco - computed;
- else
- tmp_delta = computed - f_vco;
- if (tmp_delta < delta) {
- delta = tmp_delta;
- m = testm + 1;
- n = testn + 1;
- }
- }
- }
- f_vco = ref_clk * n / m;
- if (f_vco < 100000)
- s = 0;
- else if (f_vco < 140000)
- s = 1;
- else if (f_vco < 180000)
- s = 2;
- else
- s = 3;
-
- drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n",
- clock, f_vco, m, n, p, s);
-
- pixpllc->m = m;
- pixpllc->n = n;
- pixpllc->p = p;
- pixpllc->s = s;
-
- return 0;
-}
-
-static void
-mgag200_pixpll_update_g200(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
-{
- struct mga_device *mdev = pixpll->mdev;
- unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
- u8 xpixpllcm, xpixpllcn, xpixpllcp;
-
- pixpllcm = pixpllc->m - 1;
- pixpllcn = pixpllc->n - 1;
- pixpllcp = pixpllc->p - 1;
- pixpllcs = pixpllc->s;
-
- xpixpllcm = pixpllcm;
- xpixpllcn = pixpllcn;
- xpixpllcp = (pixpllcs << 3) | pixpllcp;
-
- WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
-
- WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
- WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
- WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
-}
-
-static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200 = {
- .compute = mgag200_pixpll_compute_g200,
- .update = mgag200_pixpll_update_g200,
-};
-
-/*
- * G200SE
- */
-
-static int mgag200_pixpll_compute_g200se_00(struct mgag200_pll *pixpll, long clock,
- struct mgag200_pll_values *pixpllc)
-{
- static const unsigned int vcomax = 320000;
- static const unsigned int vcomin = 160000;
- static const unsigned int pllreffreq = 25000;
-
- unsigned int delta, tmpdelta, permitteddelta;
- unsigned int testp, testm, testn;
- unsigned int p, m, n, s;
- unsigned int computed;
-
- m = n = p = s = 0;
- delta = 0xffffffff;
- permitteddelta = clock * 5 / 1000;
-
- for (testp = 8; testp > 0; testp /= 2) {
- if (clock * testp > vcomax)
- continue;
- if (clock * testp < vcomin)
- continue;
-
- for (testn = 17; testn < 256; testn++) {
- for (testm = 1; testm < 32; testm++) {
- computed = (pllreffreq * testn) / (testm * testp);
- if (computed > clock)
- tmpdelta = computed - clock;
- else
- tmpdelta = clock - computed;
- if (tmpdelta < delta) {
- delta = tmpdelta;
- m = testm;
- n = testn;
- p = testp;
- }
- }
- }
- }
-
- if (delta > permitteddelta) {
- pr_warn("PLL delta too large\n");
- return -EINVAL;
- }
-
- pixpllc->m = m;
- pixpllc->n = n;
- pixpllc->p = p;
- pixpllc->s = s;
-
- return 0;
-}
-
-static void mgag200_pixpll_update_g200se_00(struct mgag200_pll *pixpll,
- const struct mgag200_pll_values *pixpllc)
-{
- unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
- u8 xpixpllcm, xpixpllcn, xpixpllcp;
- struct mga_device *mdev = pixpll->mdev;
-
- pixpllcm = pixpllc->m - 1;
- pixpllcn = pixpllc->n - 1;
- pixpllcp = pixpllc->p - 1;
- pixpllcs = pixpllc->s;
-
- xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1);
- xpixpllcn = pixpllcn;
- xpixpllcp = (pixpllcs << 3) | pixpllcp;
-
- WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
-
- WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
- WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
- WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
-}
-
-static int mgag200_pixpll_compute_g200se_04(struct mgag200_pll *pixpll, long clock,
- struct mgag200_pll_values *pixpllc)
-{
- static const unsigned int vcomax = 1600000;
- static const unsigned int vcomin = 800000;
- static const unsigned int pllreffreq = 25000;
- static const unsigned int pvalues_e4[] = {16, 14, 12, 10, 8, 6, 4, 2, 1};
-
- unsigned int delta, tmpdelta, permitteddelta;
- unsigned int testp, testm, testn;
- unsigned int p, m, n, s;
- unsigned int computed;
- unsigned int fvv;
- unsigned int i;
-
- m = n = p = s = 0;
- delta = 0xffffffff;
-
- if (clock < 25000)
- clock = 25000;
- clock = clock * 2;
-
- /* Permited delta is 0.5% as VESA Specification */
- permitteddelta = clock * 5 / 1000;
-
- for (i = 0 ; i < ARRAY_SIZE(pvalues_e4); i++) {
- testp = pvalues_e4[i];
-
- if ((clock * testp) > vcomax)
- continue;
- if ((clock * testp) < vcomin)
- continue;
-
- for (testn = 50; testn <= 256; testn++) {
- for (testm = 1; testm <= 32; testm++) {
- computed = (pllreffreq * testn) / (testm * testp);
- if (computed > clock)
- tmpdelta = computed - clock;
- else
- tmpdelta = clock - computed;
-
- if (tmpdelta < delta) {
- delta = tmpdelta;
- m = testm;
- n = testn;
- p = testp;
- }
- }
- }
- }
-
- fvv = pllreffreq * n / m;
- fvv = (fvv - 800000) / 50000;
- if (fvv > 15)
- fvv = 15;
- s = fvv << 1;
-
- if (delta > permitteddelta) {
- pr_warn("PLL delta too large\n");
- return -EINVAL;
- }
-
- pixpllc->m = m;
- pixpllc->n = n;
- pixpllc->p = p;
- pixpllc->s = s;
-
- return 0;
-}
-
-static void mgag200_pixpll_update_g200se_04(struct mgag200_pll *pixpll,
- const struct mgag200_pll_values *pixpllc)
-{
- unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
- u8 xpixpllcm, xpixpllcn, xpixpllcp;
- struct mga_device *mdev = pixpll->mdev;
-
- pixpllcm = pixpllc->m - 1;
- pixpllcn = pixpllc->n - 1;
- pixpllcp = pixpllc->p - 1;
- pixpllcs = pixpllc->s;
-
- xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1);
- xpixpllcn = pixpllcn;
- xpixpllcp = (pixpllcs << 3) | pixpllcp;
-
- WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
-
- WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
- WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
- WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
-
- WREG_DAC(0x1a, 0x09);
- msleep(20);
- WREG_DAC(0x1a, 0x01);
-}
-
-static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200se_00 = {
- .compute = mgag200_pixpll_compute_g200se_00,
- .update = mgag200_pixpll_update_g200se_00,
-};
-
-static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200se_04 = {
- .compute = mgag200_pixpll_compute_g200se_04,
- .update = mgag200_pixpll_update_g200se_04,
-};
-
-/*
- * G200WB
- */
-
-static int mgag200_pixpll_compute_g200wb(struct mgag200_pll *pixpll, long clock,
- struct mgag200_pll_values *pixpllc)
-{
- static const unsigned int vcomax = 550000;
- static const unsigned int vcomin = 150000;
- static const unsigned int pllreffreq = 48000;
-
- unsigned int delta, tmpdelta;
- unsigned int testp, testm, testn;
- unsigned int p, m, n, s;
- unsigned int computed;
-
- m = n = p = s = 0;
- delta = 0xffffffff;
-
- for (testp = 1; testp < 9; testp++) {
- if (clock * testp > vcomax)
- continue;
- if (clock * testp < vcomin)
- continue;
-
- for (testm = 1; testm < 17; testm++) {
- for (testn = 1; testn < 151; testn++) {
- computed = (pllreffreq * testn) / (testm * testp);
- if (computed > clock)
- tmpdelta = computed - clock;
- else
- tmpdelta = clock - computed;
- if (tmpdelta < delta) {
- delta = tmpdelta;
- n = testn;
- m = testm;
- p = testp;
- s = 0;
- }
- }
- }
- }
-
- pixpllc->m = m;
- pixpllc->n = n;
- pixpllc->p = p;
- pixpllc->s = s;
-
- return 0;
-}
-
-static void
-mgag200_pixpll_update_g200wb(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
-{
- unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
- u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
- int i, j, tmpcount, vcount;
- struct mga_device *mdev = pixpll->mdev;
- bool pll_locked = false;
-
- pixpllcm = pixpllc->m - 1;
- pixpllcn = pixpllc->n - 1;
- pixpllcp = pixpllc->p - 1;
- pixpllcs = pixpllc->s;
-
- xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm;
- xpixpllcn = pixpllcn;
- xpixpllcp = ((pixpllcn & GENMASK(10, 9)) >> 3) | (pixpllcs << 3) | pixpllcp;
-
- WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
-
- for (i = 0; i <= 32 && pll_locked == false; i++) {
- if (i > 0) {
- WREG8(MGAREG_CRTC_INDEX, 0x1e);
- tmp = RREG8(MGAREG_CRTC_DATA);
- if (tmp < 0xff)
- WREG8(MGAREG_CRTC_DATA, tmp+1);
- }
-
- /* set pixclkdis to 1 */
- WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
- tmp = RREG8(DAC_DATA);
- tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
- WREG8(DAC_DATA, tmp);
-
- WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
- tmp = RREG8(DAC_DATA);
- tmp |= MGA1064_REMHEADCTL_CLKDIS;
- WREG8(DAC_DATA, tmp);
-
- /* select PLL Set C */
- tmp = RREG8(MGAREG_MEM_MISC_READ);
- tmp |= 0x3 << 2;
- WREG8(MGAREG_MEM_MISC_WRITE, tmp);
-
- WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
- tmp = RREG8(DAC_DATA);
- tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80;
- WREG8(DAC_DATA, tmp);
-
- udelay(500);
-
- /* reset the PLL */
- WREG8(DAC_INDEX, MGA1064_VREF_CTL);
- tmp = RREG8(DAC_DATA);
- tmp &= ~0x04;
- WREG8(DAC_DATA, tmp);
-
- udelay(50);
-
- /* program pixel pll register */
- WREG_DAC(MGA1064_WB_PIX_PLLC_N, xpixpllcn);
- WREG_DAC(MGA1064_WB_PIX_PLLC_M, xpixpllcm);
- WREG_DAC(MGA1064_WB_PIX_PLLC_P, xpixpllcp);
-
- udelay(50);
-
- /* turn pll on */
- WREG8(DAC_INDEX, MGA1064_VREF_CTL);
- tmp = RREG8(DAC_DATA);
- tmp |= 0x04;
- WREG_DAC(MGA1064_VREF_CTL, tmp);
-
- udelay(500);
-
- /* select the pixel pll */
- WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
- tmp = RREG8(DAC_DATA);
- tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
- tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
- WREG8(DAC_DATA, tmp);
-
- WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
- tmp = RREG8(DAC_DATA);
- tmp &= ~MGA1064_REMHEADCTL_CLKSL_MSK;
- tmp |= MGA1064_REMHEADCTL_CLKSL_PLL;
- WREG8(DAC_DATA, tmp);
-
- /* reset dotclock rate bit */
- WREG8(MGAREG_SEQ_INDEX, 1);
- tmp = RREG8(MGAREG_SEQ_DATA);
- tmp &= ~0x8;
- WREG8(MGAREG_SEQ_DATA, tmp);
-
- WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
- tmp = RREG8(DAC_DATA);
- tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
- WREG8(DAC_DATA, tmp);
-
- vcount = RREG8(MGAREG_VCOUNT);
-
- for (j = 0; j < 30 && pll_locked == false; j++) {
- tmpcount = RREG8(MGAREG_VCOUNT);
- if (tmpcount < vcount)
- vcount = 0;
- if ((tmpcount - vcount) > 2)
- pll_locked = true;
- else
- udelay(5);
- }
- }
-
- WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
- tmp = RREG8(DAC_DATA);
- tmp &= ~MGA1064_REMHEADCTL_CLKDIS;
- WREG_DAC(MGA1064_REMHEADCTL, tmp);
-}
-
-static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200wb = {
- .compute = mgag200_pixpll_compute_g200wb,
- .update = mgag200_pixpll_update_g200wb,
-};
-
-/*
- * G200EV
- */
-
-static int mgag200_pixpll_compute_g200ev(struct mgag200_pll *pixpll, long clock,
- struct mgag200_pll_values *pixpllc)
-{
- static const unsigned int vcomax = 550000;
- static const unsigned int vcomin = 150000;
- static const unsigned int pllreffreq = 50000;
-
- unsigned int delta, tmpdelta;
- unsigned int testp, testm, testn;
- unsigned int p, m, n, s;
- unsigned int computed;
-
- m = n = p = s = 0;
- delta = 0xffffffff;
-
- for (testp = 16; testp > 0; testp--) {
- if (clock * testp > vcomax)
- continue;
- if (clock * testp < vcomin)
- continue;
-
- for (testn = 1; testn < 257; testn++) {
- for (testm = 1; testm < 17; testm++) {
- computed = (pllreffreq * testn) /
- (testm * testp);
- if (computed > clock)
- tmpdelta = computed - clock;
- else
- tmpdelta = clock - computed;
- if (tmpdelta < delta) {
- delta = tmpdelta;
- n = testn;
- m = testm;
- p = testp;
- }
- }
- }
- }
-
- pixpllc->m = m;
- pixpllc->n = n;
- pixpllc->p = p;
- pixpllc->s = s;
-
- return 0;
-}
-
-static void
-mgag200_pixpll_update_g200ev(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
-{
- unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
- u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
- struct mga_device *mdev = pixpll->mdev;
-
- pixpllcm = pixpllc->m - 1;
- pixpllcn = pixpllc->n - 1;
- pixpllcp = pixpllc->p - 1;
- pixpllcs = pixpllc->s;
-
- xpixpllcm = pixpllcm;
- xpixpllcn = pixpllcn;
- xpixpllcp = (pixpllcs << 3) | pixpllcp;
-
- WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
-
- WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
- tmp = RREG8(DAC_DATA);
- tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
- WREG8(DAC_DATA, tmp);
-
- tmp = RREG8(MGAREG_MEM_MISC_READ);
- tmp |= 0x3 << 2;
- WREG8(MGAREG_MEM_MISC_WRITE, tmp);
-
- WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);
- tmp = RREG8(DAC_DATA);
- WREG8(DAC_DATA, tmp & ~0x40);
-
- WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
- tmp = RREG8(DAC_DATA);
- tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
- WREG8(DAC_DATA, tmp);
-
- WREG_DAC(MGA1064_EV_PIX_PLLC_M, xpixpllcm);
- WREG_DAC(MGA1064_EV_PIX_PLLC_N, xpixpllcn);
- WREG_DAC(MGA1064_EV_PIX_PLLC_P, xpixpllcp);
-
- udelay(50);
-
- WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
- tmp = RREG8(DAC_DATA);
- tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
- WREG8(DAC_DATA, tmp);
-
- udelay(500);
-
- WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
- tmp = RREG8(DAC_DATA);
- tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
- tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
- WREG8(DAC_DATA, tmp);
-
- WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);
- tmp = RREG8(DAC_DATA);
- WREG8(DAC_DATA, tmp | 0x40);
-
- tmp = RREG8(MGAREG_MEM_MISC_READ);
- tmp |= (0x3 << 2);
- WREG8(MGAREG_MEM_MISC_WRITE, tmp);
-
- WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
- tmp = RREG8(DAC_DATA);
- tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
- WREG8(DAC_DATA, tmp);
-}
-
-static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200ev = {
- .compute = mgag200_pixpll_compute_g200ev,
- .update = mgag200_pixpll_update_g200ev,
-};
-
-/*
- * G200EH
- */
-
-static int mgag200_pixpll_compute_g200eh(struct mgag200_pll *pixpll, long clock,
- struct mgag200_pll_values *pixpllc)
-{
- static const unsigned int vcomax = 800000;
- static const unsigned int vcomin = 400000;
- static const unsigned int pllreffreq = 33333;
-
- unsigned int delta, tmpdelta;
- unsigned int testp, testm, testn;
- unsigned int p, m, n, s;
- unsigned int computed;
-
- m = n = p = s = 0;
- delta = 0xffffffff;
-
- for (testp = 16; testp > 0; testp >>= 1) {
- if (clock * testp > vcomax)
- continue;
- if (clock * testp < vcomin)
- continue;
-
- for (testm = 1; testm < 33; testm++) {
- for (testn = 17; testn < 257; testn++) {
- computed = (pllreffreq * testn) / (testm * testp);
- if (computed > clock)
- tmpdelta = computed - clock;
- else
- tmpdelta = clock - computed;
- if (tmpdelta < delta) {
- delta = tmpdelta;
- n = testn;
- m = testm;
- p = testp;
- }
- }
- }
- }
-
- pixpllc->m = m;
- pixpllc->n = n;
- pixpllc->p = p;
- pixpllc->s = s;
-
- return 0;
-}
-
-static void
-mgag200_pixpll_update_g200eh(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
-{
- unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
- u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
- int i, j, tmpcount, vcount;
- struct mga_device *mdev = pixpll->mdev;
- bool pll_locked = false;
-
- pixpllcm = pixpllc->m - 1;
- pixpllcn = pixpllc->n - 1;
- pixpllcp = pixpllc->p - 1;
- pixpllcs = pixpllc->s;
-
- xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm;
- xpixpllcn = pixpllcn;
- xpixpllcp = (pixpllcs << 3) | pixpllcp;
-
- WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
-
- for (i = 0; i <= 32 && pll_locked == false; i++) {
- WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
- tmp = RREG8(DAC_DATA);
- tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
- WREG8(DAC_DATA, tmp);
-
- tmp = RREG8(MGAREG_MEM_MISC_READ);
- tmp |= 0x3 << 2;
- WREG8(MGAREG_MEM_MISC_WRITE, tmp);
-
- WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
- tmp = RREG8(DAC_DATA);
- tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
- WREG8(DAC_DATA, tmp);
-
- udelay(500);
-
- WREG_DAC(MGA1064_EH_PIX_PLLC_M, xpixpllcm);
- WREG_DAC(MGA1064_EH_PIX_PLLC_N, xpixpllcn);
- WREG_DAC(MGA1064_EH_PIX_PLLC_P, xpixpllcp);
-
- udelay(500);
-
- WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
- tmp = RREG8(DAC_DATA);
- tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
- tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
- WREG8(DAC_DATA, tmp);
-
- WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
- tmp = RREG8(DAC_DATA);
- tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
- tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
- WREG8(DAC_DATA, tmp);
-
- vcount = RREG8(MGAREG_VCOUNT);
-
- for (j = 0; j < 30 && pll_locked == false; j++) {
- tmpcount = RREG8(MGAREG_VCOUNT);
- if (tmpcount < vcount)
- vcount = 0;
- if ((tmpcount - vcount) > 2)
- pll_locked = true;
- else
- udelay(5);
- }
- }
-}
-
-static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200eh = {
- .compute = mgag200_pixpll_compute_g200eh,
- .update = mgag200_pixpll_update_g200eh,
-};
-
-/*
- * G200EH3
- */
-
-static int mgag200_pixpll_compute_g200eh3(struct mgag200_pll *pixpll, long clock,
- struct mgag200_pll_values *pixpllc)
-{
- static const unsigned int vcomax = 3000000;
- static const unsigned int vcomin = 1500000;
- static const unsigned int pllreffreq = 25000;
-
- unsigned int delta, tmpdelta;
- unsigned int testp, testm, testn;
- unsigned int p, m, n, s;
- unsigned int computed;
-
- m = n = p = s = 0;
- delta = 0xffffffff;
- testp = 0;
-
- for (testm = 150; testm >= 6; testm--) {
- if (clock * testm > vcomax)
- continue;
- if (clock * testm < vcomin)
- continue;
- for (testn = 120; testn >= 60; testn--) {
- computed = (pllreffreq * testn) / testm;
- if (computed > clock)
- tmpdelta = computed - clock;
- else
- tmpdelta = clock - computed;
- if (tmpdelta < delta) {
- delta = tmpdelta;
- n = testn + 1;
- m = testm + 1;
- p = testp + 1;
- }
- if (delta == 0)
- break;
- }
- if (delta == 0)
- break;
- }
-
- pixpllc->m = m;
- pixpllc->n = n;
- pixpllc->p = p;
- pixpllc->s = s;
-
- return 0;
-}
-
-static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200eh3 = {
- .compute = mgag200_pixpll_compute_g200eh3,
- .update = mgag200_pixpll_update_g200eh, // same as G200EH
-};
-
-/*
- * G200ER
- */
-
-static int mgag200_pixpll_compute_g200er(struct mgag200_pll *pixpll, long clock,
- struct mgag200_pll_values *pixpllc)
-{
- static const unsigned int vcomax = 1488000;
- static const unsigned int vcomin = 1056000;
- static const unsigned int pllreffreq = 48000;
- static const unsigned int m_div_val[] = { 1, 2, 4, 8 };
-
- unsigned int delta, tmpdelta;
- int testr, testn, testm, testo;
- unsigned int p, m, n, s;
- unsigned int computed, vco;
-
- m = n = p = s = 0;
- delta = 0xffffffff;
-
- for (testr = 0; testr < 4; testr++) {
- if (delta == 0)
- break;
- for (testn = 5; testn < 129; testn++) {
- if (delta == 0)
- break;
- for (testm = 3; testm >= 0; testm--) {
- if (delta == 0)
- break;
- for (testo = 5; testo < 33; testo++) {
- vco = pllreffreq * (testn + 1) /
- (testr + 1);
- if (vco < vcomin)
- continue;
- if (vco > vcomax)
- continue;
- computed = vco / (m_div_val[testm] * (testo + 1));
- if (computed > clock)
- tmpdelta = computed - clock;
- else
- tmpdelta = clock - computed;
- if (tmpdelta < delta) {
- delta = tmpdelta;
- m = (testm | (testo << 3)) + 1;
- n = testn + 1;
- p = testr + 1;
- s = testr;
- }
- }
- }
- }
- }
-
- pixpllc->m = m;
- pixpllc->n = n;
- pixpllc->p = p;
- pixpllc->s = s;
-
- return 0;
-}
-
-static void
-mgag200_pixpll_update_g200er(struct mgag200_pll *pixpll, const struct mgag200_pll_values *pixpllc)
-{
- unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
- u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
- struct mga_device *mdev = pixpll->mdev;
-
- pixpllcm = pixpllc->m - 1;
- pixpllcn = pixpllc->n - 1;
- pixpllcp = pixpllc->p - 1;
- pixpllcs = pixpllc->s;
-
- xpixpllcm = pixpllcm;
- xpixpllcn = pixpllcn;
- xpixpllcp = (pixpllcs << 3) | pixpllcp;
-
- WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
-
- WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
- tmp = RREG8(DAC_DATA);
- tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
- WREG8(DAC_DATA, tmp);
-
- WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
- tmp = RREG8(DAC_DATA);
- tmp |= MGA1064_REMHEADCTL_CLKDIS;
- WREG8(DAC_DATA, tmp);
-
- tmp = RREG8(MGAREG_MEM_MISC_READ);
- tmp |= (0x3<<2) | 0xc0;
- WREG8(MGAREG_MEM_MISC_WRITE, tmp);
-
- WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
- tmp = RREG8(DAC_DATA);
- tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
- tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
- WREG8(DAC_DATA, tmp);
-
- udelay(500);
-
- WREG_DAC(MGA1064_ER_PIX_PLLC_N, xpixpllcn);
- WREG_DAC(MGA1064_ER_PIX_PLLC_M, xpixpllcm);
- WREG_DAC(MGA1064_ER_PIX_PLLC_P, xpixpllcp);
-
- udelay(50);
-}
-
-static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200er = {
- .compute = mgag200_pixpll_compute_g200er,
- .update = mgag200_pixpll_update_g200er,
-};
-
-/*
- * G200EW3
- */
-
-static int mgag200_pixpll_compute_g200ew3(struct mgag200_pll *pixpll, long clock,
- struct mgag200_pll_values *pixpllc)
-{
- static const unsigned int vcomax = 800000;
- static const unsigned int vcomin = 400000;
- static const unsigned int pllreffreq = 25000;
-
- unsigned int delta, tmpdelta;
- unsigned int testp, testm, testn, testp2;
- unsigned int p, m, n, s;
- unsigned int computed;
-
- m = n = p = s = 0;
- delta = 0xffffffff;
-
- for (testp = 1; testp < 8; testp++) {
- for (testp2 = 1; testp2 < 8; testp2++) {
- if (testp < testp2)
- continue;
- if ((clock * testp * testp2) > vcomax)
- continue;
- if ((clock * testp * testp2) < vcomin)
- continue;
- for (testm = 1; testm < 26; testm++) {
- for (testn = 32; testn < 2048 ; testn++) {
- computed = (pllreffreq * testn) / (testm * testp * testp2);
- if (computed > clock)
- tmpdelta = computed - clock;
- else
- tmpdelta = clock - computed;
- if (tmpdelta < delta) {
- delta = tmpdelta;
- m = testm + 1;
- n = testn + 1;
- p = testp + 1;
- s = testp2;
- }
- }
- }
- }
- }
-
- pixpllc->m = m;
- pixpllc->n = n;
- pixpllc->p = p;
- pixpllc->s = s;
-
- return 0;
-}
-
-static const struct mgag200_pll_funcs mgag200_pixpll_funcs_g200ew3 = {
- .compute = mgag200_pixpll_compute_g200ew3,
- .update = mgag200_pixpll_update_g200wb, // same as G200WB
-};
-
-/*
- * PLL initialization
- */
-
-int mgag200_pixpll_init(struct mgag200_pll *pixpll, struct mga_device *mdev)
-{
- struct drm_device *dev = &mdev->base;
- struct mgag200_g200se_device *g200se;
-
- pixpll->mdev = mdev;
-
- switch (mdev->type) {
- case G200_PCI:
- case G200_AGP:
- pixpll->funcs = &mgag200_pixpll_funcs_g200;
- break;
- case G200_SE_A:
- case G200_SE_B:
- g200se = to_mgag200_g200se_device(dev);
-
- if (g200se->unique_rev_id >= 0x04)
- pixpll->funcs = &mgag200_pixpll_funcs_g200se_04;
- else
- pixpll->funcs = &mgag200_pixpll_funcs_g200se_00;
- break;
- case G200_WB:
- pixpll->funcs = &mgag200_pixpll_funcs_g200wb;
- break;
- case G200_EV:
- pixpll->funcs = &mgag200_pixpll_funcs_g200ev;
- break;
- case G200_EH:
- pixpll->funcs = &mgag200_pixpll_funcs_g200eh;
- break;
- case G200_EH3:
- pixpll->funcs = &mgag200_pixpll_funcs_g200eh3;
- break;
- case G200_ER:
- pixpll->funcs = &mgag200_pixpll_funcs_g200er;
- break;
- case G200_EW3:
- pixpll->funcs = &mgag200_pixpll_funcs_g200ew3;
- break;
- default:
- drm_err(dev, "unknown device type %d\n", mdev->type);
- return -ENODEV;
- }
-
- return 0;
-}
diff --git a/drivers/gpu/drm/mgag200/mgag200_reg.h b/drivers/gpu/drm/mgag200/mgag200_reg.h
index 99a9ab7d9119..1019ffd6c260 100644
--- a/drivers/gpu/drm/mgag200/mgag200_reg.h
+++ b/drivers/gpu/drm/mgag200/mgag200_reg.h
@@ -96,7 +96,7 @@
#define MGAREG_SRCORG 0x2cb4
#define MGAREG_DSTORG 0x2cb8
-/* add or or this to one of the previous "power registers" to start
+/* add or this to one of the previous "power registers" to start
the drawing engine */
#define MGAREG_EXEC 0x0100