Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* Re: [BUG] radeon: suspend resume
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-07-14 20:13 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <CAG27Bk2NzdZELTeByjH5Sj_NbB+TOhYDK66aX1-9e=W_LT39Hg@mail.gmail.com>


On Jul 14, 2013, at 8:26 PM, Sami Kerola <kerolasa@iki.fi> wrote:

> Hello,
> 
> I build from Linus's tree from point
> 
> commit 9903883f1dd6e86f286b7bfa6e4b423f98c1cd9e
> 
> a kernel which has a power management suspend/resume problem.  In short I
> do not get video back at resume, and my laptop becomes completely
> unresponsive.  I have hunch the NO_HZ has something to do with issue.

You will have to bisect and found the commit that introduce the bug

as commit 9903883f1dd6e86

    Merge tag 'dm-3.11-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-dm

    Pull device-mapper changes from Alasdair G Kergon:
     "Add a device-mapper target called dm-switch to provide a multipath
      framework for storage arrays that dynamically reconfigure their
      preferred paths for different device regions.

      Fix a bug in the verity target that prevented its use with some
      specific sizes of devices.

      Improve some locking mechanisms in the device-mapper core and bufio.

      Add Mike Snitzer as a device-mapper maintainer.

      A few more clean-ups and fixes"

is a merge about device-mapper not fbdev and even Radeon drivers

Best Regards,
J.

> 
> # zgrep ^CONFIG_NO_HZ /proc/config.gz
> CONFIG_NO_HZ_COMMON=y
> CONFIG_NO_HZ_FULL=y
> CONFIG_NO_HZ=y
> 
> The NO_HZ combined with this piece of hardware results seems to be the
> issue.
> 
> 00:01.0 VGA compatible controller: Advanced Micro Devices, Inc.
> [AMD/ATI] Wrestler [Radeon HD 7310] (prog-if 00 [VGA controller])
>        Subsystem: Toshiba America Info Systems Device fb33
>        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
> ParErr- Stepping- SERR- FastB2B- DisINTx+
>        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSELúst >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
>        Latency: 0, Cache Line Size: 64 bytes
>        Interrupt: pin A routed to IRQ 49
>        Region 0: Memory at e0000000 (32-bit, prefetchable) [size%6M]
>        Region 1: I/O ports at 5000 [size%6]
>        Region 2: Memory at f0400000 (32-bit, non-prefetchable) [size%6K]
>        Expansion ROM at <unassigned> [disabled]
>        Capabilities: [50] Power Management version 3
>                Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA
> PME(D0-,D1-,D2-,D3hot-,D3cold-)
>                Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
>        Capabilities: [58] Express (v2) Root Complex Integrated Endpoint, MSI 00
>                DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s
> <4us, L1 unlimited
>                        ExtTag+ RBE+ FLReset-
>                DevCtl: Report errors: Correctable- Non-Fatal- Fatal-
> Unsupported-
>                        RlxdOrd+ ExtTag- PhantFunc- AuxPwr- NoSnoop+
>                        MaxPayload 128 bytes, MaxReadReq 128 bytes
>                DevSta: CorrErr- UncorrErr+ FatalErr- UnsuppReq+
> AuxPwr- TransPend-
>                LnkCap: Port #0, Speed unknown, Width x0, ASPM
> unknown, Latency L0 <64ns, L1 <1us
>                        ClockPM- Surprise- LLActRep- BwNot-
>                LnkCtl: ASPM Disabled; Disabled- Retrain- CommClk-
>                        ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
>                LnkSta: Speed unknown, Width x0, TrErr- Train-
> SlotClk- DLActive- BWMgmt- ABWMgmt-
>                DevCap2: Completion Timeout: Not Supported,
> TimeoutDis-, LTR-, OBFF Not Supported
>                DevCtl2: Completion Timeout: 50us to 50ms,
> TimeoutDis-, LTR-, OBFF Disabled
>                LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance- SpeedDis-
>                         Transmit Margin: Normal Operating Range,
> EnterModifiedCompliance- ComplianceSOS-
>                         Compliance De-emphasis: -6dB
>                LnkSta2: Current De-emphasis Level: -6dB,
> EqualizationComplete-, EqualizationPhase1-
>                         EqualizationPhase2-, EqualizationPhase3-,
> LinkEqualizationRequest-
>        Capabilities: [a0] MSI: Enable+ Count=1/1 Maskable- 64bit+
>                Address: 00000000fee0300c  Data: 4152
>        Capabilities: [100 v1] Vendor Specific Information: ID\001
> Rev=1 Len\x010 <?>
>        Kernel driver in use: radeon
>        Kernel modules: radeon
> 
> 
> Here are some message from journalctl from the time suspend begun, and
> resume failed.  To me the two lines with '*ERROR* radeon' does not look
> right.  The messages are result of 'echo devices > /sys/power/pm_test'.
> 
> 
> Jul 14 12:51:12 kerolasa-home kernel: PM: Hibernation mode set to 'platform'
> Jul 14 12:51:12 kerolasa-home kernel: kobject: 'vcs63'
> (ffff8800d2c09010): kobject_add_internal: parent: 'vc', set: 'devices'
> Jul 14 12:51:12 kerolasa-home kernel: kobject: 'vcs63'
> (ffff8800d2c09010): kobject_uevent_env
> Jul 14 12:51:12 kerolasa-home kernel: kobject: 'vcs63'
> (ffff8800d2c09010): fill_kobj_path: path = '/devices/virtual/vc/vcs63'
> Jul 14 12:51:12 kerolasa-home kernel: kobject: 'vcsa63'
> (ffff8800d2c08010): kobject_add_internal: parent: 'vc', set: 'devices'
> Jul 14 12:51:12 kerolasa-home kernel: kobject: 'vcsa63'
> (ffff8800d2c08010): kobject_uevent_env
> Jul 14 12:51:12 kerolasa-home kernel: kobject: 'vcsa63'
> (ffff8800d2c08010): fill_kobj_path: path > '/devices/virtual/vc/vcsa63'
> Jul 14 12:51:12 kerolasa-home kernel: PM: Marking nosave pages: [mem
> 0x0009f000-0x000fffff]
> Jul 14 12:51:12 kerolasa-home kernel: PM: Marking nosave pages: [mem
> 0xdf6bf000-0xdfbfefff]
> Jul 14 12:51:12 kerolasa-home kernel: PM: Marking nosave pages: [mem
> 0xdfc00000-0xffffffff]
> Jul 14 12:51:12 kerolasa-home kernel: PM: Basic memory bitmaps created
> Jul 14 12:51:31 kerolasa-home kernel: PM: Syncing filesystems ... done.
> Jul 14 12:51:31 kerolasa-home dhcpcd[451]: wlan0: carrier lost
> Jul 14 12:51:31 kerolasa-home dhcpcd[451]: wlan0: deleting host route
> to 192.168.1.2 via 127.0.0.1
> Jul 14 12:51:31 kerolasa-home dhcpcd[451]: wlan0: deleting route to
> 192.168.1.0/24
> Jul 14 12:51:31 kerolasa-home dhcpcd[451]: wlan0: deleting default
> route via 192.168.1.1
> Jul 14 12:51:31 kerolasa-home kernel: Freezing user space processes
> ... (elapsed 0.001 seconds) done.
> Jul 14 12:51:31 kerolasa-home kernel: PM: Preallocating image
> memory... done (allocated 187558 pages)
> Jul 14 12:51:31 kerolasa-home kernel: PM: Allocated 750232 kbytes in
> 0.32 seconds (2344.47 MB/s)
> Jul 14 12:51:31 kerolasa-home kernel: Freezing remaining freezable
> tasks ... (elapsed 0.001 seconds) done.
> Jul 14 12:51:31 kerolasa-home kernel: Suspending console(s) (use
> no_console_suspend to debug)
> Jul 14 12:51:31 kerolasa-home kernel: wlan0: deauthenticating from
> 20:f3:a3:39:74:56 by local choice (reason=3)
> Jul 14 12:51:31 kerolasa-home kernel: cfg80211: Calling CRDA to update
> world regulatory domain
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'regulatory.0'
> (ffff8800d98bc820): kobject_uevent_env
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'regulatory.0'
> (ffff8800d98bc820): fill_kobj_path: path > '/devices/platform/regulatory.0'
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '50'
> (ffff8800d8c97888): kobject_cleanup
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '50'
> (ffff8800d8c97888): calling ktype release
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '50': free name
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff8800d8c974d8): kobject_cleanup
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff8800d8c974d8): auto cleanup kobject_del
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff8800d8c974d8): calling ktype release
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff8800d8c974d8): kset_release
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs': free name
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '49'
> (ffff8800d8c97ac8): kobject_cleanup
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '49'
> (ffff8800d8c97ac8): calling ktype release
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '49': free name
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff8800d8c97b98): kobject_cleanup
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff8800d8c97b98): auto cleanup kobject_del
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff8800d8c97b98): calling ktype release
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff8800d8c97b98): kset_release
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs': free name
> Jul 14 12:51:31 kerolasa-home kernel: radeon 0000:00:01.0: fence
> driver on ring 5 use gpu addr 0x0000000000177118 and cpu addr
> 0xffffc90004ab2118
> Jul 14 12:51:31 kerolasa-home kernel: PM: freeze of devices complete
> after 631.979 msecs
> Jul 14 12:51:31 kerolasa-home kernel: hibernation debug: Waiting for 5 seconds.
> Jul 14 12:51:31 kerolasa-home kernel: usb usb1: root hub lost power or was reset
> Jul 14 12:51:31 kerolasa-home kernel: usb usb2: root hub lost power or was reset
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '43'
> (ffff880106a39dc8): kobject_cleanup
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '43'
> (ffff880106a39dc8): calling ktype release
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '43': free name
> Jul 14 12:51:31 kerolasa-home kernel: usb usb4: root hub lost power or was reset
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '44'
> (ffff880106a39d08): kobject_cleanup
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '44'
> (ffff880106a39d08): calling ktype release
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '44': free name
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '45'
> (ffff880106a39c48): kobject_cleanup
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '45'
> (ffff880106a39c48): calling ktype release
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '45': free name
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff880106a39b98): kobject_cleanup
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff880106a39b98): auto cleanup kobject_del
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff880106a39b98): calling ktype release
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff880106a39b98): kset_release
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs': free name
> Jul 14 12:51:31 kerolasa-home kernel: usb usb5: root hub lost power or was reset
> Jul 14 12:51:31 kerolasa-home kernel: xhci_hcd 0000:00:10.0: irq 43
> for MSI/MSI-X
> Jul 14 12:51:31 kerolasa-home kernel: xhci_hcd 0000:00:10.0: irq 44
> for MSI/MSI-X
> Jul 14 12:51:31 kerolasa-home kernel: rtlwifi: wireless switch is on
> Jul 14 12:51:31 kerolasa-home kernel: xhci_hcd 0000:00:10.0: irq 45
> for MSI/MSI-X
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff8800d9012118): kobject_add_internal: parent: '0000:00:10.0', set:
> '<NULL>'
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff8800d9012118): kobject_uevent_env
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff8800d9012118): kobject_uevent_env: filter function caused the
> event to drop!
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '43'
> (ffff8800d90121c8): kobject_add_internal: parent: 'msi_irqs', set:
> 'msi_irqs'
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '44'
> (ffff8800d9012e88): kobject_add_internal: parent: 'msi_irqs', set:
> 'msi_irqs'
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '45'
> (ffff8800d9012c48): kobject_add_internal: parent: 'msi_irqs', set:
> 'msi_irqs'
> Jul 14 12:51:31 kerolasa-home kernel: [drm] PCIE GART of 512M enabled
> (table at 0x0000000000145000).
> Jul 14 12:51:31 kerolasa-home kernel: radeon 0000:00:01.0: WB enabled
> Jul 14 12:51:31 kerolasa-home kernel: radeon 0000:00:01.0: fence
> driver on ring 0 use gpu addr 0x0000000018000c00 and cpu addr
> 0xffff8800d98a2c00
> Jul 14 12:51:31 kerolasa-home kernel: radeon 0000:00:01.0: fence
> driver on ring 3 use gpu addr 0x0000000018000c0c and cpu addr
> 0xffff8800d98a2c0c
> Jul 14 12:51:31 kerolasa-home kernel: snd_hda_intel 0000:00:14.2: irq
> 49 for MSI/MSI-X
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff8800d92b5718): kobject_add_internal: parent: '0000:00:14.2', set:
> '<NULL>'
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff8800d92b5718): kobject_uevent_env
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff8800d92b5718): kobject_uevent_env: filter function caused the
> event to drop!
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '49'
> (ffff8800d92b5648): kobject_add_internal: parent: 'msi_irqs', set:
> 'msi_irqs'
> Jul 14 12:51:31 kerolasa-home kernel: radeon 0000:00:01.0: fence
> driver on ring 5 use gpu addr 0x00000000007ca118 and cpu addr
> 0xffffc90005432118
> Jul 14 12:51:31 kerolasa-home kernel: snd_hda_intel 0000:00:01.1: irq
> 50 for MSI/MSI-X
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff880106a39658): kobject_add_internal: parent: '0000:00:01.1', set:
> '<NULL>'
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff880106a39658): kobject_uevent_env
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
> (ffff880106a39658): kobject_uevent_env: filter function caused the
> event to drop!
> Jul 14 12:51:31 kerolasa-home kernel: kobject: '50'
> (ffff8800d9012a08): kobject_add_internal: parent: 'msi_irqs', set:
> 'msi_irqs'
> Jul 14 12:51:31 kerolasa-home kernel: [drm] ring test on 0 succeeded in 1 usecs
> Jul 14 12:51:31 kerolasa-home kernel: [drm] ring test on 3 succeeded in 1 usecs
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'radeon_bl0'
> (ffff8800da197198): kobject_uevent_env
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'radeon_bl0'
> (ffff8800da197198): fill_kobj_path: path > '/devices/pci0000:00/0000:00:01.0/drm/card0/card0-LVDS-1/radeon_bl0'
> Jul 14 12:51:31 kerolasa-home kernel: ACPI: \_SB_.PCI0:
> ACPI_NOTIFY_BUS_CHECK event: unsupported
> Jul 14 12:51:31 kerolasa-home kernel: ACPI: \_SB_.PCI0: Bus check
> notify on _handle_hotplug_event_root
> Jul 14 12:51:31 kerolasa-home kernel: [drm] ring test on 5 succeeded in 1 usecs
> Jul 14 12:51:31 kerolasa-home kernel: [drm] UVD initialized successfully.
> Jul 14 12:51:31 kerolasa-home kernel: [drm] ib test on ring 0
> succeeded in 0 usecs
> Jul 14 12:51:31 kerolasa-home kernel: [drm] ib test on ring 3
> succeeded in 1 usecs
> Jul 14 12:51:31 kerolasa-home kernel: usb 5-4: reset high-speed USB
> device number 3 using ehci-pci
> Jul 14 12:51:31 kerolasa-home kernel: ata1: SATA link up 3.0 Gbps
> (SStatus 123 SControl 300)
> Jul 14 12:51:31 kerolasa-home kernel: ata2: SATA link up 1.5 Gbps
> (SStatus 113 SControl 300)
> Jul 14 12:51:31 kerolasa-home kernel: ata2.00: configured for UDMA/100
> Jul 14 12:51:31 kerolasa-home kernel: ata1.00: configured for UDMA/100
> Jul 14 12:51:31 kerolasa-home kernel: sd 0:0:0:0: [sda] Starting disk
> Jul 14 12:51:31 kerolasa-home kernel: radeon 0000:00:01.0: GPU lockup
> CP stall for more than 10000msec
> Jul 14 12:51:31 kerolasa-home kernel: radeon 0000:00:01.0: GPU lockup
> (waiting for 0x0000000000000004 last fence id 0x0000000000000002)
> Jul 14 12:51:31 kerolasa-home kernel: [drm:r600_uvd_ib_test] *ERROR*
> radeon: fence wait failed (-35).
> Jul 14 12:51:31 kerolasa-home kernel: [drm:radeon_ib_ring_tests]
> *ERROR* radeon: failed testing IB on ring 5 (-35).
> Jul 14 12:51:31 kerolasa-home kernel: PM: restore of devices complete
> after 11949.096 msecs
> Jul 14 12:51:31 kerolasa-home kernel: PM: Image restored successfully.
> Jul 14 12:51:31 kerolasa-home kernel: Restarting tasks ... done.
> Jul 14 12:51:31 kerolasa-home kernel: PM: Basic memory bitmaps freed
> Jul 14 12:51:31 kerolasa-home kernel: video LNXVIDEO:00: Restoring
> backlight state
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'radeon_bl0'
> (ffff8800da197198): kobject_uevent_env
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'radeon_bl0'
> (ffff8800da197198): fill_kobj_path: path > '/devices/pci0000:00/0000:00:01.0/drm/card0/card0-LVDS-1/radeon_bl0'
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0'
> (ffff8800db3b6010): kobject_uevent_env
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0'
> (ffff8800db3b6010): fill_kobj_path: path > '/devices/LNXSYSTM:00/device:00/PNP0A08:00/PNP0C0A:00/power_supply/BAT0'
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'power_supply'
> (ffff880106aba8a0): kobject_cleanup
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'power_supply'
> (ffff880106aba8a0): auto cleanup kobject_del
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'power_supply'
> (ffff880106aba8a0): calling ktype release
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'power_supply': free name
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0'
> (ffff8800db3b6010): kobject_cleanup
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0'
> (ffff8800db3b6010): calling ktype release
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0': free name
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'power_supply'
> (ffff8800d924d180): kobject_add_internal: parent: 'PNP0C0A:00', set:
> '(null)'
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0'
> (ffff8800d2c0e010): kobject_add_internal: parent: 'power_supply', set:
> 'devices'
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0'
> (ffff8800d2c0e010): kobject_uevent_env
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0'
> (ffff8800d2c0e010): fill_kobj_path: path > '/devices/LNXSYSTM:00/device:00/PNP0A08:00/PNP0C0A:00/power_supply/BAT0'
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0'
> (ffff8800d2c0e010): kobject_uevent_env
> Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0'
> (ffff8800d2c0e010): fill_kobj_path: path > '/devices/LNXSYSTM:00/device:00/PNP0A08:00/PNP0C0A:00/power_supply/BAT0'
> Jul 14 12:51:31 kerolasa-home kernel: PM: Hibernation mode set to 'platform'
> Jul 14 12:51:31 kerolasa-home kernel: PM: Marking nosave pages: [mem
> 0x0009f000-0x000fffff]
> Jul 14 12:51:31 kerolasa-home kernel: PM: Marking nosave pages: [mem
> 0xdf6bf000-0xdfbfefff]
> Jul 14 12:51:31 kerolasa-home kernel: PM: Marking nosave pages: [mem
> 0xdfc00000-0xffffffff]
> Jul 14 12:51:31 kerolasa-home kernel: PM: Basic memory bitmaps created
> Jul 14 12:51:32 kerolasa-home kernel: wlan0: authenticate with 20:f3:a3:39:74:56
> Jul 14 12:51:32 kerolasa-home kernel: wlan0: send auth to
> 20:f3:a3:39:74:56 (try 1/3)
> Jul 14 12:51:32 kerolasa-home kernel: wlan0: authenticated
> Jul 14 12:51:32 kerolasa-home kernel: wlan0: associate with
> 20:f3:a3:39:74:56 (try 1/3)
> Jul 14 12:51:32 kerolasa-home kernel: wlan0: RX AssocResp from
> 20:f3:a3:39:74:56 (capab=0x411 status=0 aid=1)
> Jul 14 12:51:32 kerolasa-home kernel: wlan0: associated
> Jul 14 12:51:32 kerolasa-home dhcpcd[451]: wlan0: carrier acquired
> 
> Let me know if more debug information or output is needed.
> 
> --
> Sami Kerola
> http://www.iki.fi/kerolasa/
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply

* [BUG] radeon: suspend resume
From: Sami Kerola @ 2013-07-14 12:26 UTC (permalink / raw)
  To: linux-fbdev

Hello,

I build from Linus's tree from point

commit 9903883f1dd6e86f286b7bfa6e4b423f98c1cd9e

a kernel which has a power management suspend/resume problem.  In short I
do not get video back at resume, and my laptop becomes completely
unresponsive.  I have hunch the NO_HZ has something to do with issue.

# zgrep ^CONFIG_NO_HZ /proc/config.gz
CONFIG_NO_HZ_COMMON=y
CONFIG_NO_HZ_FULL=y
CONFIG_NO_HZ=y

The NO_HZ combined with this piece of hardware results seems to be the
issue.

00:01.0 VGA compatible controller: Advanced Micro Devices, Inc.
[AMD/ATI] Wrestler [Radeon HD 7310] (prog-if 00 [VGA controller])
        Subsystem: Toshiba America Info Systems Device fb33
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop-
ParErr- Stepping- SERR- FastB2B- DisINTx+
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSELúst >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 0, Cache Line Size: 64 bytes
        Interrupt: pin A routed to IRQ 49
        Region 0: Memory at e0000000 (32-bit, prefetchable) [size%6M]
        Region 1: I/O ports at 5000 [size%6]
        Region 2: Memory at f0400000 (32-bit, non-prefetchable) [size%6K]
        Expansion ROM at <unassigned> [disabled]
        Capabilities: [50] Power Management version 3
                Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=0mA
PME(D0-,D1-,D2-,D3hot-,D3cold-)
                Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
        Capabilities: [58] Express (v2) Root Complex Integrated Endpoint, MSI 00
                DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s
<4us, L1 unlimited
                        ExtTag+ RBE+ FLReset-
                DevCtl: Report errors: Correctable- Non-Fatal- Fatal-
Unsupported-
                        RlxdOrd+ ExtTag- PhantFunc- AuxPwr- NoSnoop+
                        MaxPayload 128 bytes, MaxReadReq 128 bytes
                DevSta: CorrErr- UncorrErr+ FatalErr- UnsuppReq+
AuxPwr- TransPend-
                LnkCap: Port #0, Speed unknown, Width x0, ASPM
unknown, Latency L0 <64ns, L1 <1us
                        ClockPM- Surprise- LLActRep- BwNot-
                LnkCtl: ASPM Disabled; Disabled- Retrain- CommClk-
                        ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
                LnkSta: Speed unknown, Width x0, TrErr- Train-
SlotClk- DLActive- BWMgmt- ABWMgmt-
                DevCap2: Completion Timeout: Not Supported,
TimeoutDis-, LTR-, OBFF Not Supported
                DevCtl2: Completion Timeout: 50us to 50ms,
TimeoutDis-, LTR-, OBFF Disabled
                LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance- SpeedDis-
                         Transmit Margin: Normal Operating Range,
EnterModifiedCompliance- ComplianceSOS-
                         Compliance De-emphasis: -6dB
                LnkSta2: Current De-emphasis Level: -6dB,
EqualizationComplete-, EqualizationPhase1-
                         EqualizationPhase2-, EqualizationPhase3-,
LinkEqualizationRequest-
        Capabilities: [a0] MSI: Enable+ Count=1/1 Maskable- 64bit+
                Address: 00000000fee0300c  Data: 4152
        Capabilities: [100 v1] Vendor Specific Information: ID\001
Rev=1 Len\x010 <?>
        Kernel driver in use: radeon
        Kernel modules: radeon


Here are some message from journalctl from the time suspend begun, and
resume failed.  To me the two lines with '*ERROR* radeon' does not look
right.  The messages are result of 'echo devices > /sys/power/pm_test'.


Jul 14 12:51:12 kerolasa-home kernel: PM: Hibernation mode set to 'platform'
Jul 14 12:51:12 kerolasa-home kernel: kobject: 'vcs63'
(ffff8800d2c09010): kobject_add_internal: parent: 'vc', set: 'devices'
Jul 14 12:51:12 kerolasa-home kernel: kobject: 'vcs63'
(ffff8800d2c09010): kobject_uevent_env
Jul 14 12:51:12 kerolasa-home kernel: kobject: 'vcs63'
(ffff8800d2c09010): fill_kobj_path: path = '/devices/virtual/vc/vcs63'
Jul 14 12:51:12 kerolasa-home kernel: kobject: 'vcsa63'
(ffff8800d2c08010): kobject_add_internal: parent: 'vc', set: 'devices'
Jul 14 12:51:12 kerolasa-home kernel: kobject: 'vcsa63'
(ffff8800d2c08010): kobject_uevent_env
Jul 14 12:51:12 kerolasa-home kernel: kobject: 'vcsa63'
(ffff8800d2c08010): fill_kobj_path: path '/devices/virtual/vc/vcsa63'
Jul 14 12:51:12 kerolasa-home kernel: PM: Marking nosave pages: [mem
0x0009f000-0x000fffff]
Jul 14 12:51:12 kerolasa-home kernel: PM: Marking nosave pages: [mem
0xdf6bf000-0xdfbfefff]
Jul 14 12:51:12 kerolasa-home kernel: PM: Marking nosave pages: [mem
0xdfc00000-0xffffffff]
Jul 14 12:51:12 kerolasa-home kernel: PM: Basic memory bitmaps created
Jul 14 12:51:31 kerolasa-home kernel: PM: Syncing filesystems ... done.
Jul 14 12:51:31 kerolasa-home dhcpcd[451]: wlan0: carrier lost
Jul 14 12:51:31 kerolasa-home dhcpcd[451]: wlan0: deleting host route
to 192.168.1.2 via 127.0.0.1
Jul 14 12:51:31 kerolasa-home dhcpcd[451]: wlan0: deleting route to
192.168.1.0/24
Jul 14 12:51:31 kerolasa-home dhcpcd[451]: wlan0: deleting default
route via 192.168.1.1
Jul 14 12:51:31 kerolasa-home kernel: Freezing user space processes
... (elapsed 0.001 seconds) done.
Jul 14 12:51:31 kerolasa-home kernel: PM: Preallocating image
memory... done (allocated 187558 pages)
Jul 14 12:51:31 kerolasa-home kernel: PM: Allocated 750232 kbytes in
0.32 seconds (2344.47 MB/s)
Jul 14 12:51:31 kerolasa-home kernel: Freezing remaining freezable
tasks ... (elapsed 0.001 seconds) done.
Jul 14 12:51:31 kerolasa-home kernel: Suspending console(s) (use
no_console_suspend to debug)
Jul 14 12:51:31 kerolasa-home kernel: wlan0: deauthenticating from
20:f3:a3:39:74:56 by local choice (reason=3)
Jul 14 12:51:31 kerolasa-home kernel: cfg80211: Calling CRDA to update
world regulatory domain
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'regulatory.0'
(ffff8800d98bc820): kobject_uevent_env
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'regulatory.0'
(ffff8800d98bc820): fill_kobj_path: path '/devices/platform/regulatory.0'
Jul 14 12:51:31 kerolasa-home kernel: kobject: '50'
(ffff8800d8c97888): kobject_cleanup
Jul 14 12:51:31 kerolasa-home kernel: kobject: '50'
(ffff8800d8c97888): calling ktype release
Jul 14 12:51:31 kerolasa-home kernel: kobject: '50': free name
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff8800d8c974d8): kobject_cleanup
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff8800d8c974d8): auto cleanup kobject_del
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff8800d8c974d8): calling ktype release
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff8800d8c974d8): kset_release
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs': free name
Jul 14 12:51:31 kerolasa-home kernel: kobject: '49'
(ffff8800d8c97ac8): kobject_cleanup
Jul 14 12:51:31 kerolasa-home kernel: kobject: '49'
(ffff8800d8c97ac8): calling ktype release
Jul 14 12:51:31 kerolasa-home kernel: kobject: '49': free name
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff8800d8c97b98): kobject_cleanup
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff8800d8c97b98): auto cleanup kobject_del
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff8800d8c97b98): calling ktype release
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff8800d8c97b98): kset_release
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs': free name
Jul 14 12:51:31 kerolasa-home kernel: radeon 0000:00:01.0: fence
driver on ring 5 use gpu addr 0x0000000000177118 and cpu addr
0xffffc90004ab2118
Jul 14 12:51:31 kerolasa-home kernel: PM: freeze of devices complete
after 631.979 msecs
Jul 14 12:51:31 kerolasa-home kernel: hibernation debug: Waiting for 5 seconds.
Jul 14 12:51:31 kerolasa-home kernel: usb usb1: root hub lost power or was reset
Jul 14 12:51:31 kerolasa-home kernel: usb usb2: root hub lost power or was reset
Jul 14 12:51:31 kerolasa-home kernel: kobject: '43'
(ffff880106a39dc8): kobject_cleanup
Jul 14 12:51:31 kerolasa-home kernel: kobject: '43'
(ffff880106a39dc8): calling ktype release
Jul 14 12:51:31 kerolasa-home kernel: kobject: '43': free name
Jul 14 12:51:31 kerolasa-home kernel: usb usb4: root hub lost power or was reset
Jul 14 12:51:31 kerolasa-home kernel: kobject: '44'
(ffff880106a39d08): kobject_cleanup
Jul 14 12:51:31 kerolasa-home kernel: kobject: '44'
(ffff880106a39d08): calling ktype release
Jul 14 12:51:31 kerolasa-home kernel: kobject: '44': free name
Jul 14 12:51:31 kerolasa-home kernel: kobject: '45'
(ffff880106a39c48): kobject_cleanup
Jul 14 12:51:31 kerolasa-home kernel: kobject: '45'
(ffff880106a39c48): calling ktype release
Jul 14 12:51:31 kerolasa-home kernel: kobject: '45': free name
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff880106a39b98): kobject_cleanup
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff880106a39b98): auto cleanup kobject_del
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff880106a39b98): calling ktype release
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff880106a39b98): kset_release
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs': free name
Jul 14 12:51:31 kerolasa-home kernel: usb usb5: root hub lost power or was reset
Jul 14 12:51:31 kerolasa-home kernel: xhci_hcd 0000:00:10.0: irq 43
for MSI/MSI-X
Jul 14 12:51:31 kerolasa-home kernel: xhci_hcd 0000:00:10.0: irq 44
for MSI/MSI-X
Jul 14 12:51:31 kerolasa-home kernel: rtlwifi: wireless switch is on
Jul 14 12:51:31 kerolasa-home kernel: xhci_hcd 0000:00:10.0: irq 45
for MSI/MSI-X
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff8800d9012118): kobject_add_internal: parent: '0000:00:10.0', set:
'<NULL>'
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff8800d9012118): kobject_uevent_env
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff8800d9012118): kobject_uevent_env: filter function caused the
event to drop!
Jul 14 12:51:31 kerolasa-home kernel: kobject: '43'
(ffff8800d90121c8): kobject_add_internal: parent: 'msi_irqs', set:
'msi_irqs'
Jul 14 12:51:31 kerolasa-home kernel: kobject: '44'
(ffff8800d9012e88): kobject_add_internal: parent: 'msi_irqs', set:
'msi_irqs'
Jul 14 12:51:31 kerolasa-home kernel: kobject: '45'
(ffff8800d9012c48): kobject_add_internal: parent: 'msi_irqs', set:
'msi_irqs'
Jul 14 12:51:31 kerolasa-home kernel: [drm] PCIE GART of 512M enabled
(table at 0x0000000000145000).
Jul 14 12:51:31 kerolasa-home kernel: radeon 0000:00:01.0: WB enabled
Jul 14 12:51:31 kerolasa-home kernel: radeon 0000:00:01.0: fence
driver on ring 0 use gpu addr 0x0000000018000c00 and cpu addr
0xffff8800d98a2c00
Jul 14 12:51:31 kerolasa-home kernel: radeon 0000:00:01.0: fence
driver on ring 3 use gpu addr 0x0000000018000c0c and cpu addr
0xffff8800d98a2c0c
Jul 14 12:51:31 kerolasa-home kernel: snd_hda_intel 0000:00:14.2: irq
49 for MSI/MSI-X
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff8800d92b5718): kobject_add_internal: parent: '0000:00:14.2', set:
'<NULL>'
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff8800d92b5718): kobject_uevent_env
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff8800d92b5718): kobject_uevent_env: filter function caused the
event to drop!
Jul 14 12:51:31 kerolasa-home kernel: kobject: '49'
(ffff8800d92b5648): kobject_add_internal: parent: 'msi_irqs', set:
'msi_irqs'
Jul 14 12:51:31 kerolasa-home kernel: radeon 0000:00:01.0: fence
driver on ring 5 use gpu addr 0x00000000007ca118 and cpu addr
0xffffc90005432118
Jul 14 12:51:31 kerolasa-home kernel: snd_hda_intel 0000:00:01.1: irq
50 for MSI/MSI-X
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff880106a39658): kobject_add_internal: parent: '0000:00:01.1', set:
'<NULL>'
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff880106a39658): kobject_uevent_env
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'msi_irqs'
(ffff880106a39658): kobject_uevent_env: filter function caused the
event to drop!
Jul 14 12:51:31 kerolasa-home kernel: kobject: '50'
(ffff8800d9012a08): kobject_add_internal: parent: 'msi_irqs', set:
'msi_irqs'
Jul 14 12:51:31 kerolasa-home kernel: [drm] ring test on 0 succeeded in 1 usecs
Jul 14 12:51:31 kerolasa-home kernel: [drm] ring test on 3 succeeded in 1 usecs
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'radeon_bl0'
(ffff8800da197198): kobject_uevent_env
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'radeon_bl0'
(ffff8800da197198): fill_kobj_path: path '/devices/pci0000:00/0000:00:01.0/drm/card0/card0-LVDS-1/radeon_bl0'
Jul 14 12:51:31 kerolasa-home kernel: ACPI: \_SB_.PCI0:
ACPI_NOTIFY_BUS_CHECK event: unsupported
Jul 14 12:51:31 kerolasa-home kernel: ACPI: \_SB_.PCI0: Bus check
notify on _handle_hotplug_event_root
Jul 14 12:51:31 kerolasa-home kernel: [drm] ring test on 5 succeeded in 1 usecs
Jul 14 12:51:31 kerolasa-home kernel: [drm] UVD initialized successfully.
Jul 14 12:51:31 kerolasa-home kernel: [drm] ib test on ring 0
succeeded in 0 usecs
Jul 14 12:51:31 kerolasa-home kernel: [drm] ib test on ring 3
succeeded in 1 usecs
Jul 14 12:51:31 kerolasa-home kernel: usb 5-4: reset high-speed USB
device number 3 using ehci-pci
Jul 14 12:51:31 kerolasa-home kernel: ata1: SATA link up 3.0 Gbps
(SStatus 123 SControl 300)
Jul 14 12:51:31 kerolasa-home kernel: ata2: SATA link up 1.5 Gbps
(SStatus 113 SControl 300)
Jul 14 12:51:31 kerolasa-home kernel: ata2.00: configured for UDMA/100
Jul 14 12:51:31 kerolasa-home kernel: ata1.00: configured for UDMA/100
Jul 14 12:51:31 kerolasa-home kernel: sd 0:0:0:0: [sda] Starting disk
Jul 14 12:51:31 kerolasa-home kernel: radeon 0000:00:01.0: GPU lockup
CP stall for more than 10000msec
Jul 14 12:51:31 kerolasa-home kernel: radeon 0000:00:01.0: GPU lockup
(waiting for 0x0000000000000004 last fence id 0x0000000000000002)
Jul 14 12:51:31 kerolasa-home kernel: [drm:r600_uvd_ib_test] *ERROR*
radeon: fence wait failed (-35).
Jul 14 12:51:31 kerolasa-home kernel: [drm:radeon_ib_ring_tests]
*ERROR* radeon: failed testing IB on ring 5 (-35).
Jul 14 12:51:31 kerolasa-home kernel: PM: restore of devices complete
after 11949.096 msecs
Jul 14 12:51:31 kerolasa-home kernel: PM: Image restored successfully.
Jul 14 12:51:31 kerolasa-home kernel: Restarting tasks ... done.
Jul 14 12:51:31 kerolasa-home kernel: PM: Basic memory bitmaps freed
Jul 14 12:51:31 kerolasa-home kernel: video LNXVIDEO:00: Restoring
backlight state
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'radeon_bl0'
(ffff8800da197198): kobject_uevent_env
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'radeon_bl0'
(ffff8800da197198): fill_kobj_path: path '/devices/pci0000:00/0000:00:01.0/drm/card0/card0-LVDS-1/radeon_bl0'
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0'
(ffff8800db3b6010): kobject_uevent_env
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0'
(ffff8800db3b6010): fill_kobj_path: path '/devices/LNXSYSTM:00/device:00/PNP0A08:00/PNP0C0A:00/power_supply/BAT0'
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'power_supply'
(ffff880106aba8a0): kobject_cleanup
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'power_supply'
(ffff880106aba8a0): auto cleanup kobject_del
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'power_supply'
(ffff880106aba8a0): calling ktype release
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'power_supply': free name
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0'
(ffff8800db3b6010): kobject_cleanup
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0'
(ffff8800db3b6010): calling ktype release
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0': free name
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'power_supply'
(ffff8800d924d180): kobject_add_internal: parent: 'PNP0C0A:00', set:
'(null)'
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0'
(ffff8800d2c0e010): kobject_add_internal: parent: 'power_supply', set:
'devices'
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0'
(ffff8800d2c0e010): kobject_uevent_env
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0'
(ffff8800d2c0e010): fill_kobj_path: path '/devices/LNXSYSTM:00/device:00/PNP0A08:00/PNP0C0A:00/power_supply/BAT0'
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0'
(ffff8800d2c0e010): kobject_uevent_env
Jul 14 12:51:31 kerolasa-home kernel: kobject: 'BAT0'
(ffff8800d2c0e010): fill_kobj_path: path '/devices/LNXSYSTM:00/device:00/PNP0A08:00/PNP0C0A:00/power_supply/BAT0'
Jul 14 12:51:31 kerolasa-home kernel: PM: Hibernation mode set to 'platform'
Jul 14 12:51:31 kerolasa-home kernel: PM: Marking nosave pages: [mem
0x0009f000-0x000fffff]
Jul 14 12:51:31 kerolasa-home kernel: PM: Marking nosave pages: [mem
0xdf6bf000-0xdfbfefff]
Jul 14 12:51:31 kerolasa-home kernel: PM: Marking nosave pages: [mem
0xdfc00000-0xffffffff]
Jul 14 12:51:31 kerolasa-home kernel: PM: Basic memory bitmaps created
Jul 14 12:51:32 kerolasa-home kernel: wlan0: authenticate with 20:f3:a3:39:74:56
Jul 14 12:51:32 kerolasa-home kernel: wlan0: send auth to
20:f3:a3:39:74:56 (try 1/3)
Jul 14 12:51:32 kerolasa-home kernel: wlan0: authenticated
Jul 14 12:51:32 kerolasa-home kernel: wlan0: associate with
20:f3:a3:39:74:56 (try 1/3)
Jul 14 12:51:32 kerolasa-home kernel: wlan0: RX AssocResp from
20:f3:a3:39:74:56 (capab=0x411 status=0 aid=1)
Jul 14 12:51:32 kerolasa-home kernel: wlan0: associated
Jul 14 12:51:32 kerolasa-home dhcpcd[451]: wlan0: carrier acquired

Let me know if more debug information or output is needed.

--
Sami Kerola
http://www.iki.fi/kerolasa/

^ permalink raw reply

* Re: [V3 0/7] Enhance mmp display driver
From: jett zhou @ 2013-07-14  3:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130709133918.GC18477@ns203013.ovh.net>

Hi Jean
     As I checked the for-next branch, found patch4 and patch5 are
already applied.
     As checked on my side,  only apply patch1~patch3 and
patch6~patch7 is ok, so think you can apply them except for patch4/5.
     If there is still problem, please let me know, I will check it then.
Thanks

2013/7/9 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>:
> HI,
>
>         please rebase on the for-next branch as it does not apply
>
> Best Regards,
> J.
> On 19:27 Thu 27 Jun     , Jett.Zhou wrote:
>> Changelog:
>> 1 Add more comments for the mmp_display rbswap usage
>> according to Daniel's comments;
>> 2 Add fix patch for ttc_dkb on rbswap;
>> 3 Add more comments on the pitch usage and definition;
>> 4 Combine the modification on pitch of graphic and video layer
>> in one patch.
>>
>> Guoqing Li (2):
>>   video: mmp: rb swap setting update for mmp display
>>   video: mmp: optimize some register setting code
>>
>> Jett.Zhou (1):
>>   ARM: mmp: remove the legacy rbswap setting for ttc_dkb platform
>>
>> Jing Xiang (4):
>>   video: mmp: fix graphics/video layer enable/mask issue
>>   video: mmp: fix memcpy wrong size for mmp_addr issue
>>   video: mmp: calculate pitch value when fb set win
>>   video: mmp: add pitch info in mmp_win structure
>>
>>  arch/arm/mach-mmp/ttc_dkb.c     |    4 +-
>>  drivers/video/mmp/fb/mmpfb.c    |   34 +++++++++++------
>>  drivers/video/mmp/hw/mmp_ctrl.c |   79 ++++++++++++++++++++++-----------------
>>  drivers/video/mmp/hw/mmp_ctrl.h |    5 ++
>>  include/video/mmp_disp.h        |    6 +++
>>  5 files changed, 79 insertions(+), 49 deletions(-)
>>



--

----------------------------------
Best Regards
Jett Zhou

^ permalink raw reply

* Re: [PATCH] omapfb: In omapfb_probe return -EPROBE_DEFER when display driver is not loaded yet
From: Pavel Machek @ 2013-07-13 19:56 UTC (permalink / raw)
  To: Pali Rohár
  Cc: Tomi Valkeinen, Jean-Christophe Plagniol-Villard, linux-omap,
	linux-fbdev, linux-kernel, Aaro Koskinen, Tony Lindgren
In-Reply-To: <20130713182733.GA25019@amd.pavel.ucw.cz>

Hi!


> One thing I'd like to know: how do you configure kernel to get output
> on qemu? I was doing CONFIG_DEBUG_LL with specific uart, but that
> needed patching the kernel, you apparently have something more
> clever.

Aha, normal console=ttyO2 option. Got it now :-).

									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply

* Re: [PATCH] omapfb: In omapfb_probe return -EPROBE_DEFER when display driver is not loaded yet
From: Pavel Machek @ 2013-07-13 18:27 UTC (permalink / raw)
  To: Pali Rohár
  Cc: Tomi Valkeinen, Jean-Christophe Plagniol-Villard, linux-omap,
	linux-fbdev, linux-kernel, Aaro Koskinen, Tony Lindgren
In-Reply-To: <1373461739-10168-1-git-send-email-pali.rohar@gmail.com>

On Wed 2013-07-10 15:08:59, Pali Rohár wrote:
> * On RX-51 probing for acx565akm driver is later then for omapfb which cause that omapfb probe fail and framebuffer is not working
> * EPROBE_DEFER causing that kernel try to probe for omapfb later again which fixing this problem
> 
> * Without this patch display on Nokia RX-51 (N900) phone not working
> 
> Signed-off-by: Pali Rohár <pali.rohar@gmail.com>

Tested-by: Pavel Machek <pavel@ucw.cz>

(Actually, do we know which commit broke the ordering? We may want to
simply revert that one...)

BTW I'm currently trying to set-up automated scripts for n900/qemu
testing. I guess I'll try to run them on mainline kernel to catch such
stuff earlier.

One thing I'd like to know: how do you configure kernel to get output
on qemu? I was doing CONFIG_DEBUG_LL with specific uart, but that
needed patching the kernel, you apparently have something more clever.

I tried doing:

# CONFIG_DEBUG_LL is not set
CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"

but no output on console...

Thanks,
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply

* Re: [patch -next] fb: fix recent breakage in correct_chipset()
From: Randy Dunlap @ 2013-07-12 20:11 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <20130702062821.GC24410@elgon.mountain>

On 07/01/13 23:28, Dan Carpenter wrote:
> The 6e36308a6f "fb: fix atyfb build warning" isn't right.  It makes all
> the indexes off by one.  This patch reverts it and casts the
> ARRAY_SIZE() to int to silence the build warning.
> 
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>

Tomi,

My incorrect patch has been merged into mainline.
Please merge Dan's fix for it instead.

Thanks.

> diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
> index a89c15d..9b0f12c 100644
> --- a/drivers/video/aty/atyfb_base.c
> +++ b/drivers/video/aty/atyfb_base.c
> @@ -435,8 +435,8 @@ static int correct_chipset(struct atyfb_par *par)
>  	const char *name;
>  	int i;
>  
> -	for (i = ARRAY_SIZE(aty_chips); i > 0; i--)
> -		if (par->pci_id = aty_chips[i - 1].pci_id)
> +	for (i = (int)ARRAY_SIZE(aty_chips) - 1; i >= 0; i--)
> +		if (par->pci_id = aty_chips[i].pci_id)
>  			break;
>  
>  	if (i < 0)
> 


-- 
~Randy

^ permalink raw reply

* [PATCH] matroxfb: replace kmalloc and memset with kzalloc.
From: Alexandru Juncu @ 2013-07-12 14:00 UTC (permalink / raw)
  To: plagnioj; +Cc: tomi.valkeinen, alexj, linux-fbdev, linux-kernel

Signed-off-by: Alexandru Juncu <alexj@rosedu.org>
---
 drivers/video/matrox/matroxfb_base.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index 401a56e..2456529 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -2029,10 +2029,9 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm
 		return -1;
 	}
 
-	minfo = kmalloc(sizeof(*minfo), GFP_KERNEL);
+	minfo = kzalloc(sizeof(*minfo), GFP_KERNEL);
 	if (!minfo)
 		return -1;
-	memset(minfo, 0, sizeof(*minfo));
 
 	minfo->pcidev = pdev;
 	minfo->dead = 0;
-- 
1.8.1.2


^ permalink raw reply related

* [PATCH] video: nuc900fb: fix to pass correct device identity to free_irq()
From: Wei Yongjun @ 2013-07-12 13:20 UTC (permalink / raw)
  To: linux-arm-kernel

From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>

free_irq() expects the same device identity that was passed to
corresponding request_irq(), otherwise the IRQ is not freed.

Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
---
 drivers/video/nuc900fb.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c
index 8c527e5..ebd5501 100644
--- a/drivers/video/nuc900fb.c
+++ b/drivers/video/nuc900fb.c
@@ -661,7 +661,7 @@ release_clock:
 	clk_disable(fbi->clk);
 	clk_put(fbi->clk);
 release_irq:
-	free_irq(irq, fbi);
+	free_irq(irq, fbinfo);
 release_regs:
 	iounmap(fbi->io);
 release_mem_region:
@@ -702,7 +702,7 @@ static int nuc900fb_remove(struct platform_device *pdev)
 	iounmap(fbi->io);
 
 	irq = platform_get_irq(pdev, 0);
-	free_irq(irq, fbi);
+	free_irq(irq, fbinfo);
 
 	release_resource(fbi->mem);
 	kfree(fbi->mem);


^ permalink raw reply related

* [PATCH] video: sh7760fb: fix to pass correct device identity to free_irq()
From: Wei Yongjun @ 2013-07-12 13:20 UTC (permalink / raw)
  To: linux-fbdev

From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>

free_irq() expects the same device identity that was passed to
corresponding request_irq(), otherwise the IRQ is not freed.

Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
---
 drivers/video/sh7760fb.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/video/sh7760fb.c b/drivers/video/sh7760fb.c
index a8c6c43..1265b25 100644
--- a/drivers/video/sh7760fb.c
+++ b/drivers/video/sh7760fb.c
@@ -567,7 +567,7 @@ static int sh7760fb_remove(struct platform_device *dev)
 	fb_dealloc_cmap(&info->cmap);
 	sh7760fb_free_mem(info);
 	if (par->irq >= 0)
-		free_irq(par->irq, par);
+		free_irq(par->irq, &par->vsync);
 	iounmap(par->base);
 	release_mem_region(par->ioarea->start, resource_size(par->ioarea));
 	framebuffer_release(info);


^ permalink raw reply related

* Re: [PATCH RESEND] video: mxsfb: fix color settings for 18bit data bus and 32bpp
From: maxime.ripard @ 2013-07-12 12:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130703085505.GG2969@lukather>

[-- Attachment #1: Type: text/plain, Size: 1350 bytes --]

On Wed, Jul 03, 2013 at 10:55:05AM +0200, maxime.ripard@free-electrons.com wrote:
> Hi Jean-Christophe,
> 
> On Tue, Jun 18, 2013 at 10:44:17AM +0200, Hector Palacios wrote:
> > For a combination of 18bit LCD data bus width and a color
> > mode of 32bpp, the driver was setting the color mapping to
> > rgb666, which is wrong, as the color in memory realy has an
> > rgb888 layout.
> > 
> > This patch also removes the setting of flag CTRL_DF24 that
> > makes the driver dimiss the upper 2 bits when handling 32/24bpp
> > colors in a diplay with 18bit data bus width. This flag made
> > true color images display wrong in such configurations.
> > 
> > Finally, the color mapping rgb666 has also been removed as nobody
> > is using it and high level applications like Qt5 cannot work
> > with it either.
> > 
> > Reference: https://lkml.org/lkml/2013/5/23/220
> > Signed-off-by: Hector Palacios <hector.palacios@digi.com>
> > Acked-by: Juergen Beisert <jbe@pengutronix.de>
> > Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> 
> I don't see this patch in your for-next branch.
> 
> It would be really great to have it for 3.11 if possible.
> 
> Could you take a look at this patch please?

Ping?

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH 1/2] fb: backlight: HX8357: Make IM pins optionnal
From: Maxime Ripard @ 2013-07-12  9:11 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD
  Cc: Alexandre Belloni, linux-fbdev, jimwall, brian, linux-kernel,
	Richard Purdie, Florian Tobias Schandinat
In-Reply-To: <20130625135015.GM26008@lukather>

[-- Attachment #1: Type: text/plain, Size: 1200 bytes --]

On Tue, Jun 25, 2013 at 03:50:15PM +0200, Maxime Ripard wrote:
> > >  };
> > >  
> > >  static u8 hx8357_seq_power[] = {
> > > @@ -250,9 +251,11 @@ static int hx8357_lcd_init(struct lcd_device *lcdev)
> > >  	 * Set the interface selection pins to SPI mode, with three
> > >  	 * wires
> > >  	 */
> > > -	gpio_set_value_cansleep(lcd->im_pins[0], 1);
> > > -	gpio_set_value_cansleep(lcd->im_pins[1], 0);
> > > -	gpio_set_value_cansleep(lcd->im_pins[2], 1);
> > > +	if (lcd->use_im_pins) {
> > > +		gpio_set_value_cansleep(lcd->im_pins[0], 1);
> > > +		gpio_set_value_cansleep(lcd->im_pins[1], 0);
> > > +		gpio_set_value_cansleep(lcd->im_pins[2], 1);
> > > +	}
> > 
> > base on the dt probe you may have gpios betwee 0 to HX8357_NUM_IM_PINS
> > 
> > so this look wrong
> 
> How so?
> 
> HX8357_NUM_IM_PINS is defined to 3, the probe checks to see if we
> actually have HX8357_NUM_IM_PINS, otherwise returns an error, what is
> wrong in setting these pins here?

Ping?

I'd really like to get this merged, could you clarify what you want?

Thanks,
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* [RFC PATCH v1 2/2] dma-buf: add lock callback for fcntl system call
From: Inki Dae @ 2013-07-12  6:12 UTC (permalink / raw)
  To: dri-devel, linux-fbdev, linux-arm-kernel, linux-media
  Cc: maarten.lankhorst, daniel, robdclark, sumit.semwal, linux,
	kyungmin.park, myungjoo.ham, yj44.cho, Inki Dae
In-Reply-To: <1373609566-10784-1-git-send-email-inki.dae@samsung.com>

This patch adds lock callback to dma buf file operations,
and this callback will be called by fcntl system call.

With this patch, fcntl system call can be used for buffer
synchronization between CPU and CPU, and CPU and DMA in user mode.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/base/dma-buf.c |   33 +++++++++++++++++++++++++++++++++
 1 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index 9a26981..e1b8583 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -80,9 +80,42 @@ static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma)
 	return dmabuf->ops->mmap(dmabuf, vma);
 }
 
+static int dma_buf_lock(struct file *file, int cmd, struct file_lock *fl)
+{
+	struct dma_buf *dmabuf;
+	unsigned int type;
+	bool wait = false;
+
+	if (!is_dma_buf_file(file))
+		return -EINVAL;
+
+	dmabuf = file->private_data;
+
+	if ((fl->fl_type & F_UNLCK) = F_UNLCK) {
+		dmabuf_sync_single_unlock(dmabuf);
+		return 0;
+	}
+
+	/* convert flock type to dmabuf sync type. */
+	if ((fl->fl_type & F_WRLCK) = F_WRLCK)
+		type = DMA_BUF_ACCESS_W;
+	else if ((fl->fl_type & F_RDLCK) = F_RDLCK)
+		type = DMA_BUF_ACCESS_R;
+	else
+		return -EINVAL;
+
+	if (fl->fl_flags & FL_SLEEP)
+		wait = true;
+
+	/* TODO. the locking to certain region should also be considered. */
+
+	return dmabuf_sync_single_lock(dmabuf, type, wait);
+}
+
 static const struct file_operations dma_buf_fops = {
 	.release	= dma_buf_release,
 	.mmap		= dma_buf_mmap_internal,
+	.lock		= dma_buf_lock,
 };
 
 /*
-- 
1.7.5.4


^ permalink raw reply related

* [RFC PATCH v5 1/2] dmabuf-sync: Introduce buffer synchronization framework
From: Inki Dae @ 2013-07-12  6:12 UTC (permalink / raw)
  To: dri-devel, linux-fbdev, linux-arm-kernel, linux-media
  Cc: maarten.lankhorst, daniel, robdclark, sumit.semwal, linux,
	kyungmin.park, myungjoo.ham, yj44.cho, Inki Dae
In-Reply-To: <1373609566-10784-1-git-send-email-inki.dae@samsung.com>

This patch adds a buffer synchronization framework based on DMA BUF[1]
and and based on ww-mutexes[2] for lock mechanism.

The purpose of this framework is to provide not only buffer access control
to CPU and DMA but also easy-to-use interfaces for device drivers and
user application. This framework can be used for all dma devices using
system memory as dma buffer, especially for most ARM based SoCs.

Changelog v5:
- Rmove a dependence on reservation_object: the reservation_object is used
  to hook up to ttm and dma-buf for easy sharing of reservations across
  devices. However, the dmabuf sync can be used for all dma devices; v4l2
  and drm based drivers, so doesn't need the reservation_object anymore.
  With regared to this, it adds 'void *sync' to dma_buf structure.
- All patches are rebased on mainline, Linux v3.10.

Changelog v4:
- Add user side interface for buffer synchronization mechanism and update
  descriptions related to the user side interface.

Changelog v3:
- remove cache operation relevant codes and update document file.

Changelog v2:
- use atomic_add_unless to avoid potential bug.
- add a macro for checking valid access type.
- code clean.

The mechanism of this framework has the following steps,
    1. Register dmabufs to a sync object - A task gets a new sync object and
    can add one or more dmabufs that the task wants to access.
    This registering should be performed when a device context or an event
    context such as a page flip event is created or before CPU accesses a shared
    buffer.

	dma_buf_sync_get(a sync object, a dmabuf);

    2. Lock a sync object - A task tries to lock all dmabufs added in its own
    sync object. Basically, the lock mechanism uses ww-mutex[1] to avoid dead
    lock issue and for race condition between CPU and CPU, CPU and DMA, and DMA
    and DMA. Taking a lock means that others cannot access all locked dmabufs
    until the task that locked the corresponding dmabufs, unlocks all the locked
    dmabufs.
    This locking should be performed before DMA or CPU accesses these dmabufs.

	dma_buf_sync_lock(a sync object);

    3. Unlock a sync object - The task unlocks all dmabufs added in its own sync
    object. The unlock means that the DMA or CPU accesses to the dmabufs have
    been completed so that others may access them.
    This unlocking should be performed after DMA or CPU has completed accesses
    to the dmabufs.

	dma_buf_sync_unlock(a sync object);

    4. Unregister one or all dmabufs from a sync object - A task unregisters
    the given dmabufs from the sync object. This means that the task dosen't
    want to lock the dmabufs.
    The unregistering should be performed after DMA or CPU has completed
    accesses to the dmabufs or when dma_buf_sync_lock() is failed.

	dma_buf_sync_put(a sync object, a dmabuf);
	dma_buf_sync_put_all(a sync object);

    The described steps may be summarized as:
	get -> lock -> CPU or DMA access to a buffer/s -> unlock -> put

This framework includes the following two features.
    1. read (shared) and write (exclusive) locks - A task is required to declare
    the access type when the task tries to register a dmabuf;
    READ, WRITE, READ DMA, or WRITE DMA.

    The below is example codes,
	struct dmabuf_sync *sync;

	sync = dmabuf_sync_init(NULL, "test sync");

	dmabuf_sync_get(sync, dmabuf, DMA_BUF_ACCESS_R);
	...

	And the below can be used as access types:
		DMA_BUF_ACCESS_R - CPU will access a buffer for read.
		DMA_BUF_ACCESS_W - CPU will access a buffer for read or write.
		DMA_BUF_ACCESS_DMA_R - DMA will access a buffer for read
		DMA_BUF_ACCESS_DMA_W - DMA will access a buffer for read or
					write.

    2. Mandatory resource releasing - a task cannot hold a lock indefinitely.
    A task may never try to unlock a buffer after taking a lock to the buffer.
    In this case, a timer handler to the corresponding sync object is called
    in five (default) seconds and then the timed-out buffer is unlocked by work
    queue handler to avoid lockups and to enforce resources of the buffer.

The below is how to use interfaces for device driver:
	1. Allocate and Initialize a sync object:
		struct dmabuf_sync *sync;

		sync = dmabuf_sync_init(NULL, "test sync");
		...

	2. Add a dmabuf to the sync object when setting up dma buffer relevant
	   registers:
		dmabuf_sync_get(sync, dmabuf, DMA_BUF_ACCESS_READ);
		...

	3. Lock all dmabufs of the sync object before DMA or CPU accesses
	   the dmabufs:
		dmabuf_sync_lock(sync);
		...

	4. Now CPU or DMA can access all dmabufs locked in step 3.

	5. Unlock all dmabufs added in a sync object after DMA or CPU access
	   to these dmabufs is completed:
		dmabuf_sync_unlock(sync);

	   And call the following functions to release all resources,
		dmabuf_sync_put_all(sync);
		dmabuf_sync_fini(sync);

	You can refer to actual example codes:
		"drm/exynos: add dmabuf sync support for g2d driver" and
		"drm/exynos: add dmabuf sync support for kms framework" from
		https://git.kernel.org/cgit/linux/kernel/git/daeinki/
		drm-exynos.git/log/?h=dmabuf-sync

And this framework includes fcntl system call[3] as interfaces exported
to user. As you know, user sees a buffer object as a dma-buf file descriptor.
So fcntl() call with the file descriptor means to lock some buffer region being
managed by the dma-buf object.

The below is how to use interfaces for user application:
	struct flock filelock;

	1. Lock a dma buf:
		filelock.l_type = F_WRLCK or F_RDLCK;

		/* lock entire region to the dma buf. */
		filelock.lwhence = SEEK_CUR;
		filelock.l_start = 0;
		filelock.l_len = 0;

		fcntl(dmabuf fd, F_SETLKW or F_SETLK, &filelock);
		...
		CPU access to the dma buf

	2. Unlock a dma buf:
		filelock.l_type = F_UNLCK;

		fcntl(dmabuf fd, F_SETLKW or F_SETLK, &filelock);

		close(dmabuf fd) call would also unlock the dma buf. And for more
		detail, please refer to [3]

References:
[1] http://lwn.net/Articles/470339/
[2] https://patchwork.kernel.org/patch/2625361/
[3] http://linux.die.net/man/2/fcntl

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 Documentation/dma-buf-sync.txt |  290 +++++++++++++++++
 drivers/base/Kconfig           |    7 +
 drivers/base/Makefile          |    1 +
 drivers/base/dma-buf.c         |    4 +
 drivers/base/dmabuf-sync.c     |  674 ++++++++++++++++++++++++++++++++++++++++
 include/linux/dma-buf.h        |   16 +
 include/linux/dmabuf-sync.h    |  178 +++++++++++
 7 files changed, 1170 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/dma-buf-sync.txt
 create mode 100644 drivers/base/dmabuf-sync.c
 create mode 100644 include/linux/dmabuf-sync.h

diff --git a/Documentation/dma-buf-sync.txt b/Documentation/dma-buf-sync.txt
new file mode 100644
index 0000000..4427759
--- /dev/null
+++ b/Documentation/dma-buf-sync.txt
@@ -0,0 +1,290 @@
+                    DMA Buffer Synchronization Framework
+                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+                                  Inki Dae
+                      <inki dot dae at samsung dot com>
+                          <daeinki at gmail dot com>
+
+This document is a guide for device-driver writers describing the DMA buffer
+synchronization API. This document also describes how to use the API to
+use buffer synchronization mechanism between DMA and DMA, CPU and DMA, and
+CPU and CPU.
+
+The DMA Buffer synchronization API provides buffer synchronization mechanism;
+i.e., buffer access control to CPU and DMA, and easy-to-use interfaces for
+device drivers and user application. And this API can be used for all dma
+devices using system memory as dma buffer, especially for most ARM based SoCs.
+
+
+Motivation
+----------
+
+Buffer synchronization issue between DMA and DMA:
+	Sharing a buffer, a device cannot be aware of when the other device
+	will access the shared buffer: a device may access a buffer containing
+	wrong data if the device accesses the shared buffer while another
+	device is still accessing the shared buffer.
+	Therefore, a user process should have waited for the completion of DMA
+	access by another device before a device tries to access the shared
+	buffer.
+
+Buffer synchronization issue between CPU and DMA:
+	A user process should consider that when having to send a buffer, filled
+	by CPU, to a device driver for the device driver to access the buffer as
+	a input buffer while CPU and DMA are sharing the buffer.
+	This means that the user process needs to understand how the device
+	driver is worked. Hence, the conventional mechanism not only makes
+	user application complicated but also incurs performance overhead.
+
+Buffer synchronization issue between CPU and CPU:
+	In case that two processes share one buffer; shared with DMA also,
+	they may need some mechanism to allow process B to access the shared
+	buffer after the completion of CPU access by process A.
+	Therefore, process B should have waited for the completion of CPU access
+	by process A using the mechanism before trying to access the shared
+	buffer.
+
+What is the best way to solve these buffer synchronization issues?
+	We may need a common object that a device driver and a user process
+	notify the common object of when they try to access a shared buffer.
+	That way we could decide when we have to allow or not to allow for CPU
+	or DMA to access the shared buffer through the common object.
+	If so, what could become the common object? Right, that's a dma-buf[1].
+	Now we have already been using the dma-buf to share one buffer with
+	other drivers.
+
+How we can utilize multi threads for more performance?
+	DMA and CPU works individually. So CPU could perform other works while
+	DMA are performing some works, and vise versa.
+	However, in the conventional way, that is not easy to do so because
+	DMA operation is depend on CPU operation, and vice versa.
+
+	Conventional way:
+        User                                     Kernel
+        ---------------------------------------------------------------------
+        CPU writes something to src
+        send the src to driver------------------------->
+                                                 update DMA register
+        request DMA start(1)--------------------------->
+                                                 DMA start
+                <---------completion signal(2)----------
+        CPU accesses dst
+
+        (1) Request DMA start after the CPU access to src buffer is completed.
+        (2) Access dst buffer after DMA access to the dst buffer is completed.
+
+On the other hand, if there is something to control buffer access between CPU
+and DMA? The below shows that:
+
+        User(thread a)          User(thread b)            Kernel
+        ---------------------------------------------------------------------
+        send a src to driver---------------------------------->
+                                                          update DMA register
+        lock the src
+                                request DMA start(1)---------->
+        CPU acccess to src
+        unlock the src                                    lock src and dst
+                                                          DMA start
+                <-------------completion signal(2)-------------
+        lock dst                                          DMA completion
+        CPU access to dst                                 unlock src and dst
+        unlock DST
+
+        (1) Try to start DMA operation while CPU is accessing the src buffer.
+        (2) Try CPU access to dst buffer while DMA is accessing the dst buffer.
+
+	In the same way, we could reduce hand shaking overhead between
+	two processes when those processes need to share a shared buffer.
+	There may be other cases that we could reduce overhead as well.
+
+
+Basic concept
+-------------
+
+The mechanism of this framework has the following steps,
+    1. Register dmabufs to a sync object - A task gets a new sync object and
+    can add one or more dmabufs that the task wants to access.
+    This registering should be performed when a device context or an event
+    context such as a page flip event is created or before CPU accesses a shared
+    buffer.
+
+	dma_buf_sync_get(a sync object, a dmabuf);
+
+    2. Lock a sync object - A task tries to lock all dmabufs added in its own
+    sync object. Basically, the lock mechanism uses ww-mutexes[2] to avoid dead
+    lock issue and for race condition between CPU and CPU, CPU and DMA, and DMA
+    and DMA. Taking a lock means that others cannot access all locked dmabufs
+    until the task that locked the corresponding dmabufs, unlocks all the locked
+    dmabufs.
+    This locking should be performed before DMA or CPU accesses these dmabufs.
+
+	dma_buf_sync_lock(a sync object);
+
+    3. Unlock a sync object - The task unlocks all dmabufs added in its own sync
+    object. The unlock means that the DMA or CPU accesses to the dmabufs have
+    been completed so that others may access them.
+    This unlocking should be performed after DMA or CPU has completed accesses
+    to the dmabufs.
+
+	dma_buf_sync_unlock(a sync object);
+
+    4. Unregister one or all dmabufs from a sync object - A task unregisters
+    the given dmabufs from the sync object. This means that the task dosen't
+    want to lock the dmabufs.
+    The unregistering should be performed after DMA or CPU has completed
+    accesses to the dmabufs or when dma_buf_sync_lock() is failed.
+
+	dma_buf_sync_put(a sync object, a dmabuf);
+	dma_buf_sync_put_all(a sync object);
+
+    The described steps may be summarized as:
+	get -> lock -> CPU or DMA access to a buffer/s -> unlock -> put
+
+This framework includes the following two features.
+    1. read (shared) and write (exclusive) locks - A task is required to declare
+    the access type when the task tries to register a dmabuf;
+    READ, WRITE, READ DMA, or WRITE DMA.
+
+    The below is example codes,
+	struct dmabuf_sync *sync;
+
+	sync = dmabuf_sync_init(NULL, "test sync");
+
+	dmabuf_sync_get(sync, dmabuf, DMA_BUF_ACCESS_R);
+	...
+
+    2. Mandatory resource releasing - a task cannot hold a lock indefinitely.
+    A task may never try to unlock a buffer after taking a lock to the buffer.
+    In this case, a timer handler to the corresponding sync object is called
+    in five (default) seconds and then the timed-out buffer is unlocked by work
+    queue handler to avoid lockups and to enforce resources of the buffer.
+
+
+Access types
+------------
+
+DMA_BUF_ACCESS_R - CPU will access a buffer for read.
+DMA_BUF_ACCESS_W - CPU will access a buffer for read or write.
+DMA_BUF_ACCESS_DMA_R - DMA will access a buffer for read
+DMA_BUF_ACCESS_DMA_W - DMA will access a buffer for read or write.
+
+
+Generic user interfaces
+-----------------------
+
+And this framework includes fcntl system call[3] as interfaces exported
+to user. As you know, user sees a buffer object as a dma-buf file descriptor.
+So fcntl() call with the file descriptor means to lock some buffer region being
+managed by the dma-buf object.
+
+
+API set
+-------
+
+bool is_dmabuf_sync_supported(void)
+	- Check if dmabuf sync is supported or not.
+
+struct dmabuf_sync *dmabuf_sync_init(void *priv, const char *name)
+	- Allocate and initialize a new sync object. The caller can get a new
+	sync object for buffer synchronization. priv is used to set caller's
+	private data and name is the name of sync object.
+
+void dmabuf_sync_fini(struct dmabuf_sync *sync)
+	- Release all resources to the sync object.
+
+int dmabuf_sync_get(struct dmabuf_sync *sync, void *sync_buf,
+			unsigned int type)
+	- Get dmabuf sync object. Internally, this function allocates
+	a dmabuf_sync object and adds a given dmabuf to it, and also takes
+	a reference to the dmabuf. The caller can tie up multiple dmabufs
+	into one sync object by calling this function several times.
+
+void dmabuf_sync_put(struct dmabuf_sync *sync, struct dma_buf *dmabuf)
+	- Put dmabuf sync object to a given dmabuf. Internally, this function
+	removes a given dmabuf from a sync object and remove the sync object.
+	At this time, the dmabuf is putted.
+
+void dmabuf_sync_put_all(struct dmabuf_sync *sync)
+	- Put dmabuf sync object to dmabufs. Internally, this function removes
+	all dmabufs from a sync object and remove the sync object.
+	At this time, all dmabufs are putted.
+
+int dmabuf_sync_lock(struct dmabuf_sync *sync)
+	- Lock all dmabufs added in a sync object. The caller should call this
+	function prior to CPU or DMA access to the dmabufs so that others can
+	not access the dmabufs. Internally, this function avoids dead lock
+	issue with ww-mutexes.
+
+int dmabuf_sync_single_lock(struct dma_buf *dmabuf)
+	- Lock a dmabuf. The caller should call this
+	function prior to CPU or DMA access to the dmabuf so that others can
+	not access the dmabuf.
+
+int dmabuf_sync_unlock(struct dmabuf_sync *sync)
+	- Unlock all dmabufs added in a sync object. The caller should call
+	this function after CPU or DMA access to the dmabufs is completed so
+	that others can access the dmabufs.
+
+void dmabuf_sync_single_unlock(struct dma_buf *dmabuf)
+	- Unlock a dmabuf. The caller should call this function after CPU or
+	DMA access to the dmabuf is completed so that others can access
+	the dmabuf.
+
+
+Tutorial for device driver
+--------------------------
+
+1. Allocate and Initialize a sync object:
+	struct dmabuf_sync *sync;
+
+	sync = dmabuf_sync_init(NULL, "test sync");
+	...
+
+2. Add a dmabuf to the sync object when setting up dma buffer relevant registers:
+	dmabuf_sync_get(sync, dmabuf, DMA_BUF_ACCESS_READ);
+	...
+
+3. Lock all dmabufs of the sync object before DMA or CPU accesses the dmabufs:
+	dmabuf_sync_lock(sync);
+	...
+
+4. Now CPU or DMA can access all dmabufs locked in step 3.
+
+5. Unlock all dmabufs added in a sync object after DMA or CPU access to these
+   dmabufs is completed:
+	dmabuf_sync_unlock(sync);
+
+   And call the following functions to release all resources,
+	dmabuf_sync_put_all(sync);
+	dmabuf_sync_fini(sync);
+
+
+Tutorial for user application
+-----------------------------
+	struct flock filelock;
+
+1. Lock a dma buf:
+	filelock.l_type = F_WRLCK or F_RDLCK;
+
+	/* lock entire region to the dma buf. */
+	filelock.lwhence = SEEK_CUR;
+	filelock.l_start = 0;
+	filelock.l_len = 0;
+
+	fcntl(dmabuf fd, F_SETLKW or F_SETLK, &filelock);
+	...
+	CPU access to the dma buf
+
+2. Unlock a dma buf:
+	filelock.l_type = F_UNLCK;
+
+	fcntl(dmabuf fd, F_SETLKW or F_SETLK, &filelock);
+
+	close(dmabuf fd) call would also unlock the dma buf. And for more
+	detail, please refer to [3]
+
+
+References:
+[1] http://lwn.net/Articles/470339/
+[2] https://patchwork.kernel.org/patch/2625361/
+[3] http://linux.die.net/man/2/fcntl
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 5daa259..35e1518 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -200,6 +200,13 @@ config DMA_SHARED_BUFFER
 	  APIs extension; the file's descriptor can then be passed on to other
 	  driver.
 
+config DMABUF_SYNC
+	bool "DMABUF Synchronization Framework"
+	depends on DMA_SHARED_BUFFER
+	help
+	  This option enables dmabuf sync framework for buffer synchronization between
+	  DMA and DMA, CPU and DMA, and CPU and CPU.
+
 config CMA
 	bool "Contiguous Memory Allocator"
 	depends on HAVE_DMA_CONTIGUOUS && HAVE_MEMBLOCK
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 48029aa..e06a5d7 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -11,6 +11,7 @@ obj-y			+= power/
 obj-$(CONFIG_HAS_DMA)	+= dma-mapping.o
 obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
 obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf.o reservation.o
+obj-$(CONFIG_DMABUF_SYNC) += dmabuf-sync.o
 obj-$(CONFIG_ISA)	+= isa.o
 obj-$(CONFIG_FW_LOADER)	+= firmware_class.o
 obj-$(CONFIG_NUMA)	+= node.o
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index 08fe897..9a26981 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -29,6 +29,7 @@
 #include <linux/export.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
+#include <linux/dmabuf-sync.h>
 
 static inline int is_dma_buf_file(struct file *);
 
@@ -56,6 +57,8 @@ static int dma_buf_release(struct inode *inode, struct file *file)
 	list_del(&dmabuf->list_node);
 	mutex_unlock(&db_list.lock);
 
+	dmabuf_sync_reservation_fini(dmabuf);
+
 	kfree(dmabuf);
 	return 0;
 }
@@ -134,6 +137,7 @@ struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops,
 
 	file = anon_inode_getfile("dmabuf", &dma_buf_fops, dmabuf, flags);
 
+	dmabuf_sync_reservation_init(dmabuf);
 	dmabuf->file = file;
 
 	mutex_init(&dmabuf->lock);
diff --git a/drivers/base/dmabuf-sync.c b/drivers/base/dmabuf-sync.c
new file mode 100644
index 0000000..0b83111
--- /dev/null
+++ b/drivers/base/dmabuf-sync.c
@@ -0,0 +1,674 @@
+/*
+ * Copyright (C) 2013 Samsung Electronics Co.Ltd
+ * Authors:
+ *	Inki Dae <inki.dae@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#include <linux/dmabuf-sync.h>
+
+#define MAX_SYNC_TIMEOUT	5 /* Second. */
+
+int dmabuf_sync_enabled = 1;
+
+MODULE_PARM_DESC(enabled, "Check if dmabuf sync is supported or not");
+module_param_named(enabled, dmabuf_sync_enabled, int, 0444);
+
+DEFINE_WW_CLASS(dmabuf_sync_ww_class);
+EXPORT_SYMBOL(dmabuf_sync_ww_class);
+
+static void dmabuf_sync_timeout_worker(struct work_struct *work)
+{
+	struct dmabuf_sync *sync = container_of(work, struct dmabuf_sync, work);
+	struct dmabuf_sync_object *sobj;
+
+	mutex_lock(&sync->lock);
+
+	list_for_each_entry(sobj, &sync->syncs, head) {
+		if (WARN_ON(!sobj->robj))
+			continue;
+
+		mutex_lock(&sobj->robj->lock);
+
+		printk(KERN_WARNING "%s: timeout = 0x%x [type = %d, " \
+					"refcnt = %d, locked = %d]\n",
+					sync->name, (u32)sobj->dmabuf,
+					sobj->access_type,
+					atomic_read(&sobj->robj->shared_cnt),
+					sobj->robj->locked);
+
+		/* unlock only valid sync object. */
+		if (!sobj->robj->locked) {
+			mutex_unlock(&sobj->robj->lock);
+			continue;
+		}
+
+		if (sobj->robj->shared &&
+		    atomic_add_unless(&sobj->robj->shared_cnt, -1, 1)) {
+			mutex_unlock(&sobj->robj->lock);
+			continue;
+		}
+
+		mutex_unlock(&sobj->robj->lock);
+
+		ww_mutex_unlock(&sobj->robj->sync_lock);
+
+		mutex_lock(&sobj->robj->lock);
+
+		if (sobj->access_type & DMA_BUF_ACCESS_R)
+			printk(KERN_WARNING "%s: r-unlocked = 0x%x\n",
+					sync->name, (u32)sobj->dmabuf);
+		else
+			printk(KERN_WARNING "%s: w-unlocked = 0x%x\n",
+					sync->name, (u32)sobj->dmabuf);
+
+		mutex_unlock(&sobj->robj->lock);
+	}
+
+	sync->status = 0;
+	mutex_unlock(&sync->lock);
+
+	dmabuf_sync_put_all(sync);
+	dmabuf_sync_fini(sync);
+}
+
+static void dmabuf_sync_lock_timeout(unsigned long arg)
+{
+	struct dmabuf_sync *sync = (struct dmabuf_sync *)arg;
+
+	schedule_work(&sync->work);
+}
+
+static int dmabuf_sync_lock_objs(struct dmabuf_sync *sync,
+					struct ww_acquire_ctx *ctx)
+{
+	struct dmabuf_sync_object *contended_sobj = NULL;
+	struct dmabuf_sync_object *res_sobj = NULL;
+	struct dmabuf_sync_object *sobj = NULL;
+	int ret;
+
+	if (ctx)
+		ww_acquire_init(ctx, &dmabuf_sync_ww_class);
+
+retry:
+	list_for_each_entry(sobj, &sync->syncs, head) {
+		if (WARN_ON(!sobj->robj))
+			continue;
+
+		mutex_lock(&sobj->robj->lock);
+
+		/* Don't lock in case of read and read. */
+		if (sobj->robj->accessed_type & DMA_BUF_ACCESS_R &&
+		    sobj->access_type & DMA_BUF_ACCESS_R) {
+			atomic_inc(&sobj->robj->shared_cnt);
+			sobj->robj->shared = true;
+			mutex_unlock(&sobj->robj->lock);
+			continue;
+		}
+
+		if (sobj = res_sobj) {
+			res_sobj = NULL;
+			mutex_unlock(&sobj->robj->lock);
+			continue;
+		}
+
+		mutex_unlock(&sobj->robj->lock);
+
+		ret = ww_mutex_lock(&sobj->robj->sync_lock, ctx);
+		if (ret < 0) {
+			contended_sobj = sobj;
+
+			if (ret = -EDEADLK)
+				printk(KERN_WARNING"%s: deadlock = 0x%x\n",
+					sync->name, (u32)sobj->dmabuf);
+			goto err;
+		}
+
+		mutex_lock(&sobj->robj->lock);
+		sobj->robj->locked = true;
+
+		mutex_unlock(&sobj->robj->lock);
+	}
+
+	if (ctx)
+		ww_acquire_done(ctx);
+
+	init_timer(&sync->timer);
+
+	sync->timer.data = (unsigned long)sync;
+	sync->timer.function = dmabuf_sync_lock_timeout;
+	sync->timer.expires = jiffies + (HZ * MAX_SYNC_TIMEOUT);
+
+	add_timer(&sync->timer);
+
+	return 0;
+
+err:
+	list_for_each_entry_continue_reverse(sobj, &sync->syncs, head) {
+		mutex_lock(&sobj->robj->lock);
+
+		/* Don't need to unlock in case of read and read. */
+		if (atomic_add_unless(&sobj->robj->shared_cnt, -1, 1)) {
+			mutex_unlock(&sobj->robj->lock);
+			continue;
+		}
+
+		ww_mutex_unlock(&sobj->robj->sync_lock);
+		sobj->robj->locked = false;
+
+		mutex_unlock(&sobj->robj->lock);
+	}
+
+	if (res_sobj) {
+		mutex_lock(&res_sobj->robj->lock);
+
+		if (!atomic_add_unless(&res_sobj->robj->shared_cnt, -1, 1)) {
+			ww_mutex_unlock(&res_sobj->robj->sync_lock);
+			res_sobj->robj->locked = false;
+		}
+
+		mutex_unlock(&res_sobj->robj->lock);
+	}
+
+	if (ret = -EDEADLK) {
+		ww_mutex_lock_slow(&contended_sobj->robj->sync_lock, ctx);
+		res_sobj = contended_sobj;
+
+		goto retry;
+	}
+
+	if (ctx)
+		ww_acquire_fini(ctx);
+
+	return ret;
+}
+
+static void dmabuf_sync_unlock_objs(struct dmabuf_sync *sync,
+					struct ww_acquire_ctx *ctx)
+{
+	struct dmabuf_sync_object *sobj;
+
+	if (list_empty(&sync->syncs))
+		return;
+
+	mutex_lock(&sync->lock);
+
+	list_for_each_entry(sobj, &sync->syncs, head) {
+		mutex_lock(&sobj->robj->lock);
+
+		if (sobj->robj->shared) {
+			if (atomic_add_unless(&sobj->robj->shared_cnt, -1,
+						1)) {
+				mutex_unlock(&sobj->robj->lock);
+				continue;
+			}
+
+			mutex_unlock(&sobj->robj->lock);
+
+			ww_mutex_unlock(&sobj->robj->sync_lock);
+
+			mutex_lock(&sobj->robj->lock);
+			sobj->robj->shared = false;
+			sobj->robj->locked = false;
+		} else {
+			mutex_unlock(&sobj->robj->lock);
+
+			ww_mutex_unlock(&sobj->robj->sync_lock);
+
+			mutex_lock(&sobj->robj->lock);
+			sobj->robj->locked = false;
+		}
+
+		mutex_unlock(&sobj->robj->lock);
+	}
+
+	mutex_unlock(&sync->lock);
+
+	if (ctx)
+		ww_acquire_fini(ctx);
+
+	del_timer(&sync->timer);
+}
+
+/**
+ * is_dmabuf_sync_supported - Check if dmabuf sync is supported or not.
+ */
+bool is_dmabuf_sync_supported(void)
+{
+	return dmabuf_sync_enabled = 1;
+}
+EXPORT_SYMBOL(is_dmabuf_sync_supported);
+
+/**
+ * dmabuf_sync_init - Allocate and initialize a dmabuf sync.
+ *
+ * @priv: A device private data.
+ * @name: A sync object name.
+ *
+ * This function should be called when a device context or an event
+ * context such as a page flip event is created. And the created
+ * dmabuf_sync object should be set to the context.
+ * The caller can get a new sync object for buffer synchronization
+ * through this function.
+ */
+struct dmabuf_sync *dmabuf_sync_init(void *priv, const char *name)
+{
+	struct dmabuf_sync *sync;
+
+	sync = kzalloc(sizeof(*sync), GFP_KERNEL);
+	if (!sync)
+		return ERR_PTR(-ENOMEM);
+
+	strncpy(sync->name, name, ARRAY_SIZE(sync->name) - 1);
+
+	sync->priv = priv;
+	INIT_LIST_HEAD(&sync->syncs);
+	mutex_init(&sync->lock);
+	INIT_WORK(&sync->work, dmabuf_sync_timeout_worker);
+
+	return sync;
+}
+EXPORT_SYMBOL(dmabuf_sync_init);
+
+/**
+ * dmabuf_sync_fini - Release a given dmabuf sync.
+ *
+ * @sync: An object to dmabuf_sync structure.
+ *
+ * This function should be called if some operation is failed after
+ * dmabuf_sync_init call to release relevant resources, and after
+ * dmabuf_sync_unlock function is called.
+ */
+void dmabuf_sync_fini(struct dmabuf_sync *sync)
+{
+	if (WARN_ON(!sync))
+		return;
+
+	kfree(sync);
+}
+EXPORT_SYMBOL(dmabuf_sync_fini);
+
+/*
+ * dmabuf_sync_get_obj - Add a given object to syncs list.
+ *
+ * @sync: An object to dmabuf_sync structure.
+ * @dmabuf: An object to dma_buf structure.
+ * @type: A access type to a dma buf.
+ *	The DMA_BUF_ACCESS_R means that this dmabuf could be accessed by
+ *	others for read access. On the other hand, the DMA_BUF_ACCESS_W
+ *	means that this dmabuf couldn't be accessed by others but would be
+ *	accessed by caller's dma exclusively. And the DMA_BUF_ACCESS_DMA can be
+ *	combined.
+ *
+ * This function creates and initializes a new dmabuf sync object and it adds
+ * the dmabuf sync object to syncs list to track and manage all dmabufs.
+ */
+static int dmabuf_sync_get_obj(struct dmabuf_sync *sync, struct dma_buf *dmabuf,
+					unsigned int type)
+{
+	struct dmabuf_sync_object *sobj;
+
+	if (!dmabuf->sync) {
+		WARN_ON(1);
+		return -EFAULT;
+	}
+
+	if (!IS_VALID_DMA_BUF_ACCESS_TYPE(type))
+		return -EINVAL;
+
+	if ((type & DMA_BUF_ACCESS_RW) = DMA_BUF_ACCESS_RW)
+		type &= ~DMA_BUF_ACCESS_R;
+
+	sobj = kzalloc(sizeof(*sobj), GFP_KERNEL);
+	if (!sobj) {
+		WARN_ON(1);
+		return -ENOMEM;
+	}
+
+	sobj->dmabuf = dmabuf;
+	sobj->robj = dmabuf->sync;
+
+	mutex_lock(&sync->lock);
+	list_add_tail(&sobj->head, &sync->syncs);
+	mutex_unlock(&sync->lock);
+
+	get_dma_buf(dmabuf);
+
+	mutex_lock(&sobj->robj->lock);
+	sobj->access_type = type;
+	mutex_unlock(&sobj->robj->lock);
+
+	return 0;
+}
+
+/*
+ * dmabuf_sync_put_obj - Release a given sync object.
+ *
+ * @sync: An object to dmabuf_sync structure.
+ *
+ * This function should be called if some operation is failed after
+ * dmabuf_sync_get_obj call to release a given sync object.
+ */
+static void dmabuf_sync_put_obj(struct dmabuf_sync *sync,
+					struct dma_buf *dmabuf)
+{
+	struct dmabuf_sync_object *sobj;
+
+	mutex_lock(&sync->lock);
+
+	list_for_each_entry(sobj, &sync->syncs, head) {
+		if (sobj->dmabuf != dmabuf)
+			continue;
+
+		dma_buf_put(sobj->dmabuf);
+
+		list_del_init(&sobj->head);
+		kfree(sobj);
+		break;
+	}
+
+	if (list_empty(&sync->syncs))
+		sync->status = 0;
+
+	mutex_unlock(&sync->lock);
+}
+
+/*
+ * dmabuf_sync_put_objs - Release all sync objects of dmabuf_sync.
+ *
+ * @sync: An object to dmabuf_sync structure.
+ *
+ * This function should be called if some operation is failed after
+ * dmabuf_sync_get_obj call to release all sync objects.
+ */
+static void dmabuf_sync_put_objs(struct dmabuf_sync *sync)
+{
+	struct dmabuf_sync_object *sobj, *next;
+
+	mutex_lock(&sync->lock);
+
+	list_for_each_entry_safe(sobj, next, &sync->syncs, head) {
+		dma_buf_put(sobj->dmabuf);
+
+		list_del_init(&sobj->head);
+		kfree(sobj);
+	}
+
+	mutex_unlock(&sync->lock);
+
+	sync->status = 0;
+}
+
+/**
+ * dmabuf_sync_lock - lock all dmabufs added to syncs list.
+ *
+ * @sync: An object to dmabuf_sync structure.
+ *
+ * The caller should call this function prior to CPU or DMA access to
+ * the dmabufs so that others can not access the dmabufs.
+ * Internally, this function avoids dead lock issue with ww-mutex.
+ */
+int dmabuf_sync_lock(struct dmabuf_sync *sync)
+{
+	int ret;
+
+	if (!sync) {
+		WARN_ON(1);
+		return -EFAULT;
+	}
+
+	if (list_empty(&sync->syncs))
+		return -EINVAL;
+
+	if (sync->status != DMABUF_SYNC_GOT)
+		return -EINVAL;
+
+	ret = dmabuf_sync_lock_objs(sync, &sync->ctx);
+	if (ret < 0) {
+		WARN_ON(1);
+		return ret;
+	}
+
+	sync->status = DMABUF_SYNC_LOCKED;
+
+	return ret;
+}
+EXPORT_SYMBOL(dmabuf_sync_lock);
+
+/**
+ * dmabuf_sync_unlock - unlock all objects added to syncs list.
+ *
+ * @sync: An object to dmabuf_sync structure.
+ *
+ * The caller should call this function after CPU or DMA access to
+ * the dmabufs is completed so that others can access the dmabufs.
+ */
+int dmabuf_sync_unlock(struct dmabuf_sync *sync)
+{
+	if (!sync) {
+		WARN_ON(1);
+		return -EFAULT;
+	}
+
+	/* If current dmabuf sync object wasn't reserved then just return. */
+	if (sync->status != DMABUF_SYNC_LOCKED)
+		return -EAGAIN;
+
+	dmabuf_sync_unlock_objs(sync, &sync->ctx);
+
+	return 0;
+}
+EXPORT_SYMBOL(dmabuf_sync_unlock);
+
+/**
+ * dmabuf_sync_single_lock - lock a dma buf.
+ *
+ * @dmabuf: A dma buf object that tries to lock.
+ * @type: A access type to a dma buf.
+ *	The DMA_BUF_ACCESS_R means that this dmabuf could be accessed by
+ *	others for read access. On the other hand, the DMA_BUF_ACCESS_W
+ *	means that this dmabuf couldn't be accessed by others but would be
+ *	accessed by caller's dma exclusively. And the DMA_BUF_ACCESS_DMA can
+ *	be combined with other.
+ * @wait: Indicate whether caller is blocked or not.
+ *	true means that caller will be blocked, and false means that this
+ *	function will return -EAGAIN if this caller can't take the lock
+ *	right now.
+ *
+ * The caller should call this function prior to CPU or DMA access to the dmabuf
+ * so that others cannot access the dmabuf.
+ */
+int dmabuf_sync_single_lock(struct dma_buf *dmabuf, unsigned int type,
+				bool wait)
+{
+	struct dmabuf_sync_reservation *robj;
+
+	if (!dmabuf->sync) {
+		WARN_ON(1);
+		return -EFAULT;
+	}
+
+	if (!IS_VALID_DMA_BUF_ACCESS_TYPE(type)) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	get_dma_buf(dmabuf);
+	robj = dmabuf->sync;
+
+	mutex_lock(&robj->lock);
+
+	/* Don't lock in case of read and read. */
+	if (robj->accessed_type & DMA_BUF_ACCESS_R && type & DMA_BUF_ACCESS_R) {
+		atomic_inc(&robj->shared_cnt);
+		robj->shared = true;
+		mutex_unlock(&robj->lock);
+		return 0;
+	}
+
+	/*
+	 * In case of F_SETLK, just return -EAGAIN if this dmabuf has already
+	 * been locked.
+	 */
+	if (!wait && robj->locked) {
+		mutex_unlock(&robj->lock);
+		dma_buf_put(dmabuf);
+		return -EAGAIN;
+	}
+
+	mutex_unlock(&robj->lock);
+
+	mutex_lock(&robj->sync_lock.base);
+
+	mutex_lock(&robj->lock);
+	robj->locked = true;
+	mutex_unlock(&robj->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(dmabuf_sync_single_lock);
+
+/**
+ * dmabuf_sync_single_unlock - unlock a dma buf.
+ *
+ * @dmabuf: A dma buf object that tries to unlock.
+ *
+ * The caller should call this function after CPU or DMA access to
+ * the dmabuf is completed so that others can access the dmabuf.
+ */
+void dmabuf_sync_single_unlock(struct dma_buf *dmabuf)
+{
+	struct dmabuf_sync_reservation *robj;
+
+	if (!dmabuf->sync) {
+		WARN_ON(1);
+		return;
+	}
+
+	robj = dmabuf->sync;
+
+	mutex_lock(&robj->lock);
+
+	if (robj->shared) {
+		if (atomic_add_unless(&robj->shared_cnt, -1 , 1)) {
+			mutex_unlock(&robj->lock);
+			return;
+		}
+
+		robj->shared = false;
+	}
+
+	mutex_unlock(&robj->lock);
+
+	mutex_unlock(&robj->sync_lock.base);
+
+	mutex_lock(&robj->lock);
+	robj->locked = false;
+	mutex_unlock(&robj->lock);
+
+	dma_buf_put(dmabuf);
+
+	return;
+}
+EXPORT_SYMBOL(dmabuf_sync_single_unlock);
+
+/**
+ * dmabuf_sync_get - Get dmabuf sync object.
+ *
+ * @sync: An object to dmabuf_sync structure.
+ * @sync_buf: A dmabuf object to be synchronized with others.
+ * @type: A access type to a dma buf.
+ *	The DMA_BUF_ACCESS_R means that this dmabuf could be accessed by
+ *	others for read access. On the other hand, the DMA_BUF_ACCESS_W
+ *	means that this dmabuf couldn't be accessed by others but would be
+ *	accessed by caller's dma exclusively. And the DMA_BUF_ACCESS_DMA can
+ *	be combined with other.
+ *
+ * This function should be called after dmabuf_sync_init function is called.
+ * The caller can tie up multiple dmabufs into one sync object by calling this
+ * function several times. Internally, this function allocates
+ * a dmabuf_sync_object and adds a given dmabuf to it, and also takes
+ * a reference to a dmabuf.
+ */
+int dmabuf_sync_get(struct dmabuf_sync *sync, void *sync_buf, unsigned int type)
+{
+	int ret;
+
+	if (!sync || !sync_buf) {
+		WARN_ON(1);
+		return -EFAULT;
+	}
+
+	ret = dmabuf_sync_get_obj(sync, sync_buf, type);
+	if (ret < 0) {
+		WARN_ON(1);
+		return ret;
+	}
+
+	sync->status = DMABUF_SYNC_GOT;
+
+	return 0;
+}
+EXPORT_SYMBOL(dmabuf_sync_get);
+
+/**
+ * dmabuf_sync_put - Put dmabuf sync object to a given dmabuf.
+ *
+ * @sync: An object to dmabuf_sync structure.
+ * @dmabuf: An dmabuf object.
+ *
+ * This function should be called if some operation is failed after
+ * dmabuf_sync_get function is called to release the dmabuf, or
+ * dmabuf_sync_unlock function is called. Internally, this function
+ * removes a given dmabuf from a sync object and remove the sync object.
+ * At this time, the dmabuf is putted.
+ */
+void dmabuf_sync_put(struct dmabuf_sync *sync, struct dma_buf *dmabuf)
+{
+	if (!sync || !dmabuf) {
+		WARN_ON(1);
+		return;
+	}
+
+	if (list_empty(&sync->syncs))
+		return;
+
+	dmabuf_sync_put_obj(sync, dmabuf);
+}
+EXPORT_SYMBOL(dmabuf_sync_put);
+
+/**
+ * dmabuf_sync_put_all - Put dmabuf sync object to dmabufs.
+ *
+ * @sync: An object to dmabuf_sync structure.
+ *
+ * This function should be called if some operation is failed after
+ * dmabuf_sync_get function is called to release all sync objects, or
+ * dmabuf_sync_unlock function is called. Internally, this function
+ * removes dmabufs from a sync object and remove the sync object.
+ * At this time, all dmabufs are putted.
+ */
+void dmabuf_sync_put_all(struct dmabuf_sync *sync)
+{
+	if (!sync) {
+		WARN_ON(1);
+		return;
+	}
+
+	if (list_empty(&sync->syncs))
+		return;
+
+	dmabuf_sync_put_objs(sync);
+}
+EXPORT_SYMBOL(dmabuf_sync_put_all);
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
index dfac5ed..0109673 100644
--- a/include/linux/dma-buf.h
+++ b/include/linux/dma-buf.h
@@ -115,6 +115,7 @@ struct dma_buf_ops {
  * @exp_name: name of the exporter; useful for debugging.
  * @list_node: node for dma_buf accounting and debugging.
  * @priv: exporter specific private data for this buffer object.
+ * @sync: sync object linked to this dma-buf
  */
 struct dma_buf {
 	size_t size;
@@ -128,6 +129,7 @@ struct dma_buf {
 	const char *exp_name;
 	struct list_head list_node;
 	void *priv;
+	void *sync;
 };
 
 /**
@@ -148,6 +150,20 @@ struct dma_buf_attachment {
 	void *priv;
 };
 
+#define	DMA_BUF_ACCESS_R	0x1
+#define DMA_BUF_ACCESS_W	0x2
+#define DMA_BUF_ACCESS_DMA	0x4
+#define DMA_BUF_ACCESS_RW	(DMA_BUF_ACCESS_R | DMA_BUF_ACCESS_W)
+#define DMA_BUF_ACCESS_DMA_R	(DMA_BUF_ACCESS_R | DMA_BUF_ACCESS_DMA)
+#define DMA_BUF_ACCESS_DMA_W	(DMA_BUF_ACCESS_W | DMA_BUF_ACCESS_DMA)
+#define DMA_BUF_ACCESS_DMA_RW	(DMA_BUF_ACCESS_DMA_R | DMA_BUF_ACCESS_DMA_W)
+#define IS_VALID_DMA_BUF_ACCESS_TYPE(t)	(t = DMA_BUF_ACCESS_R || \
+					 t = DMA_BUF_ACCESS_W || \
+					 t = DMA_BUF_ACCESS_DMA_R || \
+					 t = DMA_BUF_ACCESS_DMA_W || \
+					 t = DMA_BUF_ACCESS_RW || \
+					 t = DMA_BUF_ACCESS_DMA_RW)
+
 /**
  * get_dma_buf - convenience wrapper for get_file.
  * @dmabuf:	[in]	pointer to dma_buf
diff --git a/include/linux/dmabuf-sync.h b/include/linux/dmabuf-sync.h
new file mode 100644
index 0000000..2502ad6
--- /dev/null
+++ b/include/linux/dmabuf-sync.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2013 Samsung Electronics Co.Ltd
+ * Authors:
+ *	Inki Dae <inki.dae@samsung.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/dma-buf.h>
+
+enum dmabuf_sync_status {
+	DMABUF_SYNC_GOT		= 1,
+	DMABUF_SYNC_LOCKED,
+};
+
+struct dmabuf_sync_reservation {
+	struct ww_mutex		sync_lock;
+	struct mutex		lock;
+	atomic_t		shared_cnt;
+	unsigned int		accessed_type;
+	unsigned int		shared;
+	unsigned int		locked;
+};
+
+/*
+ * A structure for dmabuf_sync_object.
+ *
+ * @head: A list head to be added to syncs list.
+ * @robj: A reservation_object object.
+ * @dma_buf: A dma_buf object.
+ * @access_type: Indicate how a current task tries to access
+ *	a given buffer.
+ */
+struct dmabuf_sync_object {
+	struct list_head		head;
+	struct dmabuf_sync_reservation	*robj;
+	struct dma_buf			*dmabuf;
+	unsigned int			access_type;
+};
+
+/*
+ * A structure for dmabuf_sync.
+ *
+ * @syncs: A list head to sync object and this is global to system.
+ * @list: A list entry used as committed list node
+ * @lock: A mutex lock to current sync object.
+ * @ctx: A current context for ww mutex.
+ * @work: A work struct to release resources at timeout.
+ * @priv: A private data.
+ * @name: A string to dmabuf sync owner.
+ * @timer: A timer list to avoid lockup and release resources.
+ * @status: Indicate current status (DMABUF_SYNC_GOT or DMABUF_SYNC_LOCKED).
+ */
+struct dmabuf_sync {
+	struct list_head	syncs;
+	struct list_head	list;
+	struct mutex		lock;
+	struct ww_acquire_ctx	ctx;
+	struct work_struct	work;
+	void			*priv;
+	char			name[64];
+	struct timer_list	timer;
+	unsigned int		status;
+};
+
+#ifdef CONFIG_DMABUF_SYNC
+
+extern struct ww_class dmabuf_sync_ww_class;
+
+static inline void dmabuf_sync_reservation_init(struct dma_buf *dmabuf)
+{
+	struct dmabuf_sync_reservation *obj;
+
+	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+	if (!obj)
+		return;
+
+	dmabuf->sync = obj;
+
+	ww_mutex_init(&obj->sync_lock, &dmabuf_sync_ww_class);
+
+	mutex_init(&obj->lock);
+	atomic_set(&obj->shared_cnt, 1);
+}
+
+static inline void dmabuf_sync_reservation_fini(struct dma_buf *dmabuf)
+{
+	struct dmabuf_sync_reservation *obj;
+
+	if (!dmabuf->sync)
+		return;
+
+	obj = dmabuf->sync;
+
+	ww_mutex_destroy(&obj->sync_lock);
+
+	kfree(obj);
+}
+
+extern bool is_dmabuf_sync_supported(void);
+
+extern struct dmabuf_sync *dmabuf_sync_init(void *priv, const char *name);
+
+extern void dmabuf_sync_fini(struct dmabuf_sync *sync);
+
+extern int dmabuf_sync_lock(struct dmabuf_sync *sync);
+
+extern int dmabuf_sync_unlock(struct dmabuf_sync *sync);
+
+int dmabuf_sync_single_lock(struct dma_buf *dmabuf, unsigned int type,
+				bool wait);
+
+void dmabuf_sync_single_unlock(struct dma_buf *dmabuf);
+
+extern int dmabuf_sync_get(struct dmabuf_sync *sync, void *sync_buf,
+				unsigned int type);
+
+extern void dmabuf_sync_put(struct dmabuf_sync *sync, struct dma_buf *dmabuf);
+
+extern void dmabuf_sync_put_all(struct dmabuf_sync *sync);
+
+#else
+
+static inline void dmabuf_sync_reservation_init(struct dma_buf *dmabuf) { }
+
+static inline void dmabuf_sync_reservation_fini(struct dma_buf *dmabuf) { }
+
+static inline bool is_dmabuf_sync_supported(void) { return false; }
+
+static inline struct dmabuf_sync *dmabuf_sync_init(void *priv,
+					const char *names)
+{
+	return ERR_PTR(0);
+}
+
+static inline void dmabuf_sync_fini(struct dmabuf_sync *sync) { }
+
+static inline int dmabuf_sync_lock(struct dmabuf_sync *sync)
+{
+	return 0;
+}
+
+static inline int dmabuf_sync_unlock(struct dmabuf_sync *sync)
+{
+	return 0;
+}
+
+static inline int dmabuf_sync_single_lock(struct dma_buf *dmabuf,
+						unsigned int type,
+						bool wait)
+{
+	return 0;
+}
+
+static inline void dmabuf_sync_single_unlock(struct dma_buf *dmabuf)
+{
+	return;
+}
+
+static inline int dmabuf_sync_get(struct dmabuf_sync *sync,
+					void *sync_buf,
+					unsigned int type)
+{
+	return 0;
+}
+
+static inline void dmabuf_sync_put(struct dmabuf_sync *sync,
+					struct dma_buf *dmabuf) { }
+
+static inline void dmabuf_sync_put_all(struct dmabuf_sync *sync) { }
+
+#endif
-- 
1.7.5.4


^ permalink raw reply related

* [RFC PATCH 0/2 v5] Introduce buffer synchronization framework
From: Inki Dae @ 2013-07-12  6:12 UTC (permalink / raw)
  To: dri-devel, linux-fbdev, linux-arm-kernel, linux-media
  Cc: maarten.lankhorst, daniel, robdclark, sumit.semwal, linux,
	kyungmin.park, myungjoo.ham, yj44.cho, Inki Dae

Hi all,

This patch set introduces a buffer synchronization framework based
on DMA BUF[1] and based on ww-mutexes[2] for lock mechanism.

The purpose of this framework is to provide not only buffer access
control to CPU and CPU, and CPU and DMA, and DMA and DMA but also
easy-to-use interfaces for device drivers and user application.
In addtion, this patch set suggests a way for enhancing performance.

For generic user mode interface, we have used fcntl system call[3].
As you know, user application sees a buffer object as a dma-buf file
descriptor. So fcntl() call with the file descriptor means to lock
some buffer region being managed by the dma-buf object.
For more detail, you can refer to the dma-buf-sync.txt in Documentation/

Moreover, we had tried to find how we could utilize limited hardware
resources more using buffer synchronization mechanism. And finally,
we have realized that it could enhance performance using multi threads
with this buffer synchronization mechanism: DMA and CPU works individually
so CPU could perform other works while DMA is performing some works,
and vise versa.

However, in the conventional way, that is not easy to do so because DMA
operation is depend on CPU operation, and vice versa.

Conventional way:
        User                                     Kernel
        ---------------------------------------------------------------------
        CPU writes something to src
        send the src to driver------------------------->
                                                 update DMA register
        request DMA start(1)--------------------------->
                                                 DMA start
                <---------completion signal(2)----------
        CPU accesses dst

        (1) Request DMA start after the CPU access to src buffer is completed.
        (2) Access dst buffer after DMA access to the dst buffer is completed.

On the other hand, if there is something to control buffer access between CPU
and DMA? The below shows that:

        User(thread a)          User(thread b)            Kernel
        ---------------------------------------------------------------------
        send a src to driver---------------------------------->
                                                          update DMA register
        lock the src
                                request DMA start(1)---------->
        CPU acccess to src
        unlock the src                                    lock src and dst
                                                          DMA start
                <-------------completion signal(2)-------------
        lock dst                                          DMA completion
        CPU access to dst                                 unlock src and dst
        unlock DST

        (1) Try to start DMA operation while CPU is accessing the src buffer.
        (2) Try CPU access to dst buffer while DMA is accessing the dst buffer.

	This means that CPU or DMA could do more works.

	In the same way, we could reduce hand shaking overhead between
	two processes when those processes need to share a shared buffer.
	There may be other cases that we could reduce overhead as well.


References:
[1] http://lwn.net/Articles/470339/
[2] https://patchwork.kernel.org/patch/2625361/
[3] http://linux.die.net/man/2/fcntl


Inki Dae (2):
  [RFC PATCH v5 1/2] dmabuf-sync: Introduce buffer synchronization framework
  [RFC PATCH v1 2/2] dma-buf: add lock callback for fcntl system call

 Documentation/dma-buf-sync.txt |  290 +++++++++++++++++
 drivers/base/Kconfig           |    7 +
 drivers/base/Makefile          |    1 +
 drivers/base/dma-buf.c         |   37 +++
 drivers/base/dmabuf-sync.c     |  674 ++++++++++++++++++++++++++++++++++++++++
 include/linux/dma-buf.h        |   16 +
 include/linux/dmabuf-sync.h    |  178 +++++++++++
 7 files changed, 1203 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/dma-buf-sync.txt
 create mode 100644 drivers/base/dmabuf-sync.c
 create mode 100644 include/linux/dmabuf-sync.h

-- 
1.7.5.4


^ permalink raw reply

* [PATCH 5/5] Documentation: DT: Add DCU framebuffer driver
From: Alison Wang @ 2013-07-12  6:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1373609276-14566-1-git-send-email-b18965@freescale.com>

This patch adds the document for DCU framebuffer driver under
Documentation/devicetree/bindings/fb/.

Signed-off-by: Alison Wang <b18965@freescale.com>
---
Changes in v2: New
- Add this document for DCU framebuffer driver.

 .../devicetree/bindings/fb/fsl-dcu-fb.txt          | 36 ++++++++++++++++++++++
 1 file changed, 36 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt

diff --git a/Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt b/Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt
new file mode 100644
index 0000000..231bda7
--- /dev/null
+++ b/Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt
@@ -0,0 +1,36 @@
+* Freescale Display Control Unit (DCU)
+
+Required properties:
+- compatible: Should be "fsl,vf610-dcu". Supported chips include
+  Vybrid VF610.
+- reg: Address and length of the register set for DCU.
+- interrupts: Should contain DCU interrupts.
+- clocks: From common clock binding: handle to DCU clock.
+- clock-names: From common clock binding: Shall be "dcu".
+- tcon-controller: The phandle of TCON controller.
+
+For the DCU initialization, we read data from TCON node.
+Required properties for TCON:
+- compatible: Should be "fsl,vf610-tcon". Supported chips include
+  Vybrid VF610.
+- reg: Address and length of the register set for TCON.
+- clocks: From common clock binding: handle to TCON clock.
+- clock-names: From common clock binding: Shall be "tcon".
+
+Examples:
+
+dcu0: dcu@40058000 {
+	compatible = "fsl,vf610-dcu";
+	reg = <0x40058000 0x1200>;
+	interrupts = <0 30 0x04>;
+	clocks = <&clks VF610_CLK_DCU0>;
+	clock-names = "dcu";
+	tcon-controller = <&tcon0>;
+};
+
+tcon0: tcon@4003d000 {
+	compatible = "fsl,vf610-tcon";
+	reg = <0x4003d000 0x1000>;
+	clocks = <&clks VF610_CLK_TCON0>;
+	clock-names = "tcon";
+};
-- 
1.8.0



^ permalink raw reply related

* [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform
From: Alison Wang @ 2013-07-12  6:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1373609276-14566-1-git-send-email-b18965@freescale.com>

The Display Controller Unit (DCU) module is a system master that
fetches graphics stored in internal or external memory and displays
them on a TFT LCD panel. A wide range of panel sizes is supported
and the timing of the interface signals is highly configurable.
Graphics are read directly from memory and then blended in real-time,
which allows for dynamic content creation with minimal CPU intervention.

The features:

(1) Full RGB888 output to TFT LCD panel.
(2) For the current LCD panel, WQVGA "480x272" is tested.
(3) Blending of each pixel using up to 4 source layers dependent on size of panel.
(4) Each graphic layer can be placed with one pixel resolution in either axis.
(5) Each graphic layer support RGB565 and RGB888 direct colors without alpha channel
and BGRA8888 direct colors with an alpha channel.
(6) Each graphic layer support alpha blending with 8-bit resolution.

This driver has been tested on Vybrid VF610 TOWER board.

Signed-off-by: Alison Wang <b18965@freescale.com>
---
Changes in v2: None

 drivers/video/Kconfig      |    9 +
 drivers/video/Makefile     |    1 +
 drivers/video/fsl-dcu-fb.c | 1091 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1101 insertions(+)
 create mode 100644 drivers/video/fsl-dcu-fb.c

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 46544d0..32dc1f8 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1978,6 +1978,15 @@ config FB_FSL_DIU
 	---help---
 	  Framebuffer driver for the Freescale SoC DIU
 
+config FB_FSL_DCU
+	tristate "Freescale DCU framebuffer support"
+	depends on FB
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	---help---
+	  Framebuffer driver for the Freescale SoC DCU
+
 config FB_W100
 	tristate "W100 frame buffer support"
 	depends on FB && ARCH_PXA
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index e8bae8d..3707a7d 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -129,6 +129,7 @@ obj-$(CONFIG_FB_IMX)              += imxfb.o
 obj-$(CONFIG_FB_S3C)		  += s3c-fb.o
 obj-$(CONFIG_FB_S3C2410)	  += s3c2410fb.o
 obj-$(CONFIG_FB_FSL_DIU)	  += fsl-diu-fb.o
+obj-$(CONFIG_FB_FSL_DCU)	  += fsl-dcu-fb.o
 obj-$(CONFIG_FB_COBALT)           += cobalt_lcdfb.o
 obj-$(CONFIG_FB_IBM_GXT4500)	  += gxt4500.o
 obj-$(CONFIG_FB_PS3)		  += ps3fb.o
diff --git a/drivers/video/fsl-dcu-fb.c b/drivers/video/fsl-dcu-fb.c
new file mode 100644
index 0000000..5571dde
--- /dev/null
+++ b/drivers/video/fsl-dcu-fb.c
@@ -0,0 +1,1091 @@
+/*
+ * Copyright 2012-2013 Freescale Semiconductor, Inc.
+ *
+ * Freescale DCU Frame Buffer device driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#define DRIVER_NAME			"fsl-dcu-fb"
+
+#define DCU_DCU_MODE			0x0010
+#define DCU_MODE_BLEND_ITER(x)		(x << 20)
+#define DCU_MODE_RASTER_EN		(1 << 14)
+#define DCU_MODE_DCU_MODE(x)		(x)
+#define DCU_MODE_DCU_MODE_MASK		0x03
+#define DCU_MODE_OFF			0
+#define DCU_MODE_NORMAL			1
+#define DCU_MODE_TEST			2
+#define DCU_MODE_COLORBAR		3
+
+#define DCU_BGND			0x0014
+#define DCU_BGND_R(x)			(x << 16)
+#define DCU_BGND_G(x)			(x << 8)
+#define DCU_BGND_B(x)			(x)
+
+#define DCU_DISP_SIZE			0x0018
+#define DCU_DISP_SIZE_DELTA_Y(x)	(x << 16)
+#define DCU_DISP_SIZE_DELTA_X(x)	(x)
+
+#define DCU_HSYN_PARA			0x001c
+#define DCU_HSYN_PARA_BP(x)		(x << 22)
+#define DCU_HSYN_PARA_PW(x)		(x << 11)
+#define DCU_HSYN_PARA_FP(x)		(x)
+
+#define DCU_VSYN_PARA			0x0020
+#define DCU_VSYN_PARA_BP(x)		(x << 22)
+#define DCU_VSYN_PARA_PW(x)		(x << 11)
+#define DCU_VSYN_PARA_FP(x)		(x)
+
+#define DCU_SYN_POL			0x0024
+#define DCU_SYN_POL_INV_PXCK_FALL	(0 << 6)
+#define DCU_SYN_POL_NEG_REMAIN		(0 << 5)
+#define DCU_SYN_POL_INV_VS_LOW		(1 << 1)
+#define DCU_SYN_POL_INV_HS_LOW		(1)
+
+#define DCU_THRESHOLD			0x0028
+#define DCU_THRESHOLD_LS_BF_VS(x)	(x << 16)
+#define DCU_THRESHOLD_OUT_BUF_HIGH(x)	(x << 8)
+#define DCU_THRESHOLD_OUT_BUF_LOW(x)	(x)
+
+#define DCU_INT_STATUS			0x002C
+#define DCU_INT_STATUS_UNDRUN		(1 << 1)
+
+#define DCU_INT_MASK			0x0030
+#define DCU_INT_MASK_UNDRUN		(1 << 1)
+
+#define DCU_DIV_RATIO			0x0054
+
+#define DCU_UPDATE_MODE			0x00cc
+#define DCU_UPDATE_MODE_MODE		(1 << 31)
+#define DCU_UPDATE_MODE_READREG		(1 << 30)
+
+#define DCU_CTRLDESCLN_1(x)		(0x200 + (x) * 0x40)
+#define DCU_CTRLDESCLN_1_HEIGHT(x)	(x << 16)
+#define DCU_CTRLDESCLN_1_WIDTH(x)	(x)
+
+#define DCU_CTRLDESCLN_2(x)		(0x204 + (x) * 0x40)
+#define DCU_CTRLDESCLN_2_POSY(x)	(x << 16)
+#define DCU_CTRLDESCLN_2_POSX(x)	(x)
+
+#define DCU_CTRLDESCLN_3(x)		(0x208 + (x) * 0x40)
+
+#define DCU_CTRLDESCLN_4(x)		(0x20c + (x) * 0x40)
+#define DCU_CTRLDESCLN_4_EN		(1 << 31)
+#define DCU_CTRLDESCLN_4_TILE_EN	(1 << 30)
+#define DCU_CTRLDESCLN_4_DATA_SEL_CLUT	(1 << 29)
+#define DCU_CTRLDESCLN_4_SAFETY_EN	(1 << 28)
+#define DCU_CTRLDESCLN_4_TRANS(x)	(x << 20)
+#define DCU_CTRLDESCLN_4_BPP(x)		(x << 16)
+#define DCU_CTRLDESCLN_4_RLE_EN		(1 << 15)
+#define DCU_CTRLDESCLN_4_LUOFFS(x)	(x << 4)
+#define DCU_CTRLDESCLN_4_BB_ON		(1 << 2)
+#define DCU_CTRLDESCLN_4_AB(x)		(x)
+
+#define DCU_CTRLDESCLN_5(x)		(0x210 + (x) * 0x40)
+#define DCU_CTRLDESCLN_5_CKMAX_R(x)	(x << 16)
+#define DCU_CTRLDESCLN_5_CKMAX_G(x)	(x << 8)
+#define DCU_CTRLDESCLN_5_CKMAX_B(x)	(x)
+
+#define DCU_CTRLDESCLN_6(x)		(0x214 + (x) * 0x40)
+#define DCU_CTRLDESCLN_6_CKMIN_R(x)	(x << 16)
+#define DCU_CTRLDESCLN_6_CKMIN_G(x)	(x << 8)
+#define DCU_CTRLDESCLN_6_CKMIN_B(x)	(x)
+
+#define DCU_CTRLDESCLN_7(x)		(0x218 + (x) * 0x40)
+#define DCU_CTRLDESCLN_7_TILE_VER(x)	(x << 16)
+#define DCU_CTRLDESCLN_7_TILE_HOR(x)	(x)
+
+#define DCU_CTRLDESCLN_8(x)		(0x21c + (x) * 0x40)
+#define DCU_CTRLDESCLN_8_FG_FCOLOR(x)	(x)
+
+#define DCU_CTRLDESCLN_9(x)		(0x220 + (x) * 0x40)
+#define DCU_CTRLDESCLN_9_BG_BCOLOR(x)	(x)
+
+#define DCU_TOTAL_LAYER_NUM		64
+#define DCU_LAYER_NUM_MAX		6
+#define DCU_LAYER_NUM			4
+
+#define BPP_16_RGB565			4
+#define BPP_24_RGB888			5
+#define BPP_32_ARGB8888			6
+
+#define TCON_CTRL1			0x0000
+#define TCON_BYPASS_ENABLE		(1 << 29)
+
+#define MFB_SET_ALPHA		_IOW('M', 0, __u8)
+#define MFB_GET_ALPHA		_IOR('M', 0, __u8)
+#define MFB_SET_LAYER		_IOW('M', 4, struct layer_display_offset)
+#define MFB_GET_LAYER		_IOR('M', 4, struct layer_display_offset)
+
+static char *fb_mode;
+static unsigned int default_bpp = 24;
+
+static struct fb_videomode dcu_mode_db[] = {
+	{
+		.name		= "480x272",
+		.refresh	= 75,
+		.xres		= 480,
+		.yres		= 272,
+		.pixclock	= 91996,
+		.left_margin	= 2,
+		.right_margin	= 2,
+		.upper_margin	= 1,
+		.lower_margin	= 1,
+		.hsync_len	= 41,
+		.vsync_len	= 2,
+		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+};
+
+/* DCU framebuffer data structure */
+struct dcu_fb_data {
+	struct fb_info *fsl_dcu_info[DCU_LAYER_NUM];
+	void __iomem *reg_base;
+	unsigned int irq;
+	struct clk *clk;
+};
+
+struct layer_display_offset {
+	int x_layer_d;
+	int y_layer_d;
+};
+
+struct mfb_info {
+	int index;
+	char *id;
+	unsigned long pseudo_palette[16];
+	unsigned char alpha;
+	unsigned char blend;
+	unsigned int count;
+	int x_layer_d;	/* layer display x offset to physical screen */
+	int y_layer_d;	/* layer display y offset to physical screen */
+	struct dcu_fb_data *parent;
+};
+
+enum mfb_index {
+	LAYER0 = 0,
+	LAYER1,
+	LAYER2,
+	LAYER3,
+};
+
+static struct mfb_info mfb_template[] = {
+	{
+	.index = LAYER0,
+	.id = "Layer0",
+	.alpha = 0xff,
+	.blend = 0,
+	.count = 0,
+	.x_layer_d = 0,
+	.y_layer_d = 0,
+	},
+	{
+	.index = LAYER1,
+	.id = "Layer1",
+	.alpha = 0xff,
+	.blend = 0,
+	.count = 0,
+	.x_layer_d = 50,
+	.y_layer_d = 50,
+	},
+	{
+	.index = LAYER2,
+	.id = "Layer2",
+	.alpha = 0xff,
+	.blend = 0,
+	.count = 0,
+	.x_layer_d = 100,
+	.y_layer_d = 100,
+	},
+	{
+	.index = LAYER3,
+	.id = "Layer3",
+	.alpha = 0xff,
+	.blend = 0,
+	.count = 0,
+	.x_layer_d = 150,
+	.y_layer_d = 150,
+	},
+};
+
+static int enable_panel(struct fb_info *info)
+{
+	struct fb_var_screeninfo *var = &info->var;
+	struct mfb_info *mfbi = info->par;
+	struct dcu_fb_data *dcufb = mfbi->parent;
+	unsigned int bpp;
+
+	writel(DCU_CTRLDESCLN_1_HEIGHT(var->yres) |
+		DCU_CTRLDESCLN_1_WIDTH(var->xres),
+		dcufb->reg_base + DCU_CTRLDESCLN_1(mfbi->index));
+	writel(DCU_CTRLDESCLN_2_POSY(mfbi->y_layer_d) |
+		DCU_CTRLDESCLN_2_POSX(mfbi->x_layer_d),
+		dcufb->reg_base + DCU_CTRLDESCLN_2(mfbi->index));
+
+	writel(info->fix.smem_start,
+		dcufb->reg_base + DCU_CTRLDESCLN_3(mfbi->index));
+
+	switch (var->bits_per_pixel) {
+	case 16:
+		bpp = BPP_16_RGB565;
+		break;
+	case 24:
+		bpp = BPP_24_RGB888;
+		break;
+	case 32:
+		bpp = BPP_32_ARGB8888;
+		break;
+	default:
+		printk(KERN_ERR "unsupported color depth: %u\n",
+			var->bits_per_pixel);
+		return -EINVAL;
+	}
+
+	writel(DCU_CTRLDESCLN_4_EN |
+		DCU_CTRLDESCLN_4_TRANS(mfbi->alpha) |
+		DCU_CTRLDESCLN_4_BPP(bpp) |
+		DCU_CTRLDESCLN_4_AB(mfbi->blend),
+		dcufb->reg_base + DCU_CTRLDESCLN_4(mfbi->index));
+
+	writel(DCU_CTRLDESCLN_5_CKMAX_R(0xff) |
+		DCU_CTRLDESCLN_5_CKMAX_G(0xff) |
+		DCU_CTRLDESCLN_5_CKMAX_B(0xff),
+		dcufb->reg_base + DCU_CTRLDESCLN_5(mfbi->index));
+	writel(DCU_CTRLDESCLN_6_CKMIN_R(0) |
+		DCU_CTRLDESCLN_6_CKMIN_G(0) |
+		DCU_CTRLDESCLN_6_CKMIN_B(0),
+		dcufb->reg_base + DCU_CTRLDESCLN_6(mfbi->index));
+
+	writel(DCU_CTRLDESCLN_7_TILE_VER(0) | DCU_CTRLDESCLN_7_TILE_HOR(0),
+		dcufb->reg_base + DCU_CTRLDESCLN_7(mfbi->index));
+
+	writel(DCU_CTRLDESCLN_8_FG_FCOLOR(0),
+		dcufb->reg_base + DCU_CTRLDESCLN_8(mfbi->index));
+	writel(DCU_CTRLDESCLN_9_BG_BCOLOR(0),
+		dcufb->reg_base + DCU_CTRLDESCLN_9(mfbi->index));
+
+	writel(DCU_UPDATE_MODE_READREG, dcufb->reg_base + DCU_UPDATE_MODE);
+	return 0;
+}
+
+static int disable_panel(struct fb_info *info)
+{
+	struct mfb_info *mfbi = info->par;
+	struct dcu_fb_data *dcufb = mfbi->parent;
+
+	writel(DCU_CTRLDESCLN_1_HEIGHT(0) |
+		DCU_CTRLDESCLN_1_WIDTH(0),
+		dcufb->reg_base + DCU_CTRLDESCLN_1(mfbi->index));
+	writel(DCU_CTRLDESCLN_2_POSY(0) | DCU_CTRLDESCLN_2_POSX(0),
+		dcufb->reg_base + DCU_CTRLDESCLN_2(mfbi->index));
+
+	writel(0, dcufb->reg_base + DCU_CTRLDESCLN_3(mfbi->index));
+	writel(0, dcufb->reg_base + DCU_CTRLDESCLN_4(mfbi->index));
+
+	writel(DCU_CTRLDESCLN_5_CKMAX_R(0) |
+		DCU_CTRLDESCLN_5_CKMAX_G(0) |
+		DCU_CTRLDESCLN_5_CKMAX_B(0),
+		dcufb->reg_base + DCU_CTRLDESCLN_5(mfbi->index));
+	writel(DCU_CTRLDESCLN_6_CKMIN_R(0) |
+		DCU_CTRLDESCLN_6_CKMIN_G(0) |
+		DCU_CTRLDESCLN_6_CKMIN_B(0),
+		dcufb->reg_base + DCU_CTRLDESCLN_6(mfbi->index));
+
+	writel(DCU_CTRLDESCLN_7_TILE_VER(0) | DCU_CTRLDESCLN_7_TILE_HOR(0),
+		dcufb->reg_base + DCU_CTRLDESCLN_7(mfbi->index));
+
+	writel(DCU_CTRLDESCLN_8_FG_FCOLOR(0),
+		dcufb->reg_base + DCU_CTRLDESCLN_8(mfbi->index));
+	writel(DCU_CTRLDESCLN_9_BG_BCOLOR(0),
+		dcufb->reg_base + DCU_CTRLDESCLN_9(mfbi->index));
+
+	writel(DCU_UPDATE_MODE_READREG, dcufb->reg_base + DCU_UPDATE_MODE);
+	return 0;
+}
+
+static void enable_controller(struct fb_info *info)
+{
+	struct mfb_info *mfbi = info->par;
+	struct dcu_fb_data *dcufb = mfbi->parent;
+	unsigned int dcu_mode;
+
+	dcu_mode = readl(dcufb->reg_base + DCU_DCU_MODE);
+	writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_NORMAL),
+		dcufb->reg_base + DCU_DCU_MODE);
+}
+
+static void disable_controller(struct fb_info *info)
+{
+	struct mfb_info *mfbi = info->par;
+	struct dcu_fb_data *dcufb = mfbi->parent;
+
+	writel(DCU_MODE_DCU_MODE(DCU_MODE_OFF),
+		dcufb->reg_base + DCU_DCU_MODE);
+}
+
+static int fsl_dcu_check_var(struct fb_var_screeninfo *var,
+		struct fb_info *info)
+{
+	if (var->xres_virtual < var->xres)
+		var->xres_virtual = var->xres;
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+
+	if (var->xoffset < 0)
+		var->xoffset = 0;
+
+	if (var->yoffset < 0)
+		var->yoffset = 0;
+
+	if (var->xoffset + info->var.xres > info->var.xres_virtual)
+		var->xoffset = info->var.xres_virtual - info->var.xres;
+
+	if (var->yoffset + info->var.yres > info->var.yres_virtual)
+		var->yoffset = info->var.yres_virtual - info->var.yres;
+
+	if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
+	    (var->bits_per_pixel != 16))
+		var->bits_per_pixel = default_bpp;
+
+	switch (var->bits_per_pixel) {
+	case 16:
+		var->red.length = 5;
+		var->red.offset = 11;
+		var->red.msb_right = 0;
+
+		var->green.length = 6;
+		var->green.offset = 5;
+		var->green.msb_right = 0;
+
+		var->blue.length = 5;
+		var->blue.offset = 0;
+		var->blue.msb_right = 0;
+
+		var->transp.length = 0;
+		var->transp.offset = 0;
+		var->transp.msb_right = 0;
+		break;
+	case 24:
+		var->red.length = 8;
+		var->red.offset = 16;
+		var->red.msb_right = 0;
+
+		var->green.length = 8;
+		var->green.offset = 8;
+		var->green.msb_right = 0;
+
+		var->blue.length = 8;
+		var->blue.offset = 0;
+		var->blue.msb_right = 0;
+
+		var->transp.length = 0;
+		var->transp.offset = 0;
+		var->transp.msb_right = 0;
+		break;
+	case 32:
+		var->red.length = 8;
+		var->red.offset = 16;
+		var->red.msb_right = 0;
+
+		var->green.length = 8;
+		var->green.offset = 8;
+		var->green.msb_right = 0;
+
+		var->blue.length = 8;
+		var->blue.offset = 0;
+		var->blue.msb_right = 0;
+
+		var->transp.length = 8;
+		var->transp.offset = 24;
+		var->transp.msb_right = 0;
+		break;
+	default:
+		printk(KERN_ERR "unsupported color depth: %u\n",
+			var->bits_per_pixel);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int calc_div_ratio(struct fb_info *info)
+{
+	struct mfb_info *mfbi = info->par;
+	struct dcu_fb_data *dcufb = mfbi->parent;
+	unsigned long dcu_clk;
+	unsigned long long tmp;
+
+	dcu_clk = clk_get_rate(dcufb->clk);
+	tmp = info->var.pixclock * (unsigned long long)dcu_clk;
+
+	do_div(tmp, 1000000);
+
+	if (do_div(tmp, 1000000) > 500000)
+		tmp++;
+
+	tmp = tmp - 1;
+	return tmp;
+}
+
+static void update_controller(struct fb_info *info)
+{
+	struct fb_var_screeninfo *var = &info->var;
+	struct mfb_info *mfbi = info->par;
+	struct dcu_fb_data *dcufb = mfbi->parent;
+	unsigned int ratio;
+
+	ratio = calc_div_ratio(info);
+	writel(ratio, dcufb->reg_base + DCU_DIV_RATIO);
+
+	writel(DCU_DISP_SIZE_DELTA_Y(var->yres) |
+		DCU_DISP_SIZE_DELTA_X(var->xres / 16),
+		dcufb->reg_base + DCU_DISP_SIZE);
+
+	/* Horizontal and vertical sync parameter */
+	writel(DCU_HSYN_PARA_BP(var->left_margin) |
+		DCU_HSYN_PARA_PW(var->hsync_len) |
+		DCU_HSYN_PARA_FP(var->right_margin),
+		dcufb->reg_base + DCU_HSYN_PARA);
+
+	writel(DCU_VSYN_PARA_BP(var->upper_margin) |
+		DCU_VSYN_PARA_PW(var->vsync_len) |
+		DCU_VSYN_PARA_FP(var->lower_margin),
+		dcufb->reg_base + DCU_VSYN_PARA);
+
+	writel(DCU_SYN_POL_INV_PXCK_FALL | DCU_SYN_POL_NEG_REMAIN |
+		DCU_SYN_POL_INV_VS_LOW | DCU_SYN_POL_INV_HS_LOW,
+		dcufb->reg_base + DCU_SYN_POL);
+
+	writel(DCU_BGND_R(0) | DCU_BGND_G(0) | DCU_BGND_B(0),
+		dcufb->reg_base + DCU_BGND);
+
+	writel(DCU_MODE_BLEND_ITER(DCU_LAYER_NUM_MAX) | DCU_MODE_RASTER_EN,
+			dcufb->reg_base + DCU_DCU_MODE);
+
+	writel(DCU_THRESHOLD_LS_BF_VS(0x3) | DCU_THRESHOLD_OUT_BUF_HIGH(0x78) |
+		DCU_THRESHOLD_OUT_BUF_LOW(0), dcufb->reg_base + DCU_THRESHOLD);
+
+	enable_controller(info);
+}
+
+static int map_video_memory(struct fb_info *info)
+{
+	u32 smem_len = info->fix.line_length * info->var.yres_virtual;
+
+	info->fix.smem_len = smem_len;
+
+	info->screen_base = dma_alloc_coherent(info->device, info->fix.smem_len,
+		(dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
+	if (!info->screen_base) {
+		printk(KERN_ERR "unable to allocate fb memory\n");
+		return -ENOMEM;
+	}
+
+	memset(info->screen_base, 0, info->fix.smem_len);
+
+	return 0;
+}
+
+static void unmap_video_memory(struct fb_info *info)
+{
+	if (!info->screen_base)
+		return;
+
+	dma_free_coherent(info->device, info->fix.smem_len,
+		info->screen_base, info->fix.smem_start);
+
+	info->screen_base = NULL;
+	info->fix.smem_start = 0;
+	info->fix.smem_len = 0;
+}
+
+static int fsl_dcu_set_layer(struct fb_info *info)
+{
+	struct mfb_info *mfbi = info->par;
+	struct fb_var_screeninfo *var = &info->var;
+	struct dcu_fb_data *dcufb = mfbi->parent;
+	int pixel_offset;
+	unsigned long addr;
+
+	pixel_offset = (var->yoffset * var->xres_virtual) + var->xoffset;
+	addr = info->fix.smem_start +
+		(pixel_offset * (var->bits_per_pixel >> 3));
+
+	writel(addr, dcufb->reg_base + DCU_CTRLDESCLN_3(mfbi->index));
+	writel(DCU_UPDATE_MODE_READREG, dcufb->reg_base + DCU_UPDATE_MODE);
+
+	return 0;
+}
+
+static int fsl_dcu_set_par(struct fb_info *info)
+{
+	unsigned long len;
+	struct fb_var_screeninfo *var = &info->var;
+	struct fb_fix_screeninfo *fix = &info->fix;
+	struct mfb_info *mfbi = info->par;
+
+	fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->accel = FB_ACCEL_NONE;
+	fix->visual = FB_VISUAL_TRUECOLOR;
+	fix->xpanstep = 1;
+	fix->ypanstep = 1;
+
+	len = info->var.yres_virtual * info->fix.line_length;
+	if (len != info->fix.smem_len) {
+		if (info->fix.smem_start)
+			unmap_video_memory(info);
+
+		if (map_video_memory(info)) {
+			printk(KERN_ERR "unable to allocate fb memory\n");
+			return -ENOMEM;
+		}
+	}
+
+	/* Only layer 0 could update LCD controller */
+	if (mfbi->index = LAYER0)
+		update_controller(info);
+
+	enable_panel(info);
+	return 0;
+}
+
+static inline __u32 CNVT_TOHW(__u32 val, __u32 width)
+{
+	return ((val<<width) + 0x7FFF - val) >> 16;
+}
+
+static int fsl_dcu_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp, struct fb_info *info)
+{
+	unsigned int val;
+	int ret = -EINVAL;
+
+	/*
+	 * If greyscale is true, then we convert the RGB value
+	 * to greyscale no matter what visual we are using.
+	 */
+	if (info->var.grayscale)
+		red = green = blue = (19595 * red + 38470 * green +
+				      7471 * blue) >> 16;
+	switch (info->fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+		/*
+		 * 16-bit True Colour.  We encode the RGB value
+		 * according to the RGB bitfield information.
+		 */
+		if (regno < 16) {
+			u32 *pal = info->pseudo_palette;
+
+			red = CNVT_TOHW(red, info->var.red.length);
+			green = CNVT_TOHW(green, info->var.green.length);
+			blue = CNVT_TOHW(blue, info->var.blue.length);
+			transp = CNVT_TOHW(transp, info->var.transp.length);
+
+			val = (red << info->var.red.offset) |
+			    (green << info->var.green.offset) |
+			    (blue << info->var.blue.offset) |
+			    (transp << info->var.transp.offset);
+
+			pal[regno] = val;
+			ret = 0;
+		}
+		break;
+	case FB_VISUAL_STATIC_PSEUDOCOLOR:
+	case FB_VISUAL_PSEUDOCOLOR:
+		break;
+	}
+
+	return ret;
+}
+
+static int fsl_dcu_pan_display(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
+{
+	if ((info->var.xoffset = var->xoffset) &&
+	    (info->var.yoffset = var->yoffset))
+		return 0;
+
+	if (var->xoffset < 0 || var->yoffset < 0
+	    || var->xoffset + info->var.xres > info->var.xres_virtual
+	    || var->yoffset + info->var.yres > info->var.yres_virtual)
+		return -EINVAL;
+
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset;
+
+	if (var->vmode & FB_VMODE_YWRAP)
+		info->var.vmode |= FB_VMODE_YWRAP;
+	else
+		info->var.vmode &= ~FB_VMODE_YWRAP;
+
+	fsl_dcu_set_layer(info);
+
+	return 0;
+}
+
+static int fsl_dcu_blank(int blank_mode, struct fb_info *info)
+{
+	switch (blank_mode) {
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+		disable_panel(info);
+		break;
+	case FB_BLANK_POWERDOWN:
+		disable_controller(info);
+		break;
+	case FB_BLANK_UNBLANK:
+		enable_panel(info);
+		break;
+	}
+
+	return 0;
+}
+
+static int fsl_dcu_ioctl(struct fb_info *info, unsigned int cmd,
+		unsigned long arg)
+{
+	struct mfb_info *mfbi = info->par;
+	struct layer_display_offset layer_d;
+	void __user *buf = (void __user *)arg;
+	unsigned char alpha;
+
+	switch (cmd) {
+	case MFB_SET_LAYER:
+		if (copy_from_user(&layer_d, buf, sizeof(layer_d)))
+			return -EFAULT;
+		mfbi->x_layer_d = layer_d.x_layer_d;
+		mfbi->y_layer_d = layer_d.y_layer_d;
+		fsl_dcu_set_par(info);
+		break;
+	case MFB_GET_LAYER:
+		layer_d.x_layer_d = mfbi->x_layer_d;
+		layer_d.y_layer_d = mfbi->y_layer_d;
+		if (copy_to_user(buf, &layer_d, sizeof(layer_d)))
+			return -EFAULT;
+		break;
+	case MFB_GET_ALPHA:
+		alpha = mfbi->alpha;
+		if (copy_to_user(buf, &alpha, sizeof(alpha)))
+			return -EFAULT;
+		break;
+	case MFB_SET_ALPHA:
+		if (copy_from_user(&alpha, buf, sizeof(alpha)))
+			return -EFAULT;
+		mfbi->blend = 1;
+		mfbi->alpha = alpha;
+		fsl_dcu_set_par(info);
+		break;
+	default:
+		printk(KERN_ERR "unknown ioctl command (0x%08X)\n", cmd);
+		return -ENOIOCTLCMD;
+	}
+
+	return 0;
+}
+
+static void enable_interrupts(struct dcu_fb_data *dcufb)
+{
+	u32 int_mask = readl(dcufb->reg_base + DCU_INT_MASK);
+
+	writel(int_mask & ~DCU_INT_MASK_UNDRUN, dcufb->reg_base + DCU_INT_MASK);
+}
+
+static void reset_layers(struct dcu_fb_data *dcufb)
+{
+	int i;
+
+	for (i = 1; i < DCU_TOTAL_LAYER_NUM; i++) {
+		writel(0, dcufb->reg_base + DCU_CTRLDESCLN_1(i));
+		writel(0, dcufb->reg_base + DCU_CTRLDESCLN_2(i));
+		writel(0, dcufb->reg_base + DCU_CTRLDESCLN_3(i));
+		writel(0, dcufb->reg_base + DCU_CTRLDESCLN_4(i));
+		writel(0, dcufb->reg_base + DCU_CTRLDESCLN_5(i));
+		writel(0, dcufb->reg_base + DCU_CTRLDESCLN_6(i));
+		writel(0, dcufb->reg_base + DCU_CTRLDESCLN_7(i));
+		writel(0, dcufb->reg_base + DCU_CTRLDESCLN_8(i));
+		writel(0, dcufb->reg_base + DCU_CTRLDESCLN_9(i));
+	}
+	writel(DCU_UPDATE_MODE_READREG, dcufb->reg_base + DCU_UPDATE_MODE);
+}
+
+static int fsl_dcu_open(struct fb_info *info, int user)
+{
+	struct mfb_info *mfbi = info->par;
+	int ret = 0;
+
+	mfbi->index = info->node;
+
+	mfbi->count++;
+	if (mfbi->count = 1) {
+		fsl_dcu_check_var(&info->var, info);
+		ret = fsl_dcu_set_par(info);
+		if (ret < 0)
+			mfbi->count--;
+		else
+			enable_interrupts(mfbi->parent);
+	}
+
+	return ret;
+}
+
+static int fsl_dcu_release(struct fb_info *info, int user)
+{
+	struct mfb_info *mfbi = info->par;
+	int ret = 0;
+
+	mfbi->count--;
+	if (mfbi->count = 0) {
+		ret = disable_panel(info);
+		if (ret < 0)
+			mfbi->count++;
+	}
+
+	return ret;
+}
+
+static struct fb_ops fsl_dcu_ops = {
+	.owner = THIS_MODULE,
+	.fb_check_var = fsl_dcu_check_var,
+	.fb_set_par = fsl_dcu_set_par,
+	.fb_setcolreg = fsl_dcu_setcolreg,
+	.fb_blank = fsl_dcu_blank,
+	.fb_pan_display = fsl_dcu_pan_display,
+	.fb_fillrect = cfb_fillrect,
+	.fb_copyarea = cfb_copyarea,
+	.fb_imageblit = cfb_imageblit,
+	.fb_ioctl = fsl_dcu_ioctl,
+	.fb_open = fsl_dcu_open,
+	.fb_release = fsl_dcu_release,
+};
+
+static int install_framebuffer(struct fb_info *info)
+{
+	struct mfb_info *mfbi = info->par;
+	struct fb_videomode *db = dcu_mode_db;
+	unsigned int dbsize = ARRAY_SIZE(dcu_mode_db);
+	int ret;
+
+	info->var.activate = FB_ACTIVATE_NOW;
+	info->fbops = &fsl_dcu_ops;
+	info->flags = FBINFO_FLAG_DEFAULT;
+	info->pseudo_palette = &mfbi->pseudo_palette;
+
+	fb_alloc_cmap(&info->cmap, 16, 0);
+
+	ret = fb_find_mode(&info->var, info, fb_mode, db, dbsize,
+			NULL, default_bpp);
+
+	if (fsl_dcu_check_var(&info->var, info)) {
+		ret = -EINVAL;
+		goto failed_checkvar;
+	}
+
+	if (register_framebuffer(info) < 0) {
+		ret = -EINVAL;
+		goto failed_register_framebuffer;
+	}
+
+	printk(KERN_INFO "fb%d: %s fb device registered successfully.\n",
+		info->node, info->fix.id);
+	return 0;
+
+failed_checkvar:
+	fb_dealloc_cmap(&info->cmap);
+failed_register_framebuffer:
+	unmap_video_memory(info);
+	fb_dealloc_cmap(&info->cmap);
+	return ret;
+}
+
+static void uninstall_framebuffer(struct fb_info *info)
+{
+	unregister_framebuffer(info);
+	unmap_video_memory(info);
+
+	if (&info->cmap)
+		fb_dealloc_cmap(&info->cmap);
+}
+
+static irqreturn_t fsl_dcu_irq(int irq, void *dev_id)
+{
+	struct dcu_fb_data *dcufb = dev_id;
+	unsigned int status = readl(dcufb->reg_base + DCU_INT_STATUS);
+	u32 dcu_mode;
+
+	if (status) {
+		if (status & DCU_INT_STATUS_UNDRUN) {
+			dcu_mode = readl(dcufb->reg_base + DCU_DCU_MODE);
+			dcu_mode &= ~DCU_MODE_DCU_MODE_MASK;
+			writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_OFF),
+				dcufb->reg_base + DCU_DCU_MODE);
+			udelay(1);
+			writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_NORMAL),
+				dcufb->reg_base + DCU_DCU_MODE);
+		}
+		writel(status, dcufb->reg_base + DCU_INT_STATUS);
+		return IRQ_HANDLED;
+	}
+	return IRQ_NONE;
+}
+
+#ifdef CONFIG_PM
+static int fsl_dcu_suspend(struct platform_device *pdev,
+		pm_message_t state)
+{
+	struct dcu_fb_data *dcufb = dev_get_drvdata(&pdev->dev);
+
+	clk_disable_unprepare(dcufb->clk);
+	return 0;
+}
+
+static int fsl_dcu_resume(struct platform_device *pdev)
+{
+	struct dcu_fb_data *dcufb = dev_get_drvdata(&pdev->dev);
+
+	clk_prepare_enable(dcufb->clk);
+	return 0;
+}
+#else
+#define fsl_dcu_suspend	NULL
+#define fsl_dcu_resume	NULL
+#endif
+
+static int bypass_tcon(struct device_node *np)
+{
+	struct device_node *tcon_np;
+	struct platform_device *tcon_pdev;
+	struct clk *tcon_clk;
+	void __iomem *tcon_reg;
+	int ret = 0;
+
+	tcon_np = of_parse_phandle(np, "tcon-controller", 0);
+	if (!tcon_np)
+		return -EINVAL;
+
+	tcon_pdev = of_find_device_by_node(tcon_np);
+	if (!tcon_pdev)
+		return -EINVAL;
+
+	tcon_clk = devm_clk_get(&tcon_pdev->dev, "tcon");
+	if (IS_ERR(tcon_clk)) {
+		ret = PTR_ERR(tcon_clk);
+		goto failed_getclock;
+	}
+	clk_prepare_enable(tcon_clk);
+
+	tcon_reg = of_iomap(tcon_np, 0);
+	if (!tcon_reg) {
+		ret = -ENOMEM;
+		goto failed_ioremap;
+	}
+	writel(TCON_BYPASS_ENABLE, tcon_reg + TCON_CTRL1);
+
+	return 0;
+
+failed_ioremap:
+	clk_disable_unprepare(tcon_clk);
+failed_getclock:
+	of_node_put(tcon_np);
+	return ret;
+}
+
+static int fsl_dcu_probe(struct platform_device *pdev)
+{
+	struct dcu_fb_data *dcufb;
+	struct mfb_info *mfbi;
+	struct resource *res;
+	int ret = 0;
+	int i;
+
+	dcufb = devm_kzalloc(&pdev->dev,
+		sizeof(struct dcu_fb_data), GFP_KERNEL);
+	if (!dcufb)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "could not get memory IO resource\n");
+		return -ENODEV;
+	}
+
+	dcufb->reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(dcufb->reg_base)) {
+		ret = PTR_ERR(dcufb->reg_base);
+		goto failed_ioremap;
+	}
+
+	dcufb->irq = platform_get_irq(pdev, 0);
+	if (!dcufb->irq) {
+		ret = -EINVAL;
+		goto failed_getirq;
+	}
+
+	ret = request_irq(dcufb->irq, fsl_dcu_irq, 0, DRIVER_NAME, dcufb);
+	if (ret) {
+		dev_err(&pdev->dev, "could not request irq\n");
+		goto failed_requestirq;
+	}
+
+	/* Put TCON in bypass mode, so the input signals from DCU are passed
+	 * through TCON unchanged */
+	ret = bypass_tcon(pdev->dev.of_node);
+	if (ret) {
+		dev_err(&pdev->dev, "could not bypass TCON\n");
+		goto failed_bypasstcon;
+	}
+
+	dcufb->clk = devm_clk_get(&pdev->dev, "dcu");
+	if (IS_ERR(dcufb->clk)) {
+		dev_err(&pdev->dev, "could not get clock\n");
+		goto failed_getclock;
+	}
+	clk_prepare_enable(dcufb->clk);
+
+	for (i = 0; i < ARRAY_SIZE(dcufb->fsl_dcu_info); i++) {
+		dcufb->fsl_dcu_info[i] +			framebuffer_alloc(sizeof(struct mfb_info), &pdev->dev);
+		if (!dcufb->fsl_dcu_info[i]) {
+			ret = ENOMEM;
+			goto failed_alloc_framebuffer;
+		}
+
+		dcufb->fsl_dcu_info[i]->fix.smem_start = 0;
+
+		mfbi = dcufb->fsl_dcu_info[i]->par;
+		memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
+		mfbi->parent = dcufb;
+
+		ret = install_framebuffer(dcufb->fsl_dcu_info[i]);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"could not register framebuffer %d\n", i);
+			goto failed_register_framebuffer;
+		}
+	}
+
+	reset_layers(mfbi->parent);
+
+	dev_set_drvdata(&pdev->dev, dcufb);
+	return 0;
+
+failed_register_framebuffer:
+	for (i = 0; i < ARRAY_SIZE(dcufb->fsl_dcu_info); i++) {
+		if (dcufb->fsl_dcu_info[i])
+			framebuffer_release(dcufb->fsl_dcu_info[i]);
+	}
+failed_alloc_framebuffer:
+failed_getclock:
+failed_bypasstcon:
+	free_irq(dcufb->irq, dcufb);
+failed_requestirq:
+failed_getirq:
+	iounmap(dcufb->reg_base);
+failed_ioremap:
+	kfree(dcufb);
+	return ret;
+}
+
+static int fsl_dcu_remove(struct platform_device *pdev)
+{
+	struct dcu_fb_data *dcufb = dev_get_drvdata(&pdev->dev);
+	int i;
+
+	disable_controller(dcufb->fsl_dcu_info[0]);
+
+	clk_disable_unprepare(dcufb->clk);
+	free_irq(dcufb->irq, dcufb);
+
+	for (i = 0; i < ARRAY_SIZE(dcufb->fsl_dcu_info); i++) {
+		uninstall_framebuffer(dcufb->fsl_dcu_info[i]);
+		framebuffer_release(dcufb->fsl_dcu_info[i]);
+	}
+
+	return 0;
+}
+
+static int fsl_dcu_setup(void)
+{
+#ifndef MODULE
+	char *opt, *options = NULL;
+	unsigned long val;
+
+	if (fb_get_options("fslfb", &options))
+		return -ENODEV;
+
+	if (!options || !*options)
+		return 0;
+
+	while ((opt = strsep(&options, ",")) != NULL) {
+		if (!*opt)
+			continue;
+		if (!strncmp(opt, "bpp=", 4)) {
+			if (!strict_strtoul(opt + 4, 10, &val))
+				default_bpp = val;
+		} else {
+			fb_mode = opt;
+		}
+	}
+#endif
+	return 0;
+}
+
+static struct of_device_id fsl_dcu_dt_ids[] = {
+	{
+		.compatible = "fsl,vf610-dcu",
+	},
+	{}
+};
+
+static struct platform_driver fsl_dcu_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = fsl_dcu_dt_ids,
+	},
+	.probe = fsl_dcu_probe,
+	.remove = fsl_dcu_remove,
+	.suspend = fsl_dcu_suspend,
+	.resume = fsl_dcu_resume,
+};
+
+static int __init fsl_dcu_init(void)
+{
+	int ret = fsl_dcu_setup();
+
+	if (ret < 0)
+		return ret;
+
+	return platform_driver_register(&fsl_dcu_driver);
+}
+
+static void __exit fsl_dcu_exit(void)
+{
+	platform_driver_unregister(&fsl_dcu_driver);
+}
+
+module_init(fsl_dcu_init);
+module_exit(fsl_dcu_exit);
+
+MODULE_AUTHOR("Alison Wang");
+MODULE_DESCRIPTION("Freescale DCU framebuffer driver");
+MODULE_LICENSE("GPL v2");
-- 
1.8.0



^ permalink raw reply related

* [PATCH 3/5] ARM: clk: vf610: Add DCU and TCON clock support
From: Alison Wang @ 2013-07-12  6:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1373609276-14566-1-git-send-email-b18965@freescale.com>

This patch adds DCU and TCON clock support for Vybrid VF610 platform.

Signed-off-by: Alison Wang <b18965@freescale.com>
---
Changes in v2: None

 arch/arm/mach-imx/clk-vf610.c           | 5 +++++
 include/dt-bindings/clock/vf610-clock.h | 3 ++-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-imx/clk-vf610.c b/arch/arm/mach-imx/clk-vf610.c
index d617c0b..c4dbe32 100644
--- a/arch/arm/mach-imx/clk-vf610.c
+++ b/arch/arm/mach-imx/clk-vf610.c
@@ -245,6 +245,8 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
 	clk[VF610_CLK_DCU1_DIV] = imx_clk_divider("dcu1_div", "dcu1_en", CCM_CSCDR3, 20, 3);
 	clk[VF610_CLK_DCU1] = imx_clk_gate2("dcu1", "dcu1_div", CCM_CCGR9, CCM_CCGRx_CGn(8));
 
+	clk[VF610_CLK_TCON0] = imx_clk_gate2("tcon0", "platform_bus", CCM_CCGR1, CCM_CCGRx_CGn(13));
+
 	clk[VF610_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", CCM_CSCMR1, 20, 2, esai_sels, 4);
 	clk[VF610_CLK_ESAI_EN] = imx_clk_gate("esai_en", "esai_sel", CCM_CSCDR2, 30);
 	clk[VF610_CLK_ESAI_DIV] = imx_clk_divider("esai_div", "esai_en", CCM_CSCDR2, 24, 4);
@@ -311,6 +313,9 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
 	clk_set_parent(clk[VF610_CLK_SAI2_SEL], clk[VF610_CLK_AUDIO_EXT]);
 	clk_set_parent(clk[VF610_CLK_SAI3_SEL], clk[VF610_CLK_AUDIO_EXT]);
 
+	clk_set_parent(clk[VF610_CLK_DCU0_SEL], clk[VF610_CLK_PLL1_PFD2]);
+	clk_set_rate(clk[VF610_CLK_DCU0_DIV], 113200000);
+
 	/* Add the clocks to provider list */
 	clk_data.clks = clk;
 	clk_data.clk_num = ARRAY_SIZE(clk);
diff --git a/include/dt-bindings/clock/vf610-clock.h b/include/dt-bindings/clock/vf610-clock.h
index 15e997f..a2fc6d9 100644
--- a/include/dt-bindings/clock/vf610-clock.h
+++ b/include/dt-bindings/clock/vf610-clock.h
@@ -158,6 +158,7 @@
 #define VF610_CLK_GPU_SEL		145
 #define VF610_CLK_GPU_EN		146
 #define VF610_CLK_GPU2D			147
-#define VF610_CLK_END			148
+#define VF610_CLK_TCON0			148
+#define VF610_CLK_END			149
 
 #endif /* __DT_BINDINGS_CLOCK_VF610_H */
-- 
1.8.0



^ permalink raw reply related

* [PATCH 2/5] ARM: dts: vf610-twr: Enable DCU and TCON devices
From: Alison Wang @ 2013-07-12  6:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1373609276-14566-1-git-send-email-b18965@freescale.com>

This patch enables DCU and TCON devices for Vybrid VF610 TOWER board.

Signed-off-by: Alison Wang <b18965@freescale.com>
---
Changes in v2: None

 arch/arm/boot/dts/vf610-twr.dts | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm/boot/dts/vf610-twr.dts b/arch/arm/boot/dts/vf610-twr.dts
index b3905f5..605fb04 100644
--- a/arch/arm/boot/dts/vf610-twr.dts
+++ b/arch/arm/boot/dts/vf610-twr.dts
@@ -36,6 +36,12 @@
 
 };
 
+&dcu0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_dcu0_1>;
+	status = "okay";
+};
+
 &fec0 {
 	phy-mode = "rmii";
 	pinctrl-names = "default";
@@ -50,6 +56,10 @@
 	status = "okay";
 };
 
+&tcon0 {
+	status = "okay";
+};
+
 &uart1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_uart1_1>;
-- 
1.8.0



^ permalink raw reply related

* [PATCH 1/5] ARM: dts: vf610: Add DCU and TCON nodes
From: Alison Wang @ 2013-07-12  6:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1373609276-14566-1-git-send-email-b18965@freescale.com>

This patch adds DCU and TCON nodes in SoC level DTS for Freescale
Vybrid VF610. It also removes useless pin for DCU0 pinctrl.

Signed-off-by: Alison Wang <b18965@freescale.com>
---
Changes in v2: None

 arch/arm/boot/dts/vf610.dtsi | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/vf610.dtsi b/arch/arm/boot/dts/vf610.dtsi
index e1eb7da..037e8f1 100644
--- a/arch/arm/boot/dts/vf610.dtsi
+++ b/arch/arm/boot/dts/vf610.dtsi
@@ -140,6 +140,14 @@
 				clock-names = "pit";
 			};
 
+			tcon0: tcon@4003d000 {
+				compatible = "fsl,vf610-tcon";
+				reg = <0x4003d000 0x1000>;
+				clocks = <&clks VF610_CLK_TCON0>;
+				clock-names = "tcon";
+				status = "disabled";
+			};
+
 			wdog@4003e000 {
 				compatible = "fsl,vf610-wdt", "fsl,imx21-wdt";
 				reg = <0x4003e000 0x1000>;
@@ -169,7 +177,6 @@
 				dcu0 {
 					pinctrl_dcu0_1: dcu0grp_1 {
 						fsl,pins = <
-						VF610_PAD_PTB8__GPIO_30		0x42
 						VF610_PAD_PTE0__DCU0_HSYNC	0x42
 						VF610_PAD_PTE1__DCU0_VSYNC	0x42
 						VF610_PAD_PTE2__DCU0_PCLK	0x42
@@ -395,6 +402,16 @@
 				reg = <0x40050000 0x1000>;
 			};
 
+			dcu0: dcu@40058000 {
+				compatible = "fsl,vf610-dcu";
+				reg = <0x40058000 0x1200>;
+				interrupts = <0 30 0x04>;
+				clocks = <&clks VF610_CLK_DCU0>;
+				clock-names = "dcu";
+				tcon-controller = <&tcon0>;
+				status = "disabled";
+			};
+
 			i2c0: i2c@40066000 {
 				#address-cells = <1>;
 				#size-cells = <0>;
-- 
1.8.0



^ permalink raw reply related

* [PATCH v2 0/5] ARM: vf610: Add DCU framebuffer driver for Vybrid VF610 platform
From: Alison Wang @ 2013-07-12  6:07 UTC (permalink / raw)
  To: linux-arm-kernel

This series contain DCU framebuffer driver for Freescale Vybrid VF610 platform.

The Display Controller Unit (DCU) module is a system master that
fetches graphics stored in internal or external memory and displays
them on a TFT LCD panel. A wide range of panel sizes is supported
and the timing of the interface signals is highly configurable.
Graphics are read directly from memory and then blended in real-time,
which allows for dynamic content creation with minimal CPU intervention.

The features:

(1) Full RGB888 output to TFT LCD panel.
(2) For the current LCD panel, WQVGA "480x272" is tested.
(3) Blending of each pixel using up to 4 source layers dependent on size of panel.
(4) Each graphic layer can be placed with one pixel resolution in either axis.
(5) Each graphic layer support RGB565 and RGB888 direct colors without alpha channel
and BGRA8888 direct colors with an alpha channel.
(6) Each graphic layer support alpha blending with 8-bit resolution.

Changes in v2:
- Add a document for DCU framebuffer driver under Documentation/devicetree/bindings/fb/.

----------------------------------------------------------------
Alison Wang (5):
      ARM: dts: vf610: Add DCU and TCON nodes
      ARM: dts: vf610-twr: Enable DCU and TCON devices
      ARM: clk: vf610: Add DCU and TCON clock support
      fb: Add DCU framebuffer driver for Vybrid VF610 platform
      Documentation: DT: Add DCU framebuffer driver

 Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt |   36 ++++
 arch/arm/boot/dts/vf610-twr.dts                     |   10 +
 arch/arm/boot/dts/vf610.dtsi                        |   19 +-
 arch/arm/mach-imx/clk-vf610.c                       |    5 +
 drivers/video/Kconfig                               |    9 +
 drivers/video/Makefile                              |    1 +
 drivers/video/fsl-dcu-fb.c                          | 1091 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/dt-bindings/clock/vf610-clock.h             |    3 +-
 8 files changed, 1172 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt
 create mode 100644 drivers/video/fsl-dcu-fb.c



^ permalink raw reply

* RE: [PATCH 1/1] OMAPDSS: Add sil9022 driver
From: Pulukuru, Srinivas @ 2013-07-11 16:41 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD, Prakash, Sathya
  Cc: Valkeinen, Tomi, Taneja, Archit, linux-omap@vger.kernel.org,
	linux-fbdev@vger.kernel.org
In-Reply-To: <20130709134033.GD18477@ns203013.ovh.net>

THis was a demo patch done to enable basic HDMI display on OMAP3 which somehow got pushed into the regular builds on OMAP3 deliverables and has since been floating around. This is not a production code that can be upstreamed. Please abandon this patch and do not up-stream in the present form. Except basic display via HDMI, there is no other functionality in this patch.

Regards,
Srinivas Pulukuru


-----Original Message-----
From: Jean-Christophe PLAGNIOL-VILLARD [mailto:plagnioj@jcrosoft.com] 
Sent: Tuesday, July 09, 2013 8:41 AM
To: Prakash, Sathya
Cc: Valkeinen, Tomi; Taneja, Archit; linux-omap@vger.kernel.org; linux-fbdev@vger.kernel.org; Pulukuru, Srinivas
Subject: Re: [PATCH 1/1] OMAPDSS: Add sil9022 driver

HI,

	Tomi can you take a look at this one your are back

Best Regards,
J.
On 14:37 Tue 09 Jul     , Sathya Prakash M R wrote:
> From: Srinivas Pulukuru <srinivas.pulukuru@ti.com>
> 
> Add driver for SIL9022 DPI-to-HDMI chip.
> 
> Signed-off-by: Srinivas Pulukuru <srinivas.pulukuru@ti.com>
> [sathyap@ti.com: Ported the driver from 2.6.32 based internal
> kernel to v3.10 kernel]
> Signed-off-by: Sathya Prakash M R <sathyap@ti.com>
> ---
> This patch was tested using the legacy OMAP3630 based Zoom3 platform.
> There is no DT support for Zoom , hence board file changes
> made locally were used for validation purpose. 
> Further, DT support will be added for a newer SOC which uses
> the sil9022 HDMI interface chip.
> 
>  drivers/video/omap2/displays/Kconfig         |    8 +
>  drivers/video/omap2/displays/Makefile        |    1 +
>  drivers/video/omap2/displays/panel-sil9022.c | 1274 ++++++++++++++++++++++++++
>  drivers/video/omap2/displays/panel-sil9022.h |  527 +++++++++++
>  4 files changed, 1810 insertions(+)
>  create mode 100644 drivers/video/omap2/displays/panel-sil9022.c
>  create mode 100644 drivers/video/omap2/displays/panel-sil9022.h
> 
> diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
> index c3853c9..53d8bb7 100644
> --- a/drivers/video/omap2/displays/Kconfig
> +++ b/drivers/video/omap2/displays/Kconfig
> @@ -39,6 +39,14 @@ config PANEL_NEC_NL8048HL11_01B
>  		This NEC NL8048HL11-01B panel is TFT LCD
>  		used in the Zoom2/3/3630 sdp boards.
>  
> +config PANEL_SIL9022
> +	tristate "HDMI interface"
> +        depends on OMAP2_DSS_DPI
> +	depends on I2C
> +	help
> +		Driver for SIL9022 DPI-to-HDMI chip
> +		Driver uses i2c to read EDID information.
> +
>  config PANEL_PICODLP
>  	tristate "TI PICO DLP mini-projector"
>  	depends on OMAP2_DSS_DPI && I2C
> diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
> index 58a5176..34cfa8e 100644
> --- a/drivers/video/omap2/displays/Makefile
> +++ b/drivers/video/omap2/displays/Makefile
> @@ -3,6 +3,7 @@ obj-$(CONFIG_PANEL_TFP410) += panel-tfp410.o
>  obj-$(CONFIG_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o
>  obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
>  obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o
> +obj-$(CONFIG_PANEL_SIL9022) += panel-sil9022.o
>  
>  obj-$(CONFIG_PANEL_TAAL) += panel-taal.o
>  obj-$(CONFIG_PANEL_PICODLP) +=  panel-picodlp.o
> diff --git a/drivers/video/omap2/displays/panel-sil9022.c b/drivers/video/omap2/displays/panel-sil9022.c
> new file mode 100644
> index 0000000..3b5cb17
> --- /dev/null
> +++ b/drivers/video/omap2/displays/panel-sil9022.c
> @@ -0,0 +1,1274 @@
> +/*
> + * drivers/video/omap2/panel-sil9022.c
> + *
> + * Copyright (C) 2009 Texas Instruments
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + *
> + * SIL9022 hdmi driver
> + * Owner: kiran Chitriki
> + *
> + */
> +
> +/***********************************/
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/string.h>
> +#include <linux/types.h>
> +#include <linux/slab.h>
> +#include <linux/io.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/i2c.h>
> +#include <linux/device.h>
> +#include <linux/delay.h>
> +#include <linux/gpio.h>
> +#include <linux/platform_device.h>
> +
> +#include <video/omapdss.h>
> +#include <video/omap-panel-data.h>
> +#include "panel-sil9022.h"
> +
> +u16 current_descriptor_addrs;
> +
> +static struct i2c_client *sil9022_client;
> +
> +static struct omap_video_timings omap_dss_hdmi_timings = {
> +	.x_res          = HDMI_XRES,
> +	.y_res          = HDMI_YRES,
> +	.pixel_clock    = HDMI_PIXCLOCK_MAX,
> +	.hfp            = 110,
> +	.hbp            = 220,
> +	.hsw            = 40,
> +	.vfp            = 5,
> +	.vbp            = 20,
> +	.vsw            = 5,
> +	.vsync_level	= OMAPDSS_SIG_ACTIVE_LOW,
> +	.hsync_level	= OMAPDSS_SIG_ACTIVE_LOW,
> +	.data_pclk_edge	= OMAPDSS_DRIVE_SIG_RISING_EDGE,
> +	.de_level	= OMAPDSS_SIG_ACTIVE_HIGH,
> +	.sync_pclk_edge	= OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
> +};
> +
> +static struct hdmi_reg_data  hdmi_tpi_audio_config_data[] = {
> +	/* Transmitter is brought to Full operation when value of power
> +	 * state register is 0x0 */
> +	{ HDMI_TPI_POWER_STATE_CTRL_REG, TPI_AVI_POWER_STATE_D0		 },
> +	/* TMDS output lines active. bit 3 1:TMDS inactive, 0: TMDS active */
> +	{ HDMI_SYS_CTRL_DATA_REG,  0x01					 },
> +	/*HDCP Enable - Disable */
> +	{ HDMI_TPI_HDCP_CONTROLDATA_REG, 0				 },
> +	/* I2S mode , Mute Enabled , PCM */
> +	{ HDMI_TPI_AUDIO_CONFIG_BYTE2_REG, TPI_AUDIO_INTERFACE_I2S |
> +					    TPI_AUDIO_MUTE_ENABLE |
> +					    TPI_AUDIO_CODING_PCM	 },
> +	/* I2S Input configuration register */
> +	{ HDMI_TPI_I2S_INPUT_CONFIG_REG, TPI_I2S_SCK_EDGE_RISING |
> +					TPI_I2S_MCLK_MULTIPLIER_256 |
> +					TPI_I2S_WS_POLARITY_HIGH |
> +					TPI_I2S_SD_JUSTIFY_LEFT |
> +					TPI_I2S_SD_DIRECTION_MSB_FIRST |
> +					TPI_I2S_FIRST_BIT_SHIFT_YES	 },
> +	/* I2S Enable ad Mapping Register */
> +	{ HDMI_TPI_I2S_ENABLE_MAPPING_REG, TPI_I2S_SD_CHANNEL_ENABLE |
> +					    TPI_I2S_SD_FIFO_0 |
> +					    TPI_I2S_DOWNSAMPLE_DISABLE |
> +					    TPI_I2S_LF_RT_SWAP_NO |
> +					    TPI_I2S_SD_CONFIG_SELECT_SD0 },
> +	{ HDMI_TPI_I2S_ENABLE_MAPPING_REG, TPI_I2S_SD_CHANNEL_DISABLE |
> +					    TPI_I2S_SD_FIFO_1 |
> +					    TPI_I2S_DOWNSAMPLE_DISABLE |
> +					    TPI_I2S_LF_RT_SWAP_NO |
> +					    TPI_I2S_SD_CONFIG_SELECT_SD1 },
> +	{ HDMI_TPI_I2S_ENABLE_MAPPING_REG, TPI_I2S_SD_CHANNEL_DISABLE |
> +					    TPI_I2S_SD_FIFO_2 |
> +					    TPI_I2S_DOWNSAMPLE_DISABLE |
> +					    TPI_I2S_LF_RT_SWAP_NO |
> +					    TPI_I2S_SD_CONFIG_SELECT_SD2 },
> +	{ HDMI_TPI_I2S_ENABLE_MAPPING_REG, TPI_I2S_SD_CHANNEL_DISABLE |
> +					    TPI_I2S_SD_FIFO_3 |
> +					    TPI_I2S_DOWNSAMPLE_DISABLE |
> +					    TPI_I2S_LF_RT_SWAP_NO |
> +					    TPI_I2S_SD_CONFIG_SELECT_SD3 },
> +	{ HDMI_TPI_AUDIO_CONFIG_BYTE3_REG, TPI_AUDIO_SAMPLE_SIZE_16 |
> +					     TPI_AUDIO_FREQ_44KHZ |
> +					     TPI_AUDIO_2_CHANNEL	 },
> +	/* Speaker Configuration  refer CEA Specification*/
> +	{ HDMI_TPI_AUDIO_CONFIG_BYTE4_REG, (0x0 << 0)},
> +	/* Stream Header Settings */
> +	{ HDMI_TPI_I2S_STRM_HDR_0_REG, I2S_CHAN_STATUS_MODE		 },
> +	{ HDMI_TPI_I2S_STRM_HDR_1_REG, I2S_CHAN_STATUS_CAT_CODE	},
> +	{ HDMI_TPI_I2S_STRM_HDR_2_REG, I2S_CHAN_SOURCE_CHANNEL_NUM	 },
> +	{ HDMI_TPI_I2S_STRM_HDR_3_REG, I2S_CHAN_ACCURACY_N_44_SAMPLING_FS },
> +	{ HDMI_TPI_I2S_STRM_HDR_4_REG, I2S_CHAN_ORIGIN_FS_N_SAMP_LENGTH  },
> +	/*     Infoframe data Select  */
> +	{ HDMI_CPI_MISC_IF_SELECT_REG, HDMI_INFOFRAME_TX_ENABLE |
> +					HDMI_INFOFRAME_TX_REPEAT |
> +					HDMI_AUDIO_INFOFRAME		 },
> +};
> +
> +static u8 misc_audio_info_frame_data[] = {
> +	MISC_INFOFRAME_TYPE | MISC_INFOFRAME_ALWAYS_SET,
> +	MISC_INFOFRAME_VERSION,
> +	MISC_INFOFRAME_LENGTH,
> +	0,				/* Checksum byte*/
> +	HDMI_SH_PCM | HDMI_SH_TWO_CHANNELS,
> +	HDMI_SH_44KHz | HDMI_SH_16BIT,	/* 44.1 KHz*/
> +	0x0,   /* Default 0*/
> +	HDMI_SH_SPKR_FLFR,
> +	HDMI_SH_0dB_ATUN | 0x1,		/* 0 dB  Attenuation*/
> +	0x0,
> +	0x0,
> +	0x0,
> +	0x0,
> +	0x0
> +};
> +
> +static u8 avi_info_frame_data[] = {
> +	0x00,
> +	0x00,
> +	0xA8,
> +	0x00,
> +	0x04,
> +	0x00,
> +	0x00,
> +	0x00,
> +	0x00,
> +	0x00,
> +	0x00,
> +	0x00,
> +	0x00,
> +	0x00
> +};
> +
> +void get_horz_vert_timing_info(u8 *edid)
> +{
> +	/*HORIZONTAL FRONT PORCH */
> +	omap_dss_hdmi_timings.hfp = edid[current_descriptor_addrs + 8];
> +	/*HORIZONTAL SYNC WIDTH */
> +	omap_dss_hdmi_timings.hsw = edid[current_descriptor_addrs + 9];
> +	/*HORIZONTAL BACK PORCH */
> +	omap_dss_hdmi_timings.hbp = (((edid[current_descriptor_addrs + 4]
> +					  & 0x0F) << 8) |
> +					edid[current_descriptor_addrs + 3]) -
> +		(omap_dss_hdmi_timings.hfp + omap_dss_hdmi_timings.hsw);
> +	/*VERTICAL FRONT PORCH */
> +	omap_dss_hdmi_timings.vfp = ((edid[current_descriptor_addrs + 10] &
> +				       0xF0) >> 4);
> +	/*VERTICAL SYNC WIDTH */
> +	omap_dss_hdmi_timings.vsw = (edid[current_descriptor_addrs + 10] &
> +				      0x0F);
> +	/*VERTICAL BACK PORCH */
> +	omap_dss_hdmi_timings.vbp = (((edid[current_descriptor_addrs + 7] &
> +					0x0F) << 8) |
> +				      edid[current_descriptor_addrs + 6]) -
> +		(omap_dss_hdmi_timings.vfp + omap_dss_hdmi_timings.vsw);
> +
> +	dev_dbg(&sil9022_client->dev, "<%s>\n"
> +				       "hfp			= %d\n"
> +				       "hsw			= %d\n"
> +				       "hbp			= %d\n"
> +				       "vfp			= %d\n"
> +				       "vsw			= %d\n"
> +				       "vbp			= %d\n",
> +		 __func__,
> +		 omap_dss_hdmi_timings.hfp,
> +		 omap_dss_hdmi_timings.hsw,
> +		 omap_dss_hdmi_timings.hbp,
> +		 omap_dss_hdmi_timings.vfp,
> +		 omap_dss_hdmi_timings.vsw,
> +		 omap_dss_hdmi_timings.vbp
> +		 );
> +
> +}
> +
> +void get_edid_timing_data(u8 *edid, u16 *pixel_clk, u16 *horizontal_res,
> +			  u16 *vertical_res)
> +{
> +	u8 offset, effective_addrs;
> +	u8 count;
> +	u8 i;
> +	u8 flag = false;
> +	/*check for 720P timing in block0 */
> +	for (count = 0; count < EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR; count++) {
> +		current_descriptor_addrs > +			EDID_DESCRIPTOR_BLOCK0_ADDRESS +
> +			count * EDID_TIMING_DESCRIPTOR_SIZE;
> +		*horizontal_res > +			(((edid[EDID_DESCRIPTOR_BLOCK0_ADDRESS + 4 +
> +			   count * EDID_TIMING_DESCRIPTOR_SIZE] & 0xF0) << 4) |
> +			 edid[EDID_DESCRIPTOR_BLOCK0_ADDRESS + 2 +
> +			 count * EDID_TIMING_DESCRIPTOR_SIZE]);
> +		*vertical_res > +			(((edid[EDID_DESCRIPTOR_BLOCK0_ADDRESS + 7 +
> +			   count * EDID_TIMING_DESCRIPTOR_SIZE] & 0xF0) << 4) |
> +			 edid[EDID_DESCRIPTOR_BLOCK0_ADDRESS + 5 +
> +			 count * EDID_TIMING_DESCRIPTOR_SIZE]);
> +
> +		dev_dbg(&sil9022_client->dev,
> +			"<%s> ***Block-0-Timing-descriptor[%d]***\n",
> +			__func__, count);
> +		for (i = current_descriptor_addrs;
> +		      i <
> +		      (current_descriptor_addrs+EDID_TIMING_DESCRIPTOR_SIZE);
> +		      i++)
> +			dev_dbg(&sil9022_client->dev,
> +				"%x =>		%x\n", i, edid[i]);
> +
> +			dev_dbg(&sil9022_client->dev,
> +				 "<%s>\n"
> +				 "E-EDID Buffer Index	= %d\n"
> +				 "horizontal_res	= %d\n"
> +				 "vertical_res		= %d\n",
> +				 __func__,
> +				 current_descriptor_addrs,
> +				 *horizontal_res,
> +				 *vertical_res
> +				 );
> +
> +		if (*horizontal_res = HDMI_XRES &&
> +		    *vertical_res = HDMI_YRES) {
> +			dev_info(&sil9022_client->dev,
> +				"<%s>\nFound EDID Data for %d x %dp\n",
> +				 __func__, *horizontal_res, *vertical_res);
> +			flag = true;
> +			break;
> +			}
> +	}
> +
> +	/*check for the Timing in block1 */
> +	if (flag != true) {
> +		offset = edid[EDID_DESCRIPTOR_BLOCK1_ADDRESS + 2];
> +		if (offset != 0) {
> +			effective_addrs = EDID_DESCRIPTOR_BLOCK1_ADDRESS
> +				+ offset;
> +			/*to determine the number of descriptor blocks */
> +			for (count = 0;
> +			      count < EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR;
> +			      count++) {
> +				current_descriptor_addrs = effective_addrs +
> +					count * EDID_TIMING_DESCRIPTOR_SIZE;
> +				*horizontal_res > +					(((edid[effective_addrs + 4 +
> +					   count*EDID_TIMING_DESCRIPTOR_SIZE] &
> +					   0xF0) << 4) |
> +					 edid[effective_addrs + 2 +
> +					 count * EDID_TIMING_DESCRIPTOR_SIZE]);
> +				*vertical_res > +					(((edid[effective_addrs + 7 +
> +					   count*EDID_TIMING_DESCRIPTOR_SIZE] &
> +					   0xF0) << 4) |
> +					 edid[effective_addrs + 5 +
> +					 count * EDID_TIMING_DESCRIPTOR_SIZE]);
> +
> +				dev_dbg(&sil9022_client->dev,
> +					 "<%s> Block1-Timing-descriptor[%d]\n",
> +					 __func__, count);
> +
> +				for (i = current_descriptor_addrs;
> +				      i < (current_descriptor_addrs+
> +					   EDID_TIMING_DESCRIPTOR_SIZE); i++)
> +					dev_dbg(&sil9022_client->dev,
> +						"%x =>		%x\n",
> +						   i, edid[i]);
> +
> +				dev_dbg(&sil9022_client->dev, "<%s>\n"
> +						"current_descriptor	= %d\n"
> +						"horizontal_res		= %d\n"
> +						"vertical_res		= %d\n",
> +					 __func__, current_descriptor_addrs,
> +					 *horizontal_res, *vertical_res);
> +
> +				if (*horizontal_res = HDMI_XRES &&
> +				    *vertical_res = HDMI_YRES) {
> +					dev_info(&sil9022_client->dev,
> +						 "<%s> Found EDID Data for "
> +						 "%d x %dp\n",
> +						 __func__,
> +						 *horizontal_res,
> +						 *vertical_res
> +						 );
> +					flag = true;
> +					break;
> +					}
> +			}
> +		}
> +	}
> +
> +	if (flag = true) {
> +		*pixel_clk = ((edid[current_descriptor_addrs + 1] << 8) |
> +			     edid[current_descriptor_addrs]);
> +
> +		omap_dss_hdmi_timings.x_res = *horizontal_res;
> +		omap_dss_hdmi_timings.y_res = *vertical_res;
> +		omap_dss_hdmi_timings.pixel_clock = *pixel_clk*10;
> +		dev_dbg(&sil9022_client->dev,
> +			 "EDID TIMING DATA supported by zoom2 FOUND\n"
> +			 "EDID DTD block address	= %d\n"
> +			 "pixel_clk			= %d\n"
> +			 "horizontal res		= %d\n"
> +			 "vertical res			= %d\n",
> +			 current_descriptor_addrs,
> +			 omap_dss_hdmi_timings.pixel_clock,
> +			 omap_dss_hdmi_timings.x_res,
> +			 omap_dss_hdmi_timings.y_res
> +			 );
> +
> +		get_horz_vert_timing_info(edid);
> +	} else {
> +
> +		dev_info(&sil9022_client->dev,
> +			 "<%s>\n"
> +			 "EDID TIMING DATA supported by zoom2 NOT FOUND\n"
> +			 "setting default timing values for 720p\n"
> +			 "pixel_clk		= %d\n"
> +			 "horizontal res	= %d\n"
> +			 "vertical res		= %d\n",
> +			 __func__,
> +			 omap_dss_hdmi_timings.pixel_clock,
> +			 omap_dss_hdmi_timings.x_res,
> +			 omap_dss_hdmi_timings.y_res
> +			 );
> +
> +		*pixel_clk = omap_dss_hdmi_timings.pixel_clock;
> +		*horizontal_res = omap_dss_hdmi_timings.x_res;
> +		*vertical_res = omap_dss_hdmi_timings.y_res;
> +	}
> +
> +
> +}
> +
> +
> +static int
> +sil9022_blockwrite_reg(struct i2c_client *client,
> +				  u8 reg, u16 alength, u8 *val, u16 *out_len)
> +{
> +	int err = 0, i;
> +	struct i2c_msg msg[1];
> +	u8 data[2];
> +
> +	if (!client->adapter) {
> +		dev_err(&client->dev, "<%s> ERROR: No HDMI Device\n", __func__);
> +		return -ENODEV;
> +	}
> +
> +	msg->addr = client->addr;
> +	msg->flags = I2C_M_WR;
> +	msg->len = 2;
> +	msg->buf = data;
> +
> +	/* high byte goes out first */
> +	data[0] = reg >> 8;
> +
> +	for (i = 0; i < alength - 1; i++) {
> +		data[1] = val[i];
> +		err = i2c_transfer(client->adapter, msg, 1);
> +		udelay(50);
> +		dev_dbg(&client->dev, "<%s> i2c Block write at 0x%x, "
> +				      "*val=%d flags=%d byte[%d] err=%d\n",
> +			__func__, data[0], data[1], msg->flags, i, err);
> +		if (err < 0)
> +			break;
> +	}
> +	/* set the number of bytes written*/
> +	*out_len = i;
> +
> +	if (err < 0) {
> +		dev_err(&client->dev, "<%s> ERROR:  i2c Block Write at 0x%x, "
> +				      "*val=%d flags=%d bytes written=%d "
> +				      "err=%d\n",
> +			__func__, data[0], data[1], msg->flags, i, err);
> +		return err;
> +	}
> +	return 0;
> +}
> +
> +static int
> +sil9022_blockread_reg(struct i2c_client *client,
> +		      u16 data_length, u16 alength,
> +		      u8 reg, u8 *val, u16 *out_len)
> +{
> +	int err = 0, i;
> +	struct i2c_msg msg[1];
> +	u8 data[2];
> +
> +	if (!client->adapter) {
> +		dev_err(&client->dev, "<%s> ERROR: No HDMI Device\n", __func__);
> +		return -ENODEV;
> +	}
> +
> +	msg->addr = client->addr;
> +	msg->flags = I2C_M_WR;
> +	msg->len = 1;
> +	msg->buf = data;
> +
> +	/* High byte goes out first */
> +	data[0] = reg;
> +	err = i2c_transfer(client->adapter, msg, 1);
> +	dev_dbg(&client->dev, "<%s> i2c Block Read1 at 0x%x, "
> +			       "*val=%d flags=%d err=%d\n",
> +		 __func__, data[0], data[1], msg->flags, err);
> +
> +	for (i = 0; i < alength; i++) {
> +		if (err >= 0) {
> +			mdelay(3);
> +			msg->flags = I2C_M_RD;
> +			msg->len = data_length;
> +			err = i2c_transfer(client->adapter, msg, 1);
> +		} else
> +			break;
> +		if (err >= 0) {
> +			val[i] = 0;
> +			/* High byte comes first */
> +			if (data_length = 1)
> +				val[i] = data[0];
> +			else if (data_length = 2)
> +				val[i] = data[1] + (data[0] << 8);
> +			dev_dbg(&client->dev, "<%s> i2c Block Read2 at 0x%x, "
> +					       "*val=%d flags=%d byte=%d "
> +					       "err=%d\n",
> +				 __func__, reg, val[i], msg->flags, i, err);
> +		} else
> +			break;
> +	}
> +	*out_len = i;
> +	dev_dbg(&client->dev, "<%s> i2c Block Read at 0x%x, bytes read = %d\n",
> +		__func__, client->addr, *out_len);
> +
> +	if (err < 0) {
> +		dev_err(&client->dev, "<%s> ERROR:  i2c Read at 0x%x, "
> +				      "*val=%d flags=%d bytes read=%d err=%d\n",
> +			__func__, reg, *val, msg->flags, i, err);
> +		return err;
> +	}
> +	return 0;
> +}
> +
> +
> +/* Write a value to a register in sil9022 device.
> + * @client: i2c driver client structure.
> + * @reg: Address of the register to read value from.
> + * @val: Value to be written to a specific register.
> + * Returns zero if successful, or non-zero otherwise.
> + */
> +static int
> +sil9022_write_reg(struct i2c_client *client, u8 reg, u8 val)
> +{
> +	int err = 0;
> +	struct i2c_msg msg[1];
> +	u8 data[2];
> +	int retries = 0;
> +
> +	if (!client->adapter) {
> +		dev_err(&client->dev, "<%s> ERROR: No HDMI Device\n", __func__);
> +		return -ENODEV;
> +	}
> +
> +retry:
> +	msg->addr = client->addr;
> +	msg->flags = I2C_M_WR;
> +	msg->len = 2;
> +	msg->buf = data;
> +
> +	data[0] = reg;
> +	data[1] = val;
> +
> +	err = i2c_transfer(client->adapter, msg, 1);
> +	dev_dbg(&client->dev, "<%s> i2c write at=%x "
> +			       "val=%x flags=%d err=%d\n",
> +		__func__, data[0], data[1], msg->flags, err);
> +	udelay(50);
> +
> +	if (err >= 0)
> +		return 0;
> +
> +	dev_err(&client->dev, "<%s> ERROR: i2c write at=%x "
> +			       "val=%x flags=%d err=%d\n",
> +		__func__, data[0], data[1], msg->flags, err);
> +	if (retries <= 5) {
> +		dev_info(&client->dev, "Retrying I2C... %d\n", retries);
> +		retries++;
> +		set_current_state(TASK_UNINTERRUPTIBLE);
> +		schedule_timeout(msecs_to_jiffies(20));
> +		goto retry;
> +	}
> +	return err;
> +}
> +
> +/*
> + * Read a value from a register in sil9022 device.
> + * The value is returned in 'val'.
> + * Returns zero if successful, or non-zero otherwise.
> + */
> +static int
> +sil9022_read_reg(struct i2c_client *client, u16 data_length, u8 reg, u8 *val)
> +{
> +	int err = 0;
> +	struct i2c_msg msg[1];
> +	u8 data[2];
> +
> +	if (!client->adapter) {
> +		dev_err(&client->dev, "<%s> ERROR: No HDMI Device\n", __func__);
> +		return -ENODEV;
> +	}
> +
> +	msg->addr = client->addr;
> +	msg->flags = I2C_M_WR;
> +	msg->len = 1;
> +	msg->buf = data;
> +
> +	data[0] = reg;
> +	err = i2c_transfer(client->adapter, msg, 1);
> +	dev_dbg(&client->dev, "<%s> i2c Read1 reg=%x val=%d "
> +			       "flags=%d err=%d\n",
> +		__func__, reg, data[1], msg->flags, err);
> +
> +	if (err >= 0) {
> +		mdelay(3);
> +		msg->flags = I2C_M_RD;
> +		msg->len = data_length;
> +		err = i2c_transfer(client->adapter, msg, 1);
> +	}
> +
> +	if (err >= 0) {
> +		*val = 0;
> +		if (data_length = 1)
> +			*val = data[0];
> +		else if (data_length = 2)
> +			*val = data[1] + (data[0] << 8);
> +		dev_dbg(&client->dev, "<%s> i2c Read2 at 0x%x, *val=%d "
> +				       "flags=%d err=%d\n",
> +			 __func__, reg, *val, msg->flags, err);
> +		return 0;
> +	}
> +
> +	dev_err(&client->dev, "<%s> ERROR: i2c Read at 0x%x, "
> +			      "*val=%d flags=%d err=%d\n",
> +		__func__, reg, *val, msg->flags, err);
> +	return err;
> +}
> +
> +static int
> +sil9022_read_edid(struct i2c_client *client, u16 len,
> +	       char *p_buffer, u16 *out_len)
> +{
> +	int err =  0;
> +	u8 val = 0;
> +	int retries = 0;
> +	int i = 0;
> +	int k = 0;
> +
> +	len = (len < HDMI_EDID_MAX_LENGTH) ? len : HDMI_EDID_MAX_LENGTH;
> +
> +	/* Request DDC bus access to read EDID info from HDTV */
> +	dev_info(&client->dev, "<%s> Reading HDMI EDID\n", __func__);
> +
> +	/* Bring transmitter to low-Power state */
> +	val = TPI_AVI_POWER_STATE_D2;
> +	err = sil9022_write_reg(client, HDMI_TPI_DEVICE_POWER_STATE_DATA, val);
> +	if (err < 0) {
> +		dev_err(&client->dev,
> +			"<%s> ERROR: Failed during bring power state - low.\n",
> +			 __func__);
> +		return err;
> +	}
> +
> +	/* Disable TMDS clock */
> +	val = 0x11;
> +	err = sil9022_write_reg(client, HDMI_SYS_CTRL_DATA_REG, val);
> +	if (err < 0) {
> +		dev_err(&client->dev,
> +			"<%s> ERROR: Failed during bring power state - low.\n",
> +			 __func__);
> +		return err;
> +	}
> +
> +	val = 0;
> +	/* Read TPI system control register*/
> +	err = sil9022_read_reg(client, 1, HDMI_SYS_CTRL_DATA_REG, &val);
> +	if (err < 0) {
> +		dev_err(&client->dev,
> +			"<%s> ERROR: Reading DDC BUS REQUEST\n", __func__);
> +		return err;
> +	}
> +
> +	/* The host writes 0x1A[2]=1 to request the
> +	 * DDC(Display Data Channel) bus
> +	 */
> +	val |= TPI_SYS_CTRL_DDC_BUS_REQUEST;
> +	err = sil9022_write_reg(client, HDMI_SYS_CTRL_DATA_REG, val);
> +	if (err < 0) {
> +		dev_err(&client->dev,
> +			"<%s> ERROR: Writing DDC BUS REQUEST\n", __func__);
> +		return err;
> +	}
> +
> +	 /*  Poll for bus DDC Bus control to be granted */
> +	dev_info(&client->dev, "<%s> Poll for DDC bus access\n", __func__);
> +	val = 0;
> +	do {
> +		err = sil9022_read_reg(client, 1, HDMI_SYS_CTRL_DATA_REG, &val);
> +		if (retries++ > 100)
> +			return err;
> +
> +	} while ((val & TPI_SYS_CTRL_DDC_BUS_GRANTED) = 0);
> +
> +	/*  Close the switch to the DDC */
> +	val |= TPI_SYS_CTRL_DDC_BUS_REQUEST | TPI_SYS_CTRL_DDC_BUS_GRANTED;
> +	err = sil9022_write_reg(client, HDMI_SYS_CTRL_DATA_REG, val);
> +	if (err < 0) {
> +		dev_err(&client->dev,
> +			"<%s> ERROR: Close switch to DDC BUS REQUEST\n",
> +			__func__);
> +		return err;
> +	}
> +
> +	memset(p_buffer, 0, len);
> +	/* change I2C SetSlaveAddress to HDMI_I2C_MONITOR_ADDRESS */
> +	/*  Read the EDID structure from the monitor I2C address  */
> +	client->addr = HDMI_I2C_MONITOR_ADDRESS;
> +	err = sil9022_blockread_reg(client, 1, len,
> +				    0x00, p_buffer, out_len);
> +	if (err < 0 || *out_len <= 0) {
> +		dev_err(&client->dev,
> +			"<%s> ERROR: Reading EDID from "
> +			"HDMI_I2C_MONITOR_ADDRESS\n", __func__);
> +		return err;
> +	}
> +
> +	for (i = 0; i < *out_len; i++) {
> +		if ((i / 18) < 3) {
> +			dev_dbg(&client->dev, "byte->%02x	%x\n",
> +				i, p_buffer[i]);
> +			continue;
> +		}
> +		if ((i/18 >= 3 && i/18 <= 6) && (i%18 = 0))
> +			dev_dbg(&client->dev, "\n DTD Block %d\n", k++);
> +
> +		if ((i/18 = 7) && (i%18 = 0))
> +			dev_dbg(&client->dev, "\n");
> +
> +		dev_dbg(&client->dev, "byte->%02x	%x\n", i, p_buffer[i]);
> +	}
> +
> +	/* Release DDC bus access */
> +	client->addr = SI9022_I2CSLAVEADDRESS;
> +	val &= ~(TPI_SYS_CTRL_DDC_BUS_REQUEST | TPI_SYS_CTRL_DDC_BUS_GRANTED);
> +	err = sil9022_write_reg(client, HDMI_SYS_CTRL_DATA_REG, val);
> +
> +	if (err < 0) {
> +		dev_err(&client->dev,
> +			"<%s> ERROR: Releasing DDC  Bus Access\n",
> +			__func__);
> +		return err;
> +		}
> +
> +	/*  Success */
> +	return 0;
> +}
> +
> +static int
> +sil9022_enable_audio(struct i2c_client *client)
> +{
> +	int err = 0;
> +	u8  val = 0;
> +	u8  crc = 0;
> +	u32 count = 0;
> +	int index = 0;
> +
> +	for (index = 0;
> +	      index < sizeof(hdmi_tpi_audio_config_data) /
> +	      sizeof(struct hdmi_reg_data);
> +	      index++) {
> +		err = sil9022_write_reg(
> +			client,
> +			hdmi_tpi_audio_config_data[index].reg_offset,
> +			hdmi_tpi_audio_config_data[index].value);
> +		if (err != 0) {
> +			dev_err(&client->dev,
> +				"<%s> ERROR: Writing "
> +				"tpi_audio_config_data[%d]={ %d, %d }\n",
> +				__func__, index,
> +				hdmi_tpi_audio_config_data[index].reg_offset,
> +				hdmi_tpi_audio_config_data[index].value);
> +			return err;
> +			}
> +		}
> +
> +	/* Fill the checksum byte for Infoframe data*/
> +	count = 0;
> +	while (count < MISC_INFOFRAME_SIZE_MEMORY) {
> +		crc += misc_audio_info_frame_data[count];
> +		count++;
> +	}
> +	crc = 0x100 - crc;
> +
> +	/* Fill CRC Byte*/
> +	misc_audio_info_frame_data[0x3] = crc;
> +
> +	for (count = 0; count < MISC_INFOFRAME_SIZE_MEMORY; count++) {
> +		err = sil9022_write_reg(client,
> +					(HDMI_CPI_MISC_IF_OFFSET + count),
> +					misc_audio_info_frame_data[count]);
> +		if (err < 0) {
> +			dev_err(&client->dev,
> +				"<%s> ERROR: writing audio info frame"
> +				" CRC data: %d\n", __func__, count);
> +			return err;
> +		}
> +	}
> +
> +	/* Decode Level 0 Packets */
> +	val = 0x2;
> +	sil9022_write_reg(client, 0xBC, val);
> +	if (err < 0) {
> +		dev_err(&client->dev,
> +			"<%s> ERROR: writing level 0 packets to 0xBC\n",
> +			__func__);
> +		return err;
> +	}
> +
> +	val = 0x24;
> +	err = sil9022_write_reg(client, 0xBD, val);
> +	if (err < 0) {
> +		dev_err(&client->dev,
> +			"<%s> ERROR: writing level 0 packets to 0xBD\n",
> +			__func__);
> +		return err;
> +	}
> +
> +	val = 0x2;
> +	err = sil9022_write_reg(client, 0xBE, val);
> +	if (err < 0) {
> +		dev_err(&client->dev,
> +			"<%s> ERROR: writing level 0 packets to 0xBE\n",
> +			__func__);
> +		return err;
> +	}
> +
> +	/* Disable Mute */
> +	val = TPI_AUDIO_INTERFACE_I2S |
> +		  TPI_AUDIO_MUTE_DISABLE |
> +		  TPI_AUDIO_CODING_PCM;
> +	err = sil9022_write_reg(client, HDMI_TPI_AUDIO_CONFIG_BYTE2_REG, val);
> +	if (err < 0) {
> +		dev_err(&client->dev,
> +			"<%s> ERROR: Disabling mute\n",
> +			__func__);
> +		return err;
> +	}
> +
> +	dev_info(&client->dev, "<%s> hdmi audio enabled\n",
> +		__func__);
> +	return 0;
> +
> +}
> +
> +static int
> +sil9022_disable_audio(struct i2c_client *client)
> +{
> +	u8 val = 0;
> +	int err = 0;
> +	/* Disable Audio */
> +	val = TPI_AUDIO_INTERFACE_DISABLE;
> +	err = sil9022_write_reg(client, HDMI_TPI_AUDIO_CONFIG_BYTE2_REG, val);
> +	if (err < 0)
> +		dev_err(&client->dev,
> +			"<%s> ERROR: Disisable audio interface", __func__);
> +
> +	dev_info(&client->dev, "<%s> hdmi audio disabled\n", __func__);
> +	return err;
> +}
> +
> +static int
> +sil9022_enable(struct omap_dss_device *dssdev)
> +{
> +	int		err;
> +	u8		val, vals[14];
> +	int		i;
> +	u16		out_len = 0;
> +	u8		edid[HDMI_EDID_MAX_LENGTH];
> +	u16		horizontal_res;
> +	u16		vertical_res;
> +	u16		pixel_clk;
> +
> +	memset(edid, 0, HDMI_EDID_MAX_LENGTH);
> +	memset(vals, 0, 14);
> +
> +	err = sil9022_read_edid(sil9022_client, HDMI_EDID_MAX_LENGTH,
> +			     edid, &out_len);
> +	if (err < 0 || out_len = 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> Unable to read EDID for monitor\n", __func__);
> +		return err;
> +	}
> +
> +	get_edid_timing_data(edid,
> +			     &pixel_clk,
> +			     &horizontal_res,
> +			     &vertical_res
> +			     );
> +
> +	/*  Fill the TPI Video Mode Data structure */
> +	vals[0] = (pixel_clk & 0xFF);                  /* Pixel clock */
> +	vals[1] = ((pixel_clk & 0xFF00) >> 8);
> +	vals[2] = VERTICAL_FREQ;                    /* Vertical freq */
> +	vals[3] = 0x00;
> +	vals[4] = (horizontal_res & 0xFF);         /* Horizontal pixels*/
> +	vals[5] = ((horizontal_res & 0xFF00) >> 8);
> +	vals[6] = (vertical_res & 0xFF);           /* Vertical pixels */
> +	vals[7] = ((vertical_res & 0xFF00) >> 8);
> +
> +	dev_info(&sil9022_client->dev, "<%s>\nHDMI Monitor E-EDID Timing Data\n"
> +				       "horizontal_res	= %d\n"
> +				       "vertical_res	= %d\n"
> +				       "pixel_clk	= %d\n"
> +				       "hfp		= %d\n"
> +				       "hsw		= %d\n"
> +				       "hbp		= %d\n"
> +				       "vfp		= %d\n"
> +				       "vsw		= %d\n"
> +				       "vbp		= %d\n",
> +		 __func__,
> +		 omap_dss_hdmi_timings.x_res,
> +		 omap_dss_hdmi_timings.y_res,
> +		 omap_dss_hdmi_timings.pixel_clock,
> +		 omap_dss_hdmi_timings.hfp,
> +		 omap_dss_hdmi_timings.hsw,
> +		 omap_dss_hdmi_timings.hbp,
> +		 omap_dss_hdmi_timings.vfp,
> +		 omap_dss_hdmi_timings.vsw,
> +		 omap_dss_hdmi_timings.vbp
> +		 );
> +
> +	dssdev->panel.timings = omap_dss_hdmi_timings;
> +	/*  Write out the TPI Video Mode Data */
> +	out_len = 0;
> +	err = sil9022_blockwrite_reg(sil9022_client,
> +				     HDMI_TPI_VIDEO_DATA_BASE_REG,
> +				     8, vals, &out_len);
> +	if (err < 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> ERROR: writing TPI video mode data\n", __func__);
> +		return err;
> +	}
> +
> +	/* Write out the TPI Pixel Repetition Data (24 bit wide bus,
> +	falling edge, no pixel replication) */
> +	val = TPI_AVI_PIXEL_REP_BUS_24BIT |
> +		TPI_AVI_PIXEL_REP_FALLING_EDGE |
> +		TPI_AVI_PIXEL_REP_NONE;
> +	err = sil9022_write_reg(sil9022_client,
> +				HDMI_TPI_PIXEL_REPETITION_REG,
> +				val);
> +	if (err < 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> ERROR: writing TPI pixel repetition data\n",
> +			__func__);
> +		return err;
> +	}
> +
> +	 /*  Write out the TPI AVI Input Format */
> +	val = TPI_AVI_INPUT_BITMODE_8BIT |
> +		TPI_AVI_INPUT_RANGE_AUTO |
> +		TPI_AVI_INPUT_COLORSPACE_RGB;
> +	err = sil9022_write_reg(sil9022_client,
> +				HDMI_TPI_AVI_IN_FORMAT_REG,
> +				val);
> +	if (err < 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> ERROR: writing TPI AVI Input format\n", __func__);
> +		return err;
> +	}
> +
> +	/*  Write out the TPI AVI Output Format */
> +	val = TPI_AVI_OUTPUT_CONV_BT709 |
> +		TPI_AVI_OUTPUT_RANGE_AUTO |
> +		TPI_AVI_OUTPUT_COLORSPACE_RGBHDMI;
> +	err = sil9022_write_reg(sil9022_client,
> +				HDMI_TPI_AVI_OUT_FORMAT_REG, val);
> +	if (err < 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> ERROR: writing TPI AVI output format\n",
> +			__func__);
> +		return err;
> +	}
> +
> +	/* Write out the TPI System Control Data to power down */
> +	val = TPI_SYS_CTRL_POWER_DOWN;
> +	err = sil9022_write_reg(sil9022_client, HDMI_SYS_CTRL_DATA_REG, val);
> +	if (err < 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> ERROR: writing TPI power down control data\n",
> +			__func__);
> +		return err;
> +	}
> +
> +	/* Write out the TPI AVI InfoFrame Data (all defaults) */
> +	/* Compute CRC*/
> +	val = 0x82 + 0x02 + 13;
> +
> +	for (i = 0; i < sizeof(avi_info_frame_data); i++)
> +		val += avi_info_frame_data[i];
> +
> +	avi_info_frame_data[0] = 0x100 - val;
> +
> +	out_len = 0;
> +	err = sil9022_blockwrite_reg(sil9022_client,
> +				     HDMI_TPI_AVI_DBYTE_BASE_REG,
> +				     sizeof(avi_info_frame_data),
> +				     avi_info_frame_data, &out_len);
> +	if (err < 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> ERROR: writing TPI AVI infoframe data\n",
> +			__func__);
> +		return err;
> +	}
> +
> +	/*  Audio Configuration  */
> +	err = sil9022_enable_audio(sil9022_client);
> +	if (err < 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> ERROR: Unable set audio configuration\n",
> +			__func__);
> +		return err;
> +	}
> +
> +	/*  Write out the TPI Device Power State (D0) */
> +	val = TPI_AVI_POWER_STATE_D0;
> +	err = sil9022_write_reg(sil9022_client,
> +				HDMI_TPI_POWER_STATE_CTRL_REG, val);
> +	if (err < 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> ERROR: Setting device power state to D0\n",
> +			__func__);
> +		return err;
> +	}
> +
> +	/* Write out the TPI System Control Data to power up and
> +	 * select output mode
> +	 */
> +	val = TPI_SYS_CTRL_POWER_ACTIVE | TPI_SYS_CTRL_OUTPUT_MODE_HDMI;
> +	err = sil9022_write_reg(sil9022_client, HDMI_SYS_CTRL_DATA_REG, val);
> +	if (err < 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> ERROR: Writing system control data\n", __func__);
> +		return err;
> +	}
> +
> +	/*  Read back TPI System Control Data to latch settings */
> +	msleep(20);
> +	err = sil9022_read_reg(sil9022_client, 1, HDMI_SYS_CTRL_DATA_REG, &val);
> +	if (err < 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> ERROR: Writing system control data\n",
> +			__func__);
> +		return err;
> +	}
> +
> +	/* HDCP Enable - Disable */
> +	val = 0;
> +	err = sil9022_write_reg(sil9022_client,
> +				HDMI_TPI_HDCP_CONTROLDATA_REG, val);
> +	if (err < 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> ERROR: Enable (1) / Disable (0) => HDCP: %d\n",
> +			__func__, val);
> +		return err;
> +	}
> +
> +	dev_info(&sil9022_client->dev, "<%s> hdmi enabled\n", __func__);
> +	return 0;
> +
> +}
> +
> +static int
> +sil9022_disable(void)
> +{
> +	u8 val = 0;
> +	int err = 0;
> +
> +	err = sil9022_disable_audio(sil9022_client);
> +	if (err < 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> ERROR: failed to disable audio\n", __func__);
> +		return err;
> +	}
> +
> +	/*  Write out the TPI System Control Data to power down  */
> +	val = TPI_SYS_CTRL_POWER_DOWN;
> +	err = sil9022_write_reg(sil9022_client, HDMI_SYS_CTRL_DATA_REG, val);
> +	if (err < 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> ERROR: writing control data - power down\n",
> +			__func__);
> +		return err;
> +	}
> +
> +	/*  Write out the TPI Device Power State (D2) */
> +	val = TPI_AVI_POWER_STATE_D2;
> +	err = sil9022_write_reg(sil9022_client,
> +			  HDMI_TPI_DEVICE_POWER_STATE_DATA, val);
> +	if (err < 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> ERROR: Setting device power state to D2\n",
> +			__func__);
> +		return err;
> +	}
> +
> +	/*  Read back TPI System Control Data to latch settings */
> +	mdelay(10);
> +	err = sil9022_read_reg(sil9022_client, 1, HDMI_SYS_CTRL_DATA_REG, &val);
> +	if (err < 0) {
> +		dev_err(&sil9022_client->dev,
> +			"<%s> ERROR:  Reading System control data "
> +			"- latch settings\n", __func__);
> +		return err;
> +	}
> +
> +	dev_info(&sil9022_client->dev, "<%s> hdmi disabled\n", __func__);
> +	return 0;
> +
> +}
> +
> +static int sil9022_set_reg_read_ctrl(struct i2c_client *client)
> +{
> +	int err = 0;
> +	u8 ver;
> +
> +	/* probe for sil9022 chip version*/
> +	err = sil9022_write_reg(client, SI9022_REG_TPI_RQB, 0x00);
> +	if (err < 0) {
> +		dev_err(&client->dev,
> +			"<%s> ERROR: Writing HDMI configuration to "
> +			"reg - SI9022_REG_TPI_RQB\n", __func__);
> +		err = -ENODEV;
> +		goto ERROR1;
> +	}
> +
> +	err = sil9022_read_reg(client, 1, SI9022_REG_CHIPID0, &ver);
> +	if (err < 0) {
> +		dev_err(&client->dev,
> +			"<%s> ERROR: Reading HDMI version Id\n", __func__);
> +		err = -ENODEV;
> +		goto ERROR1;
> +	} else if (ver != SI9022_CHIPID_902x) {
> +		dev_err(&client->dev,
> +			"<%s> Not a valid verId: 0x%x\n", __func__, ver);
> +		err = -ENODEV;
> +		goto ERROR1;
> +	} else
> +		dev_info(&client->dev,
> +			 "<%s> sil9022 HDMI Chip version = %x\n",
> +			 __func__, ver);
> +
> +	return 0;
> +ERROR1:
> +	return err;
> +}
> +
> +static inline struct sil9022_platform_data
> +*get_panel_data(const struct omap_dss_device *dssdev)
> +{
> +	return (struct sil9022_platform_data *) dssdev->data;
> +}
> +
> +
> +static int sil9022_panel_probe(struct omap_dss_device *dssdev)
> +{
> +	struct sil9022_platform_data *sidata = get_panel_data(dssdev);
> +	int r;
> +	if (!sidata)
> +		return -EINVAL;
> +
> +	dssdev->panel.timings = omap_dss_hdmi_timings;
> +
> +	if (gpio_is_valid(sidata->res_gpio)) {
> +		r = devm_gpio_request_one(&dssdev->dev, sidata->res_gpio,
> +				GPIOF_OUT_INIT_HIGH, "HDMI");
> +		if (r)
> +			return r;
> +	}
> +
> +	return 0;
> +}
> +
> +static void sil9022_panel_remove(struct omap_dss_device *dssdev)
> +{
> +	omap_dss_unregister_driver(dssdev->driver);
> +}
> +
> +
> +static int sil9022_panel_power_on(struct omap_dss_device *dssdev)
> +{
> +	int r = 0;
> +	struct sil9022_platform_data *sidata = get_panel_data(dssdev);
> +
> +	if (dssdev->state = OMAP_DSS_DISPLAY_ACTIVE)
> +		return 0;
> +
> +	if (gpio_is_valid(sidata->res_gpio))
> +		gpio_set_value_cansleep(sidata->res_gpio, 1);
> +
> +	omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
> +	omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
> +	r = omapdss_dpi_display_enable(dssdev);
> +	return r;
> +
> +}
> +
> +static void sil9022_panel_power_off(struct omap_dss_device *dssdev)
> +{
> +	struct sil9022_platform_data *sidata = get_panel_data(dssdev);
> +
> +	if (gpio_is_valid(sidata->res_gpio))
> +		gpio_set_value_cansleep(sidata->res_gpio, 0);
> +	return;
> +
> +}
> +
> +static int sil9022_panel_enable(struct omap_dss_device *dssdev)
> +{
> +	int r = 0;
> +
> +	r = sil9022_panel_power_on(dssdev);
> +	if (r)
> +			goto ERROR0;
> +	r = sil9022_set_reg_read_ctrl(sil9022_client);
> +	if (r)
> +		goto ERROR0;
> +
> +	r = sil9022_enable(dssdev);
> +	if (r)
> +		goto ERROR0;
> +	/* wait couple of vsyncs until enabling the LCD */
> +	msleep(50);
> +	return 0;
> +
> +ERROR0:
> +	return r;
> +}
> +
> +static void sil9022_panel_disable(struct omap_dss_device *dssdev)
> +{
> +	sil9022_disable();
> +	/* wait couple of vsyncs until enabling the hdmi */
> +	msleep(50);
> +	sil9022_panel_power_off(dssdev);
> +	return;
> +}
> +
> +static struct omap_dss_driver hdmi_driver = {
> +	.probe		= sil9022_panel_probe,
> +	.remove		= sil9022_panel_remove,
> +
> +	.enable		= sil9022_panel_enable,
> +	.disable		= sil9022_panel_disable,
> +
> +	.driver         = {
> +		.name   = "sil9022_panel",
> +		.owner  = THIS_MODULE,
> +	},
> +};
> +
> +static int
> +sil9022_probe(struct i2c_client *client, const struct i2c_device_id *id)
> +{
> +	int err = 0;
> +
> +	sil9022_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
> +	if (!sil9022_client) {
> +		err = -ENOMEM;
> +		goto ERROR0;
> +	}
> +	memset(sil9022_client, 0, sizeof(struct i2c_client));
> +
> +	strncpy(sil9022_client->name, client->name, I2C_NAME_SIZE);
> +	sil9022_client->addr = client->addr;
> +	sil9022_client->adapter = client->adapter;
> +
> +	err = sil9022_set_reg_read_ctrl(client);
> +	if (err)
> +		goto ERROR1;
> +
> +	omap_dss_register_driver(&hdmi_driver);
> +	return 0;
> +
> +ERROR1:
> +	kfree(sil9022_client);
> +ERROR0:
> +	return err;
> +}
> +
> +
> +static int
> +sil9022_remove(struct i2c_client *client)
> +
> +{
> +	int err = 0;
> +
> +	if (!client->adapter) {
> +		dev_err(&sil9022_client->dev, "<%s> No HDMI Device\n",
> +			__func__);
> +		return -ENODEV;
> +	}
> +	kfree(sil9022_client);
> +
> +	return err;
> +}
> +
> +static const struct i2c_device_id sil9022_id[] = {
> +	{ SIL9022_DRV_NAME, 0 },
> +	{ },
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, sil9022_id);
> +
> +static struct i2c_driver sil9022_driver = {
> +	.driver = {
> +		.name  = SIL9022_DRV_NAME,
> +		.owner = THIS_MODULE,
> +		},
> +	.probe		= sil9022_probe,
> +	.remove		= sil9022_remove,
> +	.id_table	= sil9022_id,
> +};
> +
> +static int __init
> +sil9022_init(void)
> +{
> +	int err = 0;
> +	err = i2c_add_driver(&sil9022_driver);
> +	if (err < 0) {
> +		printk(KERN_ERR "<%s> Driver registration failed\n", __func__);
> +		err = -ENODEV;
> +		goto ERROR0;
> +	}
> +
> +	if (sil9022_client = NULL) {
> +		printk(KERN_ERR "<%s> sil9022_client not allocated\n"
> +				"<%s> No HDMI Device\n", __func__, __func__);
> +		err = -ENODEV;
> +		goto ERROR0;
> +	}
> +	return 0;
> +
> +ERROR0:
> +	return err;
> +}
> +
> +static void __exit
> +sil9022_exit(void)
> +{
> +	i2c_del_driver(&sil9022_driver);
> +}
> +
> +late_initcall(sil9022_init);
> +module_exit(sil9022_exit);
> +
> +MODULE_AUTHOR("Texas Instruments");
> +MODULE_DESCRIPTION("SIL9022 HDMI Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/video/omap2/displays/panel-sil9022.h b/drivers/video/omap2/displays/panel-sil9022.h
> new file mode 100644
> index 0000000..7c920c0
> --- /dev/null
> +++ b/drivers/video/omap2/displays/panel-sil9022.h
> @@ -0,0 +1,527 @@
> +/*
> + * drivers/video/omap2/displays/panel-sil9022.c
> + *
> + * Copyright (C) 2009 Texas Instruments
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + *
> + * sil9022 hdmi driver
> + */
> +#ifndef _SI9022_H_
> +#define _SI9022_H_
> +
> +#define SIL9022_DRV_NAME		"sil9022"
> +
> +#define CLKOUT2_EN		(0x1 << 7)
> +#define CLKOUT2_DIV		(0x4 << 3)
> +#define CLKOUT2SOURCE		(0x2 << 0)
> +#define CM_CLKOUT_CTRL		0x48004D70
> +
> +#define HDMI_XRES			1280
> +#define HDMI_YRES			720
> +#define HDMI_PIXCLOCK_MAX		74250
> +#define VERTICAL_FREQ			0x3C
> +
> +#define I2C_M_WR			0
> +
> +#define SI9022_USERST_PIN		1
> +
> +#define SI9022_REG_PIX_CLK_LSB		0x00
> +#define SI9022_REG_PIX_CLK_MSB		0x01
> +
> +#define SI9022_REG_PIX_REPETITION	0x08
> +#define SI9022_REG_INPUT_FORMAT		0x09
> +#define SI9022_REG_OUTPUT_FORMAT	0x0A
> +#define SI9022_REG_SYNC_GEN_CTRL	0x60
> +
> +#define SI9022_REG_DE_CTRL		0x63
> +#define DE_DLY_MSB_BITPOS		0
> +#define HSYNCPOL_INVERT_BITPOS		4
> +#define VSYNCPOL_INVERT_BITPOS		5
> +#define DE_GENERATOR_EN_BITPOS		6
> +
> +#define SI9022_REG_PWR_STATE		0x1E
> +
> +#define SI9022_REG_TPI_RQB		0xC7
> +
> +#define SI9022_REG_INT_PAGE		0xBC
> +#define SI9022_REG_OFFSET		0xBD
> +#define	SI9022_REG_VALUE		0xBE
> +
> +#define SI9022_PLLMULT_BITPOS		0x05
> +
> +#define SI9022_REG_TPI_SYSCTRL		0x1A
> +#define I2DDCREQ_BITPOS			2
> +#define TMDS_ENABLE_BITPOS		4
> +#define HDMI_ENABLE_BITPOS		0
> +
> +#define SI9022_REG_CHIPID0		0x1B
> +#define SI9022_REG_CHIPID1		0x1C
> +#define SI9022_REG_CHIPID2		0x1D
> +#define SI9022_REG_HDCPVER		0x30
> +
> +#define SI9022_REG_INTSTATUS		0x3D
> +#define HOTPLUG_PENDING_BITPOS		0
> +#define RCV_SENSE_PENDING_BITPOS	1
> +#define HOTPLUG_SENSE_BITPOS		2
> +#define RX_SENSE_BITPOS			3
> +#define AUDIO_ERR_PENDING_BITPOS	4
> +
> +
> +#define SI9022_I2CSLAVEADDRESS		0x39
> +
> +#define SI9022_CHIPID_902x		0xB0
> +
> +#define SI9022_MAXRETRY			100
> +
> +#define SI9022_EDID_DETAILED_TIMING_OFFSET	0x36 /*EDID Detailed Timing */
> +						/*Info 0 begin offset*/
> +#define SI9022_EDID_PIX_CLK_OFFSET		0
> +#define SI9022_EDID_H_ACTIVE_OFFSET		2
> +#define SI9022_EDID_H_BLANKING_OFFSET		3
> +#define SI9022_EDID_V_ACTIVE_OFFSET		5
> +#define SI9022_EDID_V_BLANKING_OFFSET		6
> +#define SI9022_EDID_H_SYNC_OFFSET		8
> +#define SI9022_EDID_H_SYNC_PW_OFFSET		9
> +#define SI9022_EDID_V_SYNC_OFFSET		10
> +#define SI9022_EDID_V_SYNC_PW_OFFSET		10
> +#define SI9022_EDID_H_IMAGE_SIZE_OFFSET		12
> +#define SI9022_EDID_V_IMAGE_SIZE_OFFSET		13
> +#define SI9022_EDID_H_BORDER_OFFSET		15
> +#define SI9022_EDID_V_BORDER_OFFSET		16
> +#define SI9022_EDID_FLAGS_OFFSET		17
> +
> +#define SI9022_PLUG_DETECTED			0xF0
> +#define SI9022_UNPLUG_DETECTED			0xF1
> +
> +
> +/* ---------------------------------------------------------------------  */
> +#define EDID_TIMING_DESCRIPTOR_SIZE		0x12
> +#define EDID_DESCRIPTOR_BLOCK0_ADDRESS		0x36
> +#define EDID_DESCRIPTOR_BLOCK1_ADDRESS		0x80
> +#define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR	4
> +#define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR	4
> +
> +/* HDMI Connected States  */
> +#define HDMI_STATE_NOMONITOR	0	/* NOT CONNECTED */
> +#define HDMI_STATE_CONNECTED	1	/* CONNECTED */
> +#define HDMI_STATE_ON		2	/* CONNECTED AND POWERED ON */
> +
> +
> +/* HDMI EDID Length  */
> +#define HDMI_EDID_MAX_LENGTH	256
> +
> +/* HDMI EDID DTDs  */
> +#define HDMI_EDID_MAX_DTDS	4
> +
> +/* HDMI EDID DTD Tags  */
> +#define HDMI_EDID_DTD_TAG_MONITOR_NAME		0xFC
> +#define HDMI_EDID_DTD_TAG_MONITOR_SERIALNUM	0xFF
> +#define HDMI_EDID_DTD_TAG_MONITOR_LIMITS	0xFD
> +
> +
> +/* HDMI EDID Extension Data Block Tags  */
> +#define HDMI_EDID_EX_DATABLOCK_TAG_MASK		0xE0
> +#define HDMI_EDID_EX_DATABLOCK_LEN_MASK		0x1F
> +
> +#define HDMI_EDID_EX_DATABLOCK_AUDIO		0x20
> +#define HDMI_EDID_EX_DATABLOCK_VIDEO		0x40
> +#define HDMI_EDID_EX_DATABLOCK_VENDOR		0x60
> +#define HDMI_EDID_EX_DATABLOCK_SPEAKERS		0x80
> +
> +/* HDMI EDID Extenion Data Block Values: Video  */
> +#define HDMI_EDID_EX_VIDEO_NATIVE		0x80
> +#define HDMI_EDID_EX_VIDEO_MASK			0x7F
> +#define HDMI_EDID_EX_VIDEO_MAX			35
> +
> +#define HDMI_EDID_EX_VIDEO_640x480p_60Hz_4_3		1
> +#define HDMI_EDID_EX_VIDEO_720x480p_60Hz_4_3		2
> +#define HDMI_EDID_EX_VIDEO_720x480p_60Hz_16_9		3
> +#define HDMI_EDID_EX_VIDEO_1280x720p_60Hz_16_9		4
> +#define HDMI_EDID_EX_VIDEO_1920x1080i_60Hz_16_9		5
> +#define HDMI_EDID_EX_VIDEO_720x480i_60Hz_4_3		6
> +#define HDMI_EDID_EX_VIDEO_720x480i_60Hz_16_9		7
> +#define HDMI_EDID_EX_VIDEO_720x240p_60Hz_4_3		8
> +#define HDMI_EDID_EX_VIDEO_720x240p_60Hz_16_9		9
> +#define HDMI_EDID_EX_VIDEO_2880x480i_60Hz_4_3		10
> +#define HDMI_EDID_EX_VIDEO_2880x480i_60Hz_16_9		11
> +#define HDMI_EDID_EX_VIDEO_2880x480p_60Hz_4_3		12
> +#define HDMI_EDID_EX_VIDEO_2880x480p_60Hz_16_9		13
> +#define HDMI_EDID_EX_VIDEO_1440x480p_60Hz_4_3		14
> +#define HDMI_EDID_EX_VIDEO_1440x480p_60Hz_16_9		15
> +#define HDMI_EDID_EX_VIDEO_1920x1080p_60Hz_16_9		16
> +#define HDMI_EDID_EX_VIDEO_720x576p_50Hz_4_3		17
> +#define HDMI_EDID_EX_VIDEO_720x576p_50Hz_16_9		18
> +#define HDMI_EDID_EX_VIDEO_1280x720p_50Hz_16_9		19
> +#define HDMI_EDID_EX_VIDEO_1920x1080i_50Hz_16_9		20
> +#define HDMI_EDID_EX_VIDEO_720x576i_50Hz_4_3		21
> +#define HDMI_EDID_EX_VIDEO_720x576i_50Hz_16_9		22
> +#define HDMI_EDID_EX_VIDEO_720x288p_50Hz_4_3		23
> +#define HDMI_EDID_EX_VIDEO_720x288p_50Hz_16_9		24
> +#define HDMI_EDID_EX_VIDEO_2880x576i_50Hz_4_3		25
> +#define HDMI_EDID_EX_VIDEO_2880x576i_50Hz_16_9		26
> +#define HDMI_EDID_EX_VIDEO_2880x288p_50Hz_4_3		27
> +#define HDMI_EDID_EX_VIDEO_2880x288p_50Hz_16_9		28
> +#define HDMI_EDID_EX_VIDEO_1440x576p_50Hz_4_3		29
> +#define HDMI_EDID_EX_VIDEO_1440x576p_50Hz_16_9		30
> +#define HDMI_EDID_EX_VIDEO_1920x1080p_50Hz_16_9		31
> +#define HDMI_EDID_EX_VIDEO_1920x1080p_24Hz_16_9		32
> +#define HDMI_EDID_EX_VIDEO_1920x1080p_25Hz_16_9		33
> +#define HDMI_EDID_EX_VIDEO_1920x1080p_30Hz_16_9		34
> +
> +/*  HDMI TPI Registers  */
> +#define HDMI_TPI_VIDEO_DATA_BASE_REG	0x00
> +#define HDMI_TPI_PIXEL_CLK_LSB_REG	 (HDMI_TPI_VIDEO_DATA_BASE_REG + 0x00)
> +#define HDMI_TPI_PIXEL_CLK_MSB_REG (HDMI_TPI_VIDEO_DATA_BASE_REG + 0x01)
> +#define HDMI_TPI_VFREQ_LSB_REG	(HDMI_TPI_VIDEO_DATA_BASE_REG + 0x02)
> +#define HDMI_TPI_VFREQ_MSB_REG	(HDMI_TPI_VIDEO_DATA_BASE_REG + 0x03)
> +#define HDMI_TPI_PIXELS_LSB_REG	(HDMI_TPI_VIDEO_DATA_BASE_REG + 0x04)
> +#define HDMI_TPI_PIXELS_MSB_REG	(HDMI_TPI_VIDEO_DATA_BASE_REG + 0x05)
> +#define HDMI_TPI_LINES_LSB_REG		(HDMI_TPI_VIDEO_DATA_BASE_REG + 0x06)
> +#define HDMI_TPI_LINES_MSB_REG		(HDMI_TPI_VIDEO_DATA_BASE_REG + 0x07)
> +
> +#define HDMI_TPI_PIXEL_REPETITION_REG	0x08
> +
> +#define HDMI_TPI_AVI_INOUT_BASE_REG	0x09
> +#define HDMI_TPI_AVI_IN_FORMAT_REG	(HDMI_TPI_AVI_INOUT_BASE_REG + 0x00)
> +#define HDMI_TPI_AVI_OUT_FORMAT_REG	(HDMI_TPI_AVI_INOUT_BASE_REG + 0x01)
> +
> +#define HDMI_SYS_CTRL_DATA_REG		0x1A
> +
> +#define HDMI_TPI_SYN_GENERATOR_REG	0x60
> +
> +#define HDMI_TPI_VIDEO_SYN_POLARITY_REG	0x61
> +
> +#define HDMI_TPI_DE_BASE_REG			0x62
> +#define HDMI_TPI_DE_DLY_LSB_REG		(HDMI_TPI_DE_BASE_REG + 0x0)
> +#define HDMI_TPI_DE_DLY_MSB_REG		(HDMI_TPI_DE_BASE_REG + 0x1)
> +#define HDMI_TPI_DE_TOP_REG			(HDMI_TPI_DE_BASE_REG + 0x2)
> +#define HDMI_TPI_DE_RSVD_REG			(HDMI_TPI_DE_BASE_REG + 0x3)
> +#define HDMI_TPI_DE_CNT_LSB_REG		(HDMI_TPI_DE_BASE_REG + 0x4)
> +#define HDMI_TPI_DE_CNT_MSB_REG		(HDMI_TPI_DE_BASE_REG + 0x5)
> +#define HDMI_TPI_DE_LIN_LSB_REG		(HDMI_TPI_DE_BASE_REG + 0x6)
> +#define HDMI_TPI_DE_LIN_MSB_REG		(HDMI_TPI_DE_BASE_REG + 0x7)
> +
> +#define HDMI_TPI_HRES_LSB_REG		0x6A
> +#define HDMI_TPI_HRES_MSB_REG		0x6B
> +
> +#define HDMI_TPI_VRES_LSB_REG		0x6C
> +#define HDMI_TPI_VRES_MSB_REG		0x6D
> +
> +#define HDMI_TPI_RQB_REG		0xC7
> +#define HDMI_TPI_DEVID_REG		0x1B
> +#define HDMI_TPI_DEVREV_REG		0x1C
> +
> +#define HDMI_TPI_DEVICE_POWER_STATE_DATA	0x1E
> +#define HDMI_REQ_GRANT_BMODE_REG		0xC7
> +#define HDMI_TPI_DEVICE_ID_REG			0x1B
> +#define HDMI_TPI_REVISION_REG			0x1C
> +#define HDMI_TPI_ID_BYTE2_REG			0x1D
> +#define HDMI_TPI_POWER_STATE_CTRL_REG		0x1E
> +
> +#define HDMI_TPI_INTERRUPT_ENABLE_REG		0x3C
> +#define HDMI_TPI_INTERRUPT_STATUS_REG		0x3D
> +
> +
> +/* AVI InfoFrames can be readed byte by byte but must be write in a burst  */
> +#define HDMI_TPI_AVI_DBYTE_BASE_REG      0x0C
> +#define HDMI_TPI_AVI_DBYTE0_CHKSUM_REG   (HDMI_TPI_AVI_DBYTE_BASE_REG +  0x00)
> +#define HDMI_TPI_AVI_DBYTE1_REG          (HDMI_TPI_AVI_DBYTE_BASE_REG +  0x01)
> +#define HDMI_TPI_AVI_DBYTE2_REG          (HDMI_TPI_AVI_DBYTE_BASE_REG +  0x02)
> +#define HDMI_TPI_AVI_DBYTE3_REG          (HDMI_TPI_AVI_DBYTE_BASE_REG +  0x03)
> +#define HDMI_TPI_AVI_DBYTE4_REG          (HDMI_TPI_AVI_DBYTE_BASE_REG +  0x04)
> +#define HDMI_TPI_AVI_DBYTE5_REG          (HDMI_TPI_AVI_DBYTE_BASE_REG +  0x05)
> +#define HDMI_TPI_AVI_ETB_LSB_REG         (HDMI_TPI_AVI_DBYTE_BASE_REG +  0x06)
> +#define HDMI_TPI_AVI_ETB_MSB_REG         (HDMI_TPI_AVI_DBYTE_BASE_REG +  0x07)
> +#define HDMI_TPI_AVI_SBB_LSB_REG         (HDMI_TPI_AVI_DBYTE_BASE_REG +  0x08)
> +#define HDMI_TPI_AVI_SBB_MSB_REG         (HDMI_TPI_AVI_DBYTE_BASE_REG +  0x09)
> +#define HDMI_TPI_AVI_ELB_LSB_REG         (HDMI_TPI_AVI_DBYTE_BASE_REG +  0x0A)
> +#define HDMI_TPI_AVI_ELB_MSB_REG         (HDMI_TPI_AVI_DBYTE_BASE_REG +  0x0B)
> +#define HDMI_TPI_AVI_SRB_LSB_REG         (HDMI_TPI_AVI_DBYTE_BASE_REG +  0x0C)
> +#define HDMI_TPI_AVI_SRB_MSB_REG         (HDMI_TPI_AVI_DBYTE_BASE_REG +  0x0D)
> +
> +#define HDMI_CPI_MISC_IF_SELECT_REG         0xBF
> +#define HDMI_CPI_MISC_IF_OFFSET             0xC0
> +
> +#define MISC_INFOFRAME_SIZE_MEMORY          14
> +#define MISC_INFOFRAME_TYPE_SUBOFFSET       0
> +#define MISC_INFOFRAME_VERSION_SUBOFFSET    1
> +#define MISC_INFOFRAME_LENGTH_SUBOFFSET     2
> +#define MISC_INFOFRAME_CHECKSUM_SUBOFFSET   3
> +#define MISC_INFOFRAME_DBYTE1_SUBOFFSET     4
> +#define MISC_INFOFRAME_DBYTE2_SUBOFFSET     5
> +#define MISC_INFOFRAME_DBYTE3_SUBOFFSET     6
> +#define MISC_INFOFRAME_DBYTE4_SUBOFFSET     7
> +#define MISC_INFOFRAME_DBYTE5_SUBOFFSET     8
> +#define MISC_INFOFRAME_DBYTE6_SUBOFFSET     9
> +#define MISC_INFOFRAME_DBYTE7_SUBOFFSET     10
> +#define MISC_INFOFRAME_DBYTE8_SUBOFFSET     11
> +#define MISC_INFOFRAME_DBYTE9_SUBOFFSET     12
> +#define MISC_INFOFRAME_DBYTE10_SUBOFFSET    13
> +
> +#define HDMI_CPI_MISC_TYPE_REG		(HDMI_CPI_MISC_IF_OFFSET\
> +					+  MISC_INFOFRAME_TYPE_SUBOFFSET)
> +#define HDMI_CPI_MISC_VERSION_REG	(HDMI_CPI_MISC_IF_OFFSET\
> +					+  MISC_INFOFRAME_VERSION_SUBOFFSET)
> +#define HDMI_CPI_MISC_LENGTH_REG	(HDMI_CPI_MISC_IF_OFFSET\
> +					+  MISC_INFOFRAME_LENGTH_SUBOFFSET)
> +#define HDMI_CPI_MISC_CHECKSUM_REG	(HDMI_CPI_MISC_IF_OFFSET\
> +					+  MISC_INFOFRAME_CHECKSUM_SUBOFFSET)
> +#define HDMI_CPI_MISC_DBYTE1_REG        (HDMI_CPI_MISC_IF_OFFSET\
> +					+  MISC_INFOFRAME_DBYTE1_SUBOFFSET)
> +#define HDMI_CPI_MISC_DBYTE2_REG        (HDMI_CPI_MISC_IF_OFFSET\
> +					+  MISC_INFOFRAME_DBYTE2_SUBOFFSET)
> +#define HDMI_CPI_MISC_DBYTE3_REG        (HDMI_CPI_MISC_IF_OFFSET\
> +					+  MISC_INFOFRAME_DBYTE3_SUBOFFSET)
> +#define HDMI_CPI_MISC_DBYTE4_REG        (HDMI_CPI_MISC_IF_OFFSET\
> +					+  MISC_INFOFRAME_DBYTE4_SUBOFFSET)
> +#define HDMI_CPI_MISC_DBYTE5_REG        (HDMI_CPI_MISC_IF_OFFSET\
> +					+  MISC_INFOFRAME_DBYTE5_SUBOFFSET)
> +#define HDMI_CPI_MISC_DBYTE6_REG        (HDMI_CPI_MISC_IF_OFFSET\
> +					+  MISC_INFOFRAME_DBYTE6_SUBOFFSET)
> +#define HDMI_CPI_MISC_DBYTE7_REG        (HDMI_CPI_MISC_IF_OFFSET\
> +					+  MISC_INFOFRAME_DBYTE7_SUBOFFSET)
> +#define HDMI_CPI_MISC_DBYTE8_REG        (HDMI_CPI_MISC_IF_OFFSET\
> +					+  MISC_INFOFRAME_DBYTE8_SUBOFFSET)
> +#define HDMI_CPI_MISC_DBYTE9_REG        (HDMI_CPI_MISC_IF_OFFSET\
> +					+  MISC_INFOFRAME_DBYTE9_SUBOFFSET)
> +#define HDMI_CPI_MISC_DBYTE10_REG       (HDMI_CPI_MISC_IF_OFFSET\
> +					+  MISC_INFOFRAME_DBYTE10_SUBOFFSET)
> +
> +/* Audio  */
> +#define HDMI_TPI_I2S_ENABLE_MAPPING_REG     0x1F
> +#define HDMI_TPI_I2S_INPUT_CONFIG_REG       0x20
> +#define HDMI_TPI_I2S_STRM_HDR_BASE          0x21
> +#define HDMI_TPI_I2S_STRM_HDR_0_REG         (HDMI_TPI_I2S_STRM_HDR_BASE + 0)
> +#define HDMI_TPI_I2S_STRM_HDR_1_REG         (HDMI_TPI_I2S_STRM_HDR_BASE + 1)
> +#define HDMI_TPI_I2S_STRM_HDR_2_REG         (HDMI_TPI_I2S_STRM_HDR_BASE + 2)
> +#define HDMI_TPI_I2S_STRM_HDR_3_REG         (HDMI_TPI_I2S_STRM_HDR_BASE + 3)
> +#define HDMI_TPI_I2S_STRM_HDR_4_REG         (HDMI_TPI_I2S_STRM_HDR_BASE + 4)
> +#define HDMI_TPI_AUDIO_CONFIG_BYTE2_REG     0x26
> +#define HDMI_TPI_AUDIO_CONFIG_BYTE3_REG     0x27
> +#define HDMI_TPI_AUDIO_CONFIG_BYTE4_REG     0x28
> +
> +/* HDCP */
> +#define HDMI_TPI_HDCP_QUERYDATA_REG         0x29
> +#define HDMI_TPI_HDCP_CONTROLDATA_REG       0x2A
> +
> +/* HDMI_TPI_DEVICE_ID_REG  */
> +#define TPI_DEVICE_ID                       0xB0
> +
> +/* HDMI_TPI_REVISION_REG  */
> +#define TPI_REVISION                        0x00
> +
> +/* HDMI_TPI_ID_BYTE2_REG  */
> +#define TPI_ID_BYTE2_VALUE                  0x00
> +
> +/* HDMI_SYS_CTRL_DATA_REG  */
> +#define TPI_SYS_CTRL_POWER_DOWN             (1 << 4)
> +#define TPI_SYS_CTRL_POWER_ACTIVE           (0 << 4)
> +#define TPI_SYS_CTRL_AV_MUTE                (1 << 3)
> +#define TPI_SYS_CTRL_DDC_BUS_REQUEST        (1 << 2)
> +#define TPI_SYS_CTRL_DDC_BUS_GRANTED        (1 << 1)
> +#define TPI_SYS_CTRL_OUTPUT_MODE_HDMI       (1 << 0)
> +#define TPI_SYS_CTRL_OUTPUT_MODE_DVI        (0 << 0)
> +
> +
> +/* HDMI Monitor I2C default address  */
> +#define HDMI_I2C_MONITOR_ADDRESS            0x50
> +
> +
> +/* HDMI_TPI_INTR_ENABLE  */
> +#define TPI_INTR_ENABLE_SECURITY_EVENT      (1 << 5)
> +#define TPI_INTR_ENABLE_AUDIO_EVENT         (1 << 4)
> +#define TPI_INTR_ENABLE_CPI_EVENT           (1 << 3)
> +#define TPI_INTR_ENABLE_RECEIVER_EVENT      (1 << 1)
> +#define TPI_INTR_ENABLE_HOTPLUG_EVENT       (1 << 0)
> +
> +/* HDMI_TPI_INTR_STATUS  */
> +#define TPI_INTR_STATUS_SECURITY_EVENT      (1 << 5)
> +#define TPI_INTR_STATUS_AUDIO_EVENT         (1 << 4)
> +#define TPI_INTR_STATUS_POWERED_EVENT       (1 << 3)
> +#define TPI_INTR_STATUS_HOTPLUG_STATE       (1 << 2)
> +#define TPI_INTR_STATUS_RECEIVER_EVENT      (1 << 1)
> +#define TPI_INTR_STATUS_HOTPLUG_EVENT       (1 << 0)
> +
> +
> +/* HDMI_TPI_PIXEL_REPETITION  */
> +#define TPI_AVI_PIXEL_REP_BUS_24BIT         (1 << 5)
> +#define TPI_AVI_PIXEL_REP_BUS_12BIT         (0 << 5)
> +#define TPI_AVI_PIXEL_REP_RISING_EDGE       (1 << 4)
> +#define TPI_AVI_PIXEL_REP_FALLING_EDGE      (0 << 4)
> +#define TPI_AVI_PIXEL_REP_4X                (3 << 0)
> +#define TPI_AVI_PIXEL_REP_2X                (1 << 0)
> +#define TPI_AVI_PIXEL_REP_NONE              (0 << 0)
> +
> +/* HDMI_TPI_AVI_INPUT_FORMAT  */
> +#define TPI_AVI_INPUT_BITMODE_12BIT         (1 << 7)
> +#define TPI_AVI_INPUT_BITMODE_8BIT          (0 << 7)
> +#define TPI_AVI_INPUT_DITHER                (1 << 6)
> +#define TPI_AVI_INPUT_RANGE_LIMITED         (2 << 2)
> +#define TPI_AVI_INPUT_RANGE_FULL            (1 << 2)
> +#define TPI_AVI_INPUT_RANGE_AUTO            (0 << 2)
> +#define TPI_AVI_INPUT_COLORSPACE_BLACK      (3 << 0)
> +#define TPI_AVI_INPUT_COLORSPACE_YUV422     (2 << 0)
> +#define TPI_AVI_INPUT_COLORSPACE_YUV444     (1 << 0)
> +#define TPI_AVI_INPUT_COLORSPACE_RGB        (0 << 0)
> +
> +
> +/* HDMI_TPI_AVI_OUTPUT_FORMAT  */
> +#define TPI_AVI_OUTPUT_CONV_BT709           (1 << 4)
> +#define TPI_AVI_OUTPUT_CONV_BT601           (0 << 4)
> +#define TPI_AVI_OUTPUT_RANGE_LIMITED        (2 << 2)
> +#define TPI_AVI_OUTPUT_RANGE_FULL           (1 << 2)
> +#define TPI_AVI_OUTPUT_RANGE_AUTO           (0 << 2)
> +#define TPI_AVI_OUTPUT_COLORSPACE_RGBDVI    (3 << 0)
> +#define TPI_AVI_OUTPUT_COLORSPACE_YUV422    (2 << 0)
> +#define TPI_AVI_OUTPUT_COLORSPACE_YUV444    (1 << 0)
> +#define TPI_AVI_OUTPUT_COLORSPACE_RGBHDMI   (0 << 0)
> +
> +
> +/* HDMI_TPI_DEVICE_POWER_STATE  */
> +#define TPI_AVI_POWER_STATE_D3              (3 << 0)
> +#define TPI_AVI_POWER_STATE_D2              (2 << 0)
> +#define TPI_AVI_POWER_STATE_D0              (0 << 0)
> +
> +/* HDMI_TPI_AUDIO_CONFIG_BYTE2_REG  */
> +#define TPI_AUDIO_CODING_STREAM_HEADER      (0 << 0)
> +#define TPI_AUDIO_CODING_PCM                (1 << 0)
> +#define TPI_AUDIO_CODING_AC3                (2 << 0)
> +#define TPI_AUDIO_CODING_MPEG1              (3 << 0)
> +#define TPI_AUDIO_CODING_MP3                (4 << 0)
> +#define TPI_AUDIO_CODING_MPEG2              (5 << 0)
> +#define TPI_AUDIO_CODING_AAC                (6 << 0)
> +#define TPI_AUDIO_CODING_DTS                (7 << 0)
> +#define TPI_AUDIO_CODING_ATRAC              (8 << 0)
> +#define TPI_AUDIO_MUTE_DISABLE              (0 << 4)
> +#define TPI_AUDIO_MUTE_ENABLE               (1 << 4)
> +#define TPI_AUDIO_INTERFACE_DISABLE         (0 << 6)
> +#define TPI_AUDIO_INTERFACE_SPDIF           (1 << 6)
> +#define TPI_AUDIO_INTERFACE_I2S             (2 << 6)
> +
> +/* HDMI_TPI_AUDIO_CONFIG_BYTE3_REG  */
> +#define TPI_AUDIO_CHANNEL_STREAM            (0 << 0)
> +#define TPI_AUDIO_2_CHANNEL                 (1 << 0)
> +#define TPI_AUDIO_8_CHANNEL                 (7 << 0)
> +#define TPI_AUDIO_FREQ_STREAM               (0 << 3)
> +#define TPI_AUDIO_FREQ_32KHZ                (1 << 3)
> +#define TPI_AUDIO_FREQ_44KHZ                (2 << 3)
> +#define TPI_AUDIO_FREQ_48KHZ                (3 << 3)
> +#define TPI_AUDIO_FREQ_88KHZ                (4 << 3)
> +#define TPI_AUDIO_FREQ_96KHZ                (5 << 3)
> +#define TPI_AUDIO_FREQ_176KHZ               (6 << 3)
> +#define TPI_AUDIO_FREQ_192KHZ               (7 << 3)
> +#define TPI_AUDIO_SAMPLE_SIZE_STREAM        (0 << 6)
> +#define TPI_AUDIO_SAMPLE_SIZE_16            (1 << 6)
> +#define TPI_AUDIO_SAMPLE_SIZE_20            (2 << 6)
> +#define TPI_AUDIO_SAMPLE_SIZE_24            (3 << 6)
> +
> +/* HDMI_TPI_I2S_ENABLE_MAPPING_REG  */
> +#define TPI_I2S_SD_CONFIG_SELECT_SD0        (0 << 0)
> +#define TPI_I2S_SD_CONFIG_SELECT_SD1        (1 << 0)
> +#define TPI_I2S_SD_CONFIG_SELECT_SD2        (2 << 0)
> +#define TPI_I2S_SD_CONFIG_SELECT_SD3        (3 << 0)
> +#define TPI_I2S_LF_RT_SWAP_NO               (0 << 2)
> +#define TPI_I2S_LF_RT_SWAP_YES              (1 << 2)
> +#define TPI_I2S_DOWNSAMPLE_DISABLE          (0 << 3)
> +#define TPI_I2S_DOWNSAMPLE_ENABLE           (1 << 3)
> +#define TPI_I2S_SD_FIFO_0                   (0 << 4)
> +#define TPI_I2S_SD_FIFO_1                   (1 << 4)
> +#define TPI_I2S_SD_FIFO_2                   (2 << 4)
> +#define TPI_I2S_SD_FIFO_3                   (3 << 4)
> +#define TPI_I2S_SD_CHANNEL_DISABLE          (0 << 7)
> +#define TPI_I2S_SD_CHANNEL_ENABLE           (1 << 7)
> +
> +
> +/* HDMI_TPI_I2S_INPUT_CONFIG_REG  */
> +#define TPI_I2S_FIRST_BIT_SHIFT_YES         (0 << 0)
> +#define TPI_I2S_FIRST_BIT_SHIFT_NO          (1 << 0)
> +#define TPI_I2S_SD_DIRECTION_MSB_FIRST      (0 << 1)
> +#define TPI_I2S_SD_DIRECTION_LSB_FIRST      (1 << 1)
> +#define TPI_I2S_SD_JUSTIFY_LEFT             (0 << 2)
> +#define TPI_I2S_SD_JUSTIFY_RIGHT            (1 << 2)
> +#define TPI_I2S_WS_POLARITY_LOW             (0 << 3)
> +#define TPI_I2S_WS_POLARITY_HIGH            (1 << 3)
> +#define TPI_I2S_MCLK_MULTIPLIER_128         (0 << 4)
> +#define TPI_I2S_MCLK_MULTIPLIER_256         (1 << 4)
> +#define TPI_I2S_MCLK_MULTIPLIER_384         (2 << 4)
> +#define TPI_I2S_MCLK_MULTIPLIER_512         (3 << 4)
> +#define TPI_I2S_MCLK_MULTIPLIER_768         (4 << 4)
> +#define TPI_I2S_MCLK_MULTIPLIER_1024        (5 << 4)
> +#define TPI_I2S_MCLK_MULTIPLIER_1152        (6 << 4)
> +#define TPI_I2S_MCLK_MULTIPLIER_192         (7 << 4)
> +#define TPI_I2S_SCK_EDGE_FALLING            (0 << 7)
> +#define TPI_I2S_SCK_EDGE_RISING             (1 << 7)
> +
> +/* HDMI_TPI_I2S_STRM_HDR_REG                       */
> +/* the reference of this values is in IEC 60958-3  */
> +#define I2S_CHAN_STATUS_MODE                0x00
> +#define I2S_CHAN_STATUS_CAT_CODE            0x00
> +#define I2S_CHAN_SOURCE_CHANNEL_NUM         0x00
> +#define I2S_CHAN_ACCURACY_N_44_SAMPLING_FS  0x20
> +#define I2S_CHAN_ACCURACY_N_48_SAMPLING_FS  0x22
> +#define I2S_CHAN_ORIGIN_FS_N_SAMP_LENGTH    0xD2
> +
> +
> +/* MISCELLANOUS INFOFRAME VALUES  */
> +
> +#define HDMI_INFOFRAME_TX_ENABLE            (0x1 << 7)
> +#define HDMI_INFOFRAME_TX_REPEAT            (0x1 << 6)
> +#define HDMI_AUDIO_INFOFRAME                (0x2 << 0)
> +
> +/* Stream Header Data  */
> +#define HDMI_SH_PCM                         (0x1 << 4)
> +#define HDMI_SH_TWO_CHANNELS                (0x1 << 0)
> +#define HDMI_SH_44KHz                       (0x2 << 2)
> +#define HDMI_SH_48KHz                       (0x3 << 2)
> +#define HDMI_SH_16BIT                       (0x1 << 0)
> +#define HDMI_SH_SPKR_FLFR                   0x0
> +#define HDMI_SH_0dB_ATUN                    0x0
> +
> +/* MISC_TYPE  */
> +#define MISC_INFOFRAME_TYPE                 0x04  /* for Audio */
> +#define MISC_INFOFRAME_ALWAYS_SET           0x80
> +
> +/* MISC_VERSION  */
> +#define MISC_INFOFRAME_VERSION              0x01
> +
> +/* MISC_LENGTH  */
> +#define MISC_INFOFRAME_LENGTH               0x0A /*length for Audio infoframe*/
> +#define MISC_INFOFRAME_LENGTH_RSVD_BITS     0xE0
> +
> +/* MISC_DBYTE1                */
> +/* Type, Encoding, Trandport  */
> +#define MISC_DBYTE1_CT_CHK_HEADER_STREAM    0x00
> +
> +/* audio channel count  */
> +#define MISC_DBYTE1_CC_CHK_HEADER_STREAM    0x00
> +#define MISC_DBYTE1_CC_2_CHANNELS           0x01
> +
> +/* MISC_DBYTE2  */
> +/*Sample Size   */
> +#define MISC_DBYTE2_SS_CHK_HEADER_STREAM    0x00  /* for hdmi by default */
> +
> +/* Sampling Frequency  */
> +#define MISC_DBYTE2_SF_CHK_HEADER_STREAM    0x00  /* for hdmi by default */
> +
> +/* MISC_DBYTE3     */
> +/* Code Extention  */
> +#define MISC_DBYTE3_CTX_TAKE_DBYTE1         0x00  /* for hdmi by default */
> +
> +/* MISC_DBYTE4  */
> +#define MISC_DBYTE4                         0x00 /*for no multichannel( */
> +						 /* multichannel means more*/
> +						/* than 2 channels */
> +
> +/* MISC_DBYTE5  */
> +#define MISC_DBYTE5           0x00  /* for no multichannel(multichannel  */
> +					/* means more than 2 channels */
> +
> +struct hdmi_reg_data {
> +	u8 reg_offset;
> +	u8 value;
> +};
> +
> +#endif
> -- 
> 1.7.9.5
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [ANNOUNCE] second pull for fbdev this friday
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-07-11  9:52 UTC (permalink / raw)
  To: linux-fbdev

HI,

	I'm goign to send a second pull to Linus for the fbdev for 3.11

	If you have patch that I did merge (I forget or request a rebase)
	ping them a send them quick


	I plan to send the pull friday night shangahi time or max sunday

Best Regards,
J.

^ permalink raw reply

* Re: [PATCH] omapfb: In omapfb_probe return -EPROBE_DEFER when display driver is not loaded yet
From: Archit Taneja @ 2013-07-11  8:50 UTC (permalink / raw)
  To: Pali Rohár
  Cc: Tomi Valkeinen, Jean-Christophe Plagniol-Villard, linux-omap,
	linux-fbdev, linux-kernel, Pavel Machek, Aaro Koskinen,
	Tony Lindgren
In-Reply-To: <1373461739-10168-1-git-send-email-pali.rohar@gmail.com>

Hi,

On Wednesday 10 July 2013 06:38 PM, Pali Rohár wrote:
> * On RX-51 probing for acx565akm driver is later then for omapfb which cause that omapfb probe fail and framebuffer is not working
> * EPROBE_DEFER causing that kernel try to probe for omapfb later again which fixing this problem
>
> * Without this patch display on Nokia RX-51 (N900) phone not working
>
> Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
> ---
>   drivers/video/omap2/omapfb/omapfb-main.c |    9 +++++++++
>   1 file changed, 9 insertions(+)
>
> diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
> index 856917b..93e7c84 100644
> --- a/drivers/video/omap2/omapfb/omapfb-main.c
> +++ b/drivers/video/omap2/omapfb/omapfb-main.c
> @@ -2419,6 +2419,15 @@ static int omapfb_probe(struct platform_device *pdev)
>   	if (omapdss_is_initialized() = false)
>   		return -EPROBE_DEFER;
>
> +	dssdev = NULL;
> +	for_each_dss_dev(dssdev) {
> +		if (!dssdev->driver) {
> +			dev_warn(&pdev->dev, "no driver for display: %s\n",
> +				dssdev->name);
> +			return -EPROBE_DEFER;

This will make omapfb probe defer till the time every panel has a 
driver. It's possible that all the panel driver modules are never 
interested by userspace. This will lead to the panels having drivers 
also not work.

I think Tomi was working on this, it was something like making omapfb 
defer only if the default display doesn't have a driver. We can wait for 
his comment.

Archit

> +		}
> +	}
> +
>   	if (pdev->num_resources != 0) {
>   		dev_err(&pdev->dev, "probed for an unknown device\n");
>   		r = -ENODEV;
>


^ permalink raw reply

* [PATCH] vga16fb: Remove unused variable
From: Luis Henriques @ 2013-07-10 22:57 UTC (permalink / raw)
  To: linux-fbdev
  Cc: Jean-Christophe Plagniol-Villard, Tomi Valkeinen, linux-kernel

Fix build warning of unused variable:

drivers/video/vga16fb.c:1268:26: warning: unused variable ‘dev’ [-Wunused-variable]

Signed-off-by: Luis Henriques<luis.henriques@canonical.com>
---
 drivers/video/vga16fb.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
index 830ded4..2827333 100644
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -1265,7 +1265,6 @@ static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image
 
 static void vga16fb_destroy(struct fb_info *info)
 {
-	struct platform_device *dev = container_of(info->device, struct platform_device, dev);
 	iounmap(info->screen_base);
 	fb_dealloc_cmap(&info->cmap);
 	/* XXX unshare VGA regions */
-- 
1.8.1.2

^ permalink raw reply related

* [PATCH 12/12] drivers/video: don't use devm_pinctrl_get_select_default() in probe
From: Wolfram Sang @ 2013-07-10 15:57 UTC (permalink / raw)
  To: linux-kernel
  Cc: Wolfram Sang, Jean-Christophe Plagniol-Villard, Tomi Valkeinen,
	linux-fbdev
In-Reply-To: <1373471889-18107-1-git-send-email-wsa@the-dreams.de>

Since commit ab78029 (drivers/pinctrl: grab default handles from device core),
we can rely on device core for setting the default pins. Compile tested only.

Acked-by: Linus Walleij <linus.walleij@linaro.org> (personally at LCE13)
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/video/mxsfb.c |    8 --------
 1 file changed, 8 deletions(-)

diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index 3ba3771..5861ba2 100644
--- a/drivers/video/mxsfb.c
+++ b/drivers/video/mxsfb.c
@@ -46,7 +46,6 @@
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
-#include <linux/pinctrl/consumer.h>
 #include <linux/fb.h>
 #include <linux/regulator/consumer.h>
 #include <video/of_display_timing.h>
@@ -877,7 +876,6 @@ static int mxsfb_probe(struct platform_device *pdev)
 	struct mxsfb_info *host;
 	struct fb_info *fb_info;
 	struct fb_modelist *modelist;
-	struct pinctrl *pinctrl;
 	int ret;
 
 	if (of_id)
@@ -908,12 +906,6 @@ static int mxsfb_probe(struct platform_device *pdev)
 
 	host->devdata = &mxsfb_devdata[pdev->id_entry->driver_data];
 
-	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-	if (IS_ERR(pinctrl)) {
-		ret = PTR_ERR(pinctrl);
-		goto fb_release;
-	}
-
 	host->clk = devm_clk_get(&host->pdev->dev, NULL);
 	if (IS_ERR(host->clk)) {
 		ret = PTR_ERR(host->clk);
-- 
1.7.10.4


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox