2 * DMM IOMMU driver support functions for TI OMAP processors.
4 * Author: Rob Clark <rob@ti.com>
5 * Andy Gross <andy.gross@ti.com>
7 * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation version 2.
13 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
14 * kind, whether express or implied; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 #include <linux/init.h>
19 #include <linux/module.h>
20 #include <linux/platform_device.h> /* platform_device() */
21 #include <linux/errno.h>
22 #include <linux/sched.h>
23 #include <linux/wait.h>
24 #include <linux/interrupt.h>
25 #include <linux/dma-mapping.h>
26 #include <linux/slab.h>
27 #include <linux/vmalloc.h>
28 #include <linux/delay.h>
30 #include <linux/time.h>
31 #include <linux/list.h>
32 #include <linux/semaphore.h>
34 #include "omap_dmm_tiler.h"
35 #include "omap_dmm_priv.h"
37 #define DMM_DRIVER_NAME "dmm"
39 /* mappings for associating views to luts */
40 static struct tcm
*containers
[TILFMT_NFORMATS
];
41 static struct dmm
*omap_dmm
;
44 #define GEOM(xshift, yshift, bytes_per_pixel) { \
47 .cpp = (bytes_per_pixel), \
48 .slot_w = 1 << (SLOT_WIDTH_BITS - (xshift)), \
49 .slot_h = 1 << (SLOT_HEIGHT_BITS - (yshift)), \
53 uint32_t x_shft
; /* unused X-bits (as part of bpp) */
54 uint32_t y_shft
; /* unused Y-bits (as part of bpp) */
55 uint32_t cpp
; /* bytes/chars per pixel */
56 uint32_t slot_w
; /* width of each slot (in pixels) */
57 uint32_t slot_h
; /* height of each slot (in pixels) */
58 } geom
[TILFMT_NFORMATS
] = {
59 [TILFMT_8BIT
] = GEOM(0, 0, 1),
60 [TILFMT_16BIT
] = GEOM(0, 1, 2),
61 [TILFMT_32BIT
] = GEOM(1, 1, 4),
62 [TILFMT_PAGE
] = GEOM(SLOT_WIDTH_BITS
, SLOT_HEIGHT_BITS
, 1),
66 /* lookup table for registers w/ per-engine instances */
67 static const uint32_t reg
[][4] = {
68 [PAT_STATUS
] = {DMM_PAT_STATUS__0
, DMM_PAT_STATUS__1
,
69 DMM_PAT_STATUS__2
, DMM_PAT_STATUS__3
},
70 [PAT_DESCR
] = {DMM_PAT_DESCR__0
, DMM_PAT_DESCR__1
,
71 DMM_PAT_DESCR__2
, DMM_PAT_DESCR__3
},
74 /* simple allocator to grab next 16 byte aligned memory from txn */
75 static void *alloc_dma(struct dmm_txn
*txn
, size_t sz
, dma_addr_t
*pa
)
78 struct refill_engine
*engine
= txn
->engine_handle
;
80 /* dmm programming requires 16 byte aligned addresses */
81 txn
->current_pa
= round_up(txn
->current_pa
, 16);
82 txn
->current_va
= (void *)round_up((long)txn
->current_va
, 16);
84 ptr
= txn
->current_va
;
85 *pa
= txn
->current_pa
;
87 txn
->current_pa
+= sz
;
88 txn
->current_va
+= sz
;
90 BUG_ON((txn
->current_va
- engine
->refill_va
) > REFILL_BUFFER_SIZE
);
95 /* check status and spin until wait_mask comes true */
96 static int wait_status(struct refill_engine
*engine
, uint32_t wait_mask
)
98 struct dmm
*dmm
= engine
->dmm
;
99 uint32_t r
= 0, err
, i
;
101 i
= DMM_FIXED_RETRY_COUNT
;
103 r
= readl(dmm
->base
+ reg
[PAT_STATUS
][engine
->id
]);
104 err
= r
& DMM_PATSTATUS_ERR
;
108 if ((r
& wait_mask
) == wait_mask
)
120 irqreturn_t
omap_dmm_irq_handler(int irq
, void *arg
)
122 struct dmm
*dmm
= arg
;
123 uint32_t status
= readl(dmm
->base
+ DMM_PAT_IRQSTATUS
);
127 writel(status
, dmm
->base
+ DMM_PAT_IRQSTATUS
);
129 for (i
= 0; i
< dmm
->num_engines
; i
++) {
130 if (status
& DMM_IRQSTAT_LST
)
131 wake_up_interruptible(&dmm
->engines
[i
].wait_for_refill
);
140 * Get a handle for a DMM transaction
142 static struct dmm_txn
*dmm_txn_init(struct dmm
*dmm
, struct tcm
*tcm
)
144 struct dmm_txn
*txn
= NULL
;
145 struct refill_engine
*engine
= NULL
;
147 down(&dmm
->engine_sem
);
149 /* grab an idle engine */
150 spin_lock(&dmm
->list_lock
);
151 if (!list_empty(&dmm
->idle_head
)) {
152 engine
= list_entry(dmm
->idle_head
.next
, struct refill_engine
,
154 list_del(&engine
->idle_node
);
156 spin_unlock(&dmm
->list_lock
);
162 txn
->engine_handle
= engine
;
163 txn
->last_pat
= NULL
;
164 txn
->current_va
= engine
->refill_va
;
165 txn
->current_pa
= engine
->refill_pa
;
171 * Add region to DMM transaction. If pages or pages[i] is NULL, then the
172 * corresponding slot is cleared (ie. dummy_pa is programmed)
174 static int dmm_txn_append(struct dmm_txn
*txn
, struct pat_area
*area
,
175 struct page
**pages
, uint32_t npages
, uint32_t roll
)
177 dma_addr_t pat_pa
= 0;
180 struct refill_engine
*engine
= txn
->engine_handle
;
181 int columns
= (1 + area
->x1
- area
->x0
);
182 int rows
= (1 + area
->y1
- area
->y0
);
183 int i
= columns
*rows
;
184 u32
*lut
= omap_dmm
->lut
+ (engine
->tcm
->lut_id
* omap_dmm
->lut_width
*
185 omap_dmm
->lut_height
) +
186 (area
->y0
* omap_dmm
->lut_width
) + area
->x0
;
188 pat
= alloc_dma(txn
, sizeof(struct pat
), &pat_pa
);
191 txn
->last_pat
->next_pa
= (uint32_t)pat_pa
;
194 pat
->ctrl
= (struct pat_ctrl
){
196 .lut_id
= engine
->tcm
->lut_id
,
199 data
= alloc_dma(txn
, 4*i
, &pat
->data_pa
);
205 data
[i
] = (pages
&& pages
[n
]) ?
206 page_to_phys(pages
[n
]) : engine
->dmm
->dummy_pa
;
209 /* fill in lut with new addresses */
210 for (i
= 0; i
< rows
; i
++, lut
+= omap_dmm
->lut_width
)
211 memcpy(lut
, &data
[i
*columns
], columns
* sizeof(u32
));
219 * Commit the DMM transaction.
221 static int dmm_txn_commit(struct dmm_txn
*txn
, bool wait
)
224 struct refill_engine
*engine
= txn
->engine_handle
;
225 struct dmm
*dmm
= engine
->dmm
;
227 if (!txn
->last_pat
) {
228 dev_err(engine
->dmm
->dev
, "need at least one txn\n");
233 txn
->last_pat
->next_pa
= 0;
235 /* write to PAT_DESCR to clear out any pending transaction */
236 writel(0x0, dmm
->base
+ reg
[PAT_DESCR
][engine
->id
]);
238 /* wait for engine ready: */
239 ret
= wait_status(engine
, DMM_PATSTATUS_READY
);
246 writel(engine
->refill_pa
,
247 dmm
->base
+ reg
[PAT_DESCR
][engine
->id
]);
250 if (wait_event_interruptible_timeout(engine
->wait_for_refill
,
251 wait_status(engine
, DMM_PATSTATUS_READY
) == 0,
252 msecs_to_jiffies(1)) <= 0) {
253 dev_err(dmm
->dev
, "timed out waiting for done\n");
259 spin_lock(&dmm
->list_lock
);
260 list_add(&engine
->idle_node
, &dmm
->idle_head
);
261 spin_unlock(&dmm
->list_lock
);
263 up(&omap_dmm
->engine_sem
);
270 static int fill(struct tcm_area
*area
, struct page
**pages
,
271 uint32_t npages
, uint32_t roll
, bool wait
)
274 struct tcm_area slice
, area_s
;
277 txn
= dmm_txn_init(omap_dmm
, area
->tcm
);
278 if (IS_ERR_OR_NULL(txn
))
281 tcm_for_each_slice(slice
, *area
, area_s
) {
282 struct pat_area p_area
= {
283 .x0
= slice
.p0
.x
, .y0
= slice
.p0
.y
,
284 .x1
= slice
.p1
.x
, .y1
= slice
.p1
.y
,
287 ret
= dmm_txn_append(txn
, &p_area
, pages
, npages
, roll
);
291 roll
+= tcm_sizeof(slice
);
294 ret
= dmm_txn_commit(txn
, wait
);
304 /* note: slots for which pages[i] == NULL are filled w/ dummy page
306 int tiler_pin(struct tiler_block
*block
, struct page
**pages
,
307 uint32_t npages
, uint32_t roll
, bool wait
)
311 ret
= fill(&block
->area
, pages
, npages
, roll
, wait
);
319 int tiler_unpin(struct tiler_block
*block
)
321 return fill(&block
->area
, NULL
, 0, 0, false);
327 struct tiler_block
*tiler_reserve_2d(enum tiler_fmt fmt
, uint16_t w
,
328 uint16_t h
, uint16_t align
)
330 struct tiler_block
*block
= kzalloc(sizeof(*block
), GFP_KERNEL
);
334 BUG_ON(!validfmt(fmt
));
336 /* convert width/height to slots */
337 w
= DIV_ROUND_UP(w
, geom
[fmt
].slot_w
);
338 h
= DIV_ROUND_UP(h
, geom
[fmt
].slot_h
);
340 /* convert alignment to slots */
341 min_align
= max(min_align
, (geom
[fmt
].slot_w
* geom
[fmt
].cpp
));
342 align
= ALIGN(align
, min_align
);
343 align
/= geom
[fmt
].slot_w
* geom
[fmt
].cpp
;
347 ret
= tcm_reserve_2d(containers
[fmt
], w
, h
, align
, &block
->area
);
350 return ERR_PTR(-ENOMEM
);
353 /* add to allocation list */
354 spin_lock(&omap_dmm
->list_lock
);
355 list_add(&block
->alloc_node
, &omap_dmm
->alloc_head
);
356 spin_unlock(&omap_dmm
->list_lock
);
361 struct tiler_block
*tiler_reserve_1d(size_t size
)
363 struct tiler_block
*block
= kzalloc(sizeof(*block
), GFP_KERNEL
);
364 int num_pages
= (size
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
369 block
->fmt
= TILFMT_PAGE
;
371 if (tcm_reserve_1d(containers
[TILFMT_PAGE
], num_pages
,
374 return ERR_PTR(-ENOMEM
);
377 spin_lock(&omap_dmm
->list_lock
);
378 list_add(&block
->alloc_node
, &omap_dmm
->alloc_head
);
379 spin_unlock(&omap_dmm
->list_lock
);
384 /* note: if you have pin'd pages, you should have already unpin'd first! */
385 int tiler_release(struct tiler_block
*block
)
387 int ret
= tcm_free(&block
->area
);
390 dev_err(omap_dmm
->dev
, "failed to release block\n");
392 spin_lock(&omap_dmm
->list_lock
);
393 list_del(&block
->alloc_node
);
394 spin_unlock(&omap_dmm
->list_lock
);
404 /* calculate the tiler space address of a pixel in a view orientation */
405 static u32
tiler_get_address(u32 orient
, enum tiler_fmt fmt
, u32 x
, u32 y
)
407 u32 x_bits
, y_bits
, tmp
, x_mask
, y_mask
, alignment
;
409 x_bits
= CONT_WIDTH_BITS
- geom
[fmt
].x_shft
;
410 y_bits
= CONT_HEIGHT_BITS
- geom
[fmt
].y_shft
;
411 alignment
= geom
[fmt
].x_shft
+ geom
[fmt
].y_shft
;
413 /* validate coordinate */
414 x_mask
= MASK(x_bits
);
415 y_mask
= MASK(y_bits
);
417 if (x
< 0 || x
> x_mask
|| y
< 0 || y
> y_mask
)
420 /* account for mirroring */
421 if (orient
& MASK_X_INVERT
)
423 if (orient
& MASK_Y_INVERT
)
426 /* get coordinate address */
427 if (orient
& MASK_XY_FLIP
)
428 tmp
= ((x
<< y_bits
) + y
);
430 tmp
= ((y
<< x_bits
) + x
);
432 return TIL_ADDR((tmp
<< alignment
), orient
, fmt
);
435 dma_addr_t
tiler_ssptr(struct tiler_block
*block
)
437 BUG_ON(!validfmt(block
->fmt
));
439 return TILVIEW_8BIT
+ tiler_get_address(0, block
->fmt
,
440 block
->area
.p0
.x
* geom
[block
->fmt
].slot_w
,
441 block
->area
.p0
.y
* geom
[block
->fmt
].slot_h
);
444 void tiler_align(enum tiler_fmt fmt
, uint16_t *w
, uint16_t *h
)
446 BUG_ON(!validfmt(fmt
));
447 *w
= round_up(*w
, geom
[fmt
].slot_w
);
448 *h
= round_up(*h
, geom
[fmt
].slot_h
);
451 uint32_t tiler_stride(enum tiler_fmt fmt
)
453 BUG_ON(!validfmt(fmt
));
455 return 1 << (CONT_WIDTH_BITS
+ geom
[fmt
].y_shft
);
458 size_t tiler_size(enum tiler_fmt fmt
, uint16_t w
, uint16_t h
)
460 tiler_align(fmt
, &w
, &h
);
461 return geom
[fmt
].cpp
* w
* h
;
464 size_t tiler_vsize(enum tiler_fmt fmt
, uint16_t w
, uint16_t h
)
466 BUG_ON(!validfmt(fmt
));
467 return round_up(geom
[fmt
].cpp
* w
, PAGE_SIZE
) * h
;
470 bool dmm_is_initialized(void)
472 return omap_dmm
? true : false;
475 static int omap_dmm_remove(struct platform_device
*dev
)
477 struct tiler_block
*block
, *_block
;
481 /* free all area regions */
482 spin_lock(&omap_dmm
->list_lock
);
483 list_for_each_entry_safe(block
, _block
, &omap_dmm
->alloc_head
,
485 list_del(&block
->alloc_node
);
488 spin_unlock(&omap_dmm
->list_lock
);
490 for (i
= 0; i
< omap_dmm
->num_lut
; i
++)
491 if (omap_dmm
->tcm
&& omap_dmm
->tcm
[i
])
492 omap_dmm
->tcm
[i
]->deinit(omap_dmm
->tcm
[i
]);
493 kfree(omap_dmm
->tcm
);
495 kfree(omap_dmm
->engines
);
496 if (omap_dmm
->refill_va
)
497 dma_free_coherent(omap_dmm
->dev
,
498 REFILL_BUFFER_SIZE
* omap_dmm
->num_engines
,
500 omap_dmm
->refill_pa
);
501 if (omap_dmm
->dummy_page
)
502 __free_page(omap_dmm
->dummy_page
);
504 vfree(omap_dmm
->lut
);
506 if (omap_dmm
->irq
!= -1)
507 free_irq(omap_dmm
->irq
, omap_dmm
);
509 iounmap(omap_dmm
->base
);
517 static int omap_dmm_probe(struct platform_device
*dev
)
519 int ret
= -EFAULT
, i
;
520 struct tcm_area area
= {0};
521 u32 hwinfo
, pat_geom
, lut_table_size
;
522 struct resource
*mem
;
524 omap_dmm
= kzalloc(sizeof(*omap_dmm
), GFP_KERNEL
);
526 dev_err(&dev
->dev
, "failed to allocate driver data section\n");
530 /* lookup hwmod data - base address and irq */
531 mem
= platform_get_resource(dev
, IORESOURCE_MEM
, 0);
533 dev_err(&dev
->dev
, "failed to get base address resource\n");
537 omap_dmm
->base
= ioremap(mem
->start
, SZ_2K
);
539 if (!omap_dmm
->base
) {
540 dev_err(&dev
->dev
, "failed to get dmm base address\n");
544 omap_dmm
->irq
= platform_get_irq(dev
, 0);
545 if (omap_dmm
->irq
< 0) {
546 dev_err(&dev
->dev
, "failed to get IRQ resource\n");
550 omap_dmm
->dev
= &dev
->dev
;
552 hwinfo
= readl(omap_dmm
->base
+ DMM_PAT_HWINFO
);
553 omap_dmm
->num_engines
= (hwinfo
>> 24) & 0x1F;
554 omap_dmm
->num_lut
= (hwinfo
>> 16) & 0x1F;
555 omap_dmm
->container_width
= 256;
556 omap_dmm
->container_height
= 128;
558 /* read out actual LUT width and height */
559 pat_geom
= readl(omap_dmm
->base
+ DMM_PAT_GEOMETRY
);
560 omap_dmm
->lut_width
= ((pat_geom
>> 16) & 0xF) << 5;
561 omap_dmm
->lut_height
= ((pat_geom
>> 24) & 0xF) << 5;
563 /* initialize DMM registers */
564 writel(0x88888888, omap_dmm
->base
+ DMM_PAT_VIEW__0
);
565 writel(0x88888888, omap_dmm
->base
+ DMM_PAT_VIEW__1
);
566 writel(0x80808080, omap_dmm
->base
+ DMM_PAT_VIEW_MAP__0
);
567 writel(0x80000000, omap_dmm
->base
+ DMM_PAT_VIEW_MAP_BASE
);
568 writel(0x88888888, omap_dmm
->base
+ DMM_TILER_OR__0
);
569 writel(0x88888888, omap_dmm
->base
+ DMM_TILER_OR__1
);
571 ret
= request_irq(omap_dmm
->irq
, omap_dmm_irq_handler
, IRQF_SHARED
,
572 "omap_dmm_irq_handler", omap_dmm
);
575 dev_err(&dev
->dev
, "couldn't register IRQ %d, error %d\n",
581 /* Enable all interrupts for each refill engine except
582 * ERR_LUT_MISS<n> (which is just advisory, and we don't care
583 * about because we want to be able to refill live scanout
584 * buffers for accelerated pan/scroll) and FILL_DSC<n> which
585 * we just generally don't care about.
587 writel(0x7e7e7e7e, omap_dmm
->base
+ DMM_PAT_IRQENABLE_SET
);
589 lut_table_size
= omap_dmm
->lut_width
* omap_dmm
->lut_height
*
592 omap_dmm
->lut
= vmalloc(lut_table_size
* sizeof(*omap_dmm
->lut
));
593 if (!omap_dmm
->lut
) {
594 dev_err(&dev
->dev
, "could not allocate lut table\n");
599 omap_dmm
->dummy_page
= alloc_page(GFP_KERNEL
| __GFP_DMA32
);
600 if (!omap_dmm
->dummy_page
) {
601 dev_err(&dev
->dev
, "could not allocate dummy page\n");
606 /* set dma mask for device */
607 /* NOTE: this is a workaround for the hwmod not initializing properly */
608 dev
->dev
.coherent_dma_mask
= DMA_BIT_MASK(32);
610 omap_dmm
->dummy_pa
= page_to_phys(omap_dmm
->dummy_page
);
612 /* alloc refill memory */
613 omap_dmm
->refill_va
= dma_alloc_coherent(&dev
->dev
,
614 REFILL_BUFFER_SIZE
* omap_dmm
->num_engines
,
615 &omap_dmm
->refill_pa
, GFP_KERNEL
);
616 if (!omap_dmm
->refill_va
) {
617 dev_err(&dev
->dev
, "could not allocate refill memory\n");
622 omap_dmm
->engines
= kzalloc(
623 omap_dmm
->num_engines
* sizeof(struct refill_engine
),
625 if (!omap_dmm
->engines
) {
626 dev_err(&dev
->dev
, "could not allocate engines\n");
631 sema_init(&omap_dmm
->engine_sem
, omap_dmm
->num_engines
);
632 INIT_LIST_HEAD(&omap_dmm
->idle_head
);
633 for (i
= 0; i
< omap_dmm
->num_engines
; i
++) {
634 omap_dmm
->engines
[i
].id
= i
;
635 omap_dmm
->engines
[i
].dmm
= omap_dmm
;
636 omap_dmm
->engines
[i
].refill_va
= omap_dmm
->refill_va
+
637 (REFILL_BUFFER_SIZE
* i
);
638 omap_dmm
->engines
[i
].refill_pa
= omap_dmm
->refill_pa
+
639 (REFILL_BUFFER_SIZE
* i
);
640 init_waitqueue_head(&omap_dmm
->engines
[i
].wait_for_refill
);
642 list_add(&omap_dmm
->engines
[i
].idle_node
, &omap_dmm
->idle_head
);
645 omap_dmm
->tcm
= kzalloc(omap_dmm
->num_lut
* sizeof(*omap_dmm
->tcm
),
647 if (!omap_dmm
->tcm
) {
648 dev_err(&dev
->dev
, "failed to allocate lut ptrs\n");
653 /* init containers */
654 for (i
= 0; i
< omap_dmm
->num_lut
; i
++) {
655 omap_dmm
->tcm
[i
] = sita_init(omap_dmm
->container_width
,
656 omap_dmm
->container_height
,
659 if (!omap_dmm
->tcm
[i
]) {
660 dev_err(&dev
->dev
, "failed to allocate container\n");
665 omap_dmm
->tcm
[i
]->lut_id
= i
;
668 /* assign access mode containers to applicable tcm container */
669 /* OMAP 4 has 1 container for all 4 views */
670 containers
[TILFMT_8BIT
] = omap_dmm
->tcm
[0];
671 containers
[TILFMT_16BIT
] = omap_dmm
->tcm
[0];
672 containers
[TILFMT_32BIT
] = omap_dmm
->tcm
[0];
673 containers
[TILFMT_PAGE
] = omap_dmm
->tcm
[0];
675 INIT_LIST_HEAD(&omap_dmm
->alloc_head
);
676 spin_lock_init(&omap_dmm
->list_lock
);
678 area
= (struct tcm_area
) {
681 .p1
.x
= omap_dmm
->container_width
- 1,
682 .p1
.y
= omap_dmm
->container_height
- 1,
685 for (i
= 0; i
< lut_table_size
; i
++)
686 omap_dmm
->lut
[i
] = omap_dmm
->dummy_pa
;
688 /* initialize all LUTs to dummy page entries */
689 for (i
= 0; i
< omap_dmm
->num_lut
; i
++) {
690 area
.tcm
= omap_dmm
->tcm
[i
];
691 if (fill(&area
, NULL
, 0, 0, true))
692 dev_err(omap_dmm
->dev
, "refill failed");
695 dev_info(omap_dmm
->dev
, "initialized all PAT entries\n");
700 omap_dmm_remove(dev
);
708 #ifdef CONFIG_DEBUG_FS
710 static const char *alphabet
= "abcdefghijklmnopqrstuvwxyz"
711 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
712 static const char *special
= ".,:;'\"`~!^-+";
714 static void fill_map(char **map
, int xdiv
, int ydiv
, struct tcm_area
*a
,
718 for (y
= a
->p0
.y
/ ydiv
; y
<= a
->p1
.y
/ ydiv
; y
++)
719 for (x
= a
->p0
.x
/ xdiv
; x
<= a
->p1
.x
/ xdiv
; x
++)
720 if (map
[y
][x
] == ' ' || ovw
)
724 static void fill_map_pt(char **map
, int xdiv
, int ydiv
, struct tcm_pt
*p
,
727 map
[p
->y
/ ydiv
][p
->x
/ xdiv
] = c
;
730 static char read_map_pt(char **map
, int xdiv
, int ydiv
, struct tcm_pt
*p
)
732 return map
[p
->y
/ ydiv
][p
->x
/ xdiv
];
735 static int map_width(int xdiv
, int x0
, int x1
)
737 return (x1
/ xdiv
) - (x0
/ xdiv
) + 1;
740 static void text_map(char **map
, int xdiv
, char *nice
, int yd
, int x0
, int x1
)
742 char *p
= map
[yd
] + (x0
/ xdiv
);
743 int w
= (map_width(xdiv
, x0
, x1
) - strlen(nice
)) / 2;
751 static void map_1d_info(char **map
, int xdiv
, int ydiv
, char *nice
,
754 sprintf(nice
, "%dK", tcm_sizeof(*a
) * 4);
755 if (a
->p0
.y
+ 1 < a
->p1
.y
) {
756 text_map(map
, xdiv
, nice
, (a
->p0
.y
+ a
->p1
.y
) / 2 / ydiv
, 0,
758 } else if (a
->p0
.y
< a
->p1
.y
) {
759 if (strlen(nice
) < map_width(xdiv
, a
->p0
.x
, 256 - 1))
760 text_map(map
, xdiv
, nice
, a
->p0
.y
/ ydiv
,
761 a
->p0
.x
+ xdiv
, 256 - 1);
762 else if (strlen(nice
) < map_width(xdiv
, 0, a
->p1
.x
))
763 text_map(map
, xdiv
, nice
, a
->p1
.y
/ ydiv
,
765 } else if (strlen(nice
) + 1 < map_width(xdiv
, a
->p0
.x
, a
->p1
.x
)) {
766 text_map(map
, xdiv
, nice
, a
->p0
.y
/ ydiv
, a
->p0
.x
, a
->p1
.x
);
770 static void map_2d_info(char **map
, int xdiv
, int ydiv
, char *nice
,
773 sprintf(nice
, "(%d*%d)", tcm_awidth(*a
), tcm_aheight(*a
));
774 if (strlen(nice
) + 1 < map_width(xdiv
, a
->p0
.x
, a
->p1
.x
))
775 text_map(map
, xdiv
, nice
, (a
->p0
.y
+ a
->p1
.y
) / 2 / ydiv
,
779 int tiler_map_show(struct seq_file
*s
, void *arg
)
781 int xdiv
= 2, ydiv
= 1;
782 char **map
= NULL
, *global_map
;
783 struct tiler_block
*block
;
784 struct tcm_area a
, p
;
786 const char *m2d
= alphabet
;
787 const char *a2d
= special
;
788 const char *m2dp
= m2d
, *a2dp
= a2d
;
795 /* early return if dmm/tiler device is not initialized */
799 h_adj
= omap_dmm
->lut_height
/ ydiv
;
800 w_adj
= omap_dmm
->lut_width
/ xdiv
;
802 map
= kzalloc(h_adj
* sizeof(*map
), GFP_KERNEL
);
803 global_map
= kzalloc((w_adj
+ 1) * h_adj
, GFP_KERNEL
);
805 if (!map
|| !global_map
)
808 memset(global_map
, ' ', (w_adj
+ 1) * h_adj
);
809 for (i
= 0; i
< omap_dmm
->lut_height
; i
++) {
810 map
[i
] = global_map
+ i
* (w_adj
+ 1);
813 spin_lock_irqsave(&omap_dmm
->list_lock
, flags
);
815 list_for_each_entry(block
, &omap_dmm
->alloc_head
, alloc_node
) {
816 if (block
->fmt
!= TILFMT_PAGE
) {
817 fill_map(map
, xdiv
, ydiv
, &block
->area
, *m2dp
, true);
822 map_2d_info(map
, xdiv
, ydiv
, nice
, &block
->area
);
824 bool start
= read_map_pt(map
, xdiv
, ydiv
,
827 bool end
= read_map_pt(map
, xdiv
, ydiv
, &block
->area
.p1
)
829 tcm_for_each_slice(a
, block
->area
, p
)
830 fill_map(map
, xdiv
, ydiv
, &a
, '=', true);
831 fill_map_pt(map
, xdiv
, ydiv
, &block
->area
.p0
,
833 fill_map_pt(map
, xdiv
, ydiv
, &block
->area
.p1
,
835 map_1d_info(map
, xdiv
, ydiv
, nice
, &block
->area
);
839 spin_unlock_irqrestore(&omap_dmm
->list_lock
, flags
);
842 seq_printf(s
, "BEGIN DMM TILER MAP\n");
843 for (i
= 0; i
< 128; i
++)
844 seq_printf(s
, "%03d:%s\n", i
, map
[i
]);
845 seq_printf(s
, "END TILER MAP\n");
847 dev_dbg(omap_dmm
->dev
, "BEGIN DMM TILER MAP\n");
848 for (i
= 0; i
< 128; i
++)
849 dev_dbg(omap_dmm
->dev
, "%03d:%s\n", i
, map
[i
]);
850 dev_dbg(omap_dmm
->dev
, "END TILER MAP\n");
861 struct platform_driver omap_dmm_driver
= {
862 .probe
= omap_dmm_probe
,
863 .remove
= omap_dmm_remove
,
865 .owner
= THIS_MODULE
,
866 .name
= DMM_DRIVER_NAME
,
870 MODULE_LICENSE("GPL v2");
871 MODULE_AUTHOR("Andy Gross <andy.gross@ti.com>");
872 MODULE_DESCRIPTION("OMAP DMM/Tiler Driver");
873 MODULE_ALIAS("platform:" DMM_DRIVER_NAME
);