diff options
author | Timur Tabi <timur@freescale.com> | 2011-12-02 18:03:27 -0500 |
---|---|---|
committer | Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | 2011-12-19 15:03:53 -0500 |
commit | ddd3d905436b572ebadc09dcf2d12ca5b37020a0 (patch) | |
tree | fe4a7c33c2184d2f4bd1a31b25f57825498d9e42 /drivers/video/fsl-diu-fb.c | |
parent | 2d9ae7ac48c91e15e693038bf0dff004f7872aaf (diff) |
drivers/video: fsl-diu-fb: merge all allocated data into one block
The Freescale DIU driver allocates multiple blocks of memory, including
multiple DMA buffers. Merge all of these blocks into one data structure.
Specifically:
1) struct fsl_diu_data now contains everything that needs to be allocated,
except for the framebuffers themselves. DMA'able objects are aligned correctly
within the structure.
2) struct diu_addr is no longer needed, because we don't have to manage
multiple blocks of DMA memory.
3) Since there's no diu_addr any more, macro DMA_ADDR is used to calculate
the DMA address of any field in fsl_diu_data.
4) Functions allocate_buf() and free_buf() are no longer needed, because we
now assume that dma_alloc_coherent() will allocate a page-aligned block,
and everything is properly aligned with fsl_diu_data already, so we no longer
need to align any memory blocks ourselves.
5) The "dummy" area descriptor is now defined separately from the other
five ADs, so NUM_AOIS (previously called FSL_AOI_NUM) is now set to five
instead of six. Previously, all six were combined together to avoid a
separate call to allocate_buf() just for the dummy AD.
6) framebuffer_alloc() and framebuffer_release() are no longer used. The
framebuffer is initialized manually.
7) Error handling is simplified since there's only one memory buffer
allocated.
Signed-off-by: Timur Tabi <timur@freescale.com>
Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Diffstat (limited to 'drivers/video/fsl-diu-fb.c')
-rw-r--r-- | drivers/video/fsl-diu-fb.c | 326 |
1 files changed, 139 insertions, 187 deletions
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index a16beeb5f548..4d54188daa24 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c | |||
@@ -36,8 +36,7 @@ | |||
36 | #include <linux/fsl-diu-fb.h> | 36 | #include <linux/fsl-diu-fb.h> |
37 | #include "edid.h" | 37 | #include "edid.h" |
38 | 38 | ||
39 | #define FSL_AOI_NUM 6 /* 5 AOIs and one dummy AOI */ | 39 | #define NUM_AOIS 5 /* 1 for plane 0, 2 for planes 1 & 2 each */ |
40 | /* 1 for plane 0, 2 for plane 1&2 each */ | ||
41 | 40 | ||
42 | /* HW cursor parameters */ | 41 | /* HW cursor parameters */ |
43 | #define MAX_CURS 32 | 42 | #define MAX_CURS 32 |
@@ -49,12 +48,6 @@ | |||
49 | #define INT_PARERR 0x08 /* Display parameters error interrupt */ | 48 | #define INT_PARERR 0x08 /* Display parameters error interrupt */ |
50 | #define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */ | 49 | #define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */ |
51 | 50 | ||
52 | struct diu_addr { | ||
53 | void *vaddr; /* Virtual address */ | ||
54 | dma_addr_t paddr; /* Physical address */ | ||
55 | __u32 offset; | ||
56 | }; | ||
57 | |||
58 | /* | 51 | /* |
59 | * List of supported video modes | 52 | * List of supported video modes |
60 | * | 53 | * |
@@ -330,23 +323,6 @@ static unsigned int d_cache_line_size; | |||
330 | 323 | ||
331 | static DEFINE_SPINLOCK(diu_lock); | 324 | static DEFINE_SPINLOCK(diu_lock); |
332 | 325 | ||
333 | struct fsl_diu_data { | ||
334 | struct fb_info *fsl_diu_info[FSL_AOI_NUM - 1]; | ||
335 | /*FSL_AOI_NUM has one dummy AOI */ | ||
336 | struct device_attribute dev_attr; | ||
337 | struct diu_ad *dummy_ad; | ||
338 | void *dummy_aoi_virt; | ||
339 | unsigned int irq; | ||
340 | int fb_enabled; | ||
341 | enum fsl_diu_monitor_port monitor_port; | ||
342 | struct diu __iomem *diu_reg; | ||
343 | spinlock_t reg_lock; | ||
344 | struct diu_addr ad; | ||
345 | struct diu_addr gamma; | ||
346 | struct diu_addr pallete; | ||
347 | struct diu_addr cursor; | ||
348 | }; | ||
349 | |||
350 | enum mfb_index { | 326 | enum mfb_index { |
351 | PLANE0 = 0, /* Plane 0, only one AOI that fills the screen */ | 327 | PLANE0 = 0, /* Plane 0, only one AOI that fills the screen */ |
352 | PLANE1_AOI0, /* Plane 1, first AOI */ | 328 | PLANE1_AOI0, /* Plane 1, first AOI */ |
@@ -370,6 +346,44 @@ struct mfb_info { | |||
370 | u8 *edid_data; | 346 | u8 *edid_data; |
371 | }; | 347 | }; |
372 | 348 | ||
349 | /** | ||
350 | * struct fsl_diu_data - per-DIU data structure | ||
351 | * @dma_addr: DMA address of this structure | ||
352 | * @fsl_diu_info: fb_info objects, one per AOI | ||
353 | * @dev_attr: sysfs structure | ||
354 | * @irq: IRQ | ||
355 | * @fb_enabled: TRUE if the DIU is enabled, FALSE if not | ||
356 | * @monitor_port: the monitor port this DIU is connected to | ||
357 | * @diu_reg: pointer to the DIU hardware registers | ||
358 | * @reg_lock: spinlock for register access | ||
359 | * @dummy_aoi: video buffer for the 4x4 32-bit dummy AOI | ||
360 | * dummy_ad: DIU Area Descriptor for the dummy AOI | ||
361 | * @ad[]: Area Descriptors for each real AOI | ||
362 | * @gamma: gamma color table | ||
363 | * @cursor: hardware cursor data | ||
364 | * | ||
365 | * This data structure must be allocated with 32-byte alignment, so that the | ||
366 | * internal fields can be aligned properly. | ||
367 | */ | ||
368 | struct fsl_diu_data { | ||
369 | dma_addr_t dma_addr; | ||
370 | struct fb_info fsl_diu_info[NUM_AOIS]; | ||
371 | struct mfb_info mfb[NUM_AOIS]; | ||
372 | struct device_attribute dev_attr; | ||
373 | unsigned int irq; | ||
374 | int fb_enabled; | ||
375 | enum fsl_diu_monitor_port monitor_port; | ||
376 | struct diu __iomem *diu_reg; | ||
377 | spinlock_t reg_lock; | ||
378 | u8 dummy_aoi[4 * 4 * 4]; | ||
379 | struct diu_ad dummy_ad __aligned(8); | ||
380 | struct diu_ad ad[NUM_AOIS] __aligned(8); | ||
381 | u8 gamma[256 * 3] __aligned(32); | ||
382 | u8 cursor[MAX_CURS * MAX_CURS * 2] __aligned(32); | ||
383 | } __aligned(32); | ||
384 | |||
385 | /* Determine the DMA address of a member of the fsl_diu_data structure */ | ||
386 | #define DMA_ADDR(p, f) ((p)->dma_addr + offsetof(struct fsl_diu_data, f)) | ||
373 | 387 | ||
374 | static struct mfb_info mfb_template[] = { | 388 | static struct mfb_info mfb_template[] = { |
375 | { | 389 | { |
@@ -504,7 +518,7 @@ static void fsl_diu_enable_panel(struct fb_info *info) | |||
504 | wr_reg_wa(&hw->desc[0], ad->paddr); | 518 | wr_reg_wa(&hw->desc[0], ad->paddr); |
505 | break; | 519 | break; |
506 | case PLANE1_AOI0: | 520 | case PLANE1_AOI0: |
507 | cmfbi = machine_data->fsl_diu_info[2]->par; | 521 | cmfbi = &machine_data->mfb[2]; |
508 | if (hw->desc[1] != ad->paddr) { /* AOI0 closed */ | 522 | if (hw->desc[1] != ad->paddr) { /* AOI0 closed */ |
509 | if (cmfbi->count > 0) /* AOI1 open */ | 523 | if (cmfbi->count > 0) /* AOI1 open */ |
510 | ad->next_ad = | 524 | ad->next_ad = |
@@ -515,7 +529,7 @@ static void fsl_diu_enable_panel(struct fb_info *info) | |||
515 | } | 529 | } |
516 | break; | 530 | break; |
517 | case PLANE2_AOI0: | 531 | case PLANE2_AOI0: |
518 | cmfbi = machine_data->fsl_diu_info[4]->par; | 532 | cmfbi = &machine_data->mfb[4]; |
519 | if (hw->desc[2] != ad->paddr) { /* AOI0 closed */ | 533 | if (hw->desc[2] != ad->paddr) { /* AOI0 closed */ |
520 | if (cmfbi->count > 0) /* AOI1 open */ | 534 | if (cmfbi->count > 0) /* AOI1 open */ |
521 | ad->next_ad = | 535 | ad->next_ad = |
@@ -526,17 +540,17 @@ static void fsl_diu_enable_panel(struct fb_info *info) | |||
526 | } | 540 | } |
527 | break; | 541 | break; |
528 | case PLANE1_AOI1: | 542 | case PLANE1_AOI1: |
529 | pmfbi = machine_data->fsl_diu_info[1]->par; | 543 | pmfbi = &machine_data->mfb[1]; |
530 | ad->next_ad = 0; | 544 | ad->next_ad = 0; |
531 | if (hw->desc[1] == machine_data->dummy_ad->paddr) | 545 | if (hw->desc[1] == machine_data->dummy_ad.paddr) |
532 | wr_reg_wa(&hw->desc[1], ad->paddr); | 546 | wr_reg_wa(&hw->desc[1], ad->paddr); |
533 | else /* AOI0 open */ | 547 | else /* AOI0 open */ |
534 | pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); | 548 | pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); |
535 | break; | 549 | break; |
536 | case PLANE2_AOI1: | 550 | case PLANE2_AOI1: |
537 | pmfbi = machine_data->fsl_diu_info[3]->par; | 551 | pmfbi = &machine_data->mfb[3]; |
538 | ad->next_ad = 0; | 552 | ad->next_ad = 0; |
539 | if (hw->desc[2] == machine_data->dummy_ad->paddr) | 553 | if (hw->desc[2] == machine_data->dummy_ad.paddr) |
540 | wr_reg_wa(&hw->desc[2], ad->paddr); | 554 | wr_reg_wa(&hw->desc[2], ad->paddr); |
541 | else /* AOI0 was open */ | 555 | else /* AOI0 was open */ |
542 | pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); | 556 | pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); |
@@ -553,47 +567,47 @@ static void fsl_diu_disable_panel(struct fb_info *info) | |||
553 | 567 | ||
554 | switch (mfbi->index) { | 568 | switch (mfbi->index) { |
555 | case PLANE0: | 569 | case PLANE0: |
556 | if (hw->desc[0] != machine_data->dummy_ad->paddr) | 570 | if (hw->desc[0] != machine_data->dummy_ad.paddr) |
557 | wr_reg_wa(&hw->desc[0], machine_data->dummy_ad->paddr); | 571 | wr_reg_wa(&hw->desc[0], machine_data->dummy_ad.paddr); |
558 | break; | 572 | break; |
559 | case PLANE1_AOI0: | 573 | case PLANE1_AOI0: |
560 | cmfbi = machine_data->fsl_diu_info[2]->par; | 574 | cmfbi = &machine_data->mfb[2]; |
561 | if (cmfbi->count > 0) /* AOI1 is open */ | 575 | if (cmfbi->count > 0) /* AOI1 is open */ |
562 | wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr); | 576 | wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr); |
563 | /* move AOI1 to the first */ | 577 | /* move AOI1 to the first */ |
564 | else /* AOI1 was closed */ | 578 | else /* AOI1 was closed */ |
565 | wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr); | 579 | wr_reg_wa(&hw->desc[1], machine_data->dummy_ad.paddr); |
566 | /* close AOI 0 */ | 580 | /* close AOI 0 */ |
567 | break; | 581 | break; |
568 | case PLANE2_AOI0: | 582 | case PLANE2_AOI0: |
569 | cmfbi = machine_data->fsl_diu_info[4]->par; | 583 | cmfbi = &machine_data->mfb[4]; |
570 | if (cmfbi->count > 0) /* AOI1 is open */ | 584 | if (cmfbi->count > 0) /* AOI1 is open */ |
571 | wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr); | 585 | wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr); |
572 | /* move AOI1 to the first */ | 586 | /* move AOI1 to the first */ |
573 | else /* AOI1 was closed */ | 587 | else /* AOI1 was closed */ |
574 | wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr); | 588 | wr_reg_wa(&hw->desc[2], machine_data->dummy_ad.paddr); |
575 | /* close AOI 0 */ | 589 | /* close AOI 0 */ |
576 | break; | 590 | break; |
577 | case PLANE1_AOI1: | 591 | case PLANE1_AOI1: |
578 | pmfbi = machine_data->fsl_diu_info[1]->par; | 592 | pmfbi = &machine_data->mfb[1]; |
579 | if (hw->desc[1] != ad->paddr) { | 593 | if (hw->desc[1] != ad->paddr) { |
580 | /* AOI1 is not the first in the chain */ | 594 | /* AOI1 is not the first in the chain */ |
581 | if (pmfbi->count > 0) | 595 | if (pmfbi->count > 0) |
582 | /* AOI0 is open, must be the first */ | 596 | /* AOI0 is open, must be the first */ |
583 | pmfbi->ad->next_ad = 0; | 597 | pmfbi->ad->next_ad = 0; |
584 | } else /* AOI1 is the first in the chain */ | 598 | } else /* AOI1 is the first in the chain */ |
585 | wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr); | 599 | wr_reg_wa(&hw->desc[1], machine_data->dummy_ad.paddr); |
586 | /* close AOI 1 */ | 600 | /* close AOI 1 */ |
587 | break; | 601 | break; |
588 | case PLANE2_AOI1: | 602 | case PLANE2_AOI1: |
589 | pmfbi = machine_data->fsl_diu_info[3]->par; | 603 | pmfbi = &machine_data->mfb[3]; |
590 | if (hw->desc[2] != ad->paddr) { | 604 | if (hw->desc[2] != ad->paddr) { |
591 | /* AOI1 is not the first in the chain */ | 605 | /* AOI1 is not the first in the chain */ |
592 | if (pmfbi->count > 0) | 606 | if (pmfbi->count > 0) |
593 | /* AOI0 is open, must be the first */ | 607 | /* AOI0 is open, must be the first */ |
594 | pmfbi->ad->next_ad = 0; | 608 | pmfbi->ad->next_ad = 0; |
595 | } else /* AOI1 is the first in the chain */ | 609 | } else /* AOI1 is the first in the chain */ |
596 | wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr); | 610 | wr_reg_wa(&hw->desc[2], machine_data->dummy_ad.paddr); |
597 | /* close AOI 1 */ | 611 | /* close AOI 1 */ |
598 | break; | 612 | break; |
599 | } | 613 | } |
@@ -633,8 +647,8 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var, | |||
633 | int lower_aoi_is_open, upper_aoi_is_open; | 647 | int lower_aoi_is_open, upper_aoi_is_open; |
634 | __u32 base_plane_width, base_plane_height, upper_aoi_height; | 648 | __u32 base_plane_width, base_plane_height, upper_aoi_height; |
635 | 649 | ||
636 | base_plane_width = machine_data->fsl_diu_info[0]->var.xres; | 650 | base_plane_width = machine_data->fsl_diu_info[0].var.xres; |
637 | base_plane_height = machine_data->fsl_diu_info[0]->var.yres; | 651 | base_plane_height = machine_data->fsl_diu_info[0].var.yres; |
638 | 652 | ||
639 | if (mfbi->x_aoi_d < 0) | 653 | if (mfbi->x_aoi_d < 0) |
640 | mfbi->x_aoi_d = 0; | 654 | mfbi->x_aoi_d = 0; |
@@ -649,7 +663,7 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var, | |||
649 | break; | 663 | break; |
650 | case PLANE1_AOI0: | 664 | case PLANE1_AOI0: |
651 | case PLANE2_AOI0: | 665 | case PLANE2_AOI0: |
652 | lower_aoi_mfbi = machine_data->fsl_diu_info[index+1]->par; | 666 | lower_aoi_mfbi = machine_data->fsl_diu_info[index+1].par; |
653 | lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0; | 667 | lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0; |
654 | if (var->xres > base_plane_width) | 668 | if (var->xres > base_plane_width) |
655 | var->xres = base_plane_width; | 669 | var->xres = base_plane_width; |
@@ -667,9 +681,9 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var, | |||
667 | break; | 681 | break; |
668 | case PLANE1_AOI1: | 682 | case PLANE1_AOI1: |
669 | case PLANE2_AOI1: | 683 | case PLANE2_AOI1: |
670 | upper_aoi_mfbi = machine_data->fsl_diu_info[index-1]->par; | 684 | upper_aoi_mfbi = machine_data->fsl_diu_info[index-1].par; |
671 | upper_aoi_height = | 685 | upper_aoi_height = |
672 | machine_data->fsl_diu_info[index-1]->var.yres; | 686 | machine_data->fsl_diu_info[index-1].var.yres; |
673 | upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height; | 687 | upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height; |
674 | upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0; | 688 | upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0; |
675 | if (var->xres > base_plane_width) | 689 | if (var->xres > base_plane_width) |
@@ -812,15 +826,15 @@ static void update_lcdc(struct fb_info *info) | |||
812 | struct fsl_diu_data *machine_data = mfbi->parent; | 826 | struct fsl_diu_data *machine_data = mfbi->parent; |
813 | struct diu __iomem *hw; | 827 | struct diu __iomem *hw; |
814 | int i, j; | 828 | int i, j; |
815 | char __iomem *cursor_base, *gamma_table_base; | 829 | u8 *gamma_table_base; |
816 | 830 | ||
817 | u32 temp; | 831 | u32 temp; |
818 | 832 | ||
819 | hw = machine_data->diu_reg; | 833 | hw = machine_data->diu_reg; |
820 | 834 | ||
821 | diu_ops.set_monitor_port(machine_data->monitor_port); | 835 | diu_ops.set_monitor_port(machine_data->monitor_port); |
822 | gamma_table_base = machine_data->gamma.vaddr; | 836 | gamma_table_base = machine_data->gamma; |
823 | cursor_base = machine_data->cursor.vaddr; | 837 | |
824 | /* Prep for DIU init - gamma table, cursor table */ | 838 | /* Prep for DIU init - gamma table, cursor table */ |
825 | 839 | ||
826 | for (i = 0; i <= 2; i++) | 840 | for (i = 0; i <= 2; i++) |
@@ -828,14 +842,14 @@ static void update_lcdc(struct fb_info *info) | |||
828 | *gamma_table_base++ = j; | 842 | *gamma_table_base++ = j; |
829 | 843 | ||
830 | diu_ops.set_gamma_table(machine_data->monitor_port, | 844 | diu_ops.set_gamma_table(machine_data->monitor_port, |
831 | machine_data->gamma.vaddr); | 845 | machine_data->gamma); |
832 | 846 | ||
833 | disable_lcdc(info); | 847 | disable_lcdc(info); |
834 | 848 | ||
835 | /* Program DIU registers */ | 849 | /* Program DIU registers */ |
836 | 850 | ||
837 | out_be32(&hw->gamma, machine_data->gamma.paddr); | 851 | out_be32(&hw->gamma, DMA_ADDR(machine_data, gamma)); |
838 | out_be32(&hw->cursor, machine_data->cursor.paddr); | 852 | out_be32(&hw->cursor, DMA_ADDR(machine_data, cursor)); |
839 | 853 | ||
840 | out_be32(&hw->bgnd, 0x007F7F7F); /* BGND */ | 854 | out_be32(&hw->bgnd, 0x007F7F7F); /* BGND */ |
841 | out_be32(&hw->bgnd_wb, 0); /* BGND_WB */ | 855 | out_be32(&hw->bgnd_wb, 0); /* BGND_WB */ |
@@ -1423,37 +1437,6 @@ static int fsl_diu_resume(struct platform_device *ofdev) | |||
1423 | #define fsl_diu_resume NULL | 1437 | #define fsl_diu_resume NULL |
1424 | #endif /* CONFIG_PM */ | 1438 | #endif /* CONFIG_PM */ |
1425 | 1439 | ||
1426 | /* Align to 64-bit(8-byte), 32-byte, etc. */ | ||
1427 | static int allocate_buf(struct device *dev, struct diu_addr *buf, u32 size, | ||
1428 | u32 bytes_align) | ||
1429 | { | ||
1430 | u32 offset; | ||
1431 | dma_addr_t mask; | ||
1432 | |||
1433 | buf->vaddr = | ||
1434 | dma_alloc_coherent(dev, size + bytes_align, &buf->paddr, | ||
1435 | GFP_DMA | __GFP_ZERO); | ||
1436 | if (!buf->vaddr) | ||
1437 | return -ENOMEM; | ||
1438 | |||
1439 | mask = bytes_align - 1; | ||
1440 | offset = buf->paddr & mask; | ||
1441 | if (offset) { | ||
1442 | buf->offset = bytes_align - offset; | ||
1443 | buf->paddr = buf->paddr + offset; | ||
1444 | } else | ||
1445 | buf->offset = 0; | ||
1446 | |||
1447 | return 0; | ||
1448 | } | ||
1449 | |||
1450 | static void free_buf(struct device *dev, struct diu_addr *buf, u32 size, | ||
1451 | u32 bytes_align) | ||
1452 | { | ||
1453 | dma_free_coherent(dev, size + bytes_align, buf->vaddr, | ||
1454 | buf->paddr - buf->offset); | ||
1455 | } | ||
1456 | |||
1457 | static ssize_t store_monitor(struct device *device, | 1440 | static ssize_t store_monitor(struct device *device, |
1458 | struct device_attribute *attr, const char *buf, size_t count) | 1441 | struct device_attribute *attr, const char *buf, size_t count) |
1459 | { | 1442 | { |
@@ -1468,11 +1451,10 @@ static ssize_t store_monitor(struct device *device, | |||
1468 | /* All AOIs need adjust pixel format | 1451 | /* All AOIs need adjust pixel format |
1469 | * fsl_diu_set_par only change the pixsel format here | 1452 | * fsl_diu_set_par only change the pixsel format here |
1470 | * unlikely to fail. */ | 1453 | * unlikely to fail. */ |
1471 | fsl_diu_set_par(machine_data->fsl_diu_info[0]); | 1454 | unsigned int i; |
1472 | fsl_diu_set_par(machine_data->fsl_diu_info[1]); | 1455 | |
1473 | fsl_diu_set_par(machine_data->fsl_diu_info[2]); | 1456 | for (i=0; i < NUM_AOIS; i++) |
1474 | fsl_diu_set_par(machine_data->fsl_diu_info[3]); | 1457 | fsl_diu_set_par(&machine_data->fsl_diu_info[i]); |
1475 | fsl_diu_set_par(machine_data->fsl_diu_info[4]); | ||
1476 | } | 1458 | } |
1477 | return count; | 1459 | return count; |
1478 | } | 1460 | } |
@@ -1499,28 +1481,52 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev) | |||
1499 | { | 1481 | { |
1500 | struct device_node *np = pdev->dev.of_node; | 1482 | struct device_node *np = pdev->dev.of_node; |
1501 | struct mfb_info *mfbi; | 1483 | struct mfb_info *mfbi; |
1502 | phys_addr_t dummy_ad_addr = 0; | ||
1503 | int ret, i, error = 0; | ||
1504 | struct fsl_diu_data *machine_data; | 1484 | struct fsl_diu_data *machine_data; |
1505 | int diu_mode; | 1485 | int diu_mode; |
1486 | dma_addr_t dma_addr; /* DMA addr of machine_data struct */ | ||
1487 | unsigned int i; | ||
1488 | int ret; | ||
1506 | 1489 | ||
1507 | machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL); | 1490 | machine_data = dma_alloc_coherent(&pdev->dev, |
1491 | sizeof(struct fsl_diu_data), &dma_addr, GFP_DMA | __GFP_ZERO); | ||
1508 | if (!machine_data) | 1492 | if (!machine_data) |
1509 | return -ENOMEM; | 1493 | return -ENOMEM; |
1494 | machine_data->dma_addr = dma_addr; | ||
1495 | |||
1496 | /* | ||
1497 | * dma_alloc_coherent() uses a page allocator, so the address is | ||
1498 | * always page-aligned. We need the memory to be 32-byte aligned, | ||
1499 | * so that's good. However, if one day the allocator changes, we | ||
1500 | * need to catch that. It's not worth the effort to handle unaligned | ||
1501 | * alloctions now because it's highly unlikely to ever be a problem. | ||
1502 | */ | ||
1503 | if ((unsigned long)machine_data & 31) { | ||
1504 | dev_err(&pdev->dev, "misaligned allocation"); | ||
1505 | ret = -ENOMEM; | ||
1506 | goto error; | ||
1507 | } | ||
1510 | 1508 | ||
1511 | spin_lock_init(&machine_data->reg_lock); | 1509 | spin_lock_init(&machine_data->reg_lock); |
1512 | 1510 | ||
1513 | for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { | 1511 | for (i = 0; i < NUM_AOIS; i++) { |
1514 | machine_data->fsl_diu_info[i] = | 1512 | struct fb_info *info = &machine_data->fsl_diu_info[i]; |
1515 | framebuffer_alloc(sizeof(struct mfb_info), &pdev->dev); | 1513 | |
1516 | if (!machine_data->fsl_diu_info[i]) { | 1514 | info->device = &pdev->dev; |
1517 | dev_err(&pdev->dev, "cannot allocate memory\n"); | 1515 | info->par = &machine_data->mfb[i]; |
1518 | ret = -ENOMEM; | 1516 | |
1519 | goto error2; | 1517 | /* |
1520 | } | 1518 | * We store the physical address of the AD in the reserved |
1521 | mfbi = machine_data->fsl_diu_info[i]->par; | 1519 | * 'paddr' field of the AD itself. |
1520 | */ | ||
1521 | machine_data->ad[i].paddr = DMA_ADDR(machine_data, ad[i]); | ||
1522 | |||
1523 | info->fix.smem_start = 0; | ||
1524 | |||
1525 | /* Initialize the AOI data structure */ | ||
1526 | mfbi = info->par; | ||
1522 | memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); | 1527 | memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); |
1523 | mfbi->parent = machine_data; | 1528 | mfbi->parent = machine_data; |
1529 | mfbi->ad = &machine_data->ad[i]; | ||
1524 | 1530 | ||
1525 | if (mfbi->index == PLANE0) { | 1531 | if (mfbi->index == PLANE0) { |
1526 | const u8 *prop; | 1532 | const u8 *prop; |
@@ -1538,7 +1544,7 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev) | |||
1538 | if (!machine_data->diu_reg) { | 1544 | if (!machine_data->diu_reg) { |
1539 | dev_err(&pdev->dev, "cannot map DIU registers\n"); | 1545 | dev_err(&pdev->dev, "cannot map DIU registers\n"); |
1540 | ret = -EFAULT; | 1546 | ret = -EFAULT; |
1541 | goto error2; | 1547 | goto error; |
1542 | } | 1548 | } |
1543 | 1549 | ||
1544 | diu_mode = in_be32(&machine_data->diu_reg->diu_mode); | 1550 | diu_mode = in_be32(&machine_data->diu_reg->diu_mode); |
@@ -1555,41 +1561,16 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev) | |||
1555 | } | 1561 | } |
1556 | machine_data->monitor_port = monitor_port; | 1562 | machine_data->monitor_port = monitor_port; |
1557 | 1563 | ||
1558 | /* Area descriptor memory pool aligns to 64-bit boundary */ | 1564 | /* Initialize the dummy Area Descriptor */ |
1559 | if (allocate_buf(&pdev->dev, &machine_data->ad, | 1565 | machine_data->dummy_ad.addr = |
1560 | sizeof(struct diu_ad) * FSL_AOI_NUM, 8)) | 1566 | cpu_to_le32(DMA_ADDR(machine_data, dummy_aoi)); |
1561 | return -ENOMEM; | 1567 | machine_data->dummy_ad.pix_fmt = 0x88882317; |
1562 | 1568 | machine_data->dummy_ad.src_size_g_alpha = cpu_to_le32((4 << 12) | 4); | |
1563 | /* Get memory for Gamma Table - 32-byte aligned memory */ | 1569 | machine_data->dummy_ad.aoi_size = cpu_to_le32((4 << 16) | 2); |
1564 | if (allocate_buf(&pdev->dev, &machine_data->gamma, 768, 32)) { | 1570 | machine_data->dummy_ad.offset_xyi = 0; |
1565 | ret = -ENOMEM; | 1571 | machine_data->dummy_ad.offset_xyd = 0; |
1566 | goto error; | 1572 | machine_data->dummy_ad.next_ad = 0; |
1567 | } | 1573 | machine_data->dummy_ad.paddr = DMA_ADDR(machine_data, dummy_ad); |
1568 | |||
1569 | /* For performance, cursor bitmap buffer aligns to 32-byte boundary */ | ||
1570 | if (allocate_buf(&pdev->dev, &machine_data->cursor, | ||
1571 | MAX_CURS * MAX_CURS * 2, 32)) { | ||
1572 | ret = -ENOMEM; | ||
1573 | goto error; | ||
1574 | } | ||
1575 | |||
1576 | i = ARRAY_SIZE(machine_data->fsl_diu_info); | ||
1577 | machine_data->dummy_ad = (struct diu_ad *)((u32)machine_data->ad.vaddr + | ||
1578 | machine_data->ad.offset) + i; | ||
1579 | machine_data->dummy_ad->paddr = machine_data->ad.paddr + | ||
1580 | i * sizeof(struct diu_ad); | ||
1581 | machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr); | ||
1582 | if (!machine_data->dummy_aoi_virt) { | ||
1583 | ret = -ENOMEM; | ||
1584 | goto error; | ||
1585 | } | ||
1586 | machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr); | ||
1587 | machine_data->dummy_ad->pix_fmt = 0x88882317; | ||
1588 | machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4); | ||
1589 | machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) | 2); | ||
1590 | machine_data->dummy_ad->offset_xyi = 0; | ||
1591 | machine_data->dummy_ad->offset_xyd = 0; | ||
1592 | machine_data->dummy_ad->next_ad = 0; | ||
1593 | 1574 | ||
1594 | /* | 1575 | /* |
1595 | * Let DIU display splash screen if it was pre-initialized | 1576 | * Let DIU display splash screen if it was pre-initialized |
@@ -1597,19 +1578,13 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev) | |||
1597 | */ | 1578 | */ |
1598 | if (diu_mode == MFB_MODE0) | 1579 | if (diu_mode == MFB_MODE0) |
1599 | out_be32(&machine_data->diu_reg->desc[0], | 1580 | out_be32(&machine_data->diu_reg->desc[0], |
1600 | machine_data->dummy_ad->paddr); | 1581 | machine_data->dummy_ad.paddr); |
1601 | 1582 | ||
1602 | out_be32(&machine_data->diu_reg->desc[1], machine_data->dummy_ad->paddr); | 1583 | out_be32(&machine_data->diu_reg->desc[1], machine_data->dummy_ad.paddr); |
1603 | out_be32(&machine_data->diu_reg->desc[2], machine_data->dummy_ad->paddr); | 1584 | out_be32(&machine_data->diu_reg->desc[2], machine_data->dummy_ad.paddr); |
1604 | 1585 | ||
1605 | for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { | 1586 | for (i = 0; i < NUM_AOIS; i++) { |
1606 | machine_data->fsl_diu_info[i]->fix.smem_start = 0; | 1587 | ret = install_fb(&machine_data->fsl_diu_info[i]); |
1607 | mfbi = machine_data->fsl_diu_info[i]->par; | ||
1608 | mfbi->ad = (struct diu_ad *)((u32)machine_data->ad.vaddr | ||
1609 | + machine_data->ad.offset) + i; | ||
1610 | mfbi->ad->paddr = | ||
1611 | machine_data->ad.paddr + i * sizeof(struct diu_ad); | ||
1612 | ret = install_fb(machine_data->fsl_diu_info[i]); | ||
1613 | if (ret) { | 1588 | if (ret) { |
1614 | dev_err(&pdev->dev, "could not register fb %d\n", i); | 1589 | dev_err(&pdev->dev, "could not register fb %d\n", i); |
1615 | goto error; | 1590 | goto error; |
@@ -1626,9 +1601,8 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev) | |||
1626 | machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR; | 1601 | machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR; |
1627 | machine_data->dev_attr.show = show_monitor; | 1602 | machine_data->dev_attr.show = show_monitor; |
1628 | machine_data->dev_attr.store = store_monitor; | 1603 | machine_data->dev_attr.store = store_monitor; |
1629 | error = device_create_file(machine_data->fsl_diu_info[0]->dev, | 1604 | ret = device_create_file(&pdev->dev, &machine_data->dev_attr); |
1630 | &machine_data->dev_attr); | 1605 | if (ret) { |
1631 | if (error) { | ||
1632 | dev_err(&pdev->dev, "could not create sysfs file %s\n", | 1606 | dev_err(&pdev->dev, "could not create sysfs file %s\n", |
1633 | machine_data->dev_attr.attr.name); | 1607 | machine_data->dev_attr.attr.name); |
1634 | } | 1608 | } |
@@ -1637,26 +1611,13 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev) | |||
1637 | return 0; | 1611 | return 0; |
1638 | 1612 | ||
1639 | error: | 1613 | error: |
1640 | for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) | 1614 | for (i = 0; i < NUM_AOIS; i++) |
1641 | uninstall_fb(machine_data->fsl_diu_info[i]); | 1615 | uninstall_fb(&machine_data->fsl_diu_info[i]); |
1642 | 1616 | ||
1643 | if (machine_data->ad.vaddr) | ||
1644 | free_buf(&pdev->dev, &machine_data->ad, | ||
1645 | sizeof(struct diu_ad) * FSL_AOI_NUM, 8); | ||
1646 | if (machine_data->gamma.vaddr) | ||
1647 | free_buf(&pdev->dev, &machine_data->gamma, 768, 32); | ||
1648 | if (machine_data->cursor.vaddr) | ||
1649 | free_buf(&pdev->dev, &machine_data->cursor, | ||
1650 | MAX_CURS * MAX_CURS * 2, 32); | ||
1651 | if (machine_data->dummy_aoi_virt) | ||
1652 | fsl_diu_free(machine_data->dummy_aoi_virt, 64); | ||
1653 | iounmap(machine_data->diu_reg); | 1617 | iounmap(machine_data->diu_reg); |
1654 | 1618 | ||
1655 | error2: | 1619 | dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data), |
1656 | for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) | 1620 | machine_data, machine_data->dma_addr); |
1657 | if (machine_data->fsl_diu_info[i]) | ||
1658 | framebuffer_release(machine_data->fsl_diu_info[i]); | ||
1659 | kfree(machine_data); | ||
1660 | 1621 | ||
1661 | return ret; | 1622 | return ret; |
1662 | } | 1623 | } |
@@ -1667,25 +1628,16 @@ static int fsl_diu_remove(struct platform_device *pdev) | |||
1667 | int i; | 1628 | int i; |
1668 | 1629 | ||
1669 | machine_data = dev_get_drvdata(&pdev->dev); | 1630 | machine_data = dev_get_drvdata(&pdev->dev); |
1670 | disable_lcdc(machine_data->fsl_diu_info[0]); | 1631 | disable_lcdc(&machine_data->fsl_diu_info[0]); |
1671 | free_irq_local(machine_data); | 1632 | free_irq_local(machine_data); |
1672 | for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) | 1633 | |
1673 | uninstall_fb(machine_data->fsl_diu_info[i]); | 1634 | for (i = 0; i < NUM_AOIS; i++) |
1674 | if (machine_data->ad.vaddr) | 1635 | uninstall_fb(&machine_data->fsl_diu_info[i]); |
1675 | free_buf(&pdev->dev, &machine_data->ad, | 1636 | |
1676 | sizeof(struct diu_ad) * FSL_AOI_NUM, 8); | ||
1677 | if (machine_data->gamma.vaddr) | ||
1678 | free_buf(&pdev->dev, &machine_data->gamma, 768, 32); | ||
1679 | if (machine_data->cursor.vaddr) | ||
1680 | free_buf(&pdev->dev, &machine_data->cursor, | ||
1681 | MAX_CURS * MAX_CURS * 2, 32); | ||
1682 | if (machine_data->dummy_aoi_virt) | ||
1683 | fsl_diu_free(machine_data->dummy_aoi_virt, 64); | ||
1684 | iounmap(machine_data->diu_reg); | 1637 | iounmap(machine_data->diu_reg); |
1685 | for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) | 1638 | |
1686 | if (machine_data->fsl_diu_info[i]) | 1639 | dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data), |
1687 | framebuffer_release(machine_data->fsl_diu_info[i]); | 1640 | machine_data, machine_data->dma_addr); |
1688 | kfree(machine_data); | ||
1689 | 1641 | ||
1690 | return 0; | 1642 | return 0; |
1691 | } | 1643 | } |