The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm/allwinner/a10_hdmi.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   18  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   20  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   21  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   23  * SUCH DAMAGE.
   24  *
   25  * $FreeBSD$
   26  */
   27 
   28 /*
   29  * Allwinner A10/A20 HDMI TX 
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD$");
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/bus.h>
   38 #include <sys/rman.h>
   39 #include <sys/condvar.h>
   40 #include <sys/eventhandler.h>
   41 #include <sys/kernel.h>
   42 #include <sys/module.h>
   43 
   44 #include <machine/bus.h>
   45 
   46 #include <dev/ofw/ofw_bus.h>
   47 #include <dev/ofw/ofw_bus_subr.h>
   48 
   49 #include <dev/videomode/videomode.h>
   50 #include <dev/videomode/edidvar.h>
   51 
   52 #include <dev/extres/clk/clk.h>
   53 
   54 #include "hdmi_if.h"
   55 
   56 #define HDMI_CTRL               0x004
   57 #define CTRL_MODULE_EN          (1 << 31)
   58 #define HDMI_INT_STATUS         0x008
   59 #define HDMI_HPD                0x00c
   60 #define HPD_DET                 (1 << 0)
   61 #define HDMI_VID_CTRL           0x010
   62 #define VID_CTRL_VIDEO_EN       (1 << 31)
   63 #define VID_CTRL_HDMI_MODE      (1 << 30)
   64 #define VID_CTRL_INTERLACE      (1 << 4)
   65 #define VID_CTRL_REPEATER_2X    (1 << 0)
   66 #define HDMI_VID_TIMING0        0x014
   67 #define VID_ACT_V(v)            (((v) - 1) << 16)
   68 #define VID_ACT_H(h)            (((h) - 1) << 0)
   69 #define HDMI_VID_TIMING1        0x018
   70 #define VID_VBP(vbp)            (((vbp) - 1) << 16)
   71 #define VID_HBP(hbp)            (((hbp) - 1) << 0)
   72 #define HDMI_VID_TIMING2        0x01c
   73 #define VID_VFP(vfp)            (((vfp) - 1) << 16)
   74 #define VID_HFP(hfp)            (((hfp) - 1) << 0)
   75 #define HDMI_VID_TIMING3        0x020
   76 #define VID_VSPW(vspw)          (((vspw) - 1) << 16)
   77 #define VID_HSPW(hspw)          (((hspw) - 1) << 0)
   78 #define HDMI_VID_TIMING4        0x024
   79 #define TX_CLOCK_NORMAL         0x03e00000
   80 #define VID_VSYNC_ACTSEL        (1 << 1)
   81 #define VID_HSYNC_ACTSEL        (1 << 0)
   82 #define HDMI_AUD_CTRL           0x040
   83 #define AUD_CTRL_EN             (1 << 31)
   84 #define AUD_CTRL_RST            (1 << 30)
   85 #define HDMI_ADMA_CTRL          0x044
   86 #define HDMI_ADMA_MODE          (1 << 31)
   87 #define HDMI_ADMA_MODE_DDMA     (0 << 31)
   88 #define HDMI_ADMA_MODE_NDMA     (1 << 31)
   89 #define HDMI_AUD_FMT            0x048
   90 #define AUD_FMT_CH(n)           ((n) - 1)
   91 #define HDMI_PCM_CTRL           0x04c
   92 #define HDMI_AUD_CTS            0x050
   93 #define HDMI_AUD_N              0x054
   94 #define HDMI_AUD_CH_STATUS0     0x058
   95 #define CH_STATUS0_FS_FREQ      (0xf << 24)
   96 #define CH_STATUS0_FS_FREQ_48   (2 << 24)
   97 #define HDMI_AUD_CH_STATUS1     0x05c
   98 #define CH_STATUS1_WORD_LEN     (0x7 << 1)
   99 #define CH_STATUS1_WORD_LEN_16  (1 << 1)
  100 #define HDMI_AUDIO_RESET_RETRY  1000
  101 #define HDMI_AUDIO_CHANNELS     2
  102 #define HDMI_AUDIO_CHANNELMAP   0x76543210
  103 #define HDMI_AUDIO_N            6144    /* 48 kHz */
  104 #define HDMI_AUDIO_CTS(r, n)    ((((r) * 10) * ((n) / 128)) / 480)
  105 #define HDMI_PADCTRL0           0x200
  106 #define PADCTRL0_BIASEN         (1 << 31)
  107 #define PADCTRL0_LDOCEN         (1 << 30)
  108 #define PADCTRL0_LDODEN         (1 << 29)
  109 #define PADCTRL0_PWENC          (1 << 28)
  110 #define PADCTRL0_PWEND          (1 << 27)
  111 #define PADCTRL0_PWENG          (1 << 26)
  112 #define PADCTRL0_CKEN           (1 << 25)
  113 #define PADCTRL0_SEN            (1 << 24)
  114 #define PADCTRL0_TXEN           (1 << 23)
  115 #define HDMI_PADCTRL1           0x204
  116 #define PADCTRL1_AMP_OPT        (1 << 23)
  117 #define PADCTRL1_AMPCK_OPT      (1 << 22)
  118 #define PADCTRL1_DMP_OPT        (1 << 21)
  119 #define PADCTRL1_EMP_OPT        (1 << 20)
  120 #define PADCTRL1_EMPCK_OPT      (1 << 19)
  121 #define PADCTRL1_PWSCK          (1 << 18)
  122 #define PADCTRL1_PWSDT          (1 << 17)
  123 #define PADCTRL1_REG_CSMPS      (1 << 16)
  124 #define PADCTRL1_REG_DEN        (1 << 15)
  125 #define PADCTRL1_REG_DENCK      (1 << 14)
  126 #define PADCTRL1_REG_PLRCK      (1 << 13)
  127 #define PADCTRL1_REG_EMP        (0x7 << 10)
  128 #define PADCTRL1_REG_EMP_EN     (0x2 << 10)
  129 #define PADCTRL1_REG_CD         (0x3 << 8)
  130 #define PADCTRL1_REG_CKSS       (0x3 << 6)
  131 #define PADCTRL1_REG_CKSS_1X    (0x1 << 6)
  132 #define PADCTRL1_REG_CKSS_2X    (0x0 << 6)
  133 #define PADCTRL1_REG_AMP        (0x7 << 3)
  134 #define PADCTRL1_REG_AMP_EN     (0x6 << 3)
  135 #define PADCTRL1_REG_PLR        (0x7 << 0)
  136 #define HDMI_PLLCTRL0           0x208
  137 #define PLLCTRL0_PLL_EN         (1 << 31)
  138 #define PLLCTRL0_BWS            (1 << 30)
  139 #define PLLCTRL0_HV_IS_33       (1 << 29)
  140 #define PLLCTRL0_LDO1_EN        (1 << 28)
  141 #define PLLCTRL0_LDO2_EN        (1 << 27)
  142 #define PLLCTRL0_SDIV2          (1 << 25)
  143 #define PLLCTRL0_VCO_GAIN       (0x1 << 22)
  144 #define PLLCTRL0_S              (0x7 << 17)
  145 #define PLLCTRL0_CP_S           (0xf << 12)
  146 #define PLLCTRL0_CS             (0x7 << 8)
  147 #define PLLCTRL0_PREDIV(x)      ((x) << 4)
  148 #define PLLCTRL0_VCO_S          (0x8 << 0)
  149 #define HDMI_PLLDBG0            0x20c
  150 #define PLLDBG0_CKIN_SEL        (1 << 21)
  151 #define PLLDBG0_CKIN_SEL_PLL3   (0 << 21)
  152 #define PLLDBG0_CKIN_SEL_PLL7   (1 << 21)
  153 #define HDMI_PKTCTRL0           0x2f0
  154 #define HDMI_PKTCTRL1           0x2f4
  155 #define PKTCTRL_PACKET(n,t)     ((t) << ((n) << 2))
  156 #define PKT_NULL                0
  157 #define PKT_GC                  1
  158 #define PKT_AVI                 2
  159 #define PKT_AI                  3
  160 #define PKT_SPD                 5
  161 #define PKT_END                 15
  162 #define DDC_CTRL                0x500
  163 #define CTRL_DDC_EN             (1 << 31)
  164 #define CTRL_DDC_ACMD_START     (1 << 30)
  165 #define CTRL_DDC_FIFO_DIR       (1 << 8)
  166 #define CTRL_DDC_FIFO_DIR_READ  (0 << 8)
  167 #define CTRL_DDC_FIFO_DIR_WRITE (1 << 8)
  168 #define CTRL_DDC_SWRST          (1 << 0)
  169 #define DDC_SLAVE_ADDR          0x504
  170 #define SLAVE_ADDR_SEG_SHIFT    24
  171 #define SLAVE_ADDR_EDDC_SHIFT   16
  172 #define SLAVE_ADDR_OFFSET_SHIFT 8
  173 #define SLAVE_ADDR_SHIFT        0
  174 #define DDC_INT_STATUS          0x50c
  175 #define INT_STATUS_XFER_DONE    (1 << 0)
  176 #define DDC_FIFO_CTRL           0x510
  177 #define FIFO_CTRL_CLEAR         (1 << 31)
  178 #define DDC_BYTE_COUNTER        0x51c
  179 #define DDC_COMMAND             0x520
  180 #define COMMAND_EOREAD          (4 << 0)
  181 #define DDC_CLOCK               0x528
  182 #define DDC_CLOCK_M             (1 << 3)
  183 #define DDC_CLOCK_N             (5 << 0)
  184 #define DDC_FIFO                0x518
  185 #define SWRST_DELAY             1000
  186 #define DDC_DELAY               1000
  187 #define DDC_RETRY               1000
  188 #define DDC_BLKLEN              16
  189 #define DDC_ADDR                0x50
  190 #define EDDC_ADDR               0x60
  191 #define EDID_LENGTH             128
  192 #define DDC_CTRL_LINE           0x540
  193 #define DDC_LINE_SCL_ENABLE     (1 << 8)
  194 #define DDC_LINE_SDA_ENABLE     (1 << 9)
  195 #define HDMI_ENABLE_DELAY       50000
  196 #define DDC_READ_RETRY          4
  197 #define EXT_TAG                 0x00
  198 #define CEA_TAG_ID              0x02
  199 #define CEA_DTD                 0x03
  200 #define DTD_BASIC_AUDIO         (1 << 6)
  201 #define CEA_REV                 0x02
  202 #define CEA_DATA_OFF            0x03
  203 #define CEA_DATA_START          4
  204 #define BLOCK_TAG(x)            (((x) >> 5) & 0x7)
  205 #define BLOCK_TAG_VSDB          3
  206 #define BLOCK_LEN(x)            ((x) & 0x1f)
  207 #define HDMI_VSDB_MINLEN        5
  208 #define HDMI_OUI                "\x03\x0c\x00"
  209 #define HDMI_OUI_LEN            3
  210 #define HDMI_DEFAULT_FREQ       297000000
  211 
  212 struct a10hdmi_softc {
  213         struct resource         *res;
  214 
  215         struct intr_config_hook mode_hook;
  216 
  217         uint8_t                 edid[EDID_LENGTH];
  218 
  219         int                     has_hdmi;
  220         int                     has_audio;
  221 
  222         clk_t                   clk_ahb;
  223         clk_t                   clk_hdmi;
  224         clk_t                   clk_lcd;
  225 };
  226 
  227 static struct resource_spec a10hdmi_spec[] = {
  228         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
  229         { -1, 0 }
  230 };
  231 
  232 #define HDMI_READ(sc, reg)              bus_read_4((sc)->res, (reg))
  233 #define HDMI_WRITE(sc, reg, val)        bus_write_4((sc)->res, (reg), (val))
  234 
  235 static void
  236 a10hdmi_init(struct a10hdmi_softc *sc)
  237 {
  238         /* Enable the HDMI module */
  239         HDMI_WRITE(sc, HDMI_CTRL, CTRL_MODULE_EN);
  240 
  241         /* Configure PLL/DRV settings */
  242         HDMI_WRITE(sc, HDMI_PADCTRL0, PADCTRL0_BIASEN | PADCTRL0_LDOCEN |
  243             PADCTRL0_LDODEN | PADCTRL0_PWENC | PADCTRL0_PWEND |
  244             PADCTRL0_PWENG | PADCTRL0_CKEN | PADCTRL0_TXEN);
  245         HDMI_WRITE(sc, HDMI_PADCTRL1, PADCTRL1_AMP_OPT | PADCTRL1_AMPCK_OPT |
  246             PADCTRL1_EMP_OPT | PADCTRL1_EMPCK_OPT | PADCTRL1_REG_DEN |
  247             PADCTRL1_REG_DENCK | PADCTRL1_REG_EMP_EN | PADCTRL1_REG_AMP_EN);
  248 
  249         /* Select PLL3 as input clock */
  250         HDMI_WRITE(sc, HDMI_PLLDBG0, PLLDBG0_CKIN_SEL_PLL3);
  251 
  252         DELAY(HDMI_ENABLE_DELAY);
  253 }
  254 
  255 static void
  256 a10hdmi_hpd(void *arg)
  257 {
  258         struct a10hdmi_softc *sc;
  259         device_t dev;
  260         uint32_t hpd;
  261 
  262         dev = arg;
  263         sc = device_get_softc(dev);
  264 
  265         hpd = HDMI_READ(sc, HDMI_HPD);
  266         if ((hpd & HPD_DET) == HPD_DET)
  267                 EVENTHANDLER_INVOKE(hdmi_event, dev, HDMI_EVENT_CONNECTED);
  268 
  269         config_intrhook_disestablish(&sc->mode_hook);
  270 }
  271 
  272 static int
  273 a10hdmi_probe(device_t dev)
  274 {
  275         if (!ofw_bus_status_okay(dev))
  276                 return (ENXIO);
  277 
  278         if (!ofw_bus_is_compatible(dev, "allwinner,sun7i-a20-hdmi"))
  279                 return (ENXIO);
  280 
  281         device_set_desc(dev, "Allwinner HDMI TX");
  282         return (BUS_PROBE_DEFAULT);
  283 }
  284 
  285 static int
  286 a10hdmi_attach(device_t dev)
  287 {
  288         struct a10hdmi_softc *sc;
  289         int error;
  290 
  291         sc = device_get_softc(dev);
  292 
  293         if (bus_alloc_resources(dev, a10hdmi_spec, &sc->res)) {
  294                 device_printf(dev, "cannot allocate resources for device\n");
  295                 return (ENXIO);
  296         }
  297 
  298         /* Setup clocks */
  299         error = clk_get_by_ofw_name(dev, 0, "ahb", &sc->clk_ahb);
  300         if (error != 0) {
  301                 device_printf(dev, "cannot find ahb clock\n");
  302                 return (error);
  303         }
  304         error = clk_get_by_ofw_name(dev, 0, "hdmi", &sc->clk_hdmi);
  305         if (error != 0) {
  306                 device_printf(dev, "cannot find hdmi clock\n");
  307                 return (error);
  308         }
  309         error = clk_get_by_ofw_name(dev, 0, "lcd", &sc->clk_lcd);
  310         if (error != 0) {
  311                 device_printf(dev, "cannot find lcd clock\n");
  312         }
  313         /* Enable HDMI clock */
  314         error = clk_enable(sc->clk_hdmi);
  315         if (error != 0) {
  316                 device_printf(dev, "cannot enable hdmi clock\n");
  317                 return (error);
  318         }
  319         /* Gating AHB clock for HDMI */
  320         error = clk_enable(sc->clk_ahb);
  321         if (error != 0) {
  322                 device_printf(dev, "cannot enable ahb gate\n");
  323                 return (error);
  324         }
  325 
  326         a10hdmi_init(sc);
  327 
  328         sc->mode_hook.ich_func = a10hdmi_hpd;
  329         sc->mode_hook.ich_arg = dev;
  330 
  331         error = config_intrhook_establish(&sc->mode_hook);
  332         if (error != 0)
  333                 return (error);
  334 
  335         return (0);
  336 }
  337 
  338 static int
  339 a10hdmi_ddc_xfer(struct a10hdmi_softc *sc, uint16_t addr, uint8_t seg,
  340     uint8_t off, int len)
  341 {
  342         uint32_t val;
  343         int retry;
  344 
  345         /* Set FIFO direction to read */
  346         val = HDMI_READ(sc, DDC_CTRL);
  347         val &= ~CTRL_DDC_FIFO_DIR;
  348         val |= CTRL_DDC_FIFO_DIR_READ;
  349         HDMI_WRITE(sc, DDC_CTRL, val);
  350 
  351         /* Setup DDC slave address */
  352         val = (addr << SLAVE_ADDR_SHIFT) | (seg << SLAVE_ADDR_SEG_SHIFT) |
  353             (EDDC_ADDR << SLAVE_ADDR_EDDC_SHIFT) |
  354             (off << SLAVE_ADDR_OFFSET_SHIFT);
  355         HDMI_WRITE(sc, DDC_SLAVE_ADDR, val);
  356 
  357         /* Clear FIFO */
  358         val = HDMI_READ(sc, DDC_FIFO_CTRL);
  359         val |= FIFO_CTRL_CLEAR;
  360         HDMI_WRITE(sc, DDC_FIFO_CTRL, val);
  361 
  362         /* Set transfer length */
  363         HDMI_WRITE(sc, DDC_BYTE_COUNTER, len);
  364 
  365         /* Set command to "Explicit Offset Address Read" */
  366         HDMI_WRITE(sc, DDC_COMMAND, COMMAND_EOREAD);
  367 
  368         /* Start transfer */
  369         val = HDMI_READ(sc, DDC_CTRL);
  370         val |= CTRL_DDC_ACMD_START;
  371         HDMI_WRITE(sc, DDC_CTRL, val);
  372 
  373         /* Wait for command to start */
  374         retry = DDC_RETRY;
  375         while (--retry > 0) {
  376                 val = HDMI_READ(sc, DDC_CTRL);
  377                 if ((val & CTRL_DDC_ACMD_START) == 0)
  378                         break;
  379                 DELAY(DDC_DELAY);
  380         }
  381         if (retry == 0)
  382                 return (ETIMEDOUT);
  383 
  384         /* Ensure that the transfer completed */
  385         val = HDMI_READ(sc, DDC_INT_STATUS);
  386         if ((val & INT_STATUS_XFER_DONE) == 0)
  387                 return (EIO);
  388 
  389         return (0);
  390 }
  391 
  392 static int
  393 a10hdmi_ddc_read(struct a10hdmi_softc *sc, int block, uint8_t *edid)
  394 {
  395         int resid, off, len, error;
  396         uint8_t *pbuf;
  397 
  398         pbuf = edid;
  399         resid = EDID_LENGTH;
  400         off = (block & 1) ? EDID_LENGTH : 0;
  401 
  402         while (resid > 0) {
  403                 len = min(resid, DDC_BLKLEN);
  404                 error = a10hdmi_ddc_xfer(sc, DDC_ADDR, block >> 1, off, len);
  405                 if (error != 0)
  406                         return (error);
  407 
  408                 bus_read_multi_1(sc->res, DDC_FIFO, pbuf, len);
  409 
  410                 pbuf += len;
  411                 off += len;
  412                 resid -= len;
  413         }
  414 
  415         return (0);
  416 }
  417 
  418 static int
  419 a10hdmi_detect_hdmi_vsdb(uint8_t *edid)
  420 {
  421         int off, p, btag, blen;
  422 
  423         if (edid[EXT_TAG] != CEA_TAG_ID)
  424                 return (0);
  425 
  426         off = edid[CEA_DATA_OFF];
  427 
  428         /* CEA data block collection starts at byte 4 */
  429         if (off <= CEA_DATA_START)
  430                 return (0);
  431 
  432         /* Parse the CEA data blocks */
  433         for (p = CEA_DATA_START; p < off;) {
  434                 btag = BLOCK_TAG(edid[p]);
  435                 blen = BLOCK_LEN(edid[p]);
  436 
  437                 /* Make sure the length is sane */
  438                 if (p + blen + 1 > off)
  439                         break;
  440 
  441                 /* Look for a VSDB with the HDMI 24-bit IEEE registration ID */
  442                 if (btag == BLOCK_TAG_VSDB && blen >= HDMI_VSDB_MINLEN &&
  443                     memcmp(&edid[p + 1], HDMI_OUI, HDMI_OUI_LEN) == 0)
  444                         return (1);
  445 
  446                 /* Next data block */
  447                 p += (1 + blen);
  448         }
  449 
  450         return (0);
  451 }
  452 
  453 static void
  454 a10hdmi_detect_hdmi(struct a10hdmi_softc *sc, int *phdmi, int *paudio)
  455 {
  456         struct edid_info ei;
  457         uint8_t edid[EDID_LENGTH];
  458         int block;
  459 
  460         *phdmi = *paudio = 0;
  461 
  462         if (edid_parse(sc->edid, &ei) != 0)
  463                 return;
  464 
  465         /* Scan through extension blocks, looking for a CEA-861 block. */
  466         for (block = 1; block <= ei.edid_ext_block_count; block++) {
  467                 if (a10hdmi_ddc_read(sc, block, edid) != 0)
  468                         return;
  469 
  470                 if (a10hdmi_detect_hdmi_vsdb(edid) != 0) {
  471                         *phdmi = 1;
  472                         *paudio = ((edid[CEA_DTD] & DTD_BASIC_AUDIO) != 0);
  473                         return;
  474                 }
  475         }
  476 }
  477 
  478 static int
  479 a10hdmi_get_edid(device_t dev, uint8_t **edid, uint32_t *edid_len)
  480 {
  481         struct a10hdmi_softc *sc;
  482         int error, retry;
  483 
  484         sc = device_get_softc(dev);
  485         retry = DDC_READ_RETRY;
  486 
  487         while (--retry > 0) {
  488                 /* I2C software reset */
  489                 HDMI_WRITE(sc, DDC_FIFO_CTRL, 0);
  490                 HDMI_WRITE(sc, DDC_CTRL, CTRL_DDC_EN | CTRL_DDC_SWRST);
  491                 DELAY(SWRST_DELAY);
  492                 if (HDMI_READ(sc, DDC_CTRL) & CTRL_DDC_SWRST) {
  493                         device_printf(dev, "DDC software reset failed\n");
  494                         return (ENXIO);
  495                 }
  496 
  497                 /* Configure DDC clock */
  498                 HDMI_WRITE(sc, DDC_CLOCK, DDC_CLOCK_M | DDC_CLOCK_N);
  499 
  500                 /* Enable SDA/SCL */
  501                 HDMI_WRITE(sc, DDC_CTRL_LINE,
  502                     DDC_LINE_SCL_ENABLE | DDC_LINE_SDA_ENABLE);
  503 
  504                 /* Read EDID block */
  505                 error = a10hdmi_ddc_read(sc, 0, sc->edid);
  506                 if (error == 0) {
  507                         *edid = sc->edid;
  508                         *edid_len = sizeof(sc->edid);
  509                         break;
  510                 }
  511         }
  512 
  513         if (error == 0)
  514                 a10hdmi_detect_hdmi(sc, &sc->has_hdmi, &sc->has_audio);
  515         else
  516                 sc->has_hdmi = sc->has_audio = 0;
  517 
  518         return (error);
  519 }
  520 
  521 static void
  522 a10hdmi_set_audiomode(device_t dev, const struct videomode *mode)
  523 {
  524         struct a10hdmi_softc *sc;
  525         uint32_t val;
  526         int retry;
  527 
  528         sc = device_get_softc(dev);
  529 
  530         /* Disable and reset audio module and wait for reset bit to clear */
  531         HDMI_WRITE(sc, HDMI_AUD_CTRL, AUD_CTRL_RST);
  532         for (retry = HDMI_AUDIO_RESET_RETRY; retry > 0; retry--) {
  533                 val = HDMI_READ(sc, HDMI_AUD_CTRL);
  534                 if ((val & AUD_CTRL_RST) == 0)
  535                         break;
  536         }
  537         if (retry == 0) {
  538                 device_printf(dev, "timeout waiting for audio module\n");
  539                 return;
  540         }
  541 
  542         if (!sc->has_audio)
  543                 return;
  544 
  545         /* DMA and FIFO control */
  546         HDMI_WRITE(sc, HDMI_ADMA_CTRL, HDMI_ADMA_MODE_DDMA);
  547 
  548         /* Audio format control (LPCM, S16LE, stereo) */
  549         HDMI_WRITE(sc, HDMI_AUD_FMT, AUD_FMT_CH(HDMI_AUDIO_CHANNELS));
  550 
  551         /* Channel mappings */
  552         HDMI_WRITE(sc, HDMI_PCM_CTRL, HDMI_AUDIO_CHANNELMAP);
  553 
  554         /* Clocks */
  555         HDMI_WRITE(sc, HDMI_AUD_CTS,
  556             HDMI_AUDIO_CTS(mode->dot_clock, HDMI_AUDIO_N));
  557         HDMI_WRITE(sc, HDMI_AUD_N, HDMI_AUDIO_N);
  558 
  559         /* Set sampling frequency to 48 kHz, word length to 16-bit */
  560         HDMI_WRITE(sc, HDMI_AUD_CH_STATUS0, CH_STATUS0_FS_FREQ_48);
  561         HDMI_WRITE(sc, HDMI_AUD_CH_STATUS1, CH_STATUS1_WORD_LEN_16);
  562 
  563         /* Enable */
  564         HDMI_WRITE(sc, HDMI_AUD_CTRL, AUD_CTRL_EN);
  565 }
  566 
  567 static int
  568 a10hdmi_get_tcon_config(struct a10hdmi_softc *sc, int *div, int *dbl)
  569 {
  570         uint64_t lcd_fin, lcd_fout;
  571         clk_t clk_lcd_parent;
  572         const char *pname;
  573         int error;
  574 
  575         error = clk_get_parent(sc->clk_lcd, &clk_lcd_parent);
  576         if (error != 0)
  577                 return (error);
  578 
  579         /* Get the LCD CH1 special clock 2 divider */
  580         error = clk_get_freq(sc->clk_lcd, &lcd_fout);
  581         if (error != 0)
  582                 return (error);
  583         error = clk_get_freq(clk_lcd_parent, &lcd_fin);
  584         if (error != 0)
  585                 return (error);
  586         *div = lcd_fin / lcd_fout;
  587 
  588         /* Detect LCD CH1 special clock using a 1X or 2X source */
  589         /* XXX */
  590         pname = clk_get_name(clk_lcd_parent);
  591         if (strcmp(pname, "pll3") == 0 || strcmp(pname, "pll7") == 0)
  592                 *dbl = 0;
  593         else
  594                 *dbl = 1;
  595 
  596         return (0);
  597 }
  598 
  599 static int
  600 a10hdmi_set_videomode(device_t dev, const struct videomode *mode)
  601 {
  602         struct a10hdmi_softc *sc;
  603         int error, clk_div, clk_dbl;
  604         int dblscan, hfp, hspw, hbp, vfp, vspw, vbp;
  605         uint32_t val;
  606 
  607         sc = device_get_softc(dev);
  608         dblscan = !!(mode->flags & VID_DBLSCAN);
  609         hfp = mode->hsync_start - mode->hdisplay;
  610         hspw = mode->hsync_end - mode->hsync_start;
  611         hbp = mode->htotal - mode->hsync_start;
  612         vfp = mode->vsync_start - mode->vdisplay;
  613         vspw = mode->vsync_end - mode->vsync_start;
  614         vbp = mode->vtotal - mode->vsync_start;
  615 
  616         error = a10hdmi_get_tcon_config(sc, &clk_div, &clk_dbl);
  617         if (error != 0) {
  618                 device_printf(dev, "couldn't get tcon config: %d\n", error);
  619                 return (error);
  620         }
  621 
  622         /* Clear interrupt status */
  623         HDMI_WRITE(sc, HDMI_INT_STATUS, HDMI_READ(sc, HDMI_INT_STATUS));
  624 
  625         /* Clock setup */
  626         val = HDMI_READ(sc, HDMI_PADCTRL1);
  627         val &= ~PADCTRL1_REG_CKSS;
  628         val |= (clk_dbl ? PADCTRL1_REG_CKSS_2X : PADCTRL1_REG_CKSS_1X);
  629         HDMI_WRITE(sc, HDMI_PADCTRL1, val);
  630         HDMI_WRITE(sc, HDMI_PLLCTRL0, PLLCTRL0_PLL_EN | PLLCTRL0_BWS |
  631             PLLCTRL0_HV_IS_33 | PLLCTRL0_LDO1_EN | PLLCTRL0_LDO2_EN |
  632             PLLCTRL0_SDIV2 | PLLCTRL0_VCO_GAIN | PLLCTRL0_S |
  633             PLLCTRL0_CP_S | PLLCTRL0_CS | PLLCTRL0_PREDIV(clk_div) |
  634             PLLCTRL0_VCO_S);
  635 
  636         /* Setup display settings */
  637         if (bootverbose)
  638                 device_printf(dev, "HDMI: %s, Audio: %s\n",
  639                     sc->has_hdmi ? "yes" : "no", sc->has_audio ? "yes" : "no");
  640         val = 0;
  641         if (sc->has_hdmi)
  642                 val |= VID_CTRL_HDMI_MODE;
  643         if (mode->flags & VID_INTERLACE)
  644                 val |= VID_CTRL_INTERLACE;
  645         if (mode->flags & VID_DBLSCAN)
  646                 val |= VID_CTRL_REPEATER_2X;
  647         HDMI_WRITE(sc, HDMI_VID_CTRL, val);
  648 
  649         /* Setup display timings */
  650         HDMI_WRITE(sc, HDMI_VID_TIMING0,
  651             VID_ACT_V(mode->vdisplay) | VID_ACT_H(mode->hdisplay << dblscan));
  652         HDMI_WRITE(sc, HDMI_VID_TIMING1,
  653             VID_VBP(vbp) | VID_HBP(hbp << dblscan));
  654         HDMI_WRITE(sc, HDMI_VID_TIMING2,
  655             VID_VFP(vfp) | VID_HFP(hfp << dblscan));
  656         HDMI_WRITE(sc, HDMI_VID_TIMING3,
  657             VID_VSPW(vspw) | VID_HSPW(hspw << dblscan));
  658         val = TX_CLOCK_NORMAL;
  659         if (mode->flags & VID_PVSYNC)
  660                 val |= VID_VSYNC_ACTSEL;
  661         if (mode->flags & VID_PHSYNC)
  662                 val |= VID_HSYNC_ACTSEL;
  663         HDMI_WRITE(sc, HDMI_VID_TIMING4, val);
  664 
  665         /* This is an ordered list of infoframe packets that the HDMI
  666          * transmitter will send. Transmit packets in the following order:
  667          *  1. General control packet
  668          *  2. AVI infoframe
  669          *  3. Audio infoframe
  670          * There are 2 registers with 4 slots each. The list is terminated
  671          * with the special PKT_END marker.
  672          */
  673         HDMI_WRITE(sc, HDMI_PKTCTRL0,
  674             PKTCTRL_PACKET(0, PKT_GC) | PKTCTRL_PACKET(1, PKT_AVI) |
  675             PKTCTRL_PACKET(2, PKT_AI) | PKTCTRL_PACKET(3, PKT_END));
  676         HDMI_WRITE(sc, HDMI_PKTCTRL1, 0);
  677 
  678         /* Setup audio */
  679         a10hdmi_set_audiomode(dev, mode);
  680 
  681         return (0);
  682 }
  683 
  684 static int
  685 a10hdmi_enable(device_t dev, int onoff)
  686 {
  687         struct a10hdmi_softc *sc;
  688         uint32_t val;
  689 
  690         sc = device_get_softc(dev);
  691 
  692         /* Enable or disable video output */
  693         val = HDMI_READ(sc, HDMI_VID_CTRL);
  694         if (onoff)
  695                 val |= VID_CTRL_VIDEO_EN;
  696         else
  697                 val &= ~VID_CTRL_VIDEO_EN;
  698         HDMI_WRITE(sc, HDMI_VID_CTRL, val);
  699 
  700         return (0);
  701 }
  702 
  703 static device_method_t a10hdmi_methods[] = {
  704         /* Device interface */
  705         DEVMETHOD(device_probe,         a10hdmi_probe),
  706         DEVMETHOD(device_attach,        a10hdmi_attach),
  707 
  708         /* HDMI interface */
  709         DEVMETHOD(hdmi_get_edid,        a10hdmi_get_edid),
  710         DEVMETHOD(hdmi_set_videomode,   a10hdmi_set_videomode),
  711         DEVMETHOD(hdmi_enable,          a10hdmi_enable),
  712 
  713         DEVMETHOD_END
  714 };
  715 
  716 static driver_t a10hdmi_driver = {
  717         "a10hdmi",
  718         a10hdmi_methods,
  719         sizeof(struct a10hdmi_softc),
  720 };
  721 
  722 static devclass_t a10hdmi_devclass;
  723 
  724 DRIVER_MODULE(a10hdmi, simplebus, a10hdmi_driver, a10hdmi_devclass, 0, 0);
  725 MODULE_VERSION(a10hdmi, 1);

Cache object: 82d12b5158720469817b9da1b7367f5a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.