18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * T1042 platform DIU operation 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2014 Freescale Semiconductor Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/init.h> 98c2ecf20Sopenharmony_ci#include <linux/io.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/of.h> 138c2ecf20Sopenharmony_ci#include <linux/of_address.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <sysdev/fsl_soc.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/*DIU Pixel ClockCR offset in scfg*/ 188c2ecf20Sopenharmony_ci#define CCSR_SCFG_PIXCLKCR 0x28 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* DIU Pixel Clock bits of the PIXCLKCR */ 218c2ecf20Sopenharmony_ci#define PIXCLKCR_PXCKEN 0x80000000 228c2ecf20Sopenharmony_ci#define PIXCLKCR_PXCKINV 0x40000000 238c2ecf20Sopenharmony_ci#define PIXCLKCR_PXCKDLY 0x0000FF00 248c2ecf20Sopenharmony_ci#define PIXCLKCR_PXCLK_MASK 0x00FF0000 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* Some CPLD register definitions */ 278c2ecf20Sopenharmony_ci#define CPLD_DIUCSR 0x16 288c2ecf20Sopenharmony_ci#define CPLD_DIUCSR_DVIEN 0x80 298c2ecf20Sopenharmony_ci#define CPLD_DIUCSR_BACKLIGHT 0x0f 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistruct device_node *cpld_node; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/** 348c2ecf20Sopenharmony_ci * t1042rdb_set_monitor_port: switch the output to a different monitor port 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_cistatic void t1042rdb_set_monitor_port(enum fsl_diu_monitor_port port) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci void __iomem *cpld_base; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci cpld_base = of_iomap(cpld_node, 0); 418c2ecf20Sopenharmony_ci if (!cpld_base) { 428c2ecf20Sopenharmony_ci pr_err("%s: Could not map cpld registers\n", __func__); 438c2ecf20Sopenharmony_ci goto exit; 448c2ecf20Sopenharmony_ci } 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci switch (port) { 478c2ecf20Sopenharmony_ci case FSL_DIU_PORT_DVI: 488c2ecf20Sopenharmony_ci /* Enable the DVI(HDMI) port, disable the DFP and 498c2ecf20Sopenharmony_ci * the backlight 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci clrbits8(cpld_base + CPLD_DIUCSR, CPLD_DIUCSR_DVIEN); 528c2ecf20Sopenharmony_ci break; 538c2ecf20Sopenharmony_ci case FSL_DIU_PORT_LVDS: 548c2ecf20Sopenharmony_ci /* 558c2ecf20Sopenharmony_ci * LVDS also needs backlight enabled, otherwise the display 568c2ecf20Sopenharmony_ci * will be blank. 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_ci /* Enable the DFP port, disable the DVI*/ 598c2ecf20Sopenharmony_ci setbits8(cpld_base + CPLD_DIUCSR, 0x01 << 8); 608c2ecf20Sopenharmony_ci setbits8(cpld_base + CPLD_DIUCSR, 0x01 << 4); 618c2ecf20Sopenharmony_ci setbits8(cpld_base + CPLD_DIUCSR, CPLD_DIUCSR_BACKLIGHT); 628c2ecf20Sopenharmony_ci break; 638c2ecf20Sopenharmony_ci default: 648c2ecf20Sopenharmony_ci pr_err("%s: Unsupported monitor port %i\n", __func__, port); 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci iounmap(cpld_base); 688c2ecf20Sopenharmony_ciexit: 698c2ecf20Sopenharmony_ci of_node_put(cpld_node); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/** 738c2ecf20Sopenharmony_ci * t1042rdb_set_pixel_clock: program the DIU's clock 748c2ecf20Sopenharmony_ci * @pixclock: pixel clock in ps (pico seconds) 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_cistatic void t1042rdb_set_pixel_clock(unsigned int pixclock) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct device_node *scfg_np; 798c2ecf20Sopenharmony_ci void __iomem *scfg; 808c2ecf20Sopenharmony_ci unsigned long freq; 818c2ecf20Sopenharmony_ci u64 temp; 828c2ecf20Sopenharmony_ci u32 pxclk; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci scfg_np = of_find_compatible_node(NULL, NULL, "fsl,t1040-scfg"); 858c2ecf20Sopenharmony_ci if (!scfg_np) { 868c2ecf20Sopenharmony_ci pr_err("%s: Missing scfg node. Can not display video.\n", 878c2ecf20Sopenharmony_ci __func__); 888c2ecf20Sopenharmony_ci return; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci scfg = of_iomap(scfg_np, 0); 928c2ecf20Sopenharmony_ci of_node_put(scfg_np); 938c2ecf20Sopenharmony_ci if (!scfg) { 948c2ecf20Sopenharmony_ci pr_err("%s: Could not map device. Can not display video.\n", 958c2ecf20Sopenharmony_ci __func__); 968c2ecf20Sopenharmony_ci return; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* Convert pixclock into frequency */ 1008c2ecf20Sopenharmony_ci temp = 1000000000000ULL; 1018c2ecf20Sopenharmony_ci do_div(temp, pixclock); 1028c2ecf20Sopenharmony_ci freq = temp; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* 1058c2ecf20Sopenharmony_ci * 'pxclk' is the ratio of the platform clock to the pixel clock. 1068c2ecf20Sopenharmony_ci * This number is programmed into the PIXCLKCR register, and the valid 1078c2ecf20Sopenharmony_ci * range of values is 2-255. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_ci pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq); 1108c2ecf20Sopenharmony_ci pxclk = clamp_t(u32, pxclk, 2, 255); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* Disable the pixel clock, and set it to non-inverted and no delay */ 1138c2ecf20Sopenharmony_ci clrbits32(scfg + CCSR_SCFG_PIXCLKCR, 1148c2ecf20Sopenharmony_ci PIXCLKCR_PXCKEN | PIXCLKCR_PXCKDLY | PIXCLKCR_PXCLK_MASK); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci /* Enable the clock and set the pxclk */ 1178c2ecf20Sopenharmony_ci setbits32(scfg + CCSR_SCFG_PIXCLKCR, PIXCLKCR_PXCKEN | (pxclk << 16)); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci iounmap(scfg); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/** 1238c2ecf20Sopenharmony_ci * t1042rdb_valid_monitor_port: set the monitor port for sysfs 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_cistatic enum fsl_diu_monitor_port 1268c2ecf20Sopenharmony_cit1042rdb_valid_monitor_port(enum fsl_diu_monitor_port port) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci switch (port) { 1298c2ecf20Sopenharmony_ci case FSL_DIU_PORT_DVI: 1308c2ecf20Sopenharmony_ci case FSL_DIU_PORT_LVDS: 1318c2ecf20Sopenharmony_ci return port; 1328c2ecf20Sopenharmony_ci default: 1338c2ecf20Sopenharmony_ci return FSL_DIU_PORT_DVI; /* Dual-link LVDS is not supported */ 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic int __init t1042rdb_diu_init(void) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci cpld_node = of_find_compatible_node(NULL, NULL, "fsl,t1042rdb-cpld"); 1408c2ecf20Sopenharmony_ci if (!cpld_node) 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci diu_ops.set_monitor_port = t1042rdb_set_monitor_port; 1448c2ecf20Sopenharmony_ci diu_ops.set_pixel_clock = t1042rdb_set_pixel_clock; 1458c2ecf20Sopenharmony_ci diu_ops.valid_monitor_port = t1042rdb_valid_monitor_port; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci return 0; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ciearly_initcall(t1042rdb_diu_init); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 153