Path: blob/master/arch/powerpc/platforms/85xx/t1042rdb_diu.c
26481 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* T1042 platform DIU operation3*4* Copyright 2014 Freescale Semiconductor Inc.5*/67#include <linux/init.h>8#include <linux/io.h>9#include <linux/kernel.h>10#include <linux/module.h>11#include <linux/of.h>12#include <linux/of_address.h>1314#include <sysdev/fsl_soc.h>1516/*DIU Pixel ClockCR offset in scfg*/17#define CCSR_SCFG_PIXCLKCR 0x281819/* DIU Pixel Clock bits of the PIXCLKCR */20#define PIXCLKCR_PXCKEN 0x8000000021#define PIXCLKCR_PXCKINV 0x4000000022#define PIXCLKCR_PXCKDLY 0x0000FF0023#define PIXCLKCR_PXCLK_MASK 0x00FF00002425/* Some CPLD register definitions */26#define CPLD_DIUCSR 0x1627#define CPLD_DIUCSR_DVIEN 0x8028#define CPLD_DIUCSR_BACKLIGHT 0x0f2930struct device_node *cpld_node;3132/**33* t1042rdb_set_monitor_port: switch the output to a different monitor port34*/35static void t1042rdb_set_monitor_port(enum fsl_diu_monitor_port port)36{37void __iomem *cpld_base;3839cpld_base = of_iomap(cpld_node, 0);40if (!cpld_base) {41pr_err("%s: Could not map cpld registers\n", __func__);42goto exit;43}4445switch (port) {46case FSL_DIU_PORT_DVI:47/* Enable the DVI(HDMI) port, disable the DFP and48* the backlight49*/50clrbits8(cpld_base + CPLD_DIUCSR, CPLD_DIUCSR_DVIEN);51break;52case FSL_DIU_PORT_LVDS:53/*54* LVDS also needs backlight enabled, otherwise the display55* will be blank.56*/57/* Enable the DFP port, disable the DVI*/58setbits8(cpld_base + CPLD_DIUCSR, 0x01 << 8);59setbits8(cpld_base + CPLD_DIUCSR, 0x01 << 4);60setbits8(cpld_base + CPLD_DIUCSR, CPLD_DIUCSR_BACKLIGHT);61break;62default:63pr_err("%s: Unsupported monitor port %i\n", __func__, port);64}6566iounmap(cpld_base);67exit:68of_node_put(cpld_node);69}7071/**72* t1042rdb_set_pixel_clock: program the DIU's clock73* @pixclock: pixel clock in ps (pico seconds)74*/75static void t1042rdb_set_pixel_clock(unsigned int pixclock)76{77struct device_node *scfg_np;78void __iomem *scfg;79unsigned long freq;80u64 temp;81u32 pxclk;8283scfg_np = of_find_compatible_node(NULL, NULL, "fsl,t1040-scfg");84if (!scfg_np) {85pr_err("%s: Missing scfg node. Can not display video.\n",86__func__);87return;88}8990scfg = of_iomap(scfg_np, 0);91of_node_put(scfg_np);92if (!scfg) {93pr_err("%s: Could not map device. Can not display video.\n",94__func__);95return;96}9798/* Convert pixclock into frequency */99temp = 1000000000000ULL;100do_div(temp, pixclock);101freq = temp;102103/*104* 'pxclk' is the ratio of the platform clock to the pixel clock.105* This number is programmed into the PIXCLKCR register, and the valid106* range of values is 2-255.107*/108pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq);109pxclk = clamp_t(u32, pxclk, 2, 255);110111/* Disable the pixel clock, and set it to non-inverted and no delay */112clrbits32(scfg + CCSR_SCFG_PIXCLKCR,113PIXCLKCR_PXCKEN | PIXCLKCR_PXCKDLY | PIXCLKCR_PXCLK_MASK);114115/* Enable the clock and set the pxclk */116setbits32(scfg + CCSR_SCFG_PIXCLKCR, PIXCLKCR_PXCKEN | (pxclk << 16));117118iounmap(scfg);119}120121/**122* t1042rdb_valid_monitor_port: set the monitor port for sysfs123*/124static enum fsl_diu_monitor_port125t1042rdb_valid_monitor_port(enum fsl_diu_monitor_port port)126{127switch (port) {128case FSL_DIU_PORT_DVI:129case FSL_DIU_PORT_LVDS:130return port;131default:132return FSL_DIU_PORT_DVI; /* Dual-link LVDS is not supported */133}134}135136static int __init t1042rdb_diu_init(void)137{138cpld_node = of_find_compatible_node(NULL, NULL, "fsl,t1042rdb-cpld");139if (!cpld_node)140return 0;141142diu_ops.set_monitor_port = t1042rdb_set_monitor_port;143diu_ops.set_pixel_clock = t1042rdb_set_pixel_clock;144diu_ops.valid_monitor_port = t1042rdb_valid_monitor_port;145146return 0;147}148149early_initcall(t1042rdb_diu_init);150151MODULE_DESCRIPTION("Freescale T1042 DIU driver");152MODULE_LICENSE("GPL");153154155