cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

video_gx.c (9908B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Geode GX video processor device.
      4 *
      5 *   Copyright (C) 2006 Arcom Control Systems Ltd.
      6 *
      7 *   Portions from AMD's original 2.4 driver:
      8 *     Copyright (C) 2004 Advanced Micro Devices, Inc.
      9 */
     10#include <linux/fb.h>
     11#include <linux/delay.h>
     12#include <asm/io.h>
     13#include <asm/delay.h>
     14#include <asm/msr.h>
     15#include <linux/cs5535.h>
     16
     17#include "gxfb.h"
     18
     19
     20/*
     21 * Tables of register settings for various DOTCLKs.
     22 */
     23struct gx_pll_entry {
     24	long pixclock; /* ps */
     25	u32 sys_rstpll_bits;
     26	u32 dotpll_value;
     27};
     28
     29#define POSTDIV3 ((u32)MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3)
     30#define PREMULT2 ((u32)MSR_GLCP_SYS_RSTPLL_DOTPREMULT2)
     31#define PREDIV2  ((u32)MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3)
     32
     33static const struct gx_pll_entry gx_pll_table_48MHz[] = {
     34	{ 40123, POSTDIV3,	    0x00000BF2 },	/*  24.9230 */
     35	{ 39721, 0,		    0x00000037 },	/*  25.1750 */
     36	{ 35308, POSTDIV3|PREMULT2, 0x00000B1A },	/*  28.3220 */
     37	{ 31746, POSTDIV3,	    0x000002D2 },	/*  31.5000 */
     38	{ 27777, POSTDIV3|PREMULT2, 0x00000FE2 },	/*  36.0000 */
     39	{ 26666, POSTDIV3,	    0x0000057A },	/*  37.5000 */
     40	{ 25000, POSTDIV3,	    0x0000030A },	/*  40.0000 */
     41	{ 22271, 0,		    0x00000063 },	/*  44.9000 */
     42	{ 20202, 0,		    0x0000054B },	/*  49.5000 */
     43	{ 20000, 0,		    0x0000026E },	/*  50.0000 */
     44	{ 19860, PREMULT2,	    0x00000037 },	/*  50.3500 */
     45	{ 18518, POSTDIV3|PREMULT2, 0x00000B0D },	/*  54.0000 */
     46	{ 17777, 0,		    0x00000577 },	/*  56.2500 */
     47	{ 17733, 0,		    0x000007F7 },	/*  56.3916 */
     48	{ 17653, 0,		    0x0000057B },	/*  56.6444 */
     49	{ 16949, PREMULT2,	    0x00000707 },	/*  59.0000 */
     50	{ 15873, POSTDIV3|PREMULT2, 0x00000B39 },	/*  63.0000 */
     51	{ 15384, POSTDIV3|PREMULT2, 0x00000B45 },	/*  65.0000 */
     52	{ 14814, POSTDIV3|PREMULT2, 0x00000FC1 },	/*  67.5000 */
     53	{ 14124, POSTDIV3,	    0x00000561 },	/*  70.8000 */
     54	{ 13888, POSTDIV3,	    0x000007E1 },	/*  72.0000 */
     55	{ 13426, PREMULT2,	    0x00000F4A },	/*  74.4810 */
     56	{ 13333, 0,		    0x00000052 },	/*  75.0000 */
     57	{ 12698, 0,		    0x00000056 },	/*  78.7500 */
     58	{ 12500, POSTDIV3|PREMULT2, 0x00000709 },	/*  80.0000 */
     59	{ 11135, PREMULT2,	    0x00000262 },	/*  89.8000 */
     60	{ 10582, 0,		    0x000002D2 },	/*  94.5000 */
     61	{ 10101, PREMULT2,	    0x00000B4A },	/*  99.0000 */
     62	{ 10000, PREMULT2,	    0x00000036 },	/* 100.0000 */
     63	{  9259, 0,		    0x000007E2 },	/* 108.0000 */
     64	{  8888, 0,		    0x000007F6 },	/* 112.5000 */
     65	{  7692, POSTDIV3|PREMULT2, 0x00000FB0 },	/* 130.0000 */
     66	{  7407, POSTDIV3|PREMULT2, 0x00000B50 },	/* 135.0000 */
     67	{  6349, 0,		    0x00000055 },	/* 157.5000 */
     68	{  6172, 0,		    0x000009C1 },	/* 162.0000 */
     69	{  5787, PREMULT2,	    0x0000002D },	/* 172.798  */
     70	{  5698, 0,		    0x000002C1 },	/* 175.5000 */
     71	{  5291, 0,		    0x000002D1 },	/* 189.0000 */
     72	{  4938, 0,		    0x00000551 },	/* 202.5000 */
     73	{  4357, 0,		    0x0000057D },	/* 229.5000 */
     74};
     75
     76static const struct gx_pll_entry gx_pll_table_14MHz[] = {
     77	{ 39721, 0, 0x00000037 },	/*  25.1750 */
     78	{ 35308, 0, 0x00000B7B },	/*  28.3220 */
     79	{ 31746, 0, 0x000004D3 },	/*  31.5000 */
     80	{ 27777, 0, 0x00000BE3 },	/*  36.0000 */
     81	{ 26666, 0, 0x0000074F },	/*  37.5000 */
     82	{ 25000, 0, 0x0000050B },	/*  40.0000 */
     83	{ 22271, 0, 0x00000063 },	/*  44.9000 */
     84	{ 20202, 0, 0x0000054B },	/*  49.5000 */
     85	{ 20000, 0, 0x0000026E },	/*  50.0000 */
     86	{ 19860, 0, 0x000007C3 },	/*  50.3500 */
     87	{ 18518, 0, 0x000007E3 },	/*  54.0000 */
     88	{ 17777, 0, 0x00000577 },	/*  56.2500 */
     89	{ 17733, 0, 0x000002FB },	/*  56.3916 */
     90	{ 17653, 0, 0x0000057B },	/*  56.6444 */
     91	{ 16949, 0, 0x0000058B },	/*  59.0000 */
     92	{ 15873, 0, 0x0000095E },	/*  63.0000 */
     93	{ 15384, 0, 0x0000096A },	/*  65.0000 */
     94	{ 14814, 0, 0x00000BC2 },	/*  67.5000 */
     95	{ 14124, 0, 0x0000098A },	/*  70.8000 */
     96	{ 13888, 0, 0x00000BE2 },	/*  72.0000 */
     97	{ 13333, 0, 0x00000052 },	/*  75.0000 */
     98	{ 12698, 0, 0x00000056 },	/*  78.7500 */
     99	{ 12500, 0, 0x0000050A },	/*  80.0000 */
    100	{ 11135, 0, 0x0000078E },	/*  89.8000 */
    101	{ 10582, 0, 0x000002D2 },	/*  94.5000 */
    102	{ 10101, 0, 0x000011F6 },	/*  99.0000 */
    103	{ 10000, 0, 0x0000054E },	/* 100.0000 */
    104	{  9259, 0, 0x000007E2 },	/* 108.0000 */
    105	{  8888, 0, 0x000002FA },	/* 112.5000 */
    106	{  7692, 0, 0x00000BB1 },	/* 130.0000 */
    107	{  7407, 0, 0x00000975 },	/* 135.0000 */
    108	{  6349, 0, 0x00000055 },	/* 157.5000 */
    109	{  6172, 0, 0x000009C1 },	/* 162.0000 */
    110	{  5698, 0, 0x000002C1 },	/* 175.5000 */
    111	{  5291, 0, 0x00000539 },	/* 189.0000 */
    112	{  4938, 0, 0x00000551 },	/* 202.5000 */
    113	{  4357, 0, 0x0000057D },	/* 229.5000 */
    114};
    115
    116void gx_set_dclk_frequency(struct fb_info *info)
    117{
    118	const struct gx_pll_entry *pll_table;
    119	int pll_table_len;
    120	int i, best_i;
    121	long min, diff;
    122	u64 dotpll, sys_rstpll;
    123	int timeout = 1000;
    124
    125	/* Rev. 1 Geode GXs use a 14 MHz reference clock instead of 48 MHz. */
    126	if (cpu_data(0).x86_stepping == 1) {
    127		pll_table = gx_pll_table_14MHz;
    128		pll_table_len = ARRAY_SIZE(gx_pll_table_14MHz);
    129	} else {
    130		pll_table = gx_pll_table_48MHz;
    131		pll_table_len = ARRAY_SIZE(gx_pll_table_48MHz);
    132	}
    133
    134	/* Search the table for the closest pixclock. */
    135	best_i = 0;
    136	min = abs(pll_table[0].pixclock - info->var.pixclock);
    137	for (i = 1; i < pll_table_len; i++) {
    138		diff = abs(pll_table[i].pixclock - info->var.pixclock);
    139		if (diff < min) {
    140			min = diff;
    141			best_i = i;
    142		}
    143	}
    144
    145	rdmsrl(MSR_GLCP_SYS_RSTPLL, sys_rstpll);
    146	rdmsrl(MSR_GLCP_DOTPLL, dotpll);
    147
    148	/* Program new M, N and P. */
    149	dotpll &= 0x00000000ffffffffull;
    150	dotpll |= (u64)pll_table[best_i].dotpll_value << 32;
    151	dotpll |= MSR_GLCP_DOTPLL_DOTRESET;
    152	dotpll &= ~MSR_GLCP_DOTPLL_BYPASS;
    153
    154	wrmsrl(MSR_GLCP_DOTPLL, dotpll);
    155
    156	/* Program dividers. */
    157	sys_rstpll &= ~( MSR_GLCP_SYS_RSTPLL_DOTPREDIV2
    158			 | MSR_GLCP_SYS_RSTPLL_DOTPREMULT2
    159			 | MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3 );
    160	sys_rstpll |= pll_table[best_i].sys_rstpll_bits;
    161
    162	wrmsrl(MSR_GLCP_SYS_RSTPLL, sys_rstpll);
    163
    164	/* Clear reset bit to start PLL. */
    165	dotpll &= ~(MSR_GLCP_DOTPLL_DOTRESET);
    166	wrmsrl(MSR_GLCP_DOTPLL, dotpll);
    167
    168	/* Wait for LOCK bit. */
    169	do {
    170		rdmsrl(MSR_GLCP_DOTPLL, dotpll);
    171	} while (timeout-- && !(dotpll & MSR_GLCP_DOTPLL_LOCK));
    172}
    173
    174static void
    175gx_configure_tft(struct fb_info *info)
    176{
    177	struct gxfb_par *par = info->par;
    178	unsigned long val;
    179	unsigned long fp;
    180
    181	/* Set up the DF pad select MSR */
    182
    183	rdmsrl(MSR_GX_MSR_PADSEL, val);
    184	val &= ~MSR_GX_MSR_PADSEL_MASK;
    185	val |= MSR_GX_MSR_PADSEL_TFT;
    186	wrmsrl(MSR_GX_MSR_PADSEL, val);
    187
    188	/* Turn off the panel */
    189
    190	fp = read_fp(par, FP_PM);
    191	fp &= ~FP_PM_P;
    192	write_fp(par, FP_PM, fp);
    193
    194	/* Set timing 1 */
    195
    196	fp = read_fp(par, FP_PT1);
    197	fp &= FP_PT1_VSIZE_MASK;
    198	fp |= info->var.yres << FP_PT1_VSIZE_SHIFT;
    199	write_fp(par, FP_PT1, fp);
    200
    201	/* Timing 2 */
    202	/* Set bits that are always on for TFT */
    203
    204	fp = 0x0F100000;
    205
    206	/* Configure sync polarity */
    207
    208	if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
    209		fp |= FP_PT2_VSP;
    210
    211	if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
    212		fp |= FP_PT2_HSP;
    213
    214	write_fp(par, FP_PT2, fp);
    215
    216	/*  Set the dither control */
    217	write_fp(par, FP_DFC, FP_DFC_NFI);
    218
    219	/* Enable the FP data and power (in case the BIOS didn't) */
    220
    221	fp = read_vp(par, VP_DCFG);
    222	fp |= VP_DCFG_FP_PWR_EN | VP_DCFG_FP_DATA_EN;
    223	write_vp(par, VP_DCFG, fp);
    224
    225	/* Unblank the panel */
    226
    227	fp = read_fp(par, FP_PM);
    228	fp |= FP_PM_P;
    229	write_fp(par, FP_PM, fp);
    230}
    231
    232void gx_configure_display(struct fb_info *info)
    233{
    234	struct gxfb_par *par = info->par;
    235	u32 dcfg, misc;
    236
    237	/* Write the display configuration */
    238	dcfg = read_vp(par, VP_DCFG);
    239
    240	/* Disable hsync and vsync */
    241	dcfg &= ~(VP_DCFG_VSYNC_EN | VP_DCFG_HSYNC_EN);
    242	write_vp(par, VP_DCFG, dcfg);
    243
    244	/* Clear bits from existing mode. */
    245	dcfg &= ~(VP_DCFG_CRT_SYNC_SKW
    246		  | VP_DCFG_CRT_HSYNC_POL   | VP_DCFG_CRT_VSYNC_POL
    247		  | VP_DCFG_VSYNC_EN        | VP_DCFG_HSYNC_EN);
    248
    249	/* Set default sync skew.  */
    250	dcfg |= VP_DCFG_CRT_SYNC_SKW_DEFAULT;
    251
    252	/* Enable hsync and vsync. */
    253	dcfg |= VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN;
    254
    255	misc = read_vp(par, VP_MISC);
    256
    257	/* Disable gamma correction */
    258	misc |= VP_MISC_GAM_EN;
    259
    260	if (par->enable_crt) {
    261
    262		/* Power up the CRT DACs */
    263		misc &= ~(VP_MISC_APWRDN | VP_MISC_DACPWRDN);
    264		write_vp(par, VP_MISC, misc);
    265
    266		/* Only change the sync polarities if we are running
    267		 * in CRT mode.  The FP polarities will be handled in
    268		 * gxfb_configure_tft */
    269		if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
    270			dcfg |= VP_DCFG_CRT_HSYNC_POL;
    271		if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
    272			dcfg |= VP_DCFG_CRT_VSYNC_POL;
    273	} else {
    274		/* Power down the CRT DACs if in FP mode */
    275		misc |= (VP_MISC_APWRDN | VP_MISC_DACPWRDN);
    276		write_vp(par, VP_MISC, misc);
    277	}
    278
    279	/* Enable the display logic */
    280	/* Set up the DACS to blank normally */
    281
    282	dcfg |= VP_DCFG_CRT_EN | VP_DCFG_DAC_BL_EN;
    283
    284	/* Enable the external DAC VREF? */
    285
    286	write_vp(par, VP_DCFG, dcfg);
    287
    288	/* Set up the flat panel (if it is enabled) */
    289
    290	if (par->enable_crt == 0)
    291		gx_configure_tft(info);
    292}
    293
    294int gx_blank_display(struct fb_info *info, int blank_mode)
    295{
    296	struct gxfb_par *par = info->par;
    297	u32 dcfg, fp_pm;
    298	int blank, hsync, vsync, crt;
    299
    300	/* CRT power saving modes. */
    301	switch (blank_mode) {
    302	case FB_BLANK_UNBLANK:
    303		blank = 0; hsync = 1; vsync = 1; crt = 1;
    304		break;
    305	case FB_BLANK_NORMAL:
    306		blank = 1; hsync = 1; vsync = 1; crt = 1;
    307		break;
    308	case FB_BLANK_VSYNC_SUSPEND:
    309		blank = 1; hsync = 1; vsync = 0; crt = 1;
    310		break;
    311	case FB_BLANK_HSYNC_SUSPEND:
    312		blank = 1; hsync = 0; vsync = 1; crt = 1;
    313		break;
    314	case FB_BLANK_POWERDOWN:
    315		blank = 1; hsync = 0; vsync = 0; crt = 0;
    316		break;
    317	default:
    318		return -EINVAL;
    319	}
    320	dcfg = read_vp(par, VP_DCFG);
    321	dcfg &= ~(VP_DCFG_DAC_BL_EN | VP_DCFG_HSYNC_EN | VP_DCFG_VSYNC_EN |
    322			VP_DCFG_CRT_EN);
    323	if (!blank)
    324		dcfg |= VP_DCFG_DAC_BL_EN;
    325	if (hsync)
    326		dcfg |= VP_DCFG_HSYNC_EN;
    327	if (vsync)
    328		dcfg |= VP_DCFG_VSYNC_EN;
    329	if (crt)
    330		dcfg |= VP_DCFG_CRT_EN;
    331	write_vp(par, VP_DCFG, dcfg);
    332
    333	/* Power on/off flat panel. */
    334
    335	if (par->enable_crt == 0) {
    336		fp_pm = read_fp(par, FP_PM);
    337		if (blank_mode == FB_BLANK_POWERDOWN)
    338			fp_pm &= ~FP_PM_P;
    339		else
    340			fp_pm |= FP_PM_P;
    341		write_fp(par, FP_PM, fp_pm);
    342	}
    343
    344	return 0;
    345}