diff options
Diffstat (limited to 'drivers/media/video/cx18/cx18-firmware.c')
-rw-r--r-- | drivers/media/video/cx18/cx18-firmware.c | 54 |
1 files changed, 13 insertions, 41 deletions
diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c index 2d630d9f7496..78fadd2ada5d 100644 --- a/drivers/media/video/cx18/cx18-firmware.c +++ b/drivers/media/video/cx18/cx18-firmware.c | |||
@@ -86,10 +86,6 @@ | |||
86 | 86 | ||
87 | #define CX18_DSP0_INTERRUPT_MASK 0xd0004C | 87 | #define CX18_DSP0_INTERRUPT_MASK 0xd0004C |
88 | 88 | ||
89 | /* Encoder/decoder firmware sizes */ | ||
90 | #define CX18_FW_CPU_SIZE (158332) | ||
91 | #define CX18_FW_APU_SIZE (141200) | ||
92 | |||
93 | #define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */ | 89 | #define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */ |
94 | #define APU_ROM_SYNC2 0x72646548 /* "rdeH" */ | 90 | #define APU_ROM_SYNC2 0x72646548 /* "rdeH" */ |
95 | 91 | ||
@@ -100,35 +96,22 @@ struct cx18_apu_rom_seghdr { | |||
100 | u32 size; | 96 | u32 size; |
101 | }; | 97 | }; |
102 | 98 | ||
103 | static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx, long size) | 99 | static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx) |
104 | { | 100 | { |
105 | const struct firmware *fw = NULL; | 101 | const struct firmware *fw = NULL; |
106 | int retries = 3; | ||
107 | int i, j; | 102 | int i, j; |
103 | unsigned size; | ||
108 | u32 __iomem *dst = (u32 __iomem *)mem; | 104 | u32 __iomem *dst = (u32 __iomem *)mem; |
109 | const u32 *src; | 105 | const u32 *src; |
110 | 106 | ||
111 | retry: | 107 | if (request_firmware(&fw, fn, &cx->dev->dev)) { |
112 | if (!retries || request_firmware(&fw, fn, &cx->dev->dev)) { | 108 | CX18_ERR("Unable to open firmware %s\n", fn); |
113 | CX18_ERR("Unable to open firmware %s (must be %ld bytes)\n", | ||
114 | fn, size); | ||
115 | CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n"); | 109 | CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n"); |
116 | return -ENOMEM; | 110 | return -ENOMEM; |
117 | } | 111 | } |
118 | 112 | ||
119 | src = (const u32 *)fw->data; | 113 | src = (const u32 *)fw->data; |
120 | 114 | ||
121 | if (fw->size != size) { | ||
122 | /* Due to race conditions in firmware loading (esp. with | ||
123 | udev <0.95) the wrong file was sometimes loaded. So we check | ||
124 | filesizes to see if at least the right-sized file was | ||
125 | loaded. If not, then we retry. */ | ||
126 | CX18_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", | ||
127 | fn, size, fw->size); | ||
128 | release_firmware(fw); | ||
129 | retries--; | ||
130 | goto retry; | ||
131 | } | ||
132 | for (i = 0; i < fw->size; i += 4096) { | 115 | for (i = 0; i < fw->size; i += 4096) { |
133 | setup_page(i); | 116 | setup_page(i); |
134 | for (j = i; j < fw->size && j < i + 4096; j += 4) { | 117 | for (j = i; j < fw->size && j < i + 4096; j += 4) { |
@@ -145,15 +128,16 @@ retry: | |||
145 | } | 128 | } |
146 | if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) | 129 | if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) |
147 | CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size); | 130 | CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size); |
131 | size = fw->size; | ||
148 | release_firmware(fw); | 132 | release_firmware(fw); |
149 | return size; | 133 | return size; |
150 | } | 134 | } |
151 | 135 | ||
152 | static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, long size) | 136 | static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx) |
153 | { | 137 | { |
154 | const struct firmware *fw = NULL; | 138 | const struct firmware *fw = NULL; |
155 | int retries = 3; | ||
156 | int i, j; | 139 | int i, j; |
140 | unsigned size; | ||
157 | const u32 *src; | 141 | const u32 *src; |
158 | struct cx18_apu_rom_seghdr seghdr; | 142 | struct cx18_apu_rom_seghdr seghdr; |
159 | const u8 *vers; | 143 | const u8 *vers; |
@@ -161,10 +145,8 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, | |||
161 | u32 apu_version = 0; | 145 | u32 apu_version = 0; |
162 | int sz; | 146 | int sz; |
163 | 147 | ||
164 | retry: | 148 | if (request_firmware(&fw, fn, &cx->dev->dev)) { |
165 | if (!retries || request_firmware(&fw, fn, &cx->dev->dev)) { | 149 | CX18_ERR("unable to open firmware %s\n", fn); |
166 | CX18_ERR("unable to open firmware %s (must be %ld bytes)\n", | ||
167 | fn, size); | ||
168 | CX18_ERR("did you put the firmware in the hotplug firmware directory?\n"); | 150 | CX18_ERR("did you put the firmware in the hotplug firmware directory?\n"); |
169 | return -ENOMEM; | 151 | return -ENOMEM; |
170 | } | 152 | } |
@@ -173,19 +155,8 @@ retry: | |||
173 | vers = fw->data + sizeof(seghdr); | 155 | vers = fw->data + sizeof(seghdr); |
174 | sz = fw->size; | 156 | sz = fw->size; |
175 | 157 | ||
176 | if (fw->size != size) { | ||
177 | /* Due to race conditions in firmware loading (esp. with | ||
178 | udev <0.95) the wrong file was sometimes loaded. So we check | ||
179 | filesizes to see if at least the right-sized file was | ||
180 | loaded. If not, then we retry. */ | ||
181 | CX18_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", | ||
182 | fn, size, fw->size); | ||
183 | release_firmware(fw); | ||
184 | retries--; | ||
185 | goto retry; | ||
186 | } | ||
187 | apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32]; | 158 | apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32]; |
188 | while (offset + sizeof(seghdr) < size) { | 159 | while (offset + sizeof(seghdr) < fw->size) { |
189 | /* TODO: byteswapping */ | 160 | /* TODO: byteswapping */ |
190 | memcpy(&seghdr, src + offset / 4, sizeof(seghdr)); | 161 | memcpy(&seghdr, src + offset / 4, sizeof(seghdr)); |
191 | offset += sizeof(seghdr); | 162 | offset += sizeof(seghdr); |
@@ -215,6 +186,7 @@ retry: | |||
215 | if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) | 186 | if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) |
216 | CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n", | 187 | CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n", |
217 | fn, apu_version, fw->size); | 188 | fn, apu_version, fw->size); |
189 | size = fw->size; | ||
218 | release_firmware(fw); | 190 | release_firmware(fw); |
219 | /* Clear bit0 for APU to start from 0 */ | 191 | /* Clear bit0 for APU to start from 0 */ |
220 | write_reg(read_reg(0xc72030) & ~1, 0xc72030); | 192 | write_reg(read_reg(0xc72030) & ~1, 0xc72030); |
@@ -340,7 +312,7 @@ int cx18_firmware_init(struct cx18 *cx) | |||
340 | /* Only if the processor is not running */ | 312 | /* Only if the processor is not running */ |
341 | if (read_reg(CX18_PROC_SOFT_RESET) & 8) { | 313 | if (read_reg(CX18_PROC_SOFT_RESET) & 8) { |
342 | int sz = load_apu_fw_direct("v4l-cx23418-apu.fw", | 314 | int sz = load_apu_fw_direct("v4l-cx23418-apu.fw", |
343 | cx->enc_mem, cx, CX18_FW_APU_SIZE); | 315 | cx->enc_mem, cx); |
344 | 316 | ||
345 | write_enc(0xE51FF004, 0); | 317 | write_enc(0xE51FF004, 0); |
346 | write_enc(0xa00000, 4); /* todo: not hardcoded */ | 318 | write_enc(0xa00000, 4); /* todo: not hardcoded */ |
@@ -348,7 +320,7 @@ int cx18_firmware_init(struct cx18 *cx) | |||
348 | cx18_msleep_timeout(500, 0); | 320 | cx18_msleep_timeout(500, 0); |
349 | 321 | ||
350 | sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw", | 322 | sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw", |
351 | cx->enc_mem, cx, CX18_FW_CPU_SIZE); | 323 | cx->enc_mem, cx); |
352 | 324 | ||
353 | if (sz > 0) { | 325 | if (sz > 0) { |
354 | int retries = 0; | 326 | int retries = 0; |