1 // Copyright 2017 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6 
7 #include <reg.h>
8 #include <stdio.h>
9 #include <trace.h>
10 #include <string.h>
11 #include <lib/cbuf.h>
12 #include <arch/arm64/periphmap.h>
13 #include <arch/arm64/smccc.h>
14 #include <kernel/thread.h>
15 #include <dev/interrupt.h>
16 #include <pdev/driver.h>
17 #include <zircon/boot/driver-config.h>
18 
19 static vaddr_t preset_base;
20 static vaddr_t hiu_base;
21 static vaddr_t hdmitx_base;
22 
23 #define TOP_OFFSET_MASK      (0x0UL << 24)
24 #define DWC_OFFSET_MASK      (0x10UL << 24)
25 #define HDMITX_ADDR_PORT                                (0x00)
26 #define HDMITX_DATA_PORT                                (0x04)
27 
28 #define DISPLAY_MASK(start, count) (((1 << (count)) - 1) << (start))
29 #define DISPLAY_SET_MASK(mask, start, count, value) \
30                         ((mask & ~DISPLAY_MASK(start, count)) | \
31                                 (((value) << (start)) & DISPLAY_MASK(start, count)))
32 
33 #define READ32_PRESET_REG(a)             readl(preset_base + a)
34 #define WRITE32_PRESET_REG(a, v)         writel(v, preset_base + a)
35 
36 #define READ32_HDMITX_REG(a)             readl(hdmitx_base + a)
37 #define WRITE32_HDMITX_REG(a, v)         writel(v, hdmitx_base + a)
38 
39 #define READ32_HHI_REG(a)                readl(hiu_base + a)
40 #define WRITE32_HHI_REG(a, v)            writel(v, hiu_base + a)
41 
42 #define SET_BIT32(x, dest, value, count, start) \
43             WRITE32_##x##_REG(dest, (READ32_##x##_REG(dest) & ~DISPLAY_MASK(start, count)) | \
44                                 (((value) << (start)) & DISPLAY_MASK(start, count)))
45 
46 #define HHI_HDMI_CLK_CNTL                               (0x73 << 2)
47 #define HHI_GCLK_MPEG2                                  (0x52 << 2)
48 #define HHI_MEM_PD_REG0                                 (0x40 << 2)
49 #define PRESET0_REGISTER                                (0x404)
50 #define PRESET2_REGISTER                                (0x40C)
51 #define HDMITX_TOP_SW_RESET                             (TOP_OFFSET_MASK + 0x000)
52 #define HDMITX_TOP_CLK_CNTL                             (TOP_OFFSET_MASK + 0x001)
53 #define HDMITX_DWC_MC_LOCKONCLOCK                       (DWC_OFFSET_MASK + 0x4006)
54 #define HDMITX_DWC_MC_CLKDIS                            (DWC_OFFSET_MASK + 0x4001)
55 #define HDMITX_DWC_A_APIINTMSK                          (DWC_OFFSET_MASK + 0x5008)
56 #define HDMITX_DWC_A_VIDPOLCFG                          (DWC_OFFSET_MASK + 0x5009)
57 #define HDMITX_DWC_A_OESSWCFG                           (DWC_OFFSET_MASK + 0x500A)
58 
hdmitx_writereg(uint32_t addr,uint32_t data)59 static void hdmitx_writereg(uint32_t addr, uint32_t data) {
60     // determine if we are writing to HDMI TOP (AMLOGIC Wrapper) or HDMI IP
61     uint32_t offset = (addr & DWC_OFFSET_MASK) >> 24;
62     addr = addr & 0xffff;
63     WRITE32_HDMITX_REG(HDMITX_ADDR_PORT + offset, addr);
64     WRITE32_HDMITX_REG(HDMITX_ADDR_PORT + offset, addr); // FIXME: Need to write twice!
65     WRITE32_HDMITX_REG(HDMITX_DATA_PORT + offset, data);
66 }
67 
s912_hdcp_init(const void * driver_data,uint32_t length)68 static void s912_hdcp_init(const void* driver_data, uint32_t length) {
69     ASSERT(length >= sizeof(dcfg_amlogic_hdcp_driver_t));
70     auto driver = static_cast<const dcfg_amlogic_hdcp_driver_t *>(driver_data);
71     ASSERT(driver->preset_phys && driver->hiu_phys && driver->hdmitx_phys);
72 
73     // get virtual addresses of our peripheral bases
74     preset_base = periph_paddr_to_vaddr(driver->preset_phys);
75     hiu_base = periph_paddr_to_vaddr(driver->hiu_phys);
76     hdmitx_base = periph_paddr_to_vaddr(driver->hdmitx_phys);
77     ASSERT(preset_base && hiu_base && hdmitx_base);
78 
79     // enable clocks
80     SET_BIT32(HHI, HHI_HDMI_CLK_CNTL, 0x0100, 16, 0);
81 
82     // enable clk81 (needed for HDMI module and a bunch of other modules)
83     SET_BIT32(HHI, HHI_GCLK_MPEG2, 1, 1, 4);
84 
85     // power up HDMI Memory (bits 15:8)
86     SET_BIT32(HHI, HHI_MEM_PD_REG0, 0, 8, 8);
87 
88     // reset hdmi related blocks (HIU, HDMI SYS, HDMI_TX)
89     WRITE32_PRESET_REG(PRESET0_REGISTER, (1 << 19));
90     WRITE32_PRESET_REG(PRESET2_REGISTER, (1 << 15));
91     WRITE32_PRESET_REG(PRESET2_REGISTER, (1 << 2));
92 
93     // // Bring HDMI out of reset
94     hdmitx_writereg(HDMITX_TOP_SW_RESET, 0);
95     spin(200);
96     hdmitx_writereg(HDMITX_TOP_CLK_CNTL, 0x000000ff);
97     hdmitx_writereg(HDMITX_DWC_MC_LOCKONCLOCK, 0xff);
98     hdmitx_writereg(HDMITX_DWC_MC_CLKDIS, 0x00);
99 
100     /* Configure HDCP */
101     uint32_t data32  = 0;
102     data32 |= (0 << 7);
103     data32 |= (0 << 6);
104     data32 |= (0 << 4);
105     data32 |= (0 << 3);
106     data32 |= (0 << 2);
107     data32 |= (0 << 1);
108     data32 |= (1 << 0);
109     hdmitx_writereg(HDMITX_DWC_A_APIINTMSK, data32);
110 
111     data32  = 0;
112     data32 |= (0 << 5);
113     data32 |= (1 << 4);
114     data32 |= (1 << 3);
115     data32 |= (1 << 1);
116     hdmitx_writereg(HDMITX_DWC_A_VIDPOLCFG, data32);
117 
118     hdmitx_writereg(HDMITX_DWC_A_OESSWCFG, 0x40);
119 
120     arm_smccc_smc(0x82000012, 0, 0, 0, 0, 0, 0, 0);
121 }
122 
123 LK_PDEV_INIT(s912_hdcp_init, KDRV_AMLOGIC_HDCP, s912_hdcp_init, LK_INIT_LEVEL_PLATFORM);
124