2 * drivers/video/tegra/host/msenc/msenc.c
4 * Tegra MSENC Module Support
6 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
22 #include <linux/slab.h> /* for kzalloc */
23 #include <linux/firmware.h>
24 #include <linux/module.h>
25 #include <asm/byteorder.h> /* for parsing ucode image wrt endianness */
26 #include <linux/delay.h> /* for udelay */
27 #include <mach/iomap.h>
31 #include "bus_client.h"
32 #include "nvhost_acm.h"
33 #include "chip_support.h"
34 #include "nvhost_memmgr.h"
36 #define MSENC_IDLE_TIMEOUT_DEFAULT 10000 /* 10 milliseconds */
37 #define MSENC_IDLE_CHECK_PERIOD 10 /* 10 usec */
38 #define MSENC_FIRMWARE_NAME "nvhost_msenc02.fw"
40 #define get_msenc(ndev) ((struct msenc *)(ndev)->dev.platform_data)
41 #define set_msenc(ndev, f) ((ndev)->dev.platform_data = f)
43 static int msenc_dma_wait_idle(struct nvhost_device *dev, u32 *timeout)
46 *timeout = MSENC_IDLE_TIMEOUT_DEFAULT;
49 u32 check = min_t(u32, MSENC_IDLE_CHECK_PERIOD, *timeout);
50 u32 dmatrfcmd = nvhost_device_readl(dev, msenc_dmatrfcmd_r());
51 u32 idle_v = msenc_dmatrfcmd_idle_v(dmatrfcmd);
53 if (msenc_dmatrfcmd_idle_true_v() == idle_v)
56 udelay(MSENC_IDLE_CHECK_PERIOD);
60 dev_err(&dev->dev, "dma idle timeout");
65 static int msenc_dma_pa_to_internal_256b(struct nvhost_device *dev,
66 phys_addr_t pa, u32 internal_offset, bool imem)
68 u32 cmd = msenc_dmatrfcmd_size_256b_f();
69 u32 pa_offset = msenc_dmatrffboffs_offs_f(pa);
70 u32 i_offset = msenc_dmatrfmoffs_offs_f(internal_offset);
71 u32 timeout = 0; /* default*/
74 cmd |= msenc_dmatrfcmd_imem_true_f();
76 nvhost_device_writel(dev, msenc_dmatrfmoffs_r(), i_offset);
77 nvhost_device_writel(dev, msenc_dmatrffboffs_r(), pa_offset);
78 nvhost_device_writel(dev, msenc_dmatrfcmd_r(), cmd);
80 return msenc_dma_wait_idle(dev, &timeout);
84 static int msenc_wait_idle(struct nvhost_device *dev, u32 *timeout)
87 *timeout = MSENC_IDLE_TIMEOUT_DEFAULT;
90 u32 check = min_t(u32, MSENC_IDLE_CHECK_PERIOD, *timeout);
91 u32 w = nvhost_device_readl(dev, msenc_idlestate_r());
95 udelay(MSENC_IDLE_CHECK_PERIOD);
102 int msenc_boot(struct nvhost_device *dev)
107 struct msenc *m = get_msenc(dev);
109 nvhost_device_writel(dev, msenc_dmactl_r(), 0);
110 nvhost_device_writel(dev, msenc_dmatrfbase_r(),
111 (m->pa + m->os.bin_data_offset) >> 8);
113 for (offset = 0; offset < m->os.data_size; offset += 256)
114 msenc_dma_pa_to_internal_256b(dev,
115 m->os.data_offset + offset,
118 msenc_dma_pa_to_internal_256b(dev, m->os.code_offset, 0, true);
120 /* setup msenc interrupts and enable interface */
121 nvhost_device_writel(dev, msenc_irqmset_r(),
122 (msenc_irqmset_ext_f(0xff) |
123 msenc_irqmset_swgen1_set_f() |
124 msenc_irqmset_swgen0_set_f() |
125 msenc_irqmset_exterr_set_f() |
126 msenc_irqmset_halt_set_f() |
127 msenc_irqmset_wdtmr_set_f()));
128 nvhost_device_writel(dev, msenc_irqdest_r(),
129 (msenc_irqdest_host_ext_f(0xff) |
130 msenc_irqdest_host_swgen1_host_f() |
131 msenc_irqdest_host_swgen0_host_f() |
132 msenc_irqdest_host_exterr_host_f() |
133 msenc_irqdest_host_halt_host_f()));
134 nvhost_device_writel(dev, msenc_itfen_r(),
135 (msenc_itfen_mthden_enable_f() |
136 msenc_itfen_ctxen_enable_f()));
139 nvhost_device_writel(dev, msenc_bootvec_r(), msenc_bootvec_vec_f(0));
140 nvhost_device_writel(dev, msenc_cpuctl_r(),
141 msenc_cpuctl_startcpu_true_f());
143 timeout = 0; /* default */
145 err = msenc_wait_idle(dev, &timeout);
147 dev_err(&dev->dev, "boot failed due to timeout");
154 static int msenc_setup_ucode_image(struct nvhost_device *dev,
156 const struct firmware *ucode_fw)
158 struct msenc *m = get_msenc(dev);
159 /* image data is little endian. */
160 struct msenc_ucode_v1 ucode;
163 /* copy the whole thing taking into account endianness */
164 for (w = 0; w < ucode_fw->size / sizeof(u32); w++)
165 ucode_ptr[w] = le32_to_cpu(((u32 *)ucode_fw->data)[w]);
167 ucode.bin_header = (struct msenc_ucode_bin_header_v1 *)ucode_ptr;
168 /* endian problems would show up right here */
169 if (ucode.bin_header->bin_magic != 0x10de) {
171 "failed to get firmware magic");
174 if (ucode.bin_header->bin_ver != 1) {
176 "unsupported firmware version");
179 /* shouldn't be bigger than what firmware thinks */
180 if (ucode.bin_header->bin_size > ucode_fw->size) {
182 "ucode image size inconsistency");
187 "ucode bin header: magic:0x%x ver:%d size:%d",
188 ucode.bin_header->bin_magic,
189 ucode.bin_header->bin_ver,
190 ucode.bin_header->bin_size);
192 "ucode bin header: os bin (header,data) offset size: 0x%x, 0x%x %d",
193 ucode.bin_header->os_bin_header_offset,
194 ucode.bin_header->os_bin_data_offset,
195 ucode.bin_header->os_bin_size);
196 ucode.os_header = (struct msenc_ucode_os_header_v1 *)
197 (((void *)ucode_ptr) + ucode.bin_header->os_bin_header_offset);
200 "os ucode header: os code (offset,size): 0x%x, 0x%x",
201 ucode.os_header->os_code_offset,
202 ucode.os_header->os_code_size);
204 "os ucode header: os data (offset,size): 0x%x, 0x%x",
205 ucode.os_header->os_data_offset,
206 ucode.os_header->os_data_size);
208 "os ucode header: num apps: %d",
209 ucode.os_header->num_apps);
211 m->os.size = ucode.bin_header->os_bin_size;
212 m->os.bin_data_offset = ucode.bin_header->os_bin_data_offset;
213 m->os.code_offset = ucode.os_header->os_code_offset;
214 m->os.data_offset = ucode.os_header->os_data_offset;
215 m->os.data_size = ucode.os_header->os_data_size;
220 int msenc_read_ucode(struct nvhost_device *dev, const char *fw_name)
222 struct msenc *m = get_msenc(dev);
223 const struct firmware *ucode_fw;
227 err = request_firmware(&ucode_fw, fw_name, &dev->dev);
229 dev_err(&dev->dev, "failed to get msenc firmware\n");
233 /* allocate pages for ucode */
234 m->mem_r = mem_op().alloc(nvhost_get_host(dev)->memmgr,
235 roundup(ucode_fw->size, PAGE_SIZE),
236 PAGE_SIZE, mem_mgr_flag_uncacheable);
237 if (IS_ERR_OR_NULL(m->mem_r)) {
238 dev_err(&dev->dev, "nvmap alloc failed");
243 ucode_ptr = mem_op().mmap(m->mem_r);
245 dev_err(&dev->dev, "nvmap mmap failed");
250 err = msenc_setup_ucode_image(dev, ucode_ptr, ucode_fw);
252 dev_err(&dev->dev, "failed to parse firmware image\n");
258 mem_op().munmap(m->mem_r, ucode_ptr);
261 release_firmware(ucode_fw);
265 void nvhost_msenc_init(struct nvhost_device *dev)
270 m = kzalloc(sizeof(struct msenc), GFP_KERNEL);
272 dev_err(&dev->dev, "couldn't alloc ucode");
277 err = msenc_read_ucode(dev, MSENC_FIRMWARE_NAME);
279 if (err || !m->valid) {
281 dev_err(&dev->dev, "ucode not valid");
285 m->pa = mem_op().pin(nvhost_get_host(dev)->memmgr, m->mem_r);
286 if (m->pa == -EINVAL || m->pa == -EINTR) {
287 dev_err(&dev->dev, "nvmap pin failed for ucode");
293 nvhost_module_busy(dev);
295 nvhost_module_idle(dev);
299 dev_err(&dev->dev, "failed");
300 mem_op().unpin(nvhost_get_host(dev)->memmgr, m->mem_r);
303 void nvhost_msenc_deinit(struct nvhost_device *dev)
305 struct msenc *m = get_msenc(dev);
307 /* unpin, free ucode memory */
309 mem_op().unpin(nvhost_get_host(dev)->memmgr, m->mem_r);
310 mem_op().put(nvhost_get_host(dev)->memmgr, m->mem_r);
315 void nvhost_msenc_finalize_poweron(struct nvhost_device *dev)
320 static int __devinit msenc_probe(struct nvhost_device *dev,
321 struct nvhost_device_id *id_table)
324 struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
326 drv->init = nvhost_msenc_init;
327 drv->deinit = nvhost_msenc_deinit;
329 err = nvhost_client_device_get_resources(dev);
333 return nvhost_client_device_init(dev);
336 static int __exit msenc_remove(struct nvhost_device *dev)
343 static int msenc_suspend(struct nvhost_device *dev, pm_message_t state)
345 return nvhost_client_device_suspend(dev);
348 static int msenc_resume(struct nvhost_device *dev)
350 dev_info(&dev->dev, "resuming\n");
355 static struct resource msenc_resources = {
357 .start = TEGRA_MSENC_BASE,
358 .end = TEGRA_MSENC_BASE + TEGRA_MSENC_SIZE - 1,
359 .flags = IORESOURCE_MEM,
362 struct nvhost_device *msenc_device;
364 static struct nvhost_driver msenc_driver = {
365 .probe = msenc_probe,
366 .remove = __exit_p(msenc_remove),
368 .suspend = msenc_suspend,
369 .resume = msenc_resume,
372 .owner = THIS_MODULE,
377 static int __init msenc_init(void)
381 msenc_device = nvhost_get_device("msenc");
385 msenc_device->resource = &msenc_resources;
386 msenc_device->num_resources = 1;
388 err = nvhost_device_register(msenc_device);
392 return nvhost_driver_register(&msenc_driver);
395 static void __exit msenc_exit(void)
397 nvhost_driver_unregister(&msenc_driver);
400 module_init(msenc_init);
401 module_exit(msenc_exit);