162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * T1042 platform DIU operation 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2014 Freescale Semiconductor Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/init.h> 962306a36Sopenharmony_ci#include <linux/io.h> 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/of.h> 1362306a36Sopenharmony_ci#include <linux/of_address.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <sysdev/fsl_soc.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/*DIU Pixel ClockCR offset in scfg*/ 1862306a36Sopenharmony_ci#define CCSR_SCFG_PIXCLKCR 0x28 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* DIU Pixel Clock bits of the PIXCLKCR */ 2162306a36Sopenharmony_ci#define PIXCLKCR_PXCKEN 0x80000000 2262306a36Sopenharmony_ci#define PIXCLKCR_PXCKINV 0x40000000 2362306a36Sopenharmony_ci#define PIXCLKCR_PXCKDLY 0x0000FF00 2462306a36Sopenharmony_ci#define PIXCLKCR_PXCLK_MASK 0x00FF0000 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* Some CPLD register definitions */ 2762306a36Sopenharmony_ci#define CPLD_DIUCSR 0x16 2862306a36Sopenharmony_ci#define CPLD_DIUCSR_DVIEN 0x80 2962306a36Sopenharmony_ci#define CPLD_DIUCSR_BACKLIGHT 0x0f 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistruct device_node *cpld_node; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/** 3462306a36Sopenharmony_ci * t1042rdb_set_monitor_port: switch the output to a different monitor port 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_cistatic void t1042rdb_set_monitor_port(enum fsl_diu_monitor_port port) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci void __iomem *cpld_base; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci cpld_base = of_iomap(cpld_node, 0); 4162306a36Sopenharmony_ci if (!cpld_base) { 4262306a36Sopenharmony_ci pr_err("%s: Could not map cpld registers\n", __func__); 4362306a36Sopenharmony_ci goto exit; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci switch (port) { 4762306a36Sopenharmony_ci case FSL_DIU_PORT_DVI: 4862306a36Sopenharmony_ci /* Enable the DVI(HDMI) port, disable the DFP and 4962306a36Sopenharmony_ci * the backlight 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci clrbits8(cpld_base + CPLD_DIUCSR, CPLD_DIUCSR_DVIEN); 5262306a36Sopenharmony_ci break; 5362306a36Sopenharmony_ci case FSL_DIU_PORT_LVDS: 5462306a36Sopenharmony_ci /* 5562306a36Sopenharmony_ci * LVDS also needs backlight enabled, otherwise the display 5662306a36Sopenharmony_ci * will be blank. 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_ci /* Enable the DFP port, disable the DVI*/ 5962306a36Sopenharmony_ci setbits8(cpld_base + CPLD_DIUCSR, 0x01 << 8); 6062306a36Sopenharmony_ci setbits8(cpld_base + CPLD_DIUCSR, 0x01 << 4); 6162306a36Sopenharmony_ci setbits8(cpld_base + CPLD_DIUCSR, CPLD_DIUCSR_BACKLIGHT); 6262306a36Sopenharmony_ci break; 6362306a36Sopenharmony_ci default: 6462306a36Sopenharmony_ci pr_err("%s: Unsupported monitor port %i\n", __func__, port); 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci iounmap(cpld_base); 6862306a36Sopenharmony_ciexit: 6962306a36Sopenharmony_ci of_node_put(cpld_node); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/** 7362306a36Sopenharmony_ci * t1042rdb_set_pixel_clock: program the DIU's clock 7462306a36Sopenharmony_ci * @pixclock: pixel clock in ps (pico seconds) 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_cistatic void t1042rdb_set_pixel_clock(unsigned int pixclock) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct device_node *scfg_np; 7962306a36Sopenharmony_ci void __iomem *scfg; 8062306a36Sopenharmony_ci unsigned long freq; 8162306a36Sopenharmony_ci u64 temp; 8262306a36Sopenharmony_ci u32 pxclk; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci scfg_np = of_find_compatible_node(NULL, NULL, "fsl,t1040-scfg"); 8562306a36Sopenharmony_ci if (!scfg_np) { 8662306a36Sopenharmony_ci pr_err("%s: Missing scfg node. Can not display video.\n", 8762306a36Sopenharmony_ci __func__); 8862306a36Sopenharmony_ci return; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci scfg = of_iomap(scfg_np, 0); 9262306a36Sopenharmony_ci of_node_put(scfg_np); 9362306a36Sopenharmony_ci if (!scfg) { 9462306a36Sopenharmony_ci pr_err("%s: Could not map device. Can not display video.\n", 9562306a36Sopenharmony_ci __func__); 9662306a36Sopenharmony_ci return; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* Convert pixclock into frequency */ 10062306a36Sopenharmony_ci temp = 1000000000000ULL; 10162306a36Sopenharmony_ci do_div(temp, pixclock); 10262306a36Sopenharmony_ci freq = temp; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci /* 10562306a36Sopenharmony_ci * 'pxclk' is the ratio of the platform clock to the pixel clock. 10662306a36Sopenharmony_ci * This number is programmed into the PIXCLKCR register, and the valid 10762306a36Sopenharmony_ci * range of values is 2-255. 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_ci pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq); 11062306a36Sopenharmony_ci pxclk = clamp_t(u32, pxclk, 2, 255); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* Disable the pixel clock, and set it to non-inverted and no delay */ 11362306a36Sopenharmony_ci clrbits32(scfg + CCSR_SCFG_PIXCLKCR, 11462306a36Sopenharmony_ci PIXCLKCR_PXCKEN | PIXCLKCR_PXCKDLY | PIXCLKCR_PXCLK_MASK); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* Enable the clock and set the pxclk */ 11762306a36Sopenharmony_ci setbits32(scfg + CCSR_SCFG_PIXCLKCR, PIXCLKCR_PXCKEN | (pxclk << 16)); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci iounmap(scfg); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/** 12362306a36Sopenharmony_ci * t1042rdb_valid_monitor_port: set the monitor port for sysfs 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_cistatic enum fsl_diu_monitor_port 12662306a36Sopenharmony_cit1042rdb_valid_monitor_port(enum fsl_diu_monitor_port port) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci switch (port) { 12962306a36Sopenharmony_ci case FSL_DIU_PORT_DVI: 13062306a36Sopenharmony_ci case FSL_DIU_PORT_LVDS: 13162306a36Sopenharmony_ci return port; 13262306a36Sopenharmony_ci default: 13362306a36Sopenharmony_ci return FSL_DIU_PORT_DVI; /* Dual-link LVDS is not supported */ 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic int __init t1042rdb_diu_init(void) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci cpld_node = of_find_compatible_node(NULL, NULL, "fsl,t1042rdb-cpld"); 14062306a36Sopenharmony_ci if (!cpld_node) 14162306a36Sopenharmony_ci return 0; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci diu_ops.set_monitor_port = t1042rdb_set_monitor_port; 14462306a36Sopenharmony_ci diu_ops.set_pixel_clock = t1042rdb_set_pixel_clock; 14562306a36Sopenharmony_ci diu_ops.valid_monitor_port = t1042rdb_valid_monitor_port; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci return 0; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ciearly_initcall(t1042rdb_diu_init); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 153