Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Tomi Valkeinen | 815 | 97.72% | 2 | 40.00% |
Ladislav Michl | 16 | 1.92% | 1 | 20.00% |
Thomas Gleixner | 2 | 0.24% | 1 | 20.00% |
Peter Ujfalusi | 1 | 0.12% | 1 | 20.00% |
Total | 834 | 5 |
// SPDX-License-Identifier: GPL-2.0-only /* * HDMI PHY * * Copyright (C) 2013 Texas Instruments Incorporated */ #include <linux/kernel.h> #include <linux/err.h> #include <linux/io.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/seq_file.h> #include <video/omapfb_dss.h> #include "dss.h" #include "hdmi.h" struct hdmi_phy_features { bool bist_ctrl; bool ldo_voltage; unsigned long max_phy; }; static const struct hdmi_phy_features *phy_feat; void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s) { #define DUMPPHY(r) seq_printf(s, "%-35s %08x\n", #r,\ hdmi_read_reg(phy->base, r)) DUMPPHY(HDMI_TXPHY_TX_CTRL); DUMPPHY(HDMI_TXPHY_DIGITAL_CTRL); DUMPPHY(HDMI_TXPHY_POWER_CTRL); DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL); if (phy_feat->bist_ctrl) DUMPPHY(HDMI_TXPHY_BIST_CONTROL); } int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes) { int i; for (i = 0; i < 8; i += 2) { u8 lane, pol; int dx, dy; dx = lanes[i]; dy = lanes[i + 1]; if (dx < 0 || dx >= 8) return -EINVAL; if (dy < 0 || dy >= 8) return -EINVAL; if (dx & 1) { if (dy != dx - 1) return -EINVAL; pol = 1; } else { if (dy != dx + 1) return -EINVAL; pol = 0; } lane = dx / 2; phy->lane_function[lane] = i / 2; phy->lane_polarity[lane] = pol; } return 0; } static void hdmi_phy_configure_lanes(struct hdmi_phy_data *phy) { static const u16 pad_cfg_list[] = { 0x0123, 0x0132, 0x0312, 0x0321, 0x0231, 0x0213, 0x1023, 0x1032, 0x3012, 0x3021, 0x2031, 0x2013, 0x1203, 0x1302, 0x3102, 0x3201, 0x2301, 0x2103, 0x1230, 0x1320, 0x3120, 0x3210, 0x2310, 0x2130, }; u16 lane_cfg = 0; int i; unsigned lane_cfg_val; u16 pol_val = 0; for (i = 0; i < 4; ++i) lane_cfg |= phy->lane_function[i] << ((3 - i) * 4); pol_val |= phy->lane_polarity[0] << 0; pol_val |= phy->lane_polarity[1] << 3; pol_val |= phy->lane_polarity[2] << 2; pol_val |= phy->lane_polarity[3] << 1; for (i = 0; i < ARRAY_SIZE(pad_cfg_list); ++i) if (pad_cfg_list[i] == lane_cfg) break; if (WARN_ON(i == ARRAY_SIZE(pad_cfg_list))) i = 0; lane_cfg_val = i; REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, lane_cfg_val, 26, 22); REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, pol_val, 30, 27); } int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk, unsigned long lfbitclk) { u8 freqout; /* * Read address 0 in order to get the SCP reset done completed * Dummy access performed to make sure reset is done */ hdmi_read_reg(phy->base, HDMI_TXPHY_TX_CTRL); /* * In OMAP5+, the HFBITCLK must be divided by 2 before issuing the * HDMI_PHYPWRCMD_LDOON command. */ if (phy_feat->bist_ctrl) REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11); /* * If the hfbitclk != lfbitclk, it means the lfbitclk was configured * to be used for TMDS. */ if (hfbitclk != lfbitclk) freqout = 0; else if (hfbitclk / 10 < phy_feat->max_phy) freqout = 1; else freqout = 2; /* * Write to phy address 0 to configure the clock * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field */ REG_FLD_MOD(phy->base, HDMI_TXPHY_TX_CTRL, freqout, 31, 30); /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */ hdmi_write_reg(phy->base, HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000); /* Setup max LDO voltage */ if (phy_feat->ldo_voltage) REG_FLD_MOD(phy->base, HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0); hdmi_phy_configure_lanes(phy); return 0; } static const struct hdmi_phy_features omap44xx_phy_feats = { .bist_ctrl = false, .ldo_voltage = true, .max_phy = 185675000, }; static const struct hdmi_phy_features omap54xx_phy_feats = { .bist_ctrl = true, .ldo_voltage = false, .max_phy = 186000000, }; static const struct hdmi_phy_features *hdmi_phy_get_features(void) { switch (omapdss_get_version()) { case OMAPDSS_VER_OMAP4430_ES1: case OMAPDSS_VER_OMAP4430_ES2: case OMAPDSS_VER_OMAP4: return &omap44xx_phy_feats; case OMAPDSS_VER_OMAP5: case OMAPDSS_VER_DRA7xx: return &omap54xx_phy_feats; default: return NULL; } } int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy) { struct resource *res; phy_feat = hdmi_phy_get_features(); if (!phy_feat) return -ENODEV; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy"); if (!res) { DSSERR("can't get PHY mem resource\n"); return -EINVAL; } phy->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(phy->base)) { DSSERR("can't ioremap TX PHY\n"); return PTR_ERR(phy->base); } return 0; }
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1