1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * cx18 firmware functions
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
6*4882a593Smuzhiyun * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include "cx18-driver.h"
10*4882a593Smuzhiyun #include "cx18-io.h"
11*4882a593Smuzhiyun #include "cx18-scb.h"
12*4882a593Smuzhiyun #include "cx18-irq.h"
13*4882a593Smuzhiyun #include "cx18-firmware.h"
14*4882a593Smuzhiyun #include "cx18-cards.h"
15*4882a593Smuzhiyun #include <linux/firmware.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #define CX18_PROC_SOFT_RESET 0xc70010
18*4882a593Smuzhiyun #define CX18_DDR_SOFT_RESET 0xc70014
19*4882a593Smuzhiyun #define CX18_CLOCK_SELECT1 0xc71000
20*4882a593Smuzhiyun #define CX18_CLOCK_SELECT2 0xc71004
21*4882a593Smuzhiyun #define CX18_HALF_CLOCK_SELECT1 0xc71008
22*4882a593Smuzhiyun #define CX18_HALF_CLOCK_SELECT2 0xc7100C
23*4882a593Smuzhiyun #define CX18_CLOCK_POLARITY1 0xc71010
24*4882a593Smuzhiyun #define CX18_CLOCK_POLARITY2 0xc71014
25*4882a593Smuzhiyun #define CX18_ADD_DELAY_ENABLE1 0xc71018
26*4882a593Smuzhiyun #define CX18_ADD_DELAY_ENABLE2 0xc7101C
27*4882a593Smuzhiyun #define CX18_CLOCK_ENABLE1 0xc71020
28*4882a593Smuzhiyun #define CX18_CLOCK_ENABLE2 0xc71024
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #define CX18_REG_BUS_TIMEOUT_EN 0xc72024
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #define CX18_FAST_CLOCK_PLL_INT 0xc78000
33*4882a593Smuzhiyun #define CX18_FAST_CLOCK_PLL_FRAC 0xc78004
34*4882a593Smuzhiyun #define CX18_FAST_CLOCK_PLL_POST 0xc78008
35*4882a593Smuzhiyun #define CX18_FAST_CLOCK_PLL_PRESCALE 0xc7800C
36*4882a593Smuzhiyun #define CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH 0xc78010
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun #define CX18_SLOW_CLOCK_PLL_INT 0xc78014
39*4882a593Smuzhiyun #define CX18_SLOW_CLOCK_PLL_FRAC 0xc78018
40*4882a593Smuzhiyun #define CX18_SLOW_CLOCK_PLL_POST 0xc7801C
41*4882a593Smuzhiyun #define CX18_MPEG_CLOCK_PLL_INT 0xc78040
42*4882a593Smuzhiyun #define CX18_MPEG_CLOCK_PLL_FRAC 0xc78044
43*4882a593Smuzhiyun #define CX18_MPEG_CLOCK_PLL_POST 0xc78048
44*4882a593Smuzhiyun #define CX18_PLL_POWER_DOWN 0xc78088
45*4882a593Smuzhiyun #define CX18_SW1_INT_STATUS 0xc73104
46*4882a593Smuzhiyun #define CX18_SW1_INT_ENABLE_PCI 0xc7311C
47*4882a593Smuzhiyun #define CX18_SW2_INT_SET 0xc73140
48*4882a593Smuzhiyun #define CX18_SW2_INT_STATUS 0xc73144
49*4882a593Smuzhiyun #define CX18_ADEC_CONTROL 0xc78120
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun #define CX18_DDR_REQUEST_ENABLE 0xc80000
52*4882a593Smuzhiyun #define CX18_DDR_CHIP_CONFIG 0xc80004
53*4882a593Smuzhiyun #define CX18_DDR_REFRESH 0xc80008
54*4882a593Smuzhiyun #define CX18_DDR_TIMING1 0xc8000C
55*4882a593Smuzhiyun #define CX18_DDR_TIMING2 0xc80010
56*4882a593Smuzhiyun #define CX18_DDR_POWER_REG 0xc8001C
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun #define CX18_DDR_TUNE_LANE 0xc80048
59*4882a593Smuzhiyun #define CX18_DDR_INITIAL_EMRS 0xc80054
60*4882a593Smuzhiyun #define CX18_DDR_MB_PER_ROW_7 0xc8009C
61*4882a593Smuzhiyun #define CX18_DDR_BASE_63_ADDR 0xc804FC
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun #define CX18_WMB_CLIENT02 0xc90108
64*4882a593Smuzhiyun #define CX18_WMB_CLIENT05 0xc90114
65*4882a593Smuzhiyun #define CX18_WMB_CLIENT06 0xc90118
66*4882a593Smuzhiyun #define CX18_WMB_CLIENT07 0xc9011C
67*4882a593Smuzhiyun #define CX18_WMB_CLIENT08 0xc90120
68*4882a593Smuzhiyun #define CX18_WMB_CLIENT09 0xc90124
69*4882a593Smuzhiyun #define CX18_WMB_CLIENT10 0xc90128
70*4882a593Smuzhiyun #define CX18_WMB_CLIENT11 0xc9012C
71*4882a593Smuzhiyun #define CX18_WMB_CLIENT12 0xc90130
72*4882a593Smuzhiyun #define CX18_WMB_CLIENT13 0xc90134
73*4882a593Smuzhiyun #define CX18_WMB_CLIENT14 0xc90138
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun #define CX18_DSP0_INTERRUPT_MASK 0xd0004C
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun #define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */
78*4882a593Smuzhiyun #define APU_ROM_SYNC2 0x72646548 /* "rdeH" */
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun struct cx18_apu_rom_seghdr {
81*4882a593Smuzhiyun u32 sync1;
82*4882a593Smuzhiyun u32 sync2;
83*4882a593Smuzhiyun u32 addr;
84*4882a593Smuzhiyun u32 size;
85*4882a593Smuzhiyun };
86*4882a593Smuzhiyun
load_cpu_fw_direct(const char * fn,u8 __iomem * mem,struct cx18 * cx)87*4882a593Smuzhiyun static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun const struct firmware *fw = NULL;
90*4882a593Smuzhiyun int i, j;
91*4882a593Smuzhiyun unsigned size;
92*4882a593Smuzhiyun u32 __iomem *dst = (u32 __iomem *)mem;
93*4882a593Smuzhiyun const u32 *src;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun if (request_firmware(&fw, fn, &cx->pci_dev->dev)) {
96*4882a593Smuzhiyun CX18_ERR("Unable to open firmware %s\n", fn);
97*4882a593Smuzhiyun CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n");
98*4882a593Smuzhiyun return -ENOMEM;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun src = (const u32 *)fw->data;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun for (i = 0; i < fw->size; i += 4096) {
104*4882a593Smuzhiyun cx18_setup_page(cx, i);
105*4882a593Smuzhiyun for (j = i; j < fw->size && j < i + 4096; j += 4) {
106*4882a593Smuzhiyun /* no need for endianness conversion on the ppc */
107*4882a593Smuzhiyun cx18_raw_writel(cx, *src, dst);
108*4882a593Smuzhiyun if (cx18_raw_readl(cx, dst) != *src) {
109*4882a593Smuzhiyun CX18_ERR("Mismatch at offset %x\n", i);
110*4882a593Smuzhiyun release_firmware(fw);
111*4882a593Smuzhiyun cx18_setup_page(cx, 0);
112*4882a593Smuzhiyun return -EIO;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun dst++;
115*4882a593Smuzhiyun src++;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
119*4882a593Smuzhiyun CX18_INFO("loaded %s firmware (%zu bytes)\n", fn, fw->size);
120*4882a593Smuzhiyun size = fw->size;
121*4882a593Smuzhiyun release_firmware(fw);
122*4882a593Smuzhiyun cx18_setup_page(cx, SCB_OFFSET);
123*4882a593Smuzhiyun return size;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
load_apu_fw_direct(const char * fn,u8 __iomem * dst,struct cx18 * cx,u32 * entry_addr)126*4882a593Smuzhiyun static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx,
127*4882a593Smuzhiyun u32 *entry_addr)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun const struct firmware *fw = NULL;
130*4882a593Smuzhiyun int i, j;
131*4882a593Smuzhiyun unsigned size;
132*4882a593Smuzhiyun const u32 *src;
133*4882a593Smuzhiyun struct cx18_apu_rom_seghdr seghdr;
134*4882a593Smuzhiyun const u8 *vers;
135*4882a593Smuzhiyun u32 offset = 0;
136*4882a593Smuzhiyun u32 apu_version = 0;
137*4882a593Smuzhiyun int sz;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun if (request_firmware(&fw, fn, &cx->pci_dev->dev)) {
140*4882a593Smuzhiyun CX18_ERR("unable to open firmware %s\n", fn);
141*4882a593Smuzhiyun CX18_ERR("did you put the firmware in the hotplug firmware directory?\n");
142*4882a593Smuzhiyun cx18_setup_page(cx, 0);
143*4882a593Smuzhiyun return -ENOMEM;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun *entry_addr = 0;
147*4882a593Smuzhiyun src = (const u32 *)fw->data;
148*4882a593Smuzhiyun vers = fw->data + sizeof(seghdr);
149*4882a593Smuzhiyun sz = fw->size;
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32];
152*4882a593Smuzhiyun while (offset + sizeof(seghdr) < fw->size) {
153*4882a593Smuzhiyun const __le32 *shptr = (__force __le32 *)src + offset / 4;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun seghdr.sync1 = le32_to_cpu(shptr[0]);
156*4882a593Smuzhiyun seghdr.sync2 = le32_to_cpu(shptr[1]);
157*4882a593Smuzhiyun seghdr.addr = le32_to_cpu(shptr[2]);
158*4882a593Smuzhiyun seghdr.size = le32_to_cpu(shptr[3]);
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun offset += sizeof(seghdr);
161*4882a593Smuzhiyun if (seghdr.sync1 != APU_ROM_SYNC1 ||
162*4882a593Smuzhiyun seghdr.sync2 != APU_ROM_SYNC2) {
163*4882a593Smuzhiyun offset += seghdr.size;
164*4882a593Smuzhiyun continue;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr,
167*4882a593Smuzhiyun seghdr.addr + seghdr.size - 1);
168*4882a593Smuzhiyun if (*entry_addr == 0)
169*4882a593Smuzhiyun *entry_addr = seghdr.addr;
170*4882a593Smuzhiyun if (offset + seghdr.size > sz)
171*4882a593Smuzhiyun break;
172*4882a593Smuzhiyun for (i = 0; i < seghdr.size; i += 4096) {
173*4882a593Smuzhiyun cx18_setup_page(cx, seghdr.addr + i);
174*4882a593Smuzhiyun for (j = i; j < seghdr.size && j < i + 4096; j += 4) {
175*4882a593Smuzhiyun /* no need for endianness conversion on the ppc */
176*4882a593Smuzhiyun cx18_raw_writel(cx, src[(offset + j) / 4],
177*4882a593Smuzhiyun dst + seghdr.addr + j);
178*4882a593Smuzhiyun if (cx18_raw_readl(cx, dst + seghdr.addr + j)
179*4882a593Smuzhiyun != src[(offset + j) / 4]) {
180*4882a593Smuzhiyun CX18_ERR("Mismatch at offset %x\n",
181*4882a593Smuzhiyun offset + j);
182*4882a593Smuzhiyun release_firmware(fw);
183*4882a593Smuzhiyun cx18_setup_page(cx, 0);
184*4882a593Smuzhiyun return -EIO;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun offset += seghdr.size;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
191*4882a593Smuzhiyun CX18_INFO("loaded %s firmware V%08x (%zu bytes)\n",
192*4882a593Smuzhiyun fn, apu_version, fw->size);
193*4882a593Smuzhiyun size = fw->size;
194*4882a593Smuzhiyun release_firmware(fw);
195*4882a593Smuzhiyun cx18_setup_page(cx, 0);
196*4882a593Smuzhiyun return size;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
cx18_halt_firmware(struct cx18 * cx)199*4882a593Smuzhiyun void cx18_halt_firmware(struct cx18 *cx)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun CX18_DEBUG_INFO("Preparing for firmware halt.\n");
202*4882a593Smuzhiyun cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET,
203*4882a593Smuzhiyun 0x0000000F, 0x000F000F);
204*4882a593Smuzhiyun cx18_write_reg_expect(cx, 0x00020002, CX18_ADEC_CONTROL,
205*4882a593Smuzhiyun 0x00000002, 0x00020002);
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun
cx18_init_power(struct cx18 * cx,int lowpwr)208*4882a593Smuzhiyun void cx18_init_power(struct cx18 *cx, int lowpwr)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun /* power-down Spare and AOM PLLs */
211*4882a593Smuzhiyun /* power-up fast, slow and mpeg PLLs */
212*4882a593Smuzhiyun cx18_write_reg(cx, 0x00000008, CX18_PLL_POWER_DOWN);
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun /* ADEC out of sleep */
215*4882a593Smuzhiyun cx18_write_reg_expect(cx, 0x00020000, CX18_ADEC_CONTROL,
216*4882a593Smuzhiyun 0x00000000, 0x00020002);
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun /*
219*4882a593Smuzhiyun * The PLL parameters are based on the external crystal frequency that
220*4882a593Smuzhiyun * would ideally be:
221*4882a593Smuzhiyun *
222*4882a593Smuzhiyun * NTSC Color subcarrier freq * 8 =
223*4882a593Smuzhiyun * 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
224*4882a593Smuzhiyun *
225*4882a593Smuzhiyun * The accidents of history and rationale that explain from where this
226*4882a593Smuzhiyun * combination of magic numbers originate can be found in:
227*4882a593Smuzhiyun *
228*4882a593Smuzhiyun * [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in
229*4882a593Smuzhiyun * the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80
230*4882a593Smuzhiyun *
231*4882a593Smuzhiyun * [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the
232*4882a593Smuzhiyun * NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83
233*4882a593Smuzhiyun *
234*4882a593Smuzhiyun * As Mike Bradley has rightly pointed out, it's not the exact crystal
235*4882a593Smuzhiyun * frequency that matters, only that all parts of the driver and
236*4882a593Smuzhiyun * firmware are using the same value (close to the ideal value).
237*4882a593Smuzhiyun *
238*4882a593Smuzhiyun * Since I have a strong suspicion that, if the firmware ever assumes a
239*4882a593Smuzhiyun * crystal value at all, it will assume 28.636360 MHz, the crystal
240*4882a593Smuzhiyun * freq used in calculations in this driver will be:
241*4882a593Smuzhiyun *
242*4882a593Smuzhiyun * xtal_freq = 28.636360 MHz
243*4882a593Smuzhiyun *
244*4882a593Smuzhiyun * an error of less than 0.13 ppm which is way, way better than any off
245*4882a593Smuzhiyun * the shelf crystal will have for accuracy anyway.
246*4882a593Smuzhiyun *
247*4882a593Smuzhiyun * Below I aim to run the PLLs' VCOs near 400 MHz to minimze errors.
248*4882a593Smuzhiyun *
249*4882a593Smuzhiyun * Many thanks to Jeff Campbell and Mike Bradley for their extensive
250*4882a593Smuzhiyun * investigation, experimentation, testing, and suggested solutions of
251*4882a593Smuzhiyun * of audio/video sync problems with SVideo and CVBS captures.
252*4882a593Smuzhiyun */
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun /* the fast clock is at 200/245 MHz */
255*4882a593Smuzhiyun /* 1 * xtal_freq * 0x0d.f7df9b8 / 2 = 200 MHz: 400 MHz pre post-divide*/
256*4882a593Smuzhiyun /* 1 * xtal_freq * 0x11.1c71eb8 / 2 = 245 MHz: 490 MHz pre post-divide*/
257*4882a593Smuzhiyun cx18_write_reg(cx, lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT);
258*4882a593Smuzhiyun cx18_write_reg(cx, lowpwr ? 0x1EFBF37 : 0x038E3D7,
259*4882a593Smuzhiyun CX18_FAST_CLOCK_PLL_FRAC);
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun cx18_write_reg(cx, 2, CX18_FAST_CLOCK_PLL_POST);
262*4882a593Smuzhiyun cx18_write_reg(cx, 1, CX18_FAST_CLOCK_PLL_PRESCALE);
263*4882a593Smuzhiyun cx18_write_reg(cx, 4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH);
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun /* set slow clock to 125/120 MHz */
266*4882a593Smuzhiyun /* xtal_freq * 0x0d.1861a20 / 3 = 125 MHz: 375 MHz before post-divide */
267*4882a593Smuzhiyun /* xtal_freq * 0x0c.92493f8 / 3 = 120 MHz: 360 MHz before post-divide */
268*4882a593Smuzhiyun cx18_write_reg(cx, lowpwr ? 0xD : 0xC, CX18_SLOW_CLOCK_PLL_INT);
269*4882a593Smuzhiyun cx18_write_reg(cx, lowpwr ? 0x30C344 : 0x124927F,
270*4882a593Smuzhiyun CX18_SLOW_CLOCK_PLL_FRAC);
271*4882a593Smuzhiyun cx18_write_reg(cx, 3, CX18_SLOW_CLOCK_PLL_POST);
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun /* mpeg clock pll 54MHz */
274*4882a593Smuzhiyun /* xtal_freq * 0xf.15f17f0 / 8 = 54 MHz: 432 MHz before post-divide */
275*4882a593Smuzhiyun cx18_write_reg(cx, 0xF, CX18_MPEG_CLOCK_PLL_INT);
276*4882a593Smuzhiyun cx18_write_reg(cx, 0x2BE2FE, CX18_MPEG_CLOCK_PLL_FRAC);
277*4882a593Smuzhiyun cx18_write_reg(cx, 8, CX18_MPEG_CLOCK_PLL_POST);
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun /* Defaults */
280*4882a593Smuzhiyun /* APU = SC or SC/2 = 125/62.5 */
281*4882a593Smuzhiyun /* EPU = SC = 125 */
282*4882a593Smuzhiyun /* DDR = FC = 180 */
283*4882a593Smuzhiyun /* ENC = SC = 125 */
284*4882a593Smuzhiyun /* AI1 = SC = 125 */
285*4882a593Smuzhiyun /* VIM2 = disabled */
286*4882a593Smuzhiyun /* PCI = FC/2 = 90 */
287*4882a593Smuzhiyun /* AI2 = disabled */
288*4882a593Smuzhiyun /* DEMUX = disabled */
289*4882a593Smuzhiyun /* AO = SC/2 = 62.5 */
290*4882a593Smuzhiyun /* SER = 54MHz */
291*4882a593Smuzhiyun /* VFC = disabled */
292*4882a593Smuzhiyun /* USB = disabled */
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun if (lowpwr) {
295*4882a593Smuzhiyun cx18_write_reg_expect(cx, 0xFFFF0020, CX18_CLOCK_SELECT1,
296*4882a593Smuzhiyun 0x00000020, 0xFFFFFFFF);
297*4882a593Smuzhiyun cx18_write_reg_expect(cx, 0xFFFF0004, CX18_CLOCK_SELECT2,
298*4882a593Smuzhiyun 0x00000004, 0xFFFFFFFF);
299*4882a593Smuzhiyun } else {
300*4882a593Smuzhiyun /* This doesn't explicitly set every clock select */
301*4882a593Smuzhiyun cx18_write_reg_expect(cx, 0x00060004, CX18_CLOCK_SELECT1,
302*4882a593Smuzhiyun 0x00000004, 0x00060006);
303*4882a593Smuzhiyun cx18_write_reg_expect(cx, 0x00060006, CX18_CLOCK_SELECT2,
304*4882a593Smuzhiyun 0x00000006, 0x00060006);
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun cx18_write_reg_expect(cx, 0xFFFF0002, CX18_HALF_CLOCK_SELECT1,
308*4882a593Smuzhiyun 0x00000002, 0xFFFFFFFF);
309*4882a593Smuzhiyun cx18_write_reg_expect(cx, 0xFFFF0104, CX18_HALF_CLOCK_SELECT2,
310*4882a593Smuzhiyun 0x00000104, 0xFFFFFFFF);
311*4882a593Smuzhiyun cx18_write_reg_expect(cx, 0xFFFF9026, CX18_CLOCK_ENABLE1,
312*4882a593Smuzhiyun 0x00009026, 0xFFFFFFFF);
313*4882a593Smuzhiyun cx18_write_reg_expect(cx, 0xFFFF3105, CX18_CLOCK_ENABLE2,
314*4882a593Smuzhiyun 0x00003105, 0xFFFFFFFF);
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
cx18_init_memory(struct cx18 * cx)317*4882a593Smuzhiyun void cx18_init_memory(struct cx18 *cx)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun cx18_msleep_timeout(10, 0);
320*4882a593Smuzhiyun cx18_write_reg_expect(cx, 0x00010000, CX18_DDR_SOFT_RESET,
321*4882a593Smuzhiyun 0x00000000, 0x00010001);
322*4882a593Smuzhiyun cx18_msleep_timeout(10, 0);
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun cx18_write_reg(cx, cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG);
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun cx18_msleep_timeout(10, 0);
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun cx18_write_reg(cx, cx->card->ddr.refresh, CX18_DDR_REFRESH);
329*4882a593Smuzhiyun cx18_write_reg(cx, cx->card->ddr.timing1, CX18_DDR_TIMING1);
330*4882a593Smuzhiyun cx18_write_reg(cx, cx->card->ddr.timing2, CX18_DDR_TIMING2);
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun cx18_msleep_timeout(10, 0);
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun /* Initialize DQS pad time */
335*4882a593Smuzhiyun cx18_write_reg(cx, cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE);
336*4882a593Smuzhiyun cx18_write_reg(cx, cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS);
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun cx18_msleep_timeout(10, 0);
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun cx18_write_reg_expect(cx, 0x00020000, CX18_DDR_SOFT_RESET,
341*4882a593Smuzhiyun 0x00000000, 0x00020002);
342*4882a593Smuzhiyun cx18_msleep_timeout(10, 0);
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun /* use power-down mode when idle */
345*4882a593Smuzhiyun cx18_write_reg(cx, 0x00000010, CX18_DDR_POWER_REG);
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun cx18_write_reg_expect(cx, 0x00010001, CX18_REG_BUS_TIMEOUT_EN,
348*4882a593Smuzhiyun 0x00000001, 0x00010001);
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun cx18_write_reg(cx, 0x48, CX18_DDR_MB_PER_ROW_7);
351*4882a593Smuzhiyun cx18_write_reg(cx, 0xE0000, CX18_DDR_BASE_63_ADDR);
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT02); /* AO */
354*4882a593Smuzhiyun cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT09); /* AI2 */
355*4882a593Smuzhiyun cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT05); /* VIM1 */
356*4882a593Smuzhiyun cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT06); /* AI1 */
357*4882a593Smuzhiyun cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT07); /* 3D comb */
358*4882a593Smuzhiyun cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT10); /* ME */
359*4882a593Smuzhiyun cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT12); /* ENC */
360*4882a593Smuzhiyun cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT13); /* PK */
361*4882a593Smuzhiyun cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT11); /* RC */
362*4882a593Smuzhiyun cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT14); /* AVO */
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun #define CX18_CPU_FIRMWARE "v4l-cx23418-cpu.fw"
366*4882a593Smuzhiyun #define CX18_APU_FIRMWARE "v4l-cx23418-apu.fw"
367*4882a593Smuzhiyun
cx18_firmware_init(struct cx18 * cx)368*4882a593Smuzhiyun int cx18_firmware_init(struct cx18 *cx)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun u32 fw_entry_addr;
371*4882a593Smuzhiyun int sz, retries;
372*4882a593Smuzhiyun u32 api_args[MAX_MB_ARGUMENTS];
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun /* Allow chip to control CLKRUN */
375*4882a593Smuzhiyun cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK);
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun /* Stop the firmware */
378*4882a593Smuzhiyun cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET,
379*4882a593Smuzhiyun 0x0000000F, 0x000F000F);
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun cx18_msleep_timeout(1, 0);
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun /* If the CPU is still running */
384*4882a593Smuzhiyun if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) == 0) {
385*4882a593Smuzhiyun CX18_ERR("%s: couldn't stop CPU to load firmware\n", __func__);
386*4882a593Smuzhiyun return -EIO;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun cx18_sw1_irq_enable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
390*4882a593Smuzhiyun cx18_sw2_irq_enable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun sz = load_cpu_fw_direct(CX18_CPU_FIRMWARE, cx->enc_mem, cx);
393*4882a593Smuzhiyun if (sz <= 0)
394*4882a593Smuzhiyun return sz;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun /* The SCB & IPC area *must* be correct before starting the firmwares */
397*4882a593Smuzhiyun cx18_init_scb(cx);
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun fw_entry_addr = 0;
400*4882a593Smuzhiyun sz = load_apu_fw_direct(CX18_APU_FIRMWARE, cx->enc_mem, cx,
401*4882a593Smuzhiyun &fw_entry_addr);
402*4882a593Smuzhiyun if (sz <= 0)
403*4882a593Smuzhiyun return sz;
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun /* Start the CPU. The CPU will take care of the APU for us. */
406*4882a593Smuzhiyun cx18_write_reg_expect(cx, 0x00080000, CX18_PROC_SOFT_RESET,
407*4882a593Smuzhiyun 0x00000000, 0x00080008);
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun /* Wait up to 500 ms for the APU to come out of reset */
410*4882a593Smuzhiyun for (retries = 0;
411*4882a593Smuzhiyun retries < 50 && (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1;
412*4882a593Smuzhiyun retries++)
413*4882a593Smuzhiyun cx18_msleep_timeout(10, 0);
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun cx18_msleep_timeout(200, 0);
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun if (retries == 50 &&
418*4882a593Smuzhiyun (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1) {
419*4882a593Smuzhiyun CX18_ERR("Could not start the CPU\n");
420*4882a593Smuzhiyun return -EIO;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun /*
424*4882a593Smuzhiyun * The CPU had once before set up to receive an interrupt for it's
425*4882a593Smuzhiyun * outgoing IRQ_CPU_TO_EPU_ACK to us. If it ever does this, we get an
426*4882a593Smuzhiyun * interrupt when it sends us an ack, but by the time we process it,
427*4882a593Smuzhiyun * that flag in the SW2 status register has been cleared by the CPU
428*4882a593Smuzhiyun * firmware. We'll prevent that not so useful condition from happening
429*4882a593Smuzhiyun * by clearing the CPU's interrupt enables for Ack IRQ's we want to
430*4882a593Smuzhiyun * process.
431*4882a593Smuzhiyun */
432*4882a593Smuzhiyun cx18_sw2_irq_disable_cpu(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun /* Try a benign command to see if the CPU is alive and well */
435*4882a593Smuzhiyun sz = cx18_vapi_result(cx, api_args, CX18_CPU_DEBUG_PEEK32, 1, 0);
436*4882a593Smuzhiyun if (sz < 0)
437*4882a593Smuzhiyun return sz;
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun /* initialize GPIO */
440*4882a593Smuzhiyun cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400);
441*4882a593Smuzhiyun return 0;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun MODULE_FIRMWARE(CX18_CPU_FIRMWARE);
445*4882a593Smuzhiyun MODULE_FIRMWARE(CX18_APU_FIRMWARE);
446