18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * drivers/video/geode/video_cs5530.c 48c2ecf20Sopenharmony_ci * -- CS5530 video device 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2005 Arcom Control Systems Ltd. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Based on AMD's original 2.4 driver: 98c2ecf20Sopenharmony_ci * Copyright (C) 2004 Advanced Micro Devices, Inc. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci#include <linux/fb.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <asm/io.h> 148c2ecf20Sopenharmony_ci#include <asm/delay.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "geodefb.h" 178c2ecf20Sopenharmony_ci#include "video_cs5530.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * CS5530 PLL table. This maps pixclocks to the appropriate PLL register 218c2ecf20Sopenharmony_ci * value. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_cistruct cs5530_pll_entry { 248c2ecf20Sopenharmony_ci long pixclock; /* ps */ 258c2ecf20Sopenharmony_ci u32 pll_value; 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic const struct cs5530_pll_entry cs5530_pll_table[] = { 298c2ecf20Sopenharmony_ci { 39721, 0x31C45801, }, /* 25.1750 MHz */ 308c2ecf20Sopenharmony_ci { 35308, 0x20E36802, }, /* 28.3220 */ 318c2ecf20Sopenharmony_ci { 31746, 0x33915801, }, /* 31.5000 */ 328c2ecf20Sopenharmony_ci { 27777, 0x31EC4801, }, /* 36.0000 */ 338c2ecf20Sopenharmony_ci { 26666, 0x21E22801, }, /* 37.5000 */ 348c2ecf20Sopenharmony_ci { 25000, 0x33088801, }, /* 40.0000 */ 358c2ecf20Sopenharmony_ci { 22271, 0x33E22801, }, /* 44.9000 */ 368c2ecf20Sopenharmony_ci { 20202, 0x336C4801, }, /* 49.5000 */ 378c2ecf20Sopenharmony_ci { 20000, 0x23088801, }, /* 50.0000 */ 388c2ecf20Sopenharmony_ci { 19860, 0x23088801, }, /* 50.3500 */ 398c2ecf20Sopenharmony_ci { 18518, 0x3708A801, }, /* 54.0000 */ 408c2ecf20Sopenharmony_ci { 17777, 0x23E36802, }, /* 56.2500 */ 418c2ecf20Sopenharmony_ci { 17733, 0x23E36802, }, /* 56.3916 */ 428c2ecf20Sopenharmony_ci { 17653, 0x23E36802, }, /* 56.6444 */ 438c2ecf20Sopenharmony_ci { 16949, 0x37C45801, }, /* 59.0000 */ 448c2ecf20Sopenharmony_ci { 15873, 0x23EC4801, }, /* 63.0000 */ 458c2ecf20Sopenharmony_ci { 15384, 0x37911801, }, /* 65.0000 */ 468c2ecf20Sopenharmony_ci { 14814, 0x37963803, }, /* 67.5000 */ 478c2ecf20Sopenharmony_ci { 14124, 0x37058803, }, /* 70.8000 */ 488c2ecf20Sopenharmony_ci { 13888, 0x3710C805, }, /* 72.0000 */ 498c2ecf20Sopenharmony_ci { 13333, 0x37E22801, }, /* 75.0000 */ 508c2ecf20Sopenharmony_ci { 12698, 0x27915801, }, /* 78.7500 */ 518c2ecf20Sopenharmony_ci { 12500, 0x37D8D802, }, /* 80.0000 */ 528c2ecf20Sopenharmony_ci { 11135, 0x27588802, }, /* 89.8000 */ 538c2ecf20Sopenharmony_ci { 10582, 0x27EC4802, }, /* 94.5000 */ 548c2ecf20Sopenharmony_ci { 10101, 0x27AC6803, }, /* 99.0000 */ 558c2ecf20Sopenharmony_ci { 10000, 0x27088801, }, /* 100.0000 */ 568c2ecf20Sopenharmony_ci { 9259, 0x2710C805, }, /* 108.0000 */ 578c2ecf20Sopenharmony_ci { 8888, 0x27E36802, }, /* 112.5000 */ 588c2ecf20Sopenharmony_ci { 7692, 0x27C58803, }, /* 130.0000 */ 598c2ecf20Sopenharmony_ci { 7407, 0x27316803, }, /* 135.0000 */ 608c2ecf20Sopenharmony_ci { 6349, 0x2F915801, }, /* 157.5000 */ 618c2ecf20Sopenharmony_ci { 6172, 0x2F08A801, }, /* 162.0000 */ 628c2ecf20Sopenharmony_ci { 5714, 0x2FB11802, }, /* 175.0000 */ 638c2ecf20Sopenharmony_ci { 5291, 0x2FEC4802, }, /* 189.0000 */ 648c2ecf20Sopenharmony_ci { 4950, 0x2F963803, }, /* 202.0000 */ 658c2ecf20Sopenharmony_ci { 4310, 0x2FB1B802, }, /* 232.0000 */ 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic void cs5530_set_dclk_frequency(struct fb_info *info) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct geodefb_par *par = info->par; 718c2ecf20Sopenharmony_ci int i; 728c2ecf20Sopenharmony_ci u32 value; 738c2ecf20Sopenharmony_ci long min, diff; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* Search the table for the closest pixclock. */ 768c2ecf20Sopenharmony_ci value = cs5530_pll_table[0].pll_value; 778c2ecf20Sopenharmony_ci min = cs5530_pll_table[0].pixclock - info->var.pixclock; 788c2ecf20Sopenharmony_ci if (min < 0) min = -min; 798c2ecf20Sopenharmony_ci for (i = 1; i < ARRAY_SIZE(cs5530_pll_table); i++) { 808c2ecf20Sopenharmony_ci diff = cs5530_pll_table[i].pixclock - info->var.pixclock; 818c2ecf20Sopenharmony_ci if (diff < 0L) diff = -diff; 828c2ecf20Sopenharmony_ci if (diff < min) { 838c2ecf20Sopenharmony_ci min = diff; 848c2ecf20Sopenharmony_ci value = cs5530_pll_table[i].pll_value; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci writel(value, par->vid_regs + CS5530_DOT_CLK_CONFIG); 898c2ecf20Sopenharmony_ci writel(value | 0x80000100, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* set reset and bypass */ 908c2ecf20Sopenharmony_ci udelay(500); /* wait for PLL to settle */ 918c2ecf20Sopenharmony_ci writel(value & 0x7FFFFFFF, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* clear reset */ 928c2ecf20Sopenharmony_ci writel(value & 0x7FFFFEFF, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* clear bypass */ 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic void cs5530_configure_display(struct fb_info *info) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci struct geodefb_par *par = info->par; 988c2ecf20Sopenharmony_ci u32 dcfg; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci dcfg = readl(par->vid_regs + CS5530_DISPLAY_CONFIG); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* Clear bits from existing mode. */ 1038c2ecf20Sopenharmony_ci dcfg &= ~(CS5530_DCFG_CRT_SYNC_SKW_MASK | CS5530_DCFG_PWR_SEQ_DLY_MASK 1048c2ecf20Sopenharmony_ci | CS5530_DCFG_CRT_HSYNC_POL | CS5530_DCFG_CRT_VSYNC_POL 1058c2ecf20Sopenharmony_ci | CS5530_DCFG_FP_PWR_EN | CS5530_DCFG_FP_DATA_EN 1068c2ecf20Sopenharmony_ci | CS5530_DCFG_DAC_PWR_EN | CS5530_DCFG_VSYNC_EN 1078c2ecf20Sopenharmony_ci | CS5530_DCFG_HSYNC_EN); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* Set default sync skew and power sequence delays. */ 1108c2ecf20Sopenharmony_ci dcfg |= (CS5530_DCFG_CRT_SYNC_SKW_INIT | CS5530_DCFG_PWR_SEQ_DLY_INIT 1118c2ecf20Sopenharmony_ci | CS5530_DCFG_GV_PAL_BYP); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci /* Enable DACs, hsync and vsync for CRTs */ 1148c2ecf20Sopenharmony_ci if (par->enable_crt) { 1158c2ecf20Sopenharmony_ci dcfg |= CS5530_DCFG_DAC_PWR_EN; 1168c2ecf20Sopenharmony_ci dcfg |= CS5530_DCFG_HSYNC_EN | CS5530_DCFG_VSYNC_EN; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci /* Enable panel power and data if using a flat panel. */ 1198c2ecf20Sopenharmony_ci if (par->panel_x > 0) { 1208c2ecf20Sopenharmony_ci dcfg |= CS5530_DCFG_FP_PWR_EN; 1218c2ecf20Sopenharmony_ci dcfg |= CS5530_DCFG_FP_DATA_EN; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* Sync polarities. */ 1258c2ecf20Sopenharmony_ci if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) 1268c2ecf20Sopenharmony_ci dcfg |= CS5530_DCFG_CRT_HSYNC_POL; 1278c2ecf20Sopenharmony_ci if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) 1288c2ecf20Sopenharmony_ci dcfg |= CS5530_DCFG_CRT_VSYNC_POL; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci writel(dcfg, par->vid_regs + CS5530_DISPLAY_CONFIG); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic int cs5530_blank_display(struct fb_info *info, int blank_mode) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci struct geodefb_par *par = info->par; 1368c2ecf20Sopenharmony_ci u32 dcfg; 1378c2ecf20Sopenharmony_ci int blank, hsync, vsync; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci switch (blank_mode) { 1408c2ecf20Sopenharmony_ci case FB_BLANK_UNBLANK: 1418c2ecf20Sopenharmony_ci blank = 0; hsync = 1; vsync = 1; 1428c2ecf20Sopenharmony_ci break; 1438c2ecf20Sopenharmony_ci case FB_BLANK_NORMAL: 1448c2ecf20Sopenharmony_ci blank = 1; hsync = 1; vsync = 1; 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: 1478c2ecf20Sopenharmony_ci blank = 1; hsync = 1; vsync = 0; 1488c2ecf20Sopenharmony_ci break; 1498c2ecf20Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: 1508c2ecf20Sopenharmony_ci blank = 1; hsync = 0; vsync = 1; 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci case FB_BLANK_POWERDOWN: 1538c2ecf20Sopenharmony_ci blank = 1; hsync = 0; vsync = 0; 1548c2ecf20Sopenharmony_ci break; 1558c2ecf20Sopenharmony_ci default: 1568c2ecf20Sopenharmony_ci return -EINVAL; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci dcfg = readl(par->vid_regs + CS5530_DISPLAY_CONFIG); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci dcfg &= ~(CS5530_DCFG_DAC_BL_EN | CS5530_DCFG_DAC_PWR_EN 1628c2ecf20Sopenharmony_ci | CS5530_DCFG_HSYNC_EN | CS5530_DCFG_VSYNC_EN 1638c2ecf20Sopenharmony_ci | CS5530_DCFG_FP_DATA_EN | CS5530_DCFG_FP_PWR_EN); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (par->enable_crt) { 1668c2ecf20Sopenharmony_ci if (!blank) 1678c2ecf20Sopenharmony_ci dcfg |= CS5530_DCFG_DAC_BL_EN | CS5530_DCFG_DAC_PWR_EN; 1688c2ecf20Sopenharmony_ci if (hsync) 1698c2ecf20Sopenharmony_ci dcfg |= CS5530_DCFG_HSYNC_EN; 1708c2ecf20Sopenharmony_ci if (vsync) 1718c2ecf20Sopenharmony_ci dcfg |= CS5530_DCFG_VSYNC_EN; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci if (par->panel_x > 0) { 1748c2ecf20Sopenharmony_ci if (!blank) 1758c2ecf20Sopenharmony_ci dcfg |= CS5530_DCFG_FP_DATA_EN; 1768c2ecf20Sopenharmony_ci if (hsync && vsync) 1778c2ecf20Sopenharmony_ci dcfg |= CS5530_DCFG_FP_PWR_EN; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci writel(dcfg, par->vid_regs + CS5530_DISPLAY_CONFIG); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci return 0; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ciconst struct geode_vid_ops cs5530_vid_ops = { 1868c2ecf20Sopenharmony_ci .set_dclk = cs5530_set_dclk_frequency, 1878c2ecf20Sopenharmony_ci .configure_display = cs5530_configure_display, 1888c2ecf20Sopenharmony_ci .blank_display = cs5530_blank_display, 1898c2ecf20Sopenharmony_ci}; 190