282 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * HDMI wrapper4 *5 * Copyright (C) 2013 Texas Instruments Incorporated6 */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 <video/omapfb_dss.h>17 18#include "dss.h"19#include "hdmi.h"20 21void hdmi_wp_dump(struct hdmi_wp_data *wp, struct seq_file *s)22{23#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, hdmi_read_reg(wp->base, r))24 25 DUMPREG(HDMI_WP_REVISION);26 DUMPREG(HDMI_WP_SYSCONFIG);27 DUMPREG(HDMI_WP_IRQSTATUS_RAW);28 DUMPREG(HDMI_WP_IRQSTATUS);29 DUMPREG(HDMI_WP_IRQENABLE_SET);30 DUMPREG(HDMI_WP_IRQENABLE_CLR);31 DUMPREG(HDMI_WP_IRQWAKEEN);32 DUMPREG(HDMI_WP_PWR_CTRL);33 DUMPREG(HDMI_WP_DEBOUNCE);34 DUMPREG(HDMI_WP_VIDEO_CFG);35 DUMPREG(HDMI_WP_VIDEO_SIZE);36 DUMPREG(HDMI_WP_VIDEO_TIMING_H);37 DUMPREG(HDMI_WP_VIDEO_TIMING_V);38 DUMPREG(HDMI_WP_CLK);39 DUMPREG(HDMI_WP_AUDIO_CFG);40 DUMPREG(HDMI_WP_AUDIO_CFG2);41 DUMPREG(HDMI_WP_AUDIO_CTRL);42 DUMPREG(HDMI_WP_AUDIO_DATA);43}44 45u32 hdmi_wp_get_irqstatus(struct hdmi_wp_data *wp)46{47 return hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);48}49 50void hdmi_wp_set_irqstatus(struct hdmi_wp_data *wp, u32 irqstatus)51{52 hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, irqstatus);53 /* flush posted write */54 hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);55}56 57void hdmi_wp_set_irqenable(struct hdmi_wp_data *wp, u32 mask)58{59 hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_SET, mask);60}61 62void hdmi_wp_clear_irqenable(struct hdmi_wp_data *wp, u32 mask)63{64 hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_CLR, mask);65}66 67/* PHY_PWR_CMD */68int hdmi_wp_set_phy_pwr(struct hdmi_wp_data *wp, enum hdmi_phy_pwr val)69{70 /* Return if already the state */71 if (REG_GET(wp->base, HDMI_WP_PWR_CTRL, 5, 4) == val)72 return 0;73 74 /* Command for power control of HDMI PHY */75 REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 7, 6);76 77 /* Status of the power control of HDMI PHY */78 if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 5, 4, val)79 != val) {80 DSSERR("Failed to set PHY power mode to %d\n", val);81 return -ETIMEDOUT;82 }83 84 return 0;85}86 87/* PLL_PWR_CMD */88int hdmi_wp_set_pll_pwr(struct hdmi_wp_data *wp, enum hdmi_pll_pwr val)89{90 /* Command for power control of HDMI PLL */91 REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 3, 2);92 93 /* wait till PHY_PWR_STATUS is set */94 if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 1, 0, val)95 != val) {96 DSSERR("Failed to set PLL_PWR_STATUS\n");97 return -ETIMEDOUT;98 }99 100 return 0;101}102 103int hdmi_wp_video_start(struct hdmi_wp_data *wp)104{105 REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, true, 31, 31);106 107 return 0;108}109 110void hdmi_wp_video_stop(struct hdmi_wp_data *wp)111{112 int i;113 114 hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, HDMI_IRQ_VIDEO_FRAME_DONE);115 116 REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, false, 31, 31);117 118 for (i = 0; i < 50; ++i) {119 u32 v;120 121 msleep(20);122 123 v = hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS_RAW);124 if (v & HDMI_IRQ_VIDEO_FRAME_DONE)125 return;126 }127 128 DSSERR("no HDMI FRAMEDONE when disabling output\n");129}130 131void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,132 struct hdmi_video_format *video_fmt)133{134 u32 l = 0;135 136 REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, video_fmt->packing_mode,137 10, 8);138 139 l |= FLD_VAL(video_fmt->y_res, 31, 16);140 l |= FLD_VAL(video_fmt->x_res, 15, 0);141 hdmi_write_reg(wp->base, HDMI_WP_VIDEO_SIZE, l);142}143 144void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,145 struct omap_video_timings *timings)146{147 u32 r;148 bool vsync_pol, hsync_pol;149 DSSDBG("Enter hdmi_wp_video_config_interface\n");150 151 vsync_pol = timings->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH;152 hsync_pol = timings->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH;153 154 r = hdmi_read_reg(wp->base, HDMI_WP_VIDEO_CFG);155 r = FLD_MOD(r, vsync_pol, 7, 7);156 r = FLD_MOD(r, hsync_pol, 6, 6);157 r = FLD_MOD(r, timings->interlace, 3, 3);158 r = FLD_MOD(r, 1, 1, 0); /* HDMI_TIMING_MASTER_24BIT */159 hdmi_write_reg(wp->base, HDMI_WP_VIDEO_CFG, r);160}161 162void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,163 struct omap_video_timings *timings)164{165 u32 timing_h = 0;166 u32 timing_v = 0;167 168 DSSDBG("Enter hdmi_wp_video_config_timing\n");169 170 timing_h |= FLD_VAL(timings->hbp, 31, 20);171 timing_h |= FLD_VAL(timings->hfp, 19, 8);172 timing_h |= FLD_VAL(timings->hsw, 7, 0);173 hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_H, timing_h);174 175 timing_v |= FLD_VAL(timings->vbp, 31, 20);176 timing_v |= FLD_VAL(timings->vfp, 19, 8);177 timing_v |= FLD_VAL(timings->vsw, 7, 0);178 hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_V, timing_v);179}180 181void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,182 struct omap_video_timings *timings, struct hdmi_config *param)183{184 DSSDBG("Enter hdmi_wp_video_init_format\n");185 186 video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444;187 video_fmt->y_res = param->timings.y_res;188 video_fmt->x_res = param->timings.x_res;189 if (param->timings.interlace)190 video_fmt->y_res /= 2;191 192 timings->hbp = param->timings.hbp;193 timings->hfp = param->timings.hfp;194 timings->hsw = param->timings.hsw;195 timings->vbp = param->timings.vbp;196 timings->vfp = param->timings.vfp;197 timings->vsw = param->timings.vsw;198 timings->vsync_level = param->timings.vsync_level;199 timings->hsync_level = param->timings.hsync_level;200 timings->interlace = param->timings.interlace;201}202 203void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,204 struct hdmi_audio_format *aud_fmt)205{206 u32 r;207 208 DSSDBG("Enter hdmi_wp_audio_config_format\n");209 210 r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG);211 if (omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES1 ||212 omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES2 ||213 omapdss_get_version() == OMAPDSS_VER_OMAP4) {214 r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);215 r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);216 }217 r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);218 r = FLD_MOD(r, aud_fmt->type, 4, 4);219 r = FLD_MOD(r, aud_fmt->justification, 3, 3);220 r = FLD_MOD(r, aud_fmt->sample_order, 2, 2);221 r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1);222 r = FLD_MOD(r, aud_fmt->sample_size, 0, 0);223 hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG, r);224}225 226void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,227 struct hdmi_audio_dma *aud_dma)228{229 u32 r;230 231 DSSDBG("Enter hdmi_wp_audio_config_dma\n");232 233 r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG2);234 r = FLD_MOD(r, aud_dma->transfer_size, 15, 8);235 r = FLD_MOD(r, aud_dma->block_size, 7, 0);236 hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG2, r);237 238 r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CTRL);239 r = FLD_MOD(r, aud_dma->mode, 9, 9);240 r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0);241 hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CTRL, r);242}243 244int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable)245{246 REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 31, 31);247 248 return 0;249}250 251int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable)252{253 REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 30, 30);254 255 return 0;256}257 258int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)259{260 struct resource *res;261 262 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wp");263 if (!res) {264 DSSERR("can't get WP mem resource\n");265 return -EINVAL;266 }267 wp->phys_base = res->start;268 269 wp->base = devm_ioremap_resource(&pdev->dev, res);270 if (IS_ERR(wp->base)) {271 DSSERR("can't ioremap HDMI WP\n");272 return PTR_ERR(wp->base);273 }274 275 return 0;276}277 278phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp)279{280 return wp->phys_base + HDMI_WP_AUDIO_DATA;281}282