Commit | Line | Data |
---|---|---|
1c1e45d1 HV |
1 | /* |
2 | * cx18 firmware functions | |
3 | * | |
4 | * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
19 | * 02111-1307 USA | |
20 | */ | |
21 | ||
22 | #include "cx18-driver.h" | |
b1526421 | 23 | #include "cx18-io.h" |
1c1e45d1 HV |
24 | #include "cx18-scb.h" |
25 | #include "cx18-irq.h" | |
26 | #include "cx18-firmware.h" | |
27 | #include "cx18-cards.h" | |
28 | #include <linux/firmware.h> | |
29 | ||
30 | #define CX18_PROC_SOFT_RESET 0xc70010 | |
31 | #define CX18_DDR_SOFT_RESET 0xc70014 | |
32 | #define CX18_CLOCK_SELECT1 0xc71000 | |
33 | #define CX18_CLOCK_SELECT2 0xc71004 | |
34 | #define CX18_HALF_CLOCK_SELECT1 0xc71008 | |
35 | #define CX18_HALF_CLOCK_SELECT2 0xc7100C | |
36 | #define CX18_CLOCK_POLARITY1 0xc71010 | |
37 | #define CX18_CLOCK_POLARITY2 0xc71014 | |
38 | #define CX18_ADD_DELAY_ENABLE1 0xc71018 | |
39 | #define CX18_ADD_DELAY_ENABLE2 0xc7101C | |
40 | #define CX18_CLOCK_ENABLE1 0xc71020 | |
41 | #define CX18_CLOCK_ENABLE2 0xc71024 | |
42 | ||
43 | #define CX18_REG_BUS_TIMEOUT_EN 0xc72024 | |
1c1e45d1 HV |
44 | |
45 | #define CX18_FAST_CLOCK_PLL_INT 0xc78000 | |
46 | #define CX18_FAST_CLOCK_PLL_FRAC 0xc78004 | |
47 | #define CX18_FAST_CLOCK_PLL_POST 0xc78008 | |
48 | #define CX18_FAST_CLOCK_PLL_PRESCALE 0xc7800C | |
49 | #define CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH 0xc78010 | |
50 | ||
51 | #define CX18_SLOW_CLOCK_PLL_INT 0xc78014 | |
52 | #define CX18_SLOW_CLOCK_PLL_FRAC 0xc78018 | |
53 | #define CX18_SLOW_CLOCK_PLL_POST 0xc7801C | |
54 | #define CX18_MPEG_CLOCK_PLL_INT 0xc78040 | |
55 | #define CX18_MPEG_CLOCK_PLL_FRAC 0xc78044 | |
56 | #define CX18_MPEG_CLOCK_PLL_POST 0xc78048 | |
57 | #define CX18_PLL_POWER_DOWN 0xc78088 | |
58 | #define CX18_SW1_INT_STATUS 0xc73104 | |
59 | #define CX18_SW1_INT_ENABLE_PCI 0xc7311C | |
60 | #define CX18_SW2_INT_SET 0xc73140 | |
61 | #define CX18_SW2_INT_STATUS 0xc73144 | |
62 | #define CX18_ADEC_CONTROL 0xc78120 | |
63 | ||
64 | #define CX18_DDR_REQUEST_ENABLE 0xc80000 | |
65 | #define CX18_DDR_CHIP_CONFIG 0xc80004 | |
66 | #define CX18_DDR_REFRESH 0xc80008 | |
67 | #define CX18_DDR_TIMING1 0xc8000C | |
68 | #define CX18_DDR_TIMING2 0xc80010 | |
69 | #define CX18_DDR_POWER_REG 0xc8001C | |
70 | ||
71 | #define CX18_DDR_TUNE_LANE 0xc80048 | |
72 | #define CX18_DDR_INITIAL_EMRS 0xc80054 | |
73 | #define CX18_DDR_MB_PER_ROW_7 0xc8009C | |
74 | #define CX18_DDR_BASE_63_ADDR 0xc804FC | |
75 | ||
76 | #define CX18_WMB_CLIENT02 0xc90108 | |
77 | #define CX18_WMB_CLIENT05 0xc90114 | |
78 | #define CX18_WMB_CLIENT06 0xc90118 | |
79 | #define CX18_WMB_CLIENT07 0xc9011C | |
80 | #define CX18_WMB_CLIENT08 0xc90120 | |
81 | #define CX18_WMB_CLIENT09 0xc90124 | |
82 | #define CX18_WMB_CLIENT10 0xc90128 | |
83 | #define CX18_WMB_CLIENT11 0xc9012C | |
84 | #define CX18_WMB_CLIENT12 0xc90130 | |
85 | #define CX18_WMB_CLIENT13 0xc90134 | |
86 | #define CX18_WMB_CLIENT14 0xc90138 | |
87 | ||
88 | #define CX18_DSP0_INTERRUPT_MASK 0xd0004C | |
89 | ||
1c1e45d1 HV |
90 | #define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */ |
91 | #define APU_ROM_SYNC2 0x72646548 /* "rdeH" */ | |
92 | ||
93 | struct cx18_apu_rom_seghdr { | |
94 | u32 sync1; | |
95 | u32 sync2; | |
96 | u32 addr; | |
97 | u32 size; | |
98 | }; | |
99 | ||
82fc52a8 | 100 | static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx) |
1c1e45d1 HV |
101 | { |
102 | const struct firmware *fw = NULL; | |
1c1e45d1 | 103 | int i, j; |
82fc52a8 | 104 | unsigned size; |
1c1e45d1 HV |
105 | u32 __iomem *dst = (u32 __iomem *)mem; |
106 | const u32 *src; | |
107 | ||
82fc52a8 HV |
108 | if (request_firmware(&fw, fn, &cx->dev->dev)) { |
109 | CX18_ERR("Unable to open firmware %s\n", fn); | |
1c1e45d1 HV |
110 | CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n"); |
111 | return -ENOMEM; | |
112 | } | |
113 | ||
114 | src = (const u32 *)fw->data; | |
115 | ||
1c1e45d1 | 116 | for (i = 0; i < fw->size; i += 4096) { |
b1526421 | 117 | cx18_setup_page(cx, i); |
1c1e45d1 HV |
118 | for (j = i; j < fw->size && j < i + 4096; j += 4) { |
119 | /* no need for endianness conversion on the ppc */ | |
b1526421 AW |
120 | cx18_raw_writel(cx, *src, dst); |
121 | if (cx18_raw_readl(cx, dst) != *src) { | |
1c1e45d1 HV |
122 | CX18_ERR("Mismatch at offset %x\n", i); |
123 | release_firmware(fw); | |
124 | return -EIO; | |
125 | } | |
126 | dst++; | |
127 | src++; | |
128 | } | |
129 | } | |
130 | if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) | |
131 | CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size); | |
82fc52a8 | 132 | size = fw->size; |
1c1e45d1 HV |
133 | release_firmware(fw); |
134 | return size; | |
135 | } | |
136 | ||
2d1a1b05 AW |
137 | static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, |
138 | u32 *entry_addr) | |
1c1e45d1 HV |
139 | { |
140 | const struct firmware *fw = NULL; | |
1c1e45d1 | 141 | int i, j; |
82fc52a8 | 142 | unsigned size; |
1c1e45d1 HV |
143 | const u32 *src; |
144 | struct cx18_apu_rom_seghdr seghdr; | |
145 | const u8 *vers; | |
146 | u32 offset = 0; | |
147 | u32 apu_version = 0; | |
148 | int sz; | |
149 | ||
82fc52a8 HV |
150 | if (request_firmware(&fw, fn, &cx->dev->dev)) { |
151 | CX18_ERR("unable to open firmware %s\n", fn); | |
1c1e45d1 HV |
152 | CX18_ERR("did you put the firmware in the hotplug firmware directory?\n"); |
153 | return -ENOMEM; | |
154 | } | |
155 | ||
2d1a1b05 | 156 | *entry_addr = 0xffffffff; |
1c1e45d1 HV |
157 | src = (const u32 *)fw->data; |
158 | vers = fw->data + sizeof(seghdr); | |
159 | sz = fw->size; | |
160 | ||
1c1e45d1 | 161 | apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32]; |
82fc52a8 | 162 | while (offset + sizeof(seghdr) < fw->size) { |
1c1e45d1 HV |
163 | /* TODO: byteswapping */ |
164 | memcpy(&seghdr, src + offset / 4, sizeof(seghdr)); | |
165 | offset += sizeof(seghdr); | |
166 | if (seghdr.sync1 != APU_ROM_SYNC1 || | |
167 | seghdr.sync2 != APU_ROM_SYNC2) { | |
168 | offset += seghdr.size; | |
169 | continue; | |
170 | } | |
171 | CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr, | |
172 | seghdr.addr + seghdr.size - 1); | |
2d1a1b05 AW |
173 | if (*entry_addr == 0xffffffff) |
174 | *entry_addr = seghdr.addr; | |
1c1e45d1 HV |
175 | if (offset + seghdr.size > sz) |
176 | break; | |
177 | for (i = 0; i < seghdr.size; i += 4096) { | |
2d1a1b05 | 178 | cx18_setup_page(cx, seghdr.addr + i); |
1c1e45d1 HV |
179 | for (j = i; j < seghdr.size && j < i + 4096; j += 4) { |
180 | /* no need for endianness conversion on the ppc */ | |
b1526421 AW |
181 | cx18_raw_writel(cx, src[(offset + j) / 4], |
182 | dst + seghdr.addr + j); | |
183 | if (cx18_raw_readl(cx, dst + seghdr.addr + j) | |
184 | != src[(offset + j) / 4]) { | |
185 | CX18_ERR("Mismatch at offset %x\n", | |
186 | offset + j); | |
1c1e45d1 HV |
187 | release_firmware(fw); |
188 | return -EIO; | |
189 | } | |
190 | } | |
191 | } | |
192 | offset += seghdr.size; | |
193 | } | |
194 | if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) | |
195 | CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n", | |
196 | fn, apu_version, fw->size); | |
82fc52a8 | 197 | size = fw->size; |
1c1e45d1 | 198 | release_firmware(fw); |
1c1e45d1 HV |
199 | return size; |
200 | } | |
201 | ||
202 | void cx18_halt_firmware(struct cx18 *cx) | |
203 | { | |
204 | CX18_DEBUG_INFO("Preparing for firmware halt.\n"); | |
ced07371 AW |
205 | cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET, |
206 | 0x0000000F, 0x000F000F); | |
207 | cx18_write_reg_expect(cx, 0x00020002, CX18_ADEC_CONTROL, | |
208 | 0x00000002, 0x00020002); | |
1c1e45d1 HV |
209 | } |
210 | ||
211 | void cx18_init_power(struct cx18 *cx, int lowpwr) | |
212 | { | |
213 | /* power-down Spare and AOM PLLs */ | |
214 | /* power-up fast, slow and mpeg PLLs */ | |
b1526421 | 215 | cx18_write_reg(cx, 0x00000008, CX18_PLL_POWER_DOWN); |
1c1e45d1 HV |
216 | |
217 | /* ADEC out of sleep */ | |
ced07371 AW |
218 | cx18_write_reg_expect(cx, 0x00020000, CX18_ADEC_CONTROL, |
219 | 0x00000000, 0x00020002); | |
1c1e45d1 HV |
220 | |
221 | /* The fast clock is at 200/245 MHz */ | |
b1526421 AW |
222 | cx18_write_reg(cx, lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT); |
223 | cx18_write_reg(cx, lowpwr ? 0x1EFBF37 : 0x038E3D7, | |
224 | CX18_FAST_CLOCK_PLL_FRAC); | |
1c1e45d1 | 225 | |
b1526421 AW |
226 | cx18_write_reg(cx, 2, CX18_FAST_CLOCK_PLL_POST); |
227 | cx18_write_reg(cx, 1, CX18_FAST_CLOCK_PLL_PRESCALE); | |
228 | cx18_write_reg(cx, 4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH); | |
1c1e45d1 HV |
229 | |
230 | /* set slow clock to 125/120 MHz */ | |
b1526421 AW |
231 | cx18_write_reg(cx, lowpwr ? 0x11 : 0x10, CX18_SLOW_CLOCK_PLL_INT); |
232 | cx18_write_reg(cx, lowpwr ? 0xEBAF05 : 0x18618A8, | |
233 | CX18_SLOW_CLOCK_PLL_FRAC); | |
234 | cx18_write_reg(cx, 4, CX18_SLOW_CLOCK_PLL_POST); | |
1c1e45d1 HV |
235 | |
236 | /* mpeg clock pll 54MHz */ | |
b1526421 AW |
237 | cx18_write_reg(cx, 0xF, CX18_MPEG_CLOCK_PLL_INT); |
238 | cx18_write_reg(cx, 0x2BCFEF, CX18_MPEG_CLOCK_PLL_FRAC); | |
239 | cx18_write_reg(cx, 8, CX18_MPEG_CLOCK_PLL_POST); | |
1c1e45d1 HV |
240 | |
241 | /* Defaults */ | |
242 | /* APU = SC or SC/2 = 125/62.5 */ | |
243 | /* EPU = SC = 125 */ | |
244 | /* DDR = FC = 180 */ | |
245 | /* ENC = SC = 125 */ | |
246 | /* AI1 = SC = 125 */ | |
247 | /* VIM2 = disabled */ | |
248 | /* PCI = FC/2 = 90 */ | |
249 | /* AI2 = disabled */ | |
250 | /* DEMUX = disabled */ | |
251 | /* AO = SC/2 = 62.5 */ | |
252 | /* SER = 54MHz */ | |
253 | /* VFC = disabled */ | |
254 | /* USB = disabled */ | |
255 | ||
ced07371 AW |
256 | if (lowpwr) { |
257 | cx18_write_reg_expect(cx, 0xFFFF0020, CX18_CLOCK_SELECT1, | |
258 | 0x00000020, 0xFFFFFFFF); | |
259 | cx18_write_reg_expect(cx, 0xFFFF0004, CX18_CLOCK_SELECT2, | |
260 | 0x00000004, 0xFFFFFFFF); | |
261 | } else { | |
262 | /* This doesn't explicitly set every clock select */ | |
263 | cx18_write_reg_expect(cx, 0x00060004, CX18_CLOCK_SELECT1, | |
264 | 0x00000004, 0x00060006); | |
265 | cx18_write_reg_expect(cx, 0x00060006, CX18_CLOCK_SELECT2, | |
266 | 0x00000006, 0x00060006); | |
267 | } | |
1c1e45d1 | 268 | |
ced07371 AW |
269 | cx18_write_reg_expect(cx, 0xFFFF0002, CX18_HALF_CLOCK_SELECT1, |
270 | 0x00000002, 0xFFFFFFFF); | |
271 | cx18_write_reg_expect(cx, 0xFFFF0104, CX18_HALF_CLOCK_SELECT2, | |
272 | 0x00000104, 0xFFFFFFFF); | |
273 | cx18_write_reg_expect(cx, 0xFFFF9026, CX18_CLOCK_ENABLE1, | |
274 | 0x00009026, 0xFFFFFFFF); | |
275 | cx18_write_reg_expect(cx, 0xFFFF3105, CX18_CLOCK_ENABLE2, | |
276 | 0x00003105, 0xFFFFFFFF); | |
1c1e45d1 HV |
277 | } |
278 | ||
279 | void cx18_init_memory(struct cx18 *cx) | |
280 | { | |
281 | cx18_msleep_timeout(10, 0); | |
ced07371 AW |
282 | cx18_write_reg_expect(cx, 0x00010000, CX18_DDR_SOFT_RESET, |
283 | 0x00000000, 0x00010001); | |
1c1e45d1 HV |
284 | cx18_msleep_timeout(10, 0); |
285 | ||
b1526421 | 286 | cx18_write_reg(cx, cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG); |
1c1e45d1 HV |
287 | |
288 | cx18_msleep_timeout(10, 0); | |
289 | ||
b1526421 AW |
290 | cx18_write_reg(cx, cx->card->ddr.refresh, CX18_DDR_REFRESH); |
291 | cx18_write_reg(cx, cx->card->ddr.timing1, CX18_DDR_TIMING1); | |
292 | cx18_write_reg(cx, cx->card->ddr.timing2, CX18_DDR_TIMING2); | |
1c1e45d1 HV |
293 | |
294 | cx18_msleep_timeout(10, 0); | |
295 | ||
296 | /* Initialize DQS pad time */ | |
b1526421 AW |
297 | cx18_write_reg(cx, cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE); |
298 | cx18_write_reg(cx, cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS); | |
1c1e45d1 HV |
299 | |
300 | cx18_msleep_timeout(10, 0); | |
301 | ||
ced07371 AW |
302 | cx18_write_reg_expect(cx, 0x00020000, CX18_DDR_SOFT_RESET, |
303 | 0x00000000, 0x00020002); | |
1c1e45d1 HV |
304 | cx18_msleep_timeout(10, 0); |
305 | ||
306 | /* use power-down mode when idle */ | |
b1526421 AW |
307 | cx18_write_reg(cx, 0x00000010, CX18_DDR_POWER_REG); |
308 | ||
ced07371 AW |
309 | cx18_write_reg_expect(cx, 0x00010001, CX18_REG_BUS_TIMEOUT_EN, |
310 | 0x00000001, 0x00010001); | |
b1526421 AW |
311 | |
312 | cx18_write_reg(cx, 0x48, CX18_DDR_MB_PER_ROW_7); | |
313 | cx18_write_reg(cx, 0xE0000, CX18_DDR_BASE_63_ADDR); | |
314 | ||
315 | cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT02); /* AO */ | |
316 | cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT09); /* AI2 */ | |
317 | cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT05); /* VIM1 */ | |
318 | cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT06); /* AI1 */ | |
319 | cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT07); /* 3D comb */ | |
320 | cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT10); /* ME */ | |
321 | cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT12); /* ENC */ | |
322 | cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT13); /* PK */ | |
323 | cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT11); /* RC */ | |
324 | cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT14); /* AVO */ | |
1c1e45d1 HV |
325 | } |
326 | ||
327 | int cx18_firmware_init(struct cx18 *cx) | |
328 | { | |
329 | /* Allow chip to control CLKRUN */ | |
b1526421 | 330 | cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK); |
1c1e45d1 | 331 | |
ced07371 AW |
332 | /* Stop the firmware */ |
333 | cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET, | |
334 | 0x0000000F, 0x000F000F); | |
1c1e45d1 HV |
335 | |
336 | cx18_msleep_timeout(1, 0); | |
337 | ||
b1526421 AW |
338 | cx18_sw1_irq_enable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); |
339 | cx18_sw2_irq_enable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); | |
1c1e45d1 HV |
340 | |
341 | /* Only if the processor is not running */ | |
b1526421 | 342 | if (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) { |
2d1a1b05 | 343 | u32 fw_entry_addr; |
1c1e45d1 | 344 | int sz = load_apu_fw_direct("v4l-cx23418-apu.fw", |
2d1a1b05 AW |
345 | cx->enc_mem, cx, &fw_entry_addr); |
346 | ||
347 | /* Clear bit0 for APU to start from 0 */ | |
348 | cx18_write_reg(cx, cx18_read_reg(cx, 0xc72030) & ~1, 0xc72030); | |
349 | ||
350 | cx18_write_enc(cx, 0xE51FF004, 0); /* ldr pc, [pc, #-4] */ | |
351 | cx18_write_enc(cx, fw_entry_addr, 4); | |
1c1e45d1 | 352 | |
b1526421 | 353 | /* Start APU */ |
ced07371 AW |
354 | cx18_write_reg_expect(cx, 0x00010000, CX18_PROC_SOFT_RESET, |
355 | 0x00000000, 0x00010001); | |
f24648e4 HV |
356 | cx18_msleep_timeout(500, 0); |
357 | ||
1c1e45d1 | 358 | sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw", |
82fc52a8 | 359 | cx->enc_mem, cx); |
1c1e45d1 HV |
360 | |
361 | if (sz > 0) { | |
362 | int retries = 0; | |
363 | ||
364 | /* start the CPU */ | |
ced07371 AW |
365 | cx18_write_reg_expect(cx, |
366 | 0x00080000, CX18_PROC_SOFT_RESET, | |
367 | 0x00000000, 0x00080008); | |
1c1e45d1 | 368 | while (retries++ < 50) { /* Loop for max 500mS */ |
b1526421 AW |
369 | if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET) |
370 | & 1) == 0) | |
1c1e45d1 HV |
371 | break; |
372 | cx18_msleep_timeout(10, 0); | |
373 | } | |
374 | cx18_msleep_timeout(200, 0); | |
375 | if (retries == 51) { | |
376 | CX18_ERR("Could not start the CPU\n"); | |
377 | return -EIO; | |
378 | } | |
379 | } | |
380 | if (sz <= 0) | |
381 | return -EIO; | |
382 | } | |
d20ceecd AW |
383 | |
384 | /* | |
385 | * The CPU firmware apparently sets up to receive an interrupt for it's | |
386 | * outgoing IRQ_CPU_TO_EPU_ACK to us (*boggle*). We get an interrupt | |
387 | * when it sends us an ack, but by the time we process it, that flag in | |
388 | * the SW2 status register has been cleared by the CPU firmware. | |
389 | * We'll prevent that not so useful behavior by clearing the CPU's | |
390 | * interrupt enables for Ack IRQ's we want to process. | |
391 | */ | |
392 | cx18_sw2_irq_disable_cpu(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); | |
393 | ||
1c1e45d1 | 394 | /* initialize GPIO */ |
ced07371 | 395 | cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400); |
1c1e45d1 HV |
396 | return 0; |
397 | } |