mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-05 20:30:41 +00:00
drm/mgag200: Provide per-device callbacks for PIXPLLC
Move the PIXPLLC code into per-model source files and wire it up with per-model callbacks. No functional changes. The PIXPLLC pixel-clock is part of the CRTC, but really separate hardware that varies with each model of the G200. Move the PIXPLLC code for each model into the per-model source file and call it from CRTC helpers via device functions. This allows to remove struct mgag200_pll and the related code. The new callbacks behave like the CRTC's atomic_check and atomic_enable functions. v3: * clean up style Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de> Reviewed-by: Jocelyn Falempe <jfalempe@redhat.com> Tested-by: Jocelyn Falempe <jfalempe@redhat.com> Acked-by: Sam Ravnborg <sam@ravnborg.org> Link: https://patchwork.freedesktop.org/patch/msgid/20220728124103.30159-12-tzimmermann@suse.de
This commit is contained in:
parent
8aeeb3144f
commit
877507bb95
@ -11,7 +11,6 @@ mgag200-y := \
|
|||||||
mgag200_g200se.o \
|
mgag200_g200se.o \
|
||||||
mgag200_g200wb.o \
|
mgag200_g200wb.o \
|
||||||
mgag200_i2c.o \
|
mgag200_i2c.o \
|
||||||
mgag200_mode.o \
|
mgag200_mode.o
|
||||||
mgag200_pll.o
|
|
||||||
|
|
||||||
obj-$(CONFIG_DRM_MGAG200) += mgag200.o
|
obj-$(CONFIG_DRM_MGAG200) += mgag200.o
|
||||||
|
@ -156,7 +156,6 @@
|
|||||||
#define MGAG200_MAX_FB_WIDTH 4096
|
#define MGAG200_MAX_FB_WIDTH 4096
|
||||||
|
|
||||||
struct mga_device;
|
struct mga_device;
|
||||||
struct mgag200_pll;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stores parameters for programming the PLLs
|
* Stores parameters for programming the PLLs
|
||||||
@ -175,17 +174,6 @@ struct mgag200_pll_values {
|
|||||||
unsigned int s;
|
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 mgag200_crtc_state {
|
||||||
struct drm_crtc_state base;
|
struct drm_crtc_state base;
|
||||||
|
|
||||||
@ -274,6 +262,20 @@ struct mgag200_device_funcs {
|
|||||||
* a new display mode.
|
* a new display mode.
|
||||||
*/
|
*/
|
||||||
void (*enable_vidrst)(struct mga_device *mdev);
|
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 mga_device {
|
||||||
@ -292,7 +294,6 @@ struct mga_device {
|
|||||||
|
|
||||||
enum mga_type type;
|
enum mga_type type;
|
||||||
|
|
||||||
struct mgag200_pll pixpll;
|
|
||||||
struct drm_plane primary_plane;
|
struct drm_plane primary_plane;
|
||||||
struct drm_crtc crtc;
|
struct drm_crtc crtc;
|
||||||
struct drm_encoder encoder;
|
struct drm_encoder encoder;
|
||||||
@ -346,11 +347,13 @@ struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct
|
|||||||
struct mga_device *mgag200_g200se_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);
|
enum mga_type type);
|
||||||
void mgag200_g200wb_init_registers(struct mga_device *mdev);
|
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_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
|
||||||
enum mga_type type);
|
enum mga_type type);
|
||||||
struct mga_device *mgag200_g200ev_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,
|
||||||
enum mga_type type);
|
enum mga_type type);
|
||||||
void mgag200_g200eh_init_registers(struct mga_device *mdev);
|
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_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
|
||||||
enum mga_type type);
|
enum mga_type type);
|
||||||
struct mga_device *mgag200_g200eh3_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,
|
||||||
@ -372,7 +375,4 @@ void mgag200_bmc_enable_vidrst(struct mga_device *mdev);
|
|||||||
/* mgag200_i2c.c */
|
/* mgag200_i2c.c */
|
||||||
int mgag200_i2c_init(struct mga_device *mdev, struct mga_i2c_chan *i2c);
|
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__ */
|
#endif /* __MGAG200_DRV_H__ */
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
|
|
||||||
|
#include <drm/drm_atomic.h>
|
||||||
#include <drm/drm_drv.h>
|
#include <drm/drm_drv.h>
|
||||||
|
|
||||||
#include "mgag200_drv.h"
|
#include "mgag200_drv.h"
|
||||||
@ -53,6 +54,112 @@ static void mgag200_g200_init_registers(struct mgag200_g200_device *g200)
|
|||||||
mgag200_init_registers(mdev);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DRM Device
|
* DRM Device
|
||||||
*/
|
*/
|
||||||
@ -184,6 +291,8 @@ static void mgag200_g200_init_refclk(struct mgag200_g200_device *g200)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct mgag200_device_funcs mgag200_g200_device_funcs = {
|
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 mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
|
||||||
|
#include <drm/drm_atomic.h>
|
||||||
#include <drm/drm_drv.h>
|
#include <drm/drm_drv.h>
|
||||||
|
|
||||||
#include "mgag200_drv.h"
|
#include "mgag200_drv.h"
|
||||||
@ -30,6 +32,133 @@ void mgag200_g200eh_init_registers(struct mga_device *mdev)
|
|||||||
mgag200_init_registers(mdev);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DRM device
|
* DRM device
|
||||||
*/
|
*/
|
||||||
@ -38,6 +167,8 @@ static const struct mgag200_device_info mgag200_g200eh_device_info =
|
|||||||
MGAG200_DEVICE_INFO_INIT(2048, 2048, 37500, false, 1, 0, false);
|
MGAG200_DEVICE_INFO_INIT(2048, 2048, 37500, false, 1, 0, false);
|
||||||
|
|
||||||
static const struct mgag200_device_funcs mgag200_g200eh_device_funcs = {
|
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 *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
|
||||||
|
@ -2,10 +2,67 @@
|
|||||||
|
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
|
||||||
|
#include <drm/drm_atomic.h>
|
||||||
#include <drm/drm_drv.h>
|
#include <drm/drm_drv.h>
|
||||||
|
|
||||||
#include "mgag200_drv.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;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DRM device
|
* DRM device
|
||||||
*/
|
*/
|
||||||
@ -14,6 +71,8 @@ static const struct mgag200_device_info mgag200_g200eh3_device_info =
|
|||||||
MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false, 1, 0, false);
|
MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false, 1, 0, false);
|
||||||
|
|
||||||
static const struct mgag200_device_funcs mgag200_g200eh3_device_funcs = {
|
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,
|
struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev,
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
|
||||||
|
#include <drm/drm_atomic.h>
|
||||||
#include <drm/drm_drv.h>
|
#include <drm/drm_drv.h>
|
||||||
|
|
||||||
#include "mgag200_drv.h"
|
#include "mgag200_drv.h"
|
||||||
@ -31,6 +33,122 @@ static void mgag200_g200er_init_registers(struct mga_device *mdev)
|
|||||||
WREG_ECRT(0x24, 0x5); /* G200ER specific */
|
WREG_ECRT(0x24, 0x5); /* G200ER specific */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DRM device
|
* DRM device
|
||||||
*/
|
*/
|
||||||
@ -39,6 +157,8 @@ static const struct mgag200_device_info mgag200_g200er_device_info =
|
|||||||
MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 1, 0, false);
|
MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 1, 0, false);
|
||||||
|
|
||||||
static const struct mgag200_device_funcs mgag200_g200er_device_funcs = {
|
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 *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
|
||||||
|
#include <drm/drm_atomic.h>
|
||||||
#include <drm/drm_drv.h>
|
#include <drm/drm_drv.h>
|
||||||
|
|
||||||
#include "mgag200_drv.h"
|
#include "mgag200_drv.h"
|
||||||
@ -31,6 +33,134 @@ static void mgag200_g200ev_init_registers(struct mga_device *mdev)
|
|||||||
mgag200_init_registers(mdev);
|
mgag200_init_registers(mdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DRM device
|
* DRM device
|
||||||
*/
|
*/
|
||||||
@ -39,6 +169,8 @@ static const struct mgag200_device_info mgag200_g200ev_device_info =
|
|||||||
MGAG200_DEVICE_INFO_INIT(2048, 2048, 32700, false, 0, 1, false);
|
MGAG200_DEVICE_INFO_INIT(2048, 2048, 32700, false, 0, 1, false);
|
||||||
|
|
||||||
static const struct mgag200_device_funcs mgag200_g200ev_device_funcs = {
|
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 *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
|
||||||
|
#include <drm/drm_atomic.h>
|
||||||
#include <drm/drm_drv.h>
|
#include <drm/drm_drv.h>
|
||||||
|
|
||||||
#include "mgag200_drv.h"
|
#include "mgag200_drv.h"
|
||||||
@ -13,6 +14,64 @@ static void mgag200_g200ew3_init_registers(struct mga_device *mdev)
|
|||||||
WREG_ECRT(0x34, 0x5); // G200EW3 specific
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DRM device
|
* DRM device
|
||||||
*/
|
*/
|
||||||
@ -23,6 +82,8 @@ static const struct mgag200_device_info mgag200_g200ew3_device_info =
|
|||||||
static const struct mgag200_device_funcs mgag200_g200ew3_device_funcs = {
|
static const struct mgag200_device_funcs mgag200_g200ew3_device_funcs = {
|
||||||
.disable_vidrst = mgag200_bmc_disable_vidrst,
|
.disable_vidrst = mgag200_bmc_disable_vidrst,
|
||||||
.enable_vidrst = mgag200_bmc_enable_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)
|
static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev)
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
|
||||||
|
#include <drm/drm_atomic.h>
|
||||||
#include <drm/drm_drv.h>
|
#include <drm/drm_drv.h>
|
||||||
|
|
||||||
#include "mgag200_drv.h"
|
#include "mgag200_drv.h"
|
||||||
@ -56,6 +58,198 @@ static void mgag200_g200se_init_registers(struct mgag200_g200se_device *g200se)
|
|||||||
mgag200_init_registers(mdev);
|
mgag200_init_registers(mdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DRM device
|
* DRM device
|
||||||
*/
|
*/
|
||||||
@ -93,7 +287,14 @@ static int mgag200_g200se_init_unique_rev_id(struct mgag200_g200se_device *g200s
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct mgag200_device_funcs mgag200_g200se_device_funcs = {
|
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,
|
struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
|
||||||
@ -101,6 +302,7 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru
|
|||||||
{
|
{
|
||||||
struct mgag200_g200se_device *g200se;
|
struct mgag200_g200se_device *g200se;
|
||||||
const struct mgag200_device_info *info;
|
const struct mgag200_device_info *info;
|
||||||
|
const struct mgag200_device_funcs *funcs;
|
||||||
struct mga_device *mdev;
|
struct mga_device *mdev;
|
||||||
struct drm_device *dev;
|
struct drm_device *dev;
|
||||||
resource_size_t vram_available;
|
resource_size_t vram_available;
|
||||||
@ -147,7 +349,12 @@ struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const stru
|
|||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = mgag200_device_init(mdev, type, info, &mgag200_g200se_device_funcs);
|
if (g200se->unique_rev_id >= 0x04)
|
||||||
|
funcs = &mgag200_g200se_04_device_funcs;
|
||||||
|
else
|
||||||
|
funcs = &mgag200_g200se_00_device_funcs;
|
||||||
|
|
||||||
|
ret = mgag200_device_init(mdev, type, info, funcs);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
|
||||||
|
#include <drm/drm_atomic.h>
|
||||||
#include <drm/drm_drv.h>
|
#include <drm/drm_drv.h>
|
||||||
|
|
||||||
#include "mgag200_drv.h"
|
#include "mgag200_drv.h"
|
||||||
@ -28,6 +30,182 @@ void mgag200_g200wb_init_registers(struct mga_device *mdev)
|
|||||||
mgag200_init_registers(mdev);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DRM device
|
* DRM device
|
||||||
*/
|
*/
|
||||||
@ -38,6 +216,8 @@ static const struct mgag200_device_info mgag200_g200wb_device_info =
|
|||||||
static const struct mgag200_device_funcs mgag200_g200wb_device_funcs = {
|
static const struct mgag200_device_funcs mgag200_g200wb_device_funcs = {
|
||||||
.disable_vidrst = mgag200_bmc_disable_vidrst,
|
.disable_vidrst = mgag200_bmc_disable_vidrst,
|
||||||
.enable_vidrst = mgag200_bmc_enable_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 *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
|
||||||
|
@ -660,9 +660,8 @@ static int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc,
|
|||||||
{
|
{
|
||||||
struct drm_device *dev = crtc->dev;
|
struct drm_device *dev = crtc->dev;
|
||||||
struct mga_device *mdev = to_mga_device(dev);
|
struct mga_device *mdev = to_mga_device(dev);
|
||||||
|
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_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
|
||||||
struct mgag200_pll *pixpll = &mdev->pixpll;
|
|
||||||
struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
|
|
||||||
struct drm_property_blob *new_gamma_lut = new_crtc_state->gamma_lut;
|
struct drm_property_blob *new_gamma_lut = new_crtc_state->gamma_lut;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -674,11 +673,12 @@ static int mgag200_crtc_helper_atomic_check(struct drm_crtc *crtc,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (new_crtc_state->mode_changed) {
|
if (new_crtc_state->mode_changed) {
|
||||||
ret = pixpll->funcs->compute(pixpll, new_crtc_state->mode.clock,
|
if (funcs->pixpllc_atomic_check) {
|
||||||
&mgag200_crtc_state->pixpllc);
|
ret = funcs->pixpllc_atomic_check(crtc, new_state);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (new_crtc_state->color_mgmt_changed && new_gamma_lut) {
|
if (new_crtc_state->color_mgmt_changed && new_gamma_lut) {
|
||||||
if (new_gamma_lut->length != MGAG200_LUT_SIZE * sizeof(struct drm_color_lut)) {
|
if (new_gamma_lut->length != MGAG200_LUT_SIZE * sizeof(struct drm_color_lut)) {
|
||||||
@ -718,7 +718,6 @@ static void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc,
|
|||||||
struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
|
struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
|
||||||
struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
|
struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
|
||||||
const struct drm_format_info *format = mgag200_crtc_state->format;
|
const struct drm_format_info *format = mgag200_crtc_state->format;
|
||||||
struct mgag200_pll *pixpll = &mdev->pixpll;
|
|
||||||
|
|
||||||
if (funcs->disable_vidrst)
|
if (funcs->disable_vidrst)
|
||||||
funcs->disable_vidrst(mdev);
|
funcs->disable_vidrst(mdev);
|
||||||
@ -726,7 +725,8 @@ static void mgag200_crtc_helper_atomic_enable(struct drm_crtc *crtc,
|
|||||||
mgag200_set_format_regs(mdev, format);
|
mgag200_set_format_regs(mdev, format);
|
||||||
mgag200_set_mode_regs(mdev, adjusted_mode);
|
mgag200_set_mode_regs(mdev, adjusted_mode);
|
||||||
|
|
||||||
pixpll->funcs->update(pixpll, &mgag200_crtc_state->pixpllc);
|
if (funcs->pixpllc_atomic_update)
|
||||||
|
funcs->pixpllc_atomic_update(crtc, old_state);
|
||||||
|
|
||||||
if (mdev->type == G200_ER)
|
if (mdev->type == G200_ER)
|
||||||
mgag200_g200er_reset_tagfifo(mdev);
|
mgag200_g200er_reset_tagfifo(mdev);
|
||||||
@ -976,10 +976,6 @@ static int mgag200_pipeline_init(struct mga_device *mdev)
|
|||||||
struct drm_connector *connector = &mdev->connector;
|
struct drm_connector *connector = &mdev->connector;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = mgag200_pixpll_init(&mdev->pixpll, mdev);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = drm_universal_plane_init(dev, primary_plane, 0,
|
ret = drm_universal_plane_init(dev, primary_plane, 0,
|
||||||
&mgag200_primary_plane_funcs,
|
&mgag200_primary_plane_funcs,
|
||||||
mgag200_primary_plane_formats,
|
mgag200_primary_plane_formats,
|
||||||
|
@ -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;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user