1/* 2 * omap_vout_vrfb.c 3 * 4 * Copyright (C) 2010 Texas Instruments. 5 * 6 * This file is licensed under the terms of the GNU General Public License 7 * version 2. This program is licensed "as is" without any warranty of any 8 * kind, whether express or implied. 9 * 10 */ 11 12#include <linux/sched.h> 13#include <linux/platform_device.h> 14#include <linux/videodev2.h> 15 16#include <media/videobuf-dma-contig.h> 17#include <media/v4l2-device.h> 18 19#include <linux/omap-dma.h> 20#include <video/omapvrfb.h> 21 22#include "omap_voutdef.h" 23#include "omap_voutlib.h" 24#include "omap_vout_vrfb.h" 25 26#define OMAP_DMA_NO_DEVICE 0 27 28/* 29 * Function for allocating video buffers 30 */ 31static int omap_vout_allocate_vrfb_buffers(struct omap_vout_device *vout, 32 unsigned int *count, int startindex) 33{ 34 int i, j; 35 36 for (i = 0; i < *count; i++) { 37 if (!vout->smsshado_virt_addr[i]) { 38 vout->smsshado_virt_addr[i] = 39 omap_vout_alloc_buffer(vout->smsshado_size, 40 &vout->smsshado_phy_addr[i]); 41 } 42 if (!vout->smsshado_virt_addr[i] && startindex != -1) { 43 if (V4L2_MEMORY_MMAP == vout->memory && i >= startindex) 44 break; 45 } 46 if (!vout->smsshado_virt_addr[i]) { 47 for (j = 0; j < i; j++) { 48 omap_vout_free_buffer( 49 vout->smsshado_virt_addr[j], 50 vout->smsshado_size); 51 vout->smsshado_virt_addr[j] = 0; 52 vout->smsshado_phy_addr[j] = 0; 53 } 54 *count = 0; 55 return -ENOMEM; 56 } 57 memset((void *) vout->smsshado_virt_addr[i], 0, 58 vout->smsshado_size); 59 } 60 return 0; 61} 62 63/* 64 * Wakes up the application once the DMA transfer to VRFB space is completed. 65 */ 66static void omap_vout_vrfb_dma_tx_callback(int lch, u16 ch_status, void *data) 67{ 68 struct vid_vrfb_dma *t = (struct vid_vrfb_dma *) data; 69 70 t->tx_status = 1; 71 wake_up_interruptible(&t->wait); 72} 73 74/* 75 * Free VRFB buffers 76 */ 77void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) 78{ 79 int j; 80 81 for (j = 0; j < VRFB_NUM_BUFS; j++) { 82 omap_vout_free_buffer(vout->smsshado_virt_addr[j], 83 vout->smsshado_size); 84 vout->smsshado_virt_addr[j] = 0; 85 vout->smsshado_phy_addr[j] = 0; 86 } 87} 88 89int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, 90 bool static_vrfb_allocation) 91{ 92 int ret = 0, i, j; 93 struct omap_vout_device *vout; 94 struct video_device *vfd; 95 int image_width, image_height; 96 int vrfb_num_bufs = VRFB_NUM_BUFS; 97 struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); 98 struct omap2video_device *vid_dev = 99 container_of(v4l2_dev, struct omap2video_device, v4l2_dev); 100 101 vout = vid_dev->vouts[vid_num]; 102 vfd = vout->vfd; 103 104 for (i = 0; i < VRFB_NUM_BUFS; i++) { 105 if (omap_vrfb_request_ctx(&vout->vrfb_context[i])) { 106 dev_info(&pdev->dev, ": VRFB allocation failed\n"); 107 for (j = 0; j < i; j++) 108 omap_vrfb_release_ctx(&vout->vrfb_context[j]); 109 ret = -ENOMEM; 110 goto free_buffers; 111 } 112 } 113 114 /* Calculate VRFB memory size */ 115 /* allocate for worst case size */ 116 image_width = VID_MAX_WIDTH / TILE_SIZE; 117 if (VID_MAX_WIDTH % TILE_SIZE) 118 image_width++; 119 120 image_width = image_width * TILE_SIZE; 121 image_height = VID_MAX_HEIGHT / TILE_SIZE; 122 123 if (VID_MAX_HEIGHT % TILE_SIZE) 124 image_height++; 125 126 image_height = image_height * TILE_SIZE; 127 vout->smsshado_size = PAGE_ALIGN(image_width * image_height * 2 * 2); 128 129 /* 130 * Request and Initialize DMA, for DMA based VRFB transfer 131 */ 132 vout->vrfb_dma_tx.dev_id = OMAP_DMA_NO_DEVICE; 133 vout->vrfb_dma_tx.dma_ch = -1; 134 vout->vrfb_dma_tx.req_status = DMA_CHAN_ALLOTED; 135 ret = omap_request_dma(vout->vrfb_dma_tx.dev_id, "VRFB DMA TX", 136 omap_vout_vrfb_dma_tx_callback, 137 (void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch); 138 if (ret < 0) { 139 vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED; 140 dev_info(&pdev->dev, ": failed to allocate DMA Channel for" 141 " video%d\n", vfd->minor); 142 } 143 init_waitqueue_head(&vout->vrfb_dma_tx.wait); 144 145 /* statically allocated the VRFB buffer is done through 146 commands line aruments */ 147 if (static_vrfb_allocation) { 148 if (omap_vout_allocate_vrfb_buffers(vout, &vrfb_num_bufs, -1)) { 149 ret = -ENOMEM; 150 goto release_vrfb_ctx; 151 } 152 vout->vrfb_static_allocation = true; 153 } 154 return 0; 155 156release_vrfb_ctx: 157 for (j = 0; j < VRFB_NUM_BUFS; j++) 158 omap_vrfb_release_ctx(&vout->vrfb_context[j]); 159free_buffers: 160 omap_vout_free_buffers(vout); 161 162 return ret; 163} 164 165/* 166 * Release the VRFB context once the module exits 167 */ 168void omap_vout_release_vrfb(struct omap_vout_device *vout) 169{ 170 int i; 171 172 for (i = 0; i < VRFB_NUM_BUFS; i++) 173 omap_vrfb_release_ctx(&vout->vrfb_context[i]); 174 175 if (vout->vrfb_dma_tx.req_status == DMA_CHAN_ALLOTED) { 176 vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED; 177 omap_free_dma(vout->vrfb_dma_tx.dma_ch); 178 } 179} 180 181/* 182 * Allocate the buffers for the VRFB space. Data is copied from V4L2 183 * buffers to the VRFB buffers using the DMA engine. 184 */ 185int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, 186 unsigned int *count, unsigned int startindex) 187{ 188 int i; 189 bool yuv_mode; 190 191 if (!is_rotation_enabled(vout)) 192 return 0; 193 194 /* If rotation is enabled, allocate memory for VRFB space also */ 195 *count = *count > VRFB_NUM_BUFS ? VRFB_NUM_BUFS : *count; 196 197 /* Allocate the VRFB buffers only if the buffers are not 198 * allocated during init time. 199 */ 200 if (!vout->vrfb_static_allocation) 201 if (omap_vout_allocate_vrfb_buffers(vout, count, startindex)) 202 return -ENOMEM; 203 204 if (vout->dss_mode == OMAP_DSS_COLOR_YUV2 || 205 vout->dss_mode == OMAP_DSS_COLOR_UYVY) 206 yuv_mode = true; 207 else 208 yuv_mode = false; 209 210 for (i = 0; i < *count; i++) 211 omap_vrfb_setup(&vout->vrfb_context[i], 212 vout->smsshado_phy_addr[i], vout->pix.width, 213 vout->pix.height, vout->bpp, yuv_mode); 214 215 return 0; 216} 217 218int omap_vout_prepare_vrfb(struct omap_vout_device *vout, 219 struct videobuf_buffer *vb) 220{ 221 dma_addr_t dmabuf; 222 struct vid_vrfb_dma *tx; 223 enum dss_rotation rotation; 224 u32 dest_frame_index = 0, src_element_index = 0; 225 u32 dest_element_index = 0, src_frame_index = 0; 226 u32 elem_count = 0, frame_count = 0, pixsize = 2; 227 228 if (!is_rotation_enabled(vout)) 229 return 0; 230 231 dmabuf = vout->buf_phy_addr[vb->i]; 232 /* If rotation is enabled, copy input buffer into VRFB 233 * memory space using DMA. We are copying input buffer 234 * into VRFB memory space of desired angle and DSS will 235 * read image VRFB memory for 0 degree angle 236 */ 237 pixsize = vout->bpp * vout->vrfb_bpp; 238 /* 239 * DMA transfer in double index mode 240 */ 241 242 /* Frame index */ 243 dest_frame_index = ((MAX_PIXELS_PER_LINE * pixsize) - 244 (vout->pix.width * vout->bpp)) + 1; 245 246 /* Source and destination parameters */ 247 src_element_index = 0; 248 src_frame_index = 0; 249 dest_element_index = 1; 250 /* Number of elements per frame */ 251 elem_count = vout->pix.width * vout->bpp; 252 frame_count = vout->pix.height; 253 tx = &vout->vrfb_dma_tx; 254 tx->tx_status = 0; 255 omap_set_dma_transfer_params(tx->dma_ch, OMAP_DMA_DATA_TYPE_S32, 256 (elem_count / 4), frame_count, OMAP_DMA_SYNC_ELEMENT, 257 tx->dev_id, 0x0); 258 /* src_port required only for OMAP1 */ 259 omap_set_dma_src_params(tx->dma_ch, 0, OMAP_DMA_AMODE_POST_INC, 260 dmabuf, src_element_index, src_frame_index); 261 /*set dma source burst mode for VRFB */ 262 omap_set_dma_src_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16); 263 rotation = calc_rotation(vout); 264 265 /* dest_port required only for OMAP1 */ 266 omap_set_dma_dest_params(tx->dma_ch, 0, OMAP_DMA_AMODE_DOUBLE_IDX, 267 vout->vrfb_context[vb->i].paddr[0], dest_element_index, 268 dest_frame_index); 269 /*set dma dest burst mode for VRFB */ 270 omap_set_dma_dest_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16); 271 omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0); 272 273 omap_start_dma(tx->dma_ch); 274 wait_event_interruptible_timeout(tx->wait, tx->tx_status == 1, 275 VRFB_TX_TIMEOUT); 276 277 if (tx->tx_status == 0) { 278 omap_stop_dma(tx->dma_ch); 279 return -EINVAL; 280 } 281 /* Store buffers physical address into an array. Addresses 282 * from this array will be used to configure DSS */ 283 vout->queued_buf_addr[vb->i] = (u8 *) 284 vout->vrfb_context[vb->i].paddr[rotation]; 285 return 0; 286} 287 288/* 289 * Calculate the buffer offsets from which the streaming should 290 * start. This offset calculation is mainly required because of 291 * the VRFB 32 pixels alignment with rotation. 292 */ 293void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) 294{ 295 enum dss_rotation rotation; 296 bool mirroring = vout->mirror; 297 struct v4l2_rect *crop = &vout->crop; 298 struct v4l2_pix_format *pix = &vout->pix; 299 int *cropped_offset = &vout->cropped_offset; 300 int vr_ps = 1, ps = 2, temp_ps = 2; 301 int offset = 0, ctop = 0, cleft = 0, line_length = 0; 302 303 rotation = calc_rotation(vout); 304 305 if (V4L2_PIX_FMT_YUYV == pix->pixelformat || 306 V4L2_PIX_FMT_UYVY == pix->pixelformat) { 307 if (is_rotation_enabled(vout)) { 308 /* 309 * ps - Actual pixel size for YUYV/UYVY for 310 * VRFB/Mirroring is 4 bytes 311 * vr_ps - Virtually pixel size for YUYV/UYVY is 312 * 2 bytes 313 */ 314 ps = 4; 315 vr_ps = 2; 316 } else { 317 ps = 2; /* otherwise the pixel size is 2 byte */ 318 } 319 } else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) { 320 ps = 4; 321 } else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) { 322 ps = 3; 323 } 324 vout->ps = ps; 325 vout->vr_ps = vr_ps; 326 327 if (is_rotation_enabled(vout)) { 328 line_length = MAX_PIXELS_PER_LINE; 329 ctop = (pix->height - crop->height) - crop->top; 330 cleft = (pix->width - crop->width) - crop->left; 331 } else { 332 line_length = pix->width; 333 } 334 vout->line_length = line_length; 335 switch (rotation) { 336 case dss_rotation_90_degree: 337 offset = vout->vrfb_context[0].yoffset * 338 vout->vrfb_context[0].bytespp; 339 temp_ps = ps / vr_ps; 340 if (!mirroring) { 341 *cropped_offset = offset + line_length * 342 temp_ps * cleft + crop->top * temp_ps; 343 } else { 344 *cropped_offset = offset + line_length * temp_ps * 345 cleft + crop->top * temp_ps + (line_length * 346 ((crop->width / (vr_ps)) - 1) * ps); 347 } 348 break; 349 case dss_rotation_180_degree: 350 offset = ((MAX_PIXELS_PER_LINE * vout->vrfb_context[0].yoffset * 351 vout->vrfb_context[0].bytespp) + 352 (vout->vrfb_context[0].xoffset * 353 vout->vrfb_context[0].bytespp)); 354 if (!mirroring) { 355 *cropped_offset = offset + (line_length * ps * ctop) + 356 (cleft / vr_ps) * ps; 357 358 } else { 359 *cropped_offset = offset + (line_length * ps * ctop) + 360 (cleft / vr_ps) * ps + (line_length * 361 (crop->height - 1) * ps); 362 } 363 break; 364 case dss_rotation_270_degree: 365 offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].xoffset * 366 vout->vrfb_context[0].bytespp; 367 temp_ps = ps / vr_ps; 368 if (!mirroring) { 369 *cropped_offset = offset + line_length * 370 temp_ps * crop->left + ctop * ps; 371 } else { 372 *cropped_offset = offset + line_length * 373 temp_ps * crop->left + ctop * ps + 374 (line_length * ((crop->width / vr_ps) - 1) * 375 ps); 376 } 377 break; 378 case dss_rotation_0_degree: 379 if (!mirroring) { 380 *cropped_offset = (line_length * ps) * 381 crop->top + (crop->left / vr_ps) * ps; 382 } else { 383 *cropped_offset = (line_length * ps) * 384 crop->top + (crop->left / vr_ps) * ps + 385 (line_length * (crop->height - 1) * ps); 386 } 387 break; 388 default: 389 *cropped_offset = (line_length * ps * crop->top) / 390 vr_ps + (crop->left * ps) / vr_ps + 391 ((crop->width / vr_ps) - 1) * ps; 392 break; 393 } 394} 395