brintos

brintos / linux-shallow public Read only

0
0
Text · 7.7 KiB · 9d83058 Raw
298 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * HDMI wrapper4 *5 * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com/6 */7 8#define DSS_SUBSYS_NAME "HDMIWP"9 10#include <linux/kernel.h>11#include <linux/err.h>12#include <linux/io.h>13#include <linux/platform_device.h>14#include <linux/seq_file.h>15 16#include "omapdss.h"17#include "dss.h"18#include "hdmi.h"19 20void hdmi_wp_dump(struct hdmi_wp_data *wp, struct seq_file *s)21{22#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, hdmi_read_reg(wp->base, r))23 24	DUMPREG(HDMI_WP_REVISION);25	DUMPREG(HDMI_WP_SYSCONFIG);26	DUMPREG(HDMI_WP_IRQSTATUS_RAW);27	DUMPREG(HDMI_WP_IRQSTATUS);28	DUMPREG(HDMI_WP_IRQENABLE_SET);29	DUMPREG(HDMI_WP_IRQENABLE_CLR);30	DUMPREG(HDMI_WP_IRQWAKEEN);31	DUMPREG(HDMI_WP_PWR_CTRL);32	DUMPREG(HDMI_WP_DEBOUNCE);33	DUMPREG(HDMI_WP_VIDEO_CFG);34	DUMPREG(HDMI_WP_VIDEO_SIZE);35	DUMPREG(HDMI_WP_VIDEO_TIMING_H);36	DUMPREG(HDMI_WP_VIDEO_TIMING_V);37	DUMPREG(HDMI_WP_CLK);38	DUMPREG(HDMI_WP_AUDIO_CFG);39	DUMPREG(HDMI_WP_AUDIO_CFG2);40	DUMPREG(HDMI_WP_AUDIO_CTRL);41	DUMPREG(HDMI_WP_AUDIO_DATA);42}43 44u32 hdmi_wp_get_irqstatus(struct hdmi_wp_data *wp)45{46	return hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);47}48 49void hdmi_wp_set_irqstatus(struct hdmi_wp_data *wp, u32 irqstatus)50{51	hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, irqstatus);52	/* flush posted write */53	hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);54}55 56void hdmi_wp_set_irqenable(struct hdmi_wp_data *wp, u32 mask)57{58	hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_SET, mask);59}60 61void hdmi_wp_clear_irqenable(struct hdmi_wp_data *wp, u32 mask)62{63	hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_CLR, mask);64}65 66/* PHY_PWR_CMD */67int hdmi_wp_set_phy_pwr(struct hdmi_wp_data *wp, enum hdmi_phy_pwr val)68{69	/* Return if already the state */70	if (REG_GET(wp->base, HDMI_WP_PWR_CTRL, 5, 4) == val)71		return 0;72 73	/* Command for power control of HDMI PHY */74	REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 7, 6);75 76	/* Status of the power control of HDMI PHY */77	if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 5, 4, val)78			!= val) {79		DSSERR("Failed to set PHY power mode to %d\n", val);80		return -ETIMEDOUT;81	}82 83	return 0;84}85 86/* PLL_PWR_CMD */87int hdmi_wp_set_pll_pwr(struct hdmi_wp_data *wp, enum hdmi_pll_pwr val)88{89	/* Command for power control of HDMI PLL */90	REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 3, 2);91 92	/* wait till PHY_PWR_STATUS is set */93	if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 1, 0, val)94			!= val) {95		DSSERR("Failed to set PLL_PWR_STATUS\n");96		return -ETIMEDOUT;97	}98 99	return 0;100}101 102int hdmi_wp_video_start(struct hdmi_wp_data *wp)103{104	REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, true, 31, 31);105 106	return 0;107}108 109void hdmi_wp_video_stop(struct hdmi_wp_data *wp)110{111	int i;112 113	hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, HDMI_IRQ_VIDEO_FRAME_DONE);114 115	REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, false, 31, 31);116 117	for (i = 0; i < 50; ++i) {118		u32 v;119 120		msleep(20);121 122		v = hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS_RAW);123		if (v & HDMI_IRQ_VIDEO_FRAME_DONE)124			return;125	}126 127	DSSERR("no HDMI FRAMEDONE when disabling output\n");128}129 130void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,131		const struct hdmi_video_format *video_fmt)132{133	u32 l = 0;134 135	REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, video_fmt->packing_mode,136		10, 8);137 138	l |= FLD_VAL(video_fmt->y_res, 31, 16);139	l |= FLD_VAL(video_fmt->x_res, 15, 0);140	hdmi_write_reg(wp->base, HDMI_WP_VIDEO_SIZE, l);141}142 143void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,144				    const struct videomode *vm)145{146	u32 r;147	bool vsync_inv, hsync_inv;148	DSSDBG("Enter hdmi_wp_video_config_interface\n");149 150	vsync_inv = !!(vm->flags & DISPLAY_FLAGS_VSYNC_LOW);151	hsync_inv = !!(vm->flags & DISPLAY_FLAGS_HSYNC_LOW);152 153	r = hdmi_read_reg(wp->base, HDMI_WP_VIDEO_CFG);154	r = FLD_MOD(r, 1, 7, 7);	/* VSYNC_POL to dispc active high */155	r = FLD_MOD(r, 1, 6, 6);	/* HSYNC_POL to dispc active high */156	r = FLD_MOD(r, vsync_inv, 5, 5);	/* CORE_VSYNC_INV */157	r = FLD_MOD(r, hsync_inv, 4, 4);	/* CORE_HSYNC_INV */158	r = FLD_MOD(r, !!(vm->flags & DISPLAY_FLAGS_INTERLACED), 3, 3);159	r = FLD_MOD(r, 1, 1, 0); /* HDMI_TIMING_MASTER_24BIT */160	hdmi_write_reg(wp->base, HDMI_WP_VIDEO_CFG, r);161}162 163void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,164				 const struct videomode *vm)165{166	u32 timing_h = 0;167	u32 timing_v = 0;168	unsigned int hsync_len_offset = 1;169 170	DSSDBG("Enter hdmi_wp_video_config_timing\n");171 172	/*173	 * On OMAP4 and OMAP5 ES1 the HSW field is programmed as is. On OMAP5174	 * ES2+ (including DRA7/AM5 SoCs) HSW field is programmed to hsync_len-1.175	 * However, we don't support OMAP5 ES1 at all, so we can just check for176	 * OMAP4 here.177	 */178	if (wp->version == 4)179		hsync_len_offset = 0;180 181	timing_h |= FLD_VAL(vm->hback_porch, 31, 20);182	timing_h |= FLD_VAL(vm->hfront_porch, 19, 8);183	timing_h |= FLD_VAL(vm->hsync_len - hsync_len_offset, 7, 0);184	hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_H, timing_h);185 186	timing_v |= FLD_VAL(vm->vback_porch, 31, 20);187	timing_v |= FLD_VAL(vm->vfront_porch, 19, 8);188	timing_v |= FLD_VAL(vm->vsync_len, 7, 0);189	hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_V, timing_v);190}191 192void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,193		struct videomode *vm, const struct hdmi_config *param)194{195	DSSDBG("Enter hdmi_wp_video_init_format\n");196 197	video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444;198	video_fmt->y_res = param->vm.vactive;199	video_fmt->x_res = param->vm.hactive;200 201	vm->hback_porch = param->vm.hback_porch;202	vm->hfront_porch = param->vm.hfront_porch;203	vm->hsync_len = param->vm.hsync_len;204	vm->vback_porch = param->vm.vback_porch;205	vm->vfront_porch = param->vm.vfront_porch;206	vm->vsync_len = param->vm.vsync_len;207 208	vm->flags = param->vm.flags;209 210	if (param->vm.flags & DISPLAY_FLAGS_INTERLACED) {211		video_fmt->y_res /= 2;212		vm->vback_porch /= 2;213		vm->vfront_porch /= 2;214		vm->vsync_len /= 2;215	}216 217	if (param->vm.flags & DISPLAY_FLAGS_DOUBLECLK) {218		video_fmt->x_res *= 2;219		vm->hfront_porch *= 2;220		vm->hsync_len *= 2;221		vm->hback_porch *= 2;222	}223}224 225void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,226		struct hdmi_audio_format *aud_fmt)227{228	u32 r;229 230	DSSDBG("Enter hdmi_wp_audio_config_format\n");231 232	r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG);233	if (wp->version == 4) {234		r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);235		r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);236	}237	r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);238	r = FLD_MOD(r, aud_fmt->type, 4, 4);239	r = FLD_MOD(r, aud_fmt->justification, 3, 3);240	r = FLD_MOD(r, aud_fmt->sample_order, 2, 2);241	r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1);242	r = FLD_MOD(r, aud_fmt->sample_size, 0, 0);243	hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG, r);244}245 246void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,247		struct hdmi_audio_dma *aud_dma)248{249	u32 r;250 251	DSSDBG("Enter hdmi_wp_audio_config_dma\n");252 253	r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG2);254	r = FLD_MOD(r, aud_dma->transfer_size, 15, 8);255	r = FLD_MOD(r, aud_dma->block_size, 7, 0);256	hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG2, r);257 258	r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CTRL);259	r = FLD_MOD(r, aud_dma->mode, 9, 9);260	r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0);261	hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CTRL, r);262}263 264int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable)265{266	REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 31, 31);267 268	return 0;269}270 271int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable)272{273	REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 30, 30);274 275	return 0;276}277 278int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp,279		 unsigned int version)280{281	struct resource *res;282 283	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wp");284	wp->base = devm_ioremap_resource(&pdev->dev, res);285	if (IS_ERR(wp->base))286		return PTR_ERR(wp->base);287 288	wp->phys_base = res->start;289	wp->version = version;290 291	return 0;292}293 294phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp)295{296	return wp->phys_base + HDMI_WP_AUDIO_DATA;297}298