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 - https://www.ti.com/
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 "omapdss.h"
0017 #include "dss.h"
0018 #include "hdmi.h"
0019 
0020 void hdmi_wp_dump(struct hdmi_wp_data *wp, struct seq_file *s)
0021 {
0022 #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, hdmi_read_reg(wp->base, r))
0023 
0024     DUMPREG(HDMI_WP_REVISION);
0025     DUMPREG(HDMI_WP_SYSCONFIG);
0026     DUMPREG(HDMI_WP_IRQSTATUS_RAW);
0027     DUMPREG(HDMI_WP_IRQSTATUS);
0028     DUMPREG(HDMI_WP_IRQENABLE_SET);
0029     DUMPREG(HDMI_WP_IRQENABLE_CLR);
0030     DUMPREG(HDMI_WP_IRQWAKEEN);
0031     DUMPREG(HDMI_WP_PWR_CTRL);
0032     DUMPREG(HDMI_WP_DEBOUNCE);
0033     DUMPREG(HDMI_WP_VIDEO_CFG);
0034     DUMPREG(HDMI_WP_VIDEO_SIZE);
0035     DUMPREG(HDMI_WP_VIDEO_TIMING_H);
0036     DUMPREG(HDMI_WP_VIDEO_TIMING_V);
0037     DUMPREG(HDMI_WP_CLK);
0038     DUMPREG(HDMI_WP_AUDIO_CFG);
0039     DUMPREG(HDMI_WP_AUDIO_CFG2);
0040     DUMPREG(HDMI_WP_AUDIO_CTRL);
0041     DUMPREG(HDMI_WP_AUDIO_DATA);
0042 }
0043 
0044 u32 hdmi_wp_get_irqstatus(struct hdmi_wp_data *wp)
0045 {
0046     return hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);
0047 }
0048 
0049 void hdmi_wp_set_irqstatus(struct hdmi_wp_data *wp, u32 irqstatus)
0050 {
0051     hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, irqstatus);
0052     /* flush posted write */
0053     hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS);
0054 }
0055 
0056 void hdmi_wp_set_irqenable(struct hdmi_wp_data *wp, u32 mask)
0057 {
0058     hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_SET, mask);
0059 }
0060 
0061 void hdmi_wp_clear_irqenable(struct hdmi_wp_data *wp, u32 mask)
0062 {
0063     hdmi_write_reg(wp->base, HDMI_WP_IRQENABLE_CLR, mask);
0064 }
0065 
0066 /* PHY_PWR_CMD */
0067 int hdmi_wp_set_phy_pwr(struct hdmi_wp_data *wp, enum hdmi_phy_pwr val)
0068 {
0069     /* Return if already the state */
0070     if (REG_GET(wp->base, HDMI_WP_PWR_CTRL, 5, 4) == val)
0071         return 0;
0072 
0073     /* Command for power control of HDMI PHY */
0074     REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 7, 6);
0075 
0076     /* Status of the power control of HDMI PHY */
0077     if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 5, 4, val)
0078             != val) {
0079         DSSERR("Failed to set PHY power mode to %d\n", val);
0080         return -ETIMEDOUT;
0081     }
0082 
0083     return 0;
0084 }
0085 
0086 /* PLL_PWR_CMD */
0087 int hdmi_wp_set_pll_pwr(struct hdmi_wp_data *wp, enum hdmi_pll_pwr val)
0088 {
0089     /* Command for power control of HDMI PLL */
0090     REG_FLD_MOD(wp->base, HDMI_WP_PWR_CTRL, val, 3, 2);
0091 
0092     /* wait till PHY_PWR_STATUS is set */
0093     if (hdmi_wait_for_bit_change(wp->base, HDMI_WP_PWR_CTRL, 1, 0, val)
0094             != val) {
0095         DSSERR("Failed to set PLL_PWR_STATUS\n");
0096         return -ETIMEDOUT;
0097     }
0098 
0099     return 0;
0100 }
0101 
0102 int hdmi_wp_video_start(struct hdmi_wp_data *wp)
0103 {
0104     REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, true, 31, 31);
0105 
0106     return 0;
0107 }
0108 
0109 void hdmi_wp_video_stop(struct hdmi_wp_data *wp)
0110 {
0111     int i;
0112 
0113     hdmi_write_reg(wp->base, HDMI_WP_IRQSTATUS, HDMI_IRQ_VIDEO_FRAME_DONE);
0114 
0115     REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, false, 31, 31);
0116 
0117     for (i = 0; i < 50; ++i) {
0118         u32 v;
0119 
0120         msleep(20);
0121 
0122         v = hdmi_read_reg(wp->base, HDMI_WP_IRQSTATUS_RAW);
0123         if (v & HDMI_IRQ_VIDEO_FRAME_DONE)
0124             return;
0125     }
0126 
0127     DSSERR("no HDMI FRAMEDONE when disabling output\n");
0128 }
0129 
0130 void hdmi_wp_video_config_format(struct hdmi_wp_data *wp,
0131         const struct hdmi_video_format *video_fmt)
0132 {
0133     u32 l = 0;
0134 
0135     REG_FLD_MOD(wp->base, HDMI_WP_VIDEO_CFG, video_fmt->packing_mode,
0136         10, 8);
0137 
0138     l |= FLD_VAL(video_fmt->y_res, 31, 16);
0139     l |= FLD_VAL(video_fmt->x_res, 15, 0);
0140     hdmi_write_reg(wp->base, HDMI_WP_VIDEO_SIZE, l);
0141 }
0142 
0143 void hdmi_wp_video_config_interface(struct hdmi_wp_data *wp,
0144                     const struct videomode *vm)
0145 {
0146     u32 r;
0147     bool vsync_inv, hsync_inv;
0148     DSSDBG("Enter hdmi_wp_video_config_interface\n");
0149 
0150     vsync_inv = !!(vm->flags & DISPLAY_FLAGS_VSYNC_LOW);
0151     hsync_inv = !!(vm->flags & DISPLAY_FLAGS_HSYNC_LOW);
0152 
0153     r = hdmi_read_reg(wp->base, HDMI_WP_VIDEO_CFG);
0154     r = FLD_MOD(r, 1, 7, 7);    /* VSYNC_POL to dispc active high */
0155     r = FLD_MOD(r, 1, 6, 6);    /* HSYNC_POL to dispc active high */
0156     r = FLD_MOD(r, vsync_inv, 5, 5);    /* CORE_VSYNC_INV */
0157     r = FLD_MOD(r, hsync_inv, 4, 4);    /* CORE_HSYNC_INV */
0158     r = FLD_MOD(r, !!(vm->flags & DISPLAY_FLAGS_INTERLACED), 3, 3);
0159     r = FLD_MOD(r, 1, 1, 0); /* HDMI_TIMING_MASTER_24BIT */
0160     hdmi_write_reg(wp->base, HDMI_WP_VIDEO_CFG, r);
0161 }
0162 
0163 void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
0164                  const struct videomode *vm)
0165 {
0166     u32 timing_h = 0;
0167     u32 timing_v = 0;
0168     unsigned int hsync_len_offset = 1;
0169 
0170     DSSDBG("Enter hdmi_wp_video_config_timing\n");
0171 
0172     /*
0173      * On OMAP4 and OMAP5 ES1 the HSW field is programmed as is. On OMAP5
0174      * ES2+ (including DRA7/AM5 SoCs) HSW field is programmed to hsync_len-1.
0175      * However, we don't support OMAP5 ES1 at all, so we can just check for
0176      * OMAP4 here.
0177      */
0178     if (wp->version == 4)
0179         hsync_len_offset = 0;
0180 
0181     timing_h |= FLD_VAL(vm->hback_porch, 31, 20);
0182     timing_h |= FLD_VAL(vm->hfront_porch, 19, 8);
0183     timing_h |= FLD_VAL(vm->hsync_len - hsync_len_offset, 7, 0);
0184     hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_H, timing_h);
0185 
0186     timing_v |= FLD_VAL(vm->vback_porch, 31, 20);
0187     timing_v |= FLD_VAL(vm->vfront_porch, 19, 8);
0188     timing_v |= FLD_VAL(vm->vsync_len, 7, 0);
0189     hdmi_write_reg(wp->base, HDMI_WP_VIDEO_TIMING_V, timing_v);
0190 }
0191 
0192 void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
0193         struct videomode *vm, const struct hdmi_config *param)
0194 {
0195     DSSDBG("Enter hdmi_wp_video_init_format\n");
0196 
0197     video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444;
0198     video_fmt->y_res = param->vm.vactive;
0199     video_fmt->x_res = param->vm.hactive;
0200 
0201     vm->hback_porch = param->vm.hback_porch;
0202     vm->hfront_porch = param->vm.hfront_porch;
0203     vm->hsync_len = param->vm.hsync_len;
0204     vm->vback_porch = param->vm.vback_porch;
0205     vm->vfront_porch = param->vm.vfront_porch;
0206     vm->vsync_len = param->vm.vsync_len;
0207 
0208     vm->flags = param->vm.flags;
0209 
0210     if (param->vm.flags & DISPLAY_FLAGS_INTERLACED) {
0211         video_fmt->y_res /= 2;
0212         vm->vback_porch /= 2;
0213         vm->vfront_porch /= 2;
0214         vm->vsync_len /= 2;
0215     }
0216 
0217     if (param->vm.flags & DISPLAY_FLAGS_DOUBLECLK) {
0218         video_fmt->x_res *= 2;
0219         vm->hfront_porch *= 2;
0220         vm->hsync_len *= 2;
0221         vm->hback_porch *= 2;
0222     }
0223 }
0224 
0225 void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
0226         struct hdmi_audio_format *aud_fmt)
0227 {
0228     u32 r;
0229 
0230     DSSDBG("Enter hdmi_wp_audio_config_format\n");
0231 
0232     r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG);
0233     if (wp->version == 4) {
0234         r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
0235         r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
0236     }
0237     r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);
0238     r = FLD_MOD(r, aud_fmt->type, 4, 4);
0239     r = FLD_MOD(r, aud_fmt->justification, 3, 3);
0240     r = FLD_MOD(r, aud_fmt->sample_order, 2, 2);
0241     r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1);
0242     r = FLD_MOD(r, aud_fmt->sample_size, 0, 0);
0243     hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG, r);
0244 }
0245 
0246 void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,
0247         struct hdmi_audio_dma *aud_dma)
0248 {
0249     u32 r;
0250 
0251     DSSDBG("Enter hdmi_wp_audio_config_dma\n");
0252 
0253     r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG2);
0254     r = FLD_MOD(r, aud_dma->transfer_size, 15, 8);
0255     r = FLD_MOD(r, aud_dma->block_size, 7, 0);
0256     hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CFG2, r);
0257 
0258     r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CTRL);
0259     r = FLD_MOD(r, aud_dma->mode, 9, 9);
0260     r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0);
0261     hdmi_write_reg(wp->base, HDMI_WP_AUDIO_CTRL, r);
0262 }
0263 
0264 int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable)
0265 {
0266     REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 31, 31);
0267 
0268     return 0;
0269 }
0270 
0271 int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable)
0272 {
0273     REG_FLD_MOD(wp->base, HDMI_WP_AUDIO_CTRL, enable, 30, 30);
0274 
0275     return 0;
0276 }
0277 
0278 int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp,
0279          unsigned int version)
0280 {
0281     struct resource *res;
0282 
0283     res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wp");
0284     wp->base = devm_ioremap_resource(&pdev->dev, res);
0285     if (IS_ERR(wp->base))
0286         return PTR_ERR(wp->base);
0287 
0288     wp->phys_base = res->start;
0289     wp->version = version;
0290 
0291     return 0;
0292 }
0293 
0294 phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp)
0295 {
0296     return wp->phys_base + HDMI_WP_AUDIO_DATA;
0297 }