162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * drivers/video/geode/video_cs5530.c 462306a36Sopenharmony_ci * -- CS5530 video device 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2005 Arcom Control Systems Ltd. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Based on AMD's original 2.4 driver: 962306a36Sopenharmony_ci * Copyright (C) 2004 Advanced Micro Devices, Inc. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci#include <linux/fb.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <asm/io.h> 1462306a36Sopenharmony_ci#include <asm/delay.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "geodefb.h" 1762306a36Sopenharmony_ci#include "video_cs5530.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * CS5530 PLL table. This maps pixclocks to the appropriate PLL register 2162306a36Sopenharmony_ci * value. 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_cistruct cs5530_pll_entry { 2462306a36Sopenharmony_ci long pixclock; /* ps */ 2562306a36Sopenharmony_ci u32 pll_value; 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic const struct cs5530_pll_entry cs5530_pll_table[] = { 2962306a36Sopenharmony_ci { 39721, 0x31C45801, }, /* 25.1750 MHz */ 3062306a36Sopenharmony_ci { 35308, 0x20E36802, }, /* 28.3220 */ 3162306a36Sopenharmony_ci { 31746, 0x33915801, }, /* 31.5000 */ 3262306a36Sopenharmony_ci { 27777, 0x31EC4801, }, /* 36.0000 */ 3362306a36Sopenharmony_ci { 26666, 0x21E22801, }, /* 37.5000 */ 3462306a36Sopenharmony_ci { 25000, 0x33088801, }, /* 40.0000 */ 3562306a36Sopenharmony_ci { 22271, 0x33E22801, }, /* 44.9000 */ 3662306a36Sopenharmony_ci { 20202, 0x336C4801, }, /* 49.5000 */ 3762306a36Sopenharmony_ci { 20000, 0x23088801, }, /* 50.0000 */ 3862306a36Sopenharmony_ci { 19860, 0x23088801, }, /* 50.3500 */ 3962306a36Sopenharmony_ci { 18518, 0x3708A801, }, /* 54.0000 */ 4062306a36Sopenharmony_ci { 17777, 0x23E36802, }, /* 56.2500 */ 4162306a36Sopenharmony_ci { 17733, 0x23E36802, }, /* 56.3916 */ 4262306a36Sopenharmony_ci { 17653, 0x23E36802, }, /* 56.6444 */ 4362306a36Sopenharmony_ci { 16949, 0x37C45801, }, /* 59.0000 */ 4462306a36Sopenharmony_ci { 15873, 0x23EC4801, }, /* 63.0000 */ 4562306a36Sopenharmony_ci { 15384, 0x37911801, }, /* 65.0000 */ 4662306a36Sopenharmony_ci { 14814, 0x37963803, }, /* 67.5000 */ 4762306a36Sopenharmony_ci { 14124, 0x37058803, }, /* 70.8000 */ 4862306a36Sopenharmony_ci { 13888, 0x3710C805, }, /* 72.0000 */ 4962306a36Sopenharmony_ci { 13333, 0x37E22801, }, /* 75.0000 */ 5062306a36Sopenharmony_ci { 12698, 0x27915801, }, /* 78.7500 */ 5162306a36Sopenharmony_ci { 12500, 0x37D8D802, }, /* 80.0000 */ 5262306a36Sopenharmony_ci { 11135, 0x27588802, }, /* 89.8000 */ 5362306a36Sopenharmony_ci { 10582, 0x27EC4802, }, /* 94.5000 */ 5462306a36Sopenharmony_ci { 10101, 0x27AC6803, }, /* 99.0000 */ 5562306a36Sopenharmony_ci { 10000, 0x27088801, }, /* 100.0000 */ 5662306a36Sopenharmony_ci { 9259, 0x2710C805, }, /* 108.0000 */ 5762306a36Sopenharmony_ci { 8888, 0x27E36802, }, /* 112.5000 */ 5862306a36Sopenharmony_ci { 7692, 0x27C58803, }, /* 130.0000 */ 5962306a36Sopenharmony_ci { 7407, 0x27316803, }, /* 135.0000 */ 6062306a36Sopenharmony_ci { 6349, 0x2F915801, }, /* 157.5000 */ 6162306a36Sopenharmony_ci { 6172, 0x2F08A801, }, /* 162.0000 */ 6262306a36Sopenharmony_ci { 5714, 0x2FB11802, }, /* 175.0000 */ 6362306a36Sopenharmony_ci { 5291, 0x2FEC4802, }, /* 189.0000 */ 6462306a36Sopenharmony_ci { 4950, 0x2F963803, }, /* 202.0000 */ 6562306a36Sopenharmony_ci { 4310, 0x2FB1B802, }, /* 232.0000 */ 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic void cs5530_set_dclk_frequency(struct fb_info *info) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci struct geodefb_par *par = info->par; 7162306a36Sopenharmony_ci int i; 7262306a36Sopenharmony_ci u32 value; 7362306a36Sopenharmony_ci long min, diff; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* Search the table for the closest pixclock. */ 7662306a36Sopenharmony_ci value = cs5530_pll_table[0].pll_value; 7762306a36Sopenharmony_ci min = cs5530_pll_table[0].pixclock - info->var.pixclock; 7862306a36Sopenharmony_ci if (min < 0) min = -min; 7962306a36Sopenharmony_ci for (i = 1; i < ARRAY_SIZE(cs5530_pll_table); i++) { 8062306a36Sopenharmony_ci diff = cs5530_pll_table[i].pixclock - info->var.pixclock; 8162306a36Sopenharmony_ci if (diff < 0L) diff = -diff; 8262306a36Sopenharmony_ci if (diff < min) { 8362306a36Sopenharmony_ci min = diff; 8462306a36Sopenharmony_ci value = cs5530_pll_table[i].pll_value; 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci writel(value, par->vid_regs + CS5530_DOT_CLK_CONFIG); 8962306a36Sopenharmony_ci writel(value | 0x80000100, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* set reset and bypass */ 9062306a36Sopenharmony_ci udelay(500); /* wait for PLL to settle */ 9162306a36Sopenharmony_ci writel(value & 0x7FFFFFFF, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* clear reset */ 9262306a36Sopenharmony_ci writel(value & 0x7FFFFEFF, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* clear bypass */ 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic void cs5530_configure_display(struct fb_info *info) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci struct geodefb_par *par = info->par; 9862306a36Sopenharmony_ci u32 dcfg; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci dcfg = readl(par->vid_regs + CS5530_DISPLAY_CONFIG); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* Clear bits from existing mode. */ 10362306a36Sopenharmony_ci dcfg &= ~(CS5530_DCFG_CRT_SYNC_SKW_MASK | CS5530_DCFG_PWR_SEQ_DLY_MASK 10462306a36Sopenharmony_ci | CS5530_DCFG_CRT_HSYNC_POL | CS5530_DCFG_CRT_VSYNC_POL 10562306a36Sopenharmony_ci | CS5530_DCFG_FP_PWR_EN | CS5530_DCFG_FP_DATA_EN 10662306a36Sopenharmony_ci | CS5530_DCFG_DAC_PWR_EN | CS5530_DCFG_VSYNC_EN 10762306a36Sopenharmony_ci | CS5530_DCFG_HSYNC_EN); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* Set default sync skew and power sequence delays. */ 11062306a36Sopenharmony_ci dcfg |= (CS5530_DCFG_CRT_SYNC_SKW_INIT | CS5530_DCFG_PWR_SEQ_DLY_INIT 11162306a36Sopenharmony_ci | CS5530_DCFG_GV_PAL_BYP); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci /* Enable DACs, hsync and vsync for CRTs */ 11462306a36Sopenharmony_ci if (par->enable_crt) { 11562306a36Sopenharmony_ci dcfg |= CS5530_DCFG_DAC_PWR_EN; 11662306a36Sopenharmony_ci dcfg |= CS5530_DCFG_HSYNC_EN | CS5530_DCFG_VSYNC_EN; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci /* Enable panel power and data if using a flat panel. */ 11962306a36Sopenharmony_ci if (par->panel_x > 0) { 12062306a36Sopenharmony_ci dcfg |= CS5530_DCFG_FP_PWR_EN; 12162306a36Sopenharmony_ci dcfg |= CS5530_DCFG_FP_DATA_EN; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* Sync polarities. */ 12562306a36Sopenharmony_ci if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) 12662306a36Sopenharmony_ci dcfg |= CS5530_DCFG_CRT_HSYNC_POL; 12762306a36Sopenharmony_ci if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) 12862306a36Sopenharmony_ci dcfg |= CS5530_DCFG_CRT_VSYNC_POL; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci writel(dcfg, par->vid_regs + CS5530_DISPLAY_CONFIG); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic int cs5530_blank_display(struct fb_info *info, int blank_mode) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci struct geodefb_par *par = info->par; 13662306a36Sopenharmony_ci u32 dcfg; 13762306a36Sopenharmony_ci int blank, hsync, vsync; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci switch (blank_mode) { 14062306a36Sopenharmony_ci case FB_BLANK_UNBLANK: 14162306a36Sopenharmony_ci blank = 0; hsync = 1; vsync = 1; 14262306a36Sopenharmony_ci break; 14362306a36Sopenharmony_ci case FB_BLANK_NORMAL: 14462306a36Sopenharmony_ci blank = 1; hsync = 1; vsync = 1; 14562306a36Sopenharmony_ci break; 14662306a36Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: 14762306a36Sopenharmony_ci blank = 1; hsync = 1; vsync = 0; 14862306a36Sopenharmony_ci break; 14962306a36Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: 15062306a36Sopenharmony_ci blank = 1; hsync = 0; vsync = 1; 15162306a36Sopenharmony_ci break; 15262306a36Sopenharmony_ci case FB_BLANK_POWERDOWN: 15362306a36Sopenharmony_ci blank = 1; hsync = 0; vsync = 0; 15462306a36Sopenharmony_ci break; 15562306a36Sopenharmony_ci default: 15662306a36Sopenharmony_ci return -EINVAL; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci dcfg = readl(par->vid_regs + CS5530_DISPLAY_CONFIG); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci dcfg &= ~(CS5530_DCFG_DAC_BL_EN | CS5530_DCFG_DAC_PWR_EN 16262306a36Sopenharmony_ci | CS5530_DCFG_HSYNC_EN | CS5530_DCFG_VSYNC_EN 16362306a36Sopenharmony_ci | CS5530_DCFG_FP_DATA_EN | CS5530_DCFG_FP_PWR_EN); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci if (par->enable_crt) { 16662306a36Sopenharmony_ci if (!blank) 16762306a36Sopenharmony_ci dcfg |= CS5530_DCFG_DAC_BL_EN | CS5530_DCFG_DAC_PWR_EN; 16862306a36Sopenharmony_ci if (hsync) 16962306a36Sopenharmony_ci dcfg |= CS5530_DCFG_HSYNC_EN; 17062306a36Sopenharmony_ci if (vsync) 17162306a36Sopenharmony_ci dcfg |= CS5530_DCFG_VSYNC_EN; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci if (par->panel_x > 0) { 17462306a36Sopenharmony_ci if (!blank) 17562306a36Sopenharmony_ci dcfg |= CS5530_DCFG_FP_DATA_EN; 17662306a36Sopenharmony_ci if (hsync && vsync) 17762306a36Sopenharmony_ci dcfg |= CS5530_DCFG_FP_PWR_EN; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci writel(dcfg, par->vid_regs + CS5530_DISPLAY_CONFIG); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci return 0; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ciconst struct geode_vid_ops cs5530_vid_ops = { 18662306a36Sopenharmony_ci .set_dclk = cs5530_set_dclk_frequency, 18762306a36Sopenharmony_ci .configure_display = cs5530_configure_display, 18862306a36Sopenharmony_ci .blank_display = cs5530_blank_display, 18962306a36Sopenharmony_ci}; 190