Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * HDMI wrapper
0004  *
0005  * Copyright (C) 2013 Texas Instruments Incorporated
0006  */
0007 
0008 #define DSS_SUBSYS_NAME "HDMIWP"
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/err.h>
0012 #include <linux/io.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/seq_file.h>
0015 
0016 #include <video/omapfb_dss.h>
0017 
0018 #include "dss.h"
0019 #include "hdmi.h"
0020 
0021 void hdmi_wp_dump(struct hdmi_wp_data *wp, struct seq_file *s)
0022 {
0023 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, hdmi_read_reg(wp->base, r))
0024 
0025     DUMPREG(HDMI_WP_REVISION);
0026     DUMPREG(HDMI_WP_SYSCONFIG);
0027     DUMPREG(HDMI_WP_IRQSTATUS_RAW);
0028     DUMPREG(HDMI_WP_IRQSTATUS);
0029     DUMPREG(HDMI_WP_IRQENABLE_SET);
0030     DUMPREG(HDMI_WP_IRQENABLE_CLR);
0031     DUMPREG(HDMI_WP_IRQWAKEEN);
0032     DUMPREG(HDMI_WP_PWR_CTRL);
0033     DUMPREG(HDMI_WP_DEBOUNCE);
0034     DUMPREG(HDMI_WP_VIDEO_CFG);
0035     DUMPREG(HDMI_WP_VIDEO_SIZE);
0036     DUMPREG(HDMI_WP_VIDEO_TIMING_H);
0037     DUMPREG(HDMI_WP_VIDEO_TIMING_V);
0038     DUMPREG(HDMI_WP_CLK);
0039     DUMPREG(HDMI_WP_AUDIO_CFG);
0040     DUMPREG(HDMI_WP_AUDIO_CFG2);
0041     DUMPREG(HDMI_WP_AUDIO_CTRL);
0042     DUMPREG(HDMI_WP_AUDIO_DATA);
0043 }
0044 
0045 u32 hdmi_wp_get_irqstatus(struct hdmi_wp_data *wp)
0046 {
0047     return hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);
0048 }
0049 
0050 void hdmi_wp_set_irqstatus(struct hdmi_wp_data *wp, u32 irqstatus)
0051 {
0052     hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, irqstatus);
0053     /* flush posted write */
0054     hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);
0055 }
0056 
0057 void hdmi_wp_set_irqenable(struct hdmi_wp_data *wp, u32 mask)
0058 {
0059     hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_SET, mask);
0060 }
0061 
0062 void hdmi_wp_clear_irqenable(struct hdmi_wp_data *wp, u32 mask)
0063 {
0064     hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_CLR, mask);
0065 }
0066 
0067 /* PHY_PWR_CMD */
0068 int hdmi_wp_set_phy_pwr(struct hdmi_wp_data *wp, enum hdmi_phy_pwr val)
0069 {
0070     /* Return if already the state */
0071     if (REG_GET(wp->base, HDMI_WP_PWR_CTRL, 5, 4) == val)
0072         return 0;
0073 
0074     /* Command for power control of HDMI PHY */
0075     REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 7, 6);
0076 
0077     /* Status of the power control of HDMI PHY */
0078     if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 5, 4, val)
0079             != val) {
0080         DSSERR("Failed to set PHY power mode to %d\n", val);
0081         return -ETIMEDOUT;
0082     }
0083 
0084     return 0;
0085 }
0086 
0087 /* PLL_PWR_CMD */
0088 int hdmi_wp_set_pll_pwr(struct hdmi_wp_data *wp, enum hdmi_pll_pwr val)
0089 {
0090     /* Command for power control of HDMI PLL */
0091     REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 3, 2);
0092 
0093     /* wait till PHY_PWR_STATUS is set */
0094     if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 1, 0, val)
0095             != val) {
0096         DSSERR("Failed to set PLL_PWR_STATUS\n");
0097         return -ETIMEDOUT;
0098     }
0099 
0100     return 0;
0101 }
0102 
0103 int hdmi_wp_video_start(struct hdmi_wp_data *wp)
0104 {
0105     REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, true, 31, 31);
0106 
0107     return 0;
0108 }
0109 
0110 void hdmi_wp_video_stop(struct hdmi_wp_data *wp)
0111 {
0112     int i;
0113 
0114     hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, HDMI_IRQ_VIDEO_FRAME_DONE);
0115 
0116     REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, false, 31, 31);
0117 
0118     for (i = 0; i < 50; ++i) {
0119         u32 v;
0120 
0121         msleep(20);
0122 
0123         v = hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS_RAW);
0124         if (v & HDMI_IRQ_VIDEO_FRAME_DONE)
0125             return;
0126     }
0127 
0128     DSSERR("no HDMI FRAMEDONE when disabling output\n");
0129 }
0130 
0131 void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,
0132         struct hdmi_video_format *video_fmt)
0133 {
0134     u32 l = 0;
0135 
0136     REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, video_fmt->packing_mode,
0137         10, 8);
0138 
0139     l |= FLD_VAL(video_fmt->y_res, 31, 16);
0140     l |= FLD_VAL(video_fmt->x_res, 15, 0);
0141     hdmi_write_reg(wp->base, HDMI_WP_VIDEO_SIZE, l);
0142 }
0143 
0144 void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
0145         struct omap_video_timings *timings)
0146 {
0147     u32 r;
0148     bool vsync_pol, hsync_pol;
0149     DSSDBG("Enter hdmi_wp_video_config_interface\n");
0150 
0151     vsync_pol = timings->vsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
0152     hsync_pol = timings->hsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
0153 
0154     r = hdmi_read_reg(wp->base, HDMI_WP_VIDEO_CFG);
0155     r = FLD_MOD(r, vsync_pol, 7, 7);
0156     r = FLD_MOD(r, hsync_pol, 6, 6);
0157     r = FLD_MOD(r, timings->interlace, 3, 3);
0158     r = FLD_MOD(r, 1, 1, 0); /* HDMI_TIMING_MASTER_24BIT */
0159     hdmi_write_reg(wp->base, HDMI_WP_VIDEO_CFG, r);
0160 }
0161 
0162 void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
0163         struct omap_video_timings *timings)
0164 {
0165     u32 timing_h = 0;
0166     u32 timing_v = 0;
0167 
0168     DSSDBG("Enter hdmi_wp_video_config_timing\n");
0169 
0170     timing_h |= FLD_VAL(timings->hbp, 31, 20);
0171     timing_h |= FLD_VAL(timings->hfp, 19, 8);
0172     timing_h |= FLD_VAL(timings->hsw, 7, 0);
0173     hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_H, timing_h);
0174 
0175     timing_v |= FLD_VAL(timings->vbp, 31, 20);
0176     timing_v |= FLD_VAL(timings->vfp, 19, 8);
0177     timing_v |= FLD_VAL(timings->vsw, 7, 0);
0178     hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_V, timing_v);
0179 }
0180 
0181 void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
0182         struct omap_video_timings *timings, struct hdmi_config *param)
0183 {
0184     DSSDBG("Enter hdmi_wp_video_init_format\n");
0185 
0186     video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444;
0187     video_fmt->y_res = param->timings.y_res;
0188     video_fmt->x_res = param->timings.x_res;
0189     if (param->timings.interlace)
0190         video_fmt->y_res /= 2;
0191 
0192     timings->hbp = param->timings.hbp;
0193     timings->hfp = param->timings.hfp;
0194     timings->hsw = param->timings.hsw;
0195     timings->vbp = param->timings.vbp;
0196     timings->vfp = param->timings.vfp;
0197     timings->vsw = param->timings.vsw;
0198     timings->vsync_level = param->timings.vsync_level;
0199     timings->hsync_level = param->timings.hsync_level;
0200     timings->interlace = param->timings.interlace;
0201 }
0202 
0203 void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
0204         struct hdmi_audio_format *aud_fmt)
0205 {
0206     u32 r;
0207 
0208     DSSDBG("Enter hdmi_wp_audio_config_format\n");
0209 
0210     r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG);
0211     if (omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES1 ||
0212         omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES2 ||
0213         omapdss_get_version() == OMAPDSS_VER_OMAP4) {
0214         r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
0215         r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
0216     }
0217     r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);
0218     r = FLD_MOD(r, aud_fmt->type, 4, 4);
0219     r = FLD_MOD(r, aud_fmt->justification, 3, 3);
0220     r = FLD_MOD(r, aud_fmt->sample_order, 2, 2);
0221     r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1);
0222     r = FLD_MOD(r, aud_fmt->sample_size, 0, 0);
0223     hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG, r);
0224 }
0225 
0226 void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,
0227         struct hdmi_audio_dma *aud_dma)
0228 {
0229     u32 r;
0230 
0231     DSSDBG("Enter hdmi_wp_audio_config_dma\n");
0232 
0233     r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG2);
0234     r = FLD_MOD(r, aud_dma->transfer_size, 15, 8);
0235     r = FLD_MOD(r, aud_dma->block_size, 7, 0);
0236     hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG2, r);
0237 
0238     r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CTRL);
0239     r = FLD_MOD(r, aud_dma->mode, 9, 9);
0240     r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0);
0241     hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CTRL, r);
0242 }
0243 
0244 int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable)
0245 {
0246     REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 31, 31);
0247 
0248     return 0;
0249 }
0250 
0251 int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable)
0252 {
0253     REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 30, 30);
0254 
0255     return 0;
0256 }
0257 
0258 int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
0259 {
0260     struct resource *res;
0261 
0262     res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wp");
0263     if (!res) {
0264         DSSERR("can't get WP mem resource\n");
0265         return -EINVAL;
0266     }
0267     wp->phys_base = res->start;
0268 
0269     wp->base = devm_ioremap_resource(&pdev->dev, res);
0270     if (IS_ERR(wp->base)) {
0271         DSSERR("can't ioremap HDMI WP\n");
0272         return PTR_ERR(wp->base);
0273     }
0274 
0275     return 0;
0276 }
0277 
0278 phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp)
0279 {
0280     return wp->phys_base + HDMI_WP_AUDIO_DATA;
0281 }