From 44830ad1a5bbbd52900c38f9c8b65e71f6d6d7d6 Mon Sep 17 00:00:00 2001 From: David Brown Date: Thu, 10 Jan 2013 16:19:01 -0800 Subject: [PATCH] msm: fb: Replace with QuIC framebuffer driver This adds support for more recent MSM chips. Including the following commits: commit 5822924ac43b56586fbe0ddb720400624e70e111 Author: Ping Li Date: Fri Nov 30 14:05:43 2012 -0500 msm: display: Add picture adjustment support for SSPP side Add picture adjustment structure input for overlay PP configuration, user can change PA setting via overlay set IOCTL Change-Id: I3b4679991ad4527565809e291fb13a73fbda2181 Signed-off-by: Ping Li commit 486846820740c2cafea0c06442a3440ecb70b4d3 Author: Pawan Kumar Date: Fri Dec 21 16:55:24 2012 +0530 msm-fb: v4l2: Add user pointer support using ION for mdp3 target -Add multi-planar user pointer support in msm v4l2 display driver using multiple ION fd's (2 fd's in case of mdp3). -Handle multi-buffer use case using memory offset along with ION fd to calculate physical address. Change-Id: I1352512cbdfb9cf2c9fc20968416d369337e433b Signed-off-by: Pawan Kumar commit 5e4ba471fa7b26de394c3836b309c20c4082c19a Author: Siddhartha Agrawal Date: Mon Nov 19 19:37:12 2012 -0800 msm_fb: display: Send current timestamp in case of timeout On timeout while waiting for the vsync, send the current timestamp to the userspace. This resolves the infinite wait seen during the bootup as SF will use this time stamp reconfigure the vsync. CRs-Fixed: 420244 Change-Id: I0d7b8750becfbb4e5c5e47b29ded6395627e8862 Signed-off-by: Siddhartha Agrawal Signed-off-by: Ajay Singh Parmar commit 14547efa9af6eecb83243148b02cc1e0ea789202 Author: Ken Zhang Date: Wed Dec 12 17:49:04 2012 -0500 msm: mdss: cache panel setting in suspend state Save panel on/off setting in suspend status to be used when resume, return success as a temp workaround. Change-Id: I10a4136d987a8dee84b2d4750699bfef919c7911 Signed-off-by: Ken Zhang commit c7966734d6fbdf5e542eb0349939cc02b0082143 Author: Ken Zhang Date: Fri Dec 21 23:12:05 2012 -0500 msm: mdss: power setting protection When mdss is in resume process, other operation needs wait until it is done. Change-Id: I93696bdb9a4b6ac88d88eeb32bfcede5e2f62c8e Signed-off-by: Ken Zhang commit 86ac956a061a1ea1e2c11214a1adebbe32511c42 Author: Ken Zhang Date: Thu Dec 13 18:57:27 2012 -0500 msm: mdss: Clear performance request data at turning on MDSS needs re-request bus and clock when resuming, clear the cached related data, as they do not reflect the hardware status. Change-Id: I4a4b7452f5f8d6fa586904b3badee5f6968110ea Signed-off-by: Ken Zhang commit 4e83b93ca279b21f0ab1e07fdee52ea41f2474f4 Author: Ken Zhang Date: Sun Dec 2 21:15:47 2012 -0500 msm: mdss: Non-blocking display commit Schedule a workqueue, do the current job in the workqueue handler. Block the second entry if the first one has not finished Display commit ioctl will do what pan_display can do, addtionally has customized setting, such as non-blocking call Change-Id: Iccced7d7540c6a8bb066f58fa245bbff5ed36fcb Signed-off-by: Ken Zhang commit 5295d8001001ceebc6392a42f3055c6c5188958d Author: Ken Zhang Date: Wed Nov 7 18:33:16 2012 -0500 msm: mdss: sync point support MSMFB_BUFFER_SYNC ioctl is added for hwc to pass in buffer fence, driver creates release fence and return to hwc. Before display update, driver waits for the fence to be signaled. Signal the release fence after update is done. Change-Id: I3d8cd5e8df1f0415832507d19cf629f4c0432164 Signed-off-by: Ken Zhang commit 1c374a84fd75e436d6a61c326fb055091b3d51e0 Author: Manoj Rao Date: Mon Dec 17 16:29:03 2012 -0800 msm: 8974: add MHL device discovery flag This change stores a static flag for keeping MHL device discovery and makes the driver flexible to function in either one of the modes. It would be very simple to make this dynamically configurable through boot param or module param. Change-Id: If3915c5861e61bc572a9b4e239a6133e5e9a138b Signed-off-by: Manoj Rao commit fcc33cdd9c2eccdcdde19e2b09d6eb3b01a783cb Author: Kuogee Hsieh Date: Tue Dec 18 09:40:25 2012 -0800 msm_fb: display: add panel's late_init Some panels need to be initialized after panel is on. Add late_init to support this feature. CRs-fixed: 433011 Change-Id: I73c623d1fe52363f070af79ce4bf7774cd84689e Signed-off-by: Kuogee Hsieh commit dbdfa637adf603082676a428f80f1260d3400b3d Author: Pawan Kumar Date: Mon Dec 17 09:47:16 2012 +0530 msm-fb: Fix sysfs node creation in mdp_probe for MDP3 targets -vsync_init null check not required for mdp3 target before creating sysfs node. -Set vsync suspend and resume flags appropriately in mdp_on for mdp3. CRs-Fixed: 393243 Change-Id: I3366df7385ca8e2ae15053c3e58332f8e32ce0cd Signed-off-by: Pawan Kumar commit 9f2514f819eced19b0880735d5d62727808ce30c Author: Manoj Rao Date: Wed Nov 28 15:23:11 2012 -0800 mhl: 8974: notify usb about non-mhl sink discovery On cable connect, USB driver triggers MHL's device discovery through an API. This device discovery should inform caller if the device is MHL or USB host mode connection since both hold ID line low. If SII 8334 Tx discovery routine returns a result of non-mhl then MHL driver should notify usb of this result else usb will not be able to proceed further with it's worker functions and state machine. Change-Id: Ie20e0dd517a191ed6df75050042bdcb0ebd01233 Signed-off-by: Manoj Rao commit f45159b358add9d3bc955dce2cce5ef62a7a75fd Author: Manoj Rao Date: Wed Nov 28 15:22:08 2012 -0800 msm: 8974: MHL set 3V reg. for the 8334 hs switch Allocate regulator from MHL driver for 3.3V which is required for the high speed switch to function and toggle between usb host mode and mhl mode Change-Id: I87a9db951ff004d0a10caa390723eefddfc0db5e Signed-off-by: Manoj Rao commit 530a5227212b62d05732f4393cf06903b4646c6d Author: Manoj Rao Date: Wed Nov 28 15:20:34 2012 -0800 msm: 8974: disable mhl device disc This discovery mechanism puts the device in complete sleep mode (D3) while leaving the device discovery disabled, and wakes up when USB driver calls the device discovery API from D3 mode by resetting the chip. Change-Id: I7db8dd86c54285a4903c582ae35f6c9d4329ec48 Signed-off-by: Manoj Rao commit 80822c3dde2e63bcdb0490426b05105252572814 Author: Manoj Rao Date: Wed Nov 28 15:18:07 2012 -0800 msm: 8974: Add intermediate power state for MHL MHL has three power states, D3 - low power sleep, D0 - high power MHL state, D2 - intermediate stage which powers up the chip but doesn't activate the MHL/TMDS lines. Change-Id: I9282a32724e0ac4f7c23233f4bfba97f548d7ac9 Signed-off-by: Manoj Rao commit affabcd25a6b74ec95350ad36ccec5b522e8dc5d Author: Manoj Rao Date: Wed Nov 28 15:15:29 2012 -0800 msm: 8974: Set MHL Tx configuration to USB state All the ID lines, D+/D- lines are configured to USB by default in this change. All the USB interrutps will be routed directly to USB, which will trigger interrupts in the USB driver. All events on ID line are handled by USB, even in the presence of MHL, USB driver triggers the device detection mechanism through established APIs. Change-Id: I7e70965cf46dfa5734918b2e21db5a162c570706 Signed-off-by: Manoj Rao commit 388c2a9db377945aefa85f06fa31dc8ac0ea9cef Author: Carl Vanderlip Date: Mon Dec 10 14:01:47 2012 -0800 video: msm: Handle timed-out histogram When the histogram collection times out (usually caused by an underrun) the hardware does not trigger a histogram done interrupt. In fact, the histogram hardware returns to its idle state after the next frame starts to draw. Thus, in the case where histogram times out waiting, changing the software state to HIST_IDLE allows histogram collection to continue. Change-Id: Ideb431209067c7d7e5a2bb94a7352ad90dd46e50 Signed-off-by: Carl Vanderlip commit 5240a97a72f320b927ffc6230a6f4f1443979acd Author: Carl Vanderlip Date: Mon Dec 3 15:52:38 2012 -0800 video: msm: Trigger no update notify on suspend Suspend is a special case in the update notify feature in that it is a known state of no upcoming updates. Cause those waiting for a "no update" notification to wake up. Change-Id: Ie415d6c8da36d9871ed1dffad095529a20ebdf88 Signed-off-by: Carl Vanderlip commit c9021777f4efbbe9dcb9293f54a0dc912e87e5fe Author: Carl Vanderlip Date: Mon Dec 10 16:48:18 2012 -0800 video: msm: Initialize Histogram LUT Initialize the Histogram LUT during MDP probe. This is required otherwise the first histogram LUT request shows a brief period of garbled colors. Change-Id: I60b3077883d0f57dfe3987d7b459477a43da09a5 Signed-off-by: Carl Vanderlip commit 004d4a2d2bd81fc8e147f0dadec2d8792e176d80 Author: Ujwal Patel Date: Thu Nov 15 12:46:10 2012 -0800 msm: mdss: hdmi: Add support for new HDMI-Audio interface Using this new interface, HDMI-Audio codec driver can retrieve sink's audio capabilities. Based on this supported capabilities and current playback clip, it will pass appropriate audio setup information to HDMI driver for configuration. Change-Id: Ia52f72d955778859c381a5e6c94aba57e40d13b2 Signed-off-by: Ujwal Patel commit b554cf695636e15504cdce72cbfe35bf89494c0a Author: Manoj Rao Date: Tue Nov 27 21:27:38 2012 -0800 msm: 8974: MHL-USB handshake API implementation This change adds the implementation of mhl discovery detection procedure, USB hand-off function. Three APIs are exposed from MHL driver to USB driver: for register/unregistering callbacks from USB and triggering device discovery detection in MHL hardware. By default, all the USB interrupts are directed to the USB hardware which is detected by USB driver and at appropriate points the USB driver triggers the MHL device discovery and uses the results to either hand control to MHL driver or continue with it's own detection mechanism. Change-Id: Ic1e22bc4c446de209f2e72d5dda8b823bfd398c8 Signed-off-by: Manoj Rao commit 5feb9b23208394f5261b330adec2cfb475706c43 Author: Aravind Venkateswaran Date: Wed Dec 12 18:18:19 2012 -0800 mdss: hdmi: Use delayed work instead of timer for HDCP reauth Upon detecting HDCP authentication failures, reauthentication attempts should be kicked off after a small delay. Instead of using kernel timers, this is achieved by having the existing HDCP work item as a delayed work. Change-Id: I7d04b33b159c718cd347576d18cffd1b705bb790 Signed-off-by: Aravind Venkateswaran commit 3aafea1d26621d712790742f2bcc70bf7bf374ab Author: Aravind Venkateswaran Date: Thu Dec 13 17:43:43 2012 -0800 mdss: hdmi: Correct HDMI Tx controller settings for DVI mode When a connected sink is operating in DVI mode, the HDMI Tx controller should also be programmed accordingly to operate in DVI mode. Change-Id: I63176b55be86a0fe73b23880fc1d45f7a2272d32 Signed-off-by: Aravind Venkateswaran commit 0f685f270692aeb54b8eed0df5e37897d77f6c7b Author: Ujwal Patel Date: Wed Dec 12 12:52:18 2012 -0800 mdss: hdmi: Fix suspend/resume watchdog crash during HDMI mirroring During device suspend, HDMI driver holds MDSS suspend context until audio is turned off. Continuous polling for audio off results in unnecessary delay in MDSS suspend as well as watchdog crash. To fix this enable/disable MDSS GDSC regulator during HDMI hpd on/off. This will make HDMI independent of MDSS module in terms of register accesses. Also increase the sleep time between consecutive poll reads in order to prevent watchdog crash. CRs-Fixed: 425536 Change-Id: I7969f0ed8bcce4a356ee6a1e29ed2af76dd345ef Signed-off-by: Ujwal Patel commit 38e405e9ce2c9723a633ad75d6c498dd178d3e4a Author: Kuogee Hsieh Date: Tue Dec 11 14:19:04 2012 -0800 msm_fb: display: wait for a vsync time before dtv_off At DTV interface, wait for a vsync time to make sure previous stage_commit had been kicked in before un-stage pipes and turn off timing generator. Otherwise iommu page fault may happen after RGB2 allocated to mixer0 due to RGB2 pipe still hold previous source address. Change-Id: I6b8bb1429b863886601ebb64b7c73771bee86764 Signed-off-by: Kuogee Hsieh commit 6d260d9645b5032b41d14b8e7d14ec12af24cd1a Author: Aravind Venkateswaran Date: Thu Nov 1 18:09:06 2012 -0700 mdss: HDMI: HDCP Implementation Implement HDCP (High-bandwidth Digital Content Protection) feature which is used to encrypt audiovisual content transmitted over the HDMI link. Change-Id: I6ab92585f979d796d1a40c0ff86d4e7363506b6a Signed-off-by: Aravind Venkateswaran commit 2f9ef2416165fa7cc4230fd1fad7ecd0cc9c1be3 Author: Ujwal Patel Date: Wed Dec 12 16:30:18 2012 -0800 msm: mdss: Fix porch value assignments based on VESA standard Panel driver's porch value representation is similar to VESA standard but framebuffer API's representation is different. Correct this conversion from one representation to other. Change-Id: I1fdc7e664de99a5ad646beef2e74f7066a00c2e0 Signed-off-by: Ujwal Patel commit ad43bed51e95782097e68840673b8abf2d096058 Author: Adrian Salido-Moreno Date: Tue Oct 16 16:08:00 2012 -0700 msm: mdss: enable border fill setup Border fill setup can be used to unset MDP pipes allocated for framebuffer replacing it with border color fill instead of contents fetched from memory. These pipes can then be used as overlays by userspace apps. Change-Id: I152dd07d867fb618cea7b72980f4bd75816e3034 Signed-off-by: Adrian Salido-Moreno commit 0d62d721aaa6ea760e4d54076aa782352dca13a7 Author: Adrian Salido-Moreno Date: Fri Oct 19 13:56:06 2012 -0700 msm: mdss: change smp blocks allocation based on fetch width Currently the ammount of shared memory pool blocks allocated for fetching latency lines is based on the full stride of image. There are cases where only a small part of the image is fetched, smp blocks should be allocated to acommodate the fetched width only, and free some memory to be used by other surfaces. Change-Id: Idaa7fbc583a2c4a5166f9e05010a0ae2ff56747a Signed-off-by: Adrian Salido-Moreno commit d27afb2e7eae9d8049f11094b686c513dbc7eed4 Author: Adrian Salido-Moreno Date: Tue Dec 11 22:58:59 2012 -0800 msm: mdss: add timeout when waiting for vsync To avoid any possible freezes while waiting for vsync, add a timeout while waiting for vsync interrupt and report a visible warning. CRs-Fixed: 428821 Change-Id: I328ac05b98741fc77eb424c313a3b3afb3e206d2 Signed-off-by: Adrian Salido-Moreno commit d691c2352dca906061899dac24bd21fc2ce91e6b Author: Adrian Salido-Moreno Date: Tue Dec 11 22:48:12 2012 -0800 msm: mdss: remove wait for ping pong done for video interfaces Wait for ping pong was used to ensure that hw is idle while programming any double buffered registers, however most registers that really are changing are double buffered. Remove for ping pong done as it's only causing frame drops and some freezes in some cases. CRs-Fixed: 428821, 426136 Change-Id: Iafebebab7faf0efcb1b3f6a8d2723d67a93d5cd9 Signed-off-by: Adrian Salido-Moreno commit ade75d570fa8f2bea13b32590c08a9993cbb9cf1 Author: Ajay Singh Parmar Date: Mon Nov 26 12:44:26 2012 +0530 msm_fb: hdmi: HDMI suspend resume event handling This change makes sure that we do the proper HDMI ON settings at resume and also send the events to user-space about current status of HPD after resume. CRs-Fixed: 422372 Change-Id: I8ca79fd07840b3227c9472588853b0ca2749760b Signed-off-by: Ajay Singh Parmar commit 598d1170a005fd7b8b746e3e3d262635047a85b5 Author: Adrian Salido-Moreno Date: Mon Dec 10 17:06:20 2012 -0800 msm: mdss: update bus bw calculations to account for is_fg flag Overlay flag is_fg is used to disabling fetching of buffers for a layer and all previous blending stages. Need to consider this as part of bus bandwidth calculations and only request bandwidth for layers that are going to be fetched by MDP. CRs-Fixed: 425643 Change-Id: Ie964f5e4ac77945ea6f84a47d337591ddfa1721c Signed-off-by: Adrian Salido-Moreno commit d0bf99c8cbbbb43ad5bb1c426efc7d8004f6bf6f Author: Huaibin Yang Date: Mon Dec 10 16:37:01 2012 -0800 msm_fb: display: fix frame rate wrong calculation For cmd mode the frame rate calculation result is wrong. Also in mdp driver there are several places to do the same calculation. So fix the wrong calculation and use a single func to do calculation. Change-Id: Iab498fb446a1d9b8295d710ffa82618d2ab6fc07 Signed-off-by: Huaibin Yang commit 1fdd101b95c275118f6a0c9c732d5559f815b1bb Author: Huaibin Yang Date: Mon Dec 10 14:04:00 2012 -0800 msm_fb: display: add wfd clk ctrl in pipe_commit mdp_clk_ctrl on is not called when commit is from overlay commit path which can cause mdp hang. mdp_clk_ctrl off should be after mdp overlay2 is done, so schedule a work in overlay2 done isr. Change-Id: I94fd08da27cfda114f5cc0056a5103f0a9b772f6 Signed-off-by: Huaibin Yang commit 8a9762e653e6f43fd361b3ccd632a1a78c1ab6fa Author: Huaibin Yang Date: Fri Dec 7 20:23:53 2012 -0800 msm_fb: display: add mdp bandwidth runtime calculation Currently mdp bandwidth request logic is based on source image size and number of layers. This logic can not support complicated mdp usecases and it is not power efficient. The logic is improved by calculating mdp bandwidth request at runtime from all pipes and mixers. CRs-fixed: 425823 Change-Id: I63206f00f8d3017a2449f8ac617fce3ba2a4d36c Signed-off-by: Huaibin Yang commit 474f8d7fdffb8405676455cfbfaebc14d067862e Author: Kuogee Hsieh Date: Mon Sep 10 10:14:49 2012 -0700 msm_fb: display: replace cmds_tx/rx with cmdlist_put/get Both dcs command and mdp pixel stream share dsi link. Dsi link confliction may cause mdp to hang up. cmdlist mechanism is introduced to serialize both dcs commands and mdp pixel stream. This patch replaces legacy cmds_tx/rx with cmdlist_put/get. Change-Id: Idfecd196d6efa281fc2c319be4ee3e76b8d49136 Signed-off-by: Kuogee Hsieh commit d43ae7260e1b79b9930036347ce568c176420287 Author: Ujwal Patel Date: Thu Nov 15 18:06:56 2012 -0800 msm: mdss: hdmi: Add support for new resolutions Add support for following new resolutions. * 2560x1600 @ 60Hz (DVI) * 3840x2160 @ 30Hz (HDMI) * 3840x2160 @ 25Hz (HDMI) * 3840x2160 @ 24Hz (HDMI) * 4096x2160 @ 24Hz (HDMI) Change-Id: I14262448fea80615c6c77b4638b0a9815efc3297 Signed-off-by: Ujwal Patel commit 793bd7b68f7ab5e2899b977293cfb67157493c77 Author: Aravind Venkateswaran Date: Fri Dec 7 14:25:47 2012 -0800 mdss: hdmi: Correct configuration for DDC ref timer This change updates the (Display Data Channel) DDC reference timer in mdss domain to the optimal value which is calculated based on the correct HDMI application clock frequency. Change-Id: I0b9f32f2fb0f16cf79bca86e270039c8cf90ed94 Signed-off-by: Aravind Venkateswaran commit 248dda2a1cacae6035fcd926a97fc8849229afce Author: Siddhartha Agrawal Date: Mon Oct 29 11:27:15 2012 -0700 msm_fb: display: Removing extra disable irq in cmds_rx API's Disable IRQ for DSI_CMD_TERM was already called in the isr. Removing the extra call present in the cmds_rx API's. Change-Id: I0000dd3166beb2a3b0c788327e1d7520e0c11a13 Signed-off-by: Siddhartha Agrawal commit 9b697535117c56cd385a0b71411e05e62776e6f5 Author: Ujwal Patel Date: Fri Nov 9 22:53:35 2012 -0800 msm: mdss: hdmi: Add support for dynamic resolution change Using new panel event, provide facility to check if HDMI can support requested resolution or not. Also if resolution change is requested while HDMI mirroring is ongoing then current mirroring needs to be shutdown and start again. Propogate this message to mdss using new panel event, MDSS_EVENT_CHECK_PARAMS. Change-Id: I87aed1b37b532724b6663509aa020b1008abfdcc Signed-off-by: Ujwal Patel commit 7bc2796befca2fa535952ced7c85f7221e3dac0b Author: Adrian Salido-Moreno Date: Wed Nov 28 18:41:33 2012 -0800 msm: mdss: support panel resolution changes Allow framebuffer resolution changes to be propagated to panel driver to support different display resolutions. Use a new panel event so that panel driver can take the decision of accepting new params. Change-Id: I04b26cbb4d06a3cbc9c4416fbb7202bb185eee9b Signed-off-by: Adrian Salido-Moreno Signed-off-by: Ujwal Patel commit 0d7257935376fdc7293a0b9ddf1d2f8056fec201 Author: Adrian Salido-Moreno Date: Wed Nov 14 17:16:03 2012 -0800 msm: mdss: cleanup usage of panel info Panel info is used to communicate between panel, mdp and framebuffer. Currently framebuffer maintains its own copy of panel_info which might cause mismatches on the latest information from panel. Change framebuffer panel_info to be a pointer to information provided by panel driver. Change-Id: Ic7ae27564d98d6b6843d1368481dda0601befccf Signed-off-by: Adrian Salido-Moreno Signed-off-by: Ujwal Patel commit cc13101bd21479dec3a629d93655bcf62462b0ba Author: Kuogee Hsieh Date: Mon Dec 3 15:36:14 2012 -0800 msm_fb: display: delete dsi clock control from cmdlist_commit cmdlist_commit perform dsi clock control which turns off dsi clock unexpectly when dsi controller is configured as command mode during booting up. This cause display panel can not be lit up. This patch drop clock control mechanism from cmdlist_commit and move dsi clock control mechanism to caller. Change-Id: I1882ea3ee1c90ac5d76958c986740582929a5e3b Signed-off-by: Kuogee Hsieh commit 946ca6389b8f8c70b62a2f1ab4d81b475395f7d8 Author: Prasad Sodagudi Date: Mon Dec 3 16:57:51 2012 +0530 video: msm: Do not use disable_irq in the spin_lock_irqsave context Both mdp_isr() and mdp_histogram_disable() uses the same spin lock mdp_spin_lock variable. One core waits for disabling mdp_isr after acquiring mdp_spin_lock and other core in mdp_isr() waits for spin lock mdp_spin_lock and dead lock between two cores. Change-Id: I73a10494ab78e92fc88a348aed4f526091b51f89 Signed-off-by: Prasad Sodagudi commit 889748cb28feb2d88ee74c7c3ce29409b857ea23 Author: Ujwal Patel Date: Mon Nov 19 16:23:58 2012 -0800 msm: mdss: hdmi: Add dimension overflow check for video resolutions MDSS based HDMI Tx controller can output 13bit h_total and v_total compare to 12bit wide from previous generation chipsets. Add overflow check to insure that controller is not programmed for incorrect dimension. Change-Id: I6c3906020da6f4aad3f1fcf8a5633731515a7569 Signed-off-by: Ujwal Patel commit 554c0755b48b77e463b7ede2a1b74abf41120370 Author: Asaf Penso Date: Tue Dec 4 11:12:04 2012 +0200 msm: mdss: Fix the order of enable/disable edp clock functions Being compatible with the required enable/disable of msm clk sequence. Change-Id: I179685a5bb4c0d7e6f4b84e18f0749b416f5e2ba Signed-off-by: Asaf Penso commit 137dfdf8781f41270dd6ff10242c082940300e75 Author: Adrian Salido-Moreno Date: Wed Nov 14 17:20:49 2012 -0800 msm: mdss: remove pm suspend handler All suspend calls are handled through early suspend, using pm suspend/resume as well can lead to HDMI being resumed before MDSS regulator is enabled, leading to HDMI hang during resume. Remove pm suspend handler completely since it's not needed. CRs-Fixed: 425657 Change-Id: I0b9d072037dfdceef90d24fba50813390191f4e0 Signed-off-by: Adrian Salido-Moreno commit 32547051b65943bd1c07c08630528741fdcfdda4 Author: Adrian Salido-Moreno Date: Fri Nov 30 18:00:16 2012 -0800 msm: mdss: fix iommu fault due to incorrect buffer unmap Any buffer that is being fetched by MDP to display on panel should not be unmapped until there is a new buffer to replace it. Ensure multiple buffer updates without a commit to display won't cause displayed buffer to be unmapped. CRs-Fixed: 420561 Change-Id: Ibe720976024d7739c36bd4f05f9f70a061ed1eb9 Signed-off-by: Adrian Salido-Moreno commit cda3246cba44c0756c2038f0fea34858e72f8555 Author: Adrian Salido-Moreno Date: Mon Sep 24 10:47:46 2012 -0700 msm: mdss: enable display debugging through debugfs Register debugfs nodes to allow dumping and writing of MDP and DSI registers for debugging purposes. Change-Id: I14d9a7f441292eef5564144707184dfa5da75d85 Signed-off-by: Adrian Salido-Moreno commit 63e30558ba162cae303f7ae655b0ab61f4253005 Author: Kuogee Hsieh Date: Fri Nov 9 10:04:20 2012 -0800 msm_fb: display: mdp4 version assigned at board file Currently, mdp version is acquired by reading mdp version register. This patch use mdp version from board file instead of reading from mdp register. Change-Id: If71be4f28caa45beea58789ca1025a338eb64de5 Signed-off-by: Kuogee Hsieh commit f8e389593cd695957834a2de6db769264c0237a9 Author: Huaibin Yang Date: Thu Nov 8 15:56:25 2012 -0800 msm_fb: display: add mdp blt mode and switch control Switching mdp blt mode is done in isr or by turning on/off timing generator. Add other options: by polling, always-on or always-off. And add support for external dtv blt mode. CRs-fixed: 390953 Change-Id: I5e9f52fc459a34cc99a0f71c04b8320edd821ff8 Signed-off-by: Huaibin Yang commit 4eb6ce68540cb523348d624b7193518fdd970898 Author: Kuogee Hsieh Date: Fri Nov 16 11:52:15 2012 -0800 msm_fb: display: Do not use ION_IOMMU_UNMAP_DELAYED Since iommu buffer will be un-mapped after two newer commits had passed, there is no need to request iommu driver to further delay un-mapping an iommu buffer. Change-Id: I8cf8d406cf509908035d12c9a04f0add12f3c7c7 Signed-off-by: Kuogee Hsieh commit 4d5e1c57b4a6d2d25c5ce04923205073fafa3898 Author: Aravind Venkateswaran Date: Tue Oct 30 14:59:26 2012 -0700 msm_fb: HDMI: Cleanup of HDMI switch device notifications HDMI switch device is used to notify userspace components of the availabilty of a connected HDMI sink. These notification should only be sent whenever HDMI cable is connected or disconnected. This patch removes all the redundant notifications. CRs-Fixed: 412575 Change-Id: Ia5e60690a87569fce5d61a9af75d446648443e9b Signed-off-by: Aravind Venkateswaran commit f3472aede02906f6e213a5a8459ca4e6f84b17d6 Author: Aravind Venkateswaran Date: Fri Nov 2 15:34:44 2012 -0700 msm_fb: HDMI: Turn on HDMI core only for supported resolution Upon receiving the notification of an HDMI cable connection, turn on HDMI core only if the default video resolution is supported by the sink. Otherwise, HDMI core would be turned on at a later time when it is configured with a supported resolution by the userspace. CRs-Fixed: 412575 Change-Id: I67cfb09bafa39646839877a66cd94f193c127a76 Signed-off-by: Aravind Venkateswaran commit cdc118275788b10175f34560470d8afedc5255eb Author: Adrian Salido-Moreno Date: Mon Nov 12 14:56:43 2012 -0800 msm: mdss: replace uevent based hw vsync events with sysfs poll Replace hw vsync ctrl logic with ability to read vsync timestamps through sysfs file when vsync ctrl is enabled from userspace. CRs-Fixed: 407684 Change-Id: I0fb973592090ed9ee81bc3d54f53a18f4c131e0f Signed-off-by: Adrian Salido-Moreno commit edf70c335df7938a1e181286f8165250491884de Author: Aravind Venkateswaran Date: Fri Oct 26 18:11:23 2012 -0700 msm_fb: HDMI: Add support for HDMI audio switch device node Add support for audio switch node in the HDMI driver that would be used to notify audio userspace components of the availability of an HDMI device. CRs-Fixed: 412575 Change-Id: Idc41caf234810db52af9fcc89d2ed4ecbcaafc3b Signed-off-by: Aravind Venkateswaran commit ae93bc59e2fc68591b76d3911ed6c29537efe949 Author: Aravind Venkateswaran Date: Fri Nov 2 14:32:41 2012 -0700 msm_fb: HDMI: Cleanup HDMI audio off sequence HDMI core should not be powered down until the audio engine has shutdown transmitting packets to the HDMI core. This change increases the time for which the driver waits for the audio engine to turn off. CRs-Fixed: 412575 Change-Id: Ie11ab6c8140f7289f74da4877c9acf9b8cd4a838 Signed-off-by: Aravind Venkateswaran commit e3ddd1499da99d52222f6d3dd031901082e8338a Author: Aravind Venkateswaran Date: Wed Nov 7 18:27:23 2012 -0800 msm_fb: dtv: Serve device off in a separate thread DTV device should not be powered down until the audio engine has shutdown. This change moves dtv audio off sequence to a separate thread so that framebuffer close system call does not get blocked. CRs-Fixed: 412575 Change-Id: I246a9e58f1367e653913773696510f375abf3d3a Signed-off-by: Aravind Venkateswaran commit 99a86cc6d78227ff566aefdfd83c195277bde02b Author: Ujwal Patel Date: Fri Nov 9 22:49:30 2012 -0800 msm: mdss: Add suspend resume support in HDMI Tx controller For primary display panels, usually power off/on during suspend/resume should suffice. But for external display panels like HDMI TVs, there is an additional hw circuitry for hot-plug detect which also needs to be turned off/on based on the state when suspend/resume is initiated. This change adds such support in HDMI Tx driver. CRs-Fixed: 413722 Change-Id: I7640d13c08f86f1ae0ae13cb2d1411f0354ca3fe Signed-off-by: Ujwal Patel commit c183e1a69eeac2348a6e2a5ac92aaf1fef0fa828 Author: Kalyan Thota Date: Fri Nov 16 18:22:02 2012 +0530 msm_fb: commit mixer stage for WFD during unset Interfaces with Borderfill pipe as base layer needs to be commited during unset which will reset the mixer cfg structure. This is needed because overlay_commit will not call stage commit as there is no buffer queued. Change-Id: Ib3347e52ae437b20d5a85a09777f13aee2672edb Signed-off-by: Kalyan Thota commit 36f267e093320a0f3b54887d0091d7d811e76d2a Author: Adrian Salido-Moreno Date: Tue Nov 20 10:41:54 2012 -0800 msm: mdss: enable secure content display In order to display secure content, secure buffers must be mapped to secured MDP context bank. Split current single IOMMU domain into secure and unsecure domains and check overlay flags to find out if content should be mapped to secure or unsecure domain. Change-Id: I510c253920b03cacf85085cb394f5281143e38e6 Signed-off-by: Adrian Salido-Moreno commit f270decc6b4cfd38070e4e867f01f043fbee3ea8 Author: Mayank Chopra Date: Fri Oct 12 20:51:47 2012 +0530 msm_fb: display: Add alpha enable check in blend FIR and M/N scalar when used for downscaling, drops alpha channel of the given layer. To notify this, alpha_drop flag is updated accordingly. This flag need not be checked for layers with no alpha plane. In some scenarios alpha_drop may get enabled for the layers with no alpha plane and cause issues realted to blend composition of layers. Check for setting alpha_drop only if source ayer has alpha plane. Change-Id: Ie64b30c045a78d0d68eb9efacc76902afae7850d Signed-off-by: Mayank Chopra commit 17e116a8ba55957248cf799de54997cf249e14c2 Author: Mayank Chopra Date: Tue Nov 6 15:28:07 2012 +0530 msm_fb: display: Fix blend configuration for command mode panels For command mode panels, blend registers does not get configured as per the use case. This leads to incorrect blending of layers resulting in lower layers (eg. wallpaper or buttons in video playback) to show above the upper ones, making overall user experience to go bad. In order to resolve the issue, blend registers are now configured properly by as per the use case. CRs-Fixed: 410029 CRs-Fixed: 415553 Change-Id: Ibe7d594e0ad6a6f4d75ed2e59c7382c09b65d624 Signed-off-by: Mayank Chopra commit b2c1661ac99c7b6821f702c810256dbaafbf7ec8 Author: Adrian Salido-Moreno Date: Wed Nov 14 22:28:23 2012 -0800 msm: mdss: release rotator sessions when all panels are suspended When all panels are suspended MDP will be shutdown, need to ensure that all rotator sessions are finished and properly closed to avoid access to MDP hw. CRs-Fixed: 409234 Change-Id: Ic1d95365a28c453ec8779d9c482a885857bf6912 Signed-off-by: Adrian Salido-Moreno commit eac7d2bb7d29f731840e96271268c545d0fe011c Author: Ujwal Patel Date: Wed Nov 14 21:53:34 2012 -0800 msm: mdss: hdmi: Replace of_get_gpio usage with of_get_named_gpio HDMI Tx driver parses platform gpio data based on index, using of_get_gpio api. Replace this index based lookup with name based lookup, using of_get_named_gpio api. Change-Id: Ic65aae1583c8c6f852c31fd454ac651fc6c8b907 Signed-off-by: Ujwal Patel commit 0791142a3e45f62ad674de0fff2437e4c58a4681 Author: Adrian Salido-Moreno Date: Wed Nov 14 21:12:43 2012 -0800 msm: mdss: add proper locking during suspend/resume operations Add locking mechanism to properly syncrhonize user space frame updates with suspend/resume operations. This should avoid some cases in which suspend operations will complete while frame update hasn't finished, leading to unwanted behavior. Change-Id: I4b254a6a547320199a6da722ef99563696686a20 Signed-off-by: Adrian Salido-Moreno commit bb08a42611e6149d0950d94126fa1143e53b8e9a Author: Adrian Salido-Moreno Date: Mon Nov 5 16:51:27 2012 -0800 msm: mdss: replace panel function pointers with single event handler There are many events in MDP that are important to acommodate the needs of different panel drivers, currently these events are propagated with function pointers. However as more use cases come into picture the ammount of events has increased, and not all of these are handled by all panel drivers. In order to provide all this information to panel driver and be able to extend it in future, create a generic way to propagate events from MDP to panel driver through a single event handler. Change-Id: Ide243f08bc4fa966ef9223b0a665cff95b9529db Signed-off-by: Adrian Salido-Moreno commit 9d450bd5c223d6dc729b0eff24a0547c8222be0c Author: Adrian Salido-Moreno Date: Wed Oct 31 15:57:42 2012 -0700 msm: mdss: fix possible deadlock while cleaning buffers Move pipe destroy logic outside of mfd lock to fix lockdep warning regarding pipe unlock logic being called within mfd lock, when mfd lock is usually locked within pipe lock and remove SSPP lock when destroying pipes. This was previously used to protect SMP allocations but these are protected by SMP lock already. Change-Id: I1c47da5d33cb4f1eb687078639adf4c4cc94f33a Signed-off-by: Adrian Salido-Moreno commit adb3920dd00f1001355e4ebbf451a5b646b3987d Author: Adrian Salido-Moreno Date: Wed Nov 14 21:46:10 2012 -0800 msm: mdss: fix possible null dereference of fb index Rotator data paths don't have a fb device assigned, assuming that it will contains a reference to fd data is incorrect. Add check to avoid NULL pointer dereference. Change-Id: Ib91e96ddc56590f2f681673b162921191e3d86da Signed-off-by: Adrian Salido-Moreno commit 5c06748c7decf51a63015579fa42cf8189727357 Author: Aravind Venkateswaran Date: Wed Oct 31 16:26:41 2012 -0700 msm_fb: HDMI: Cleanup HPD software debouncing logic Implement Hot Plug Detect (HPD) software debouncing by disabling the HPD interrupt until we finish processing a previous HPD interrupt. CRs-Fixed: 412575 Change-Id: Ia2c83f3446d09fe5bf6c6a1c4e6a9eb54ff465d6 Signed-off-by: Aravind Venkateswaran commit 9284a2701b6c030184848ba4b37c0b5019f62ed3 Author: Kalyan Thota Date: Fri Nov 2 20:55:30 2012 +0530 msm_fb: Wifi display changes for commit ioctl This change handles panel updates for WFD panel via overlay_commit interface, along with conglomeration of some common code across pan_update and overlay_commit ioctls Change-Id: I092180a4f2be801cd5b9008e99d0b712d089746b Signed-off-by: Kalyan Thota commit e41ba16cdf9d4aa7773fa33ef640ba32f5a17d7d Author: Manoj Rao Date: Thu Oct 25 16:32:32 2012 -0700 msm: 8974: MHL Driver for SI-8334 Tx The B-family device driver for SI8334 Silicon Image's Mobile High-definition Link (MHL) Transmitter implements wake-up, discovery and communication with MHL sink. The MHL-8334 Tx is attached to MSM as an I2C-client. Change-Id: I33f6c6f00011b590f9913cdbbe44544472b60982 Signed-off-by: Manoj Rao commit fe4abc1141a5620d42832137ad1dad15424b6b41 Author: Ajay Singh Parmar Date: Sat Nov 17 19:11:45 2012 +0530 msm_fb: display: Proper pipes solidfill For MPQ/hdmi as primary, solid fill the pipes only during suspend. This change also take care of the solidfill of the pipes unset during overlay and pan display at suspend. CRs-Fixed: 421461 Change-Id: I15096df681cbd94ae3cea63ecbfe915e01b7387f Signed-off-by: Ajay Singh Parmar commit 765bfd597fdc90610113cc9938c7152658d654ed Author: Kuogee Hsieh Date: Wed Nov 14 10:41:12 2012 -0800 mam_fb: display: add per stage alpha drop detection Currently, alpha drop detection is done per frame which means multiple blending stages share same alpha drop status whcih does not reflect alpah effect truly on each blending stage. This patch enforce alpha drop detection is doen per blenging stage so that alpha effect applied properly at each blending stage. Change-Id: I90f8f6395c88e665b64ae90e64b65cea1d54b41a Signed-off-by: Kuogee Hsieh commit bfdabc012c3a91e893fc9ee8473d25ca12dccf5d Author: Carl Vanderlip Date: Fri Nov 16 11:36:29 2012 -0800 video: msm: Remove adjustment to MDP revision Remove the modification of mdp_rev during mdp_probe. Not needed since board files now have the correct MDP revision data. CRs-Fixed: 417080 Change-Id: I553cb2a8e8de43b6c7b7976c3eca67d00a3cfe4f Signed-off-by: Carl Vanderlip commit ca24bda0148887716f250bbbc5debb2f80fa4331 Author: Pradeep Jilagam Date: Fri Oct 5 22:19:28 2012 +0530 msm_fb : Add timeout while waiting for vsync event Avoid eternal wait for vsync event when client tries to read the corresponding sysfs entry. This will avoid hangs when client tries to read in corner cases where the Timing Generator or the clock or IRQ gets disabled. CRs-fixed: 406752 Change-Id: I773687220b868823a9e4bfdae74361ee6487c5c6 Signed-off-by: Pradeep Jilagam Signed-off-by: Siddhartha Agrawal commit b6b7c0ef67d6bc2d82e4bbe63a946d3e8b815f69 Author: Huaibin Yang Date: Fri May 18 11:00:11 2012 -0700 msm_fb: display: extend mdp debugfs with force blt enable Enabling/disabling mixer0 or mixer1 blt mode is a critical way to debug display issues, so add debugfs interfaces to force blt mode enabled/disabled with adb shell commands. CRs-fixed: 390953 Change-Id: I96a568f22398867571a796a863c098f749f5618b Signed-off-by: Huaibin Yang commit bcafbe3fb1b630a844c4776f9bab4c65cd5cefa5 Author: Kuogee Hsieh Date: Thu Oct 4 15:55:40 2012 -0700 msm_fb: display: disable external instead primary vsync irq Since DTV is external interface of mdp, it should only control external vsync irq. Change-Id: I5f3a7087c7d4997cd40d4cc4907d8b054e37c6b6 Signed-off-by: Kuogee Hsieh commit 3eebb2e33570e32d11a757e493e12a8e79e08d6f Author: Huaibin Yang Date: Thu Nov 8 14:21:41 2012 -0800 msm_fb: display: add setting gpio-controlled backlight logic For the panels which backlight is controlled by gpio, add this logic in driver to turn on/off backlight, instead of calling board panel on/off functions, to avoid garbage display due to early backlight turn-on. CRs-fixed: 408728 Change-Id: I6f1b9bd78d96dbf1492e854edd59b05f8dec205f Signed-off-by: Huaibin Yang commit 5f91c9259a62b5dd2226bf46efc42152667b9e19 Author: Mayank Goyal Date: Wed Nov 7 16:58:09 2012 +0530 msm: rotator: Add pseudo-planar 422 H1V2 dst format for MDP4 Rotator outputs pseudo-planar 422 H1V2 for interleaved inputs on 90 degree rotation.Add changes to support MDP_Y_CRCB_H1V2, MDP_Y_CBCR_H1V2 in MDP4. CRs-Fixed: 371303 Change-Id: Ibd1cb9803b8cf8bede28bc1d9830320dd505f5be Signed-off-by: Mayank Goyal commit a3b0e08b5c65b28c81a8a4511ebacd6985793dc5 Author: Adrian Salido-Moreno Date: Tue Oct 30 13:50:23 2012 -0700 msm: mdss: import venus stride alignment requirements In order to avoid mismatch in stride assumptions between Venus and MDP, import common header file with Venus alignment requirements and configure MDP surface with these. Change-Id: Idf849b3f476eb5e2d60fec190698efd487f035cf Signed-off-by: Adrian Salido-Moreno commit c62976484ec5b681361a563d80fd5a5546287308 Author: Adrian Salido-Moreno Date: Sat Oct 20 14:08:41 2012 -0700 msm: mdss: disable fetch for all previous stages with is_fg The is_fg flag is used to disable fetch for all previous mixer stages, currently this only to disable fetch for base layer. Modify mixer setup logic to disable fetch for all previous mixer stages. CRs-Fixed: 413254 Change-Id: Ic0f101fe88a3c64db11cf43484f64f0f5e32d0d0 Signed-off-by: Adrian Salido-Moreno commit a21de442a3babb554d1a9a54eef2ef0944cbfa4e Author: Adrian Salido-Moreno Date: Fri Nov 9 16:18:07 2012 -0800 msm: mdss: disable overfetch done while scaling While programming pipe, src image size can be programmed when area outside crop rectangle contains valid contents in order to allow MDP hw to do overfetch of pixels while scaling. However for most cases in video playback the area outside the crop rectangle is only padding with invalid pixels used in order to satisfy alignment requirements. Since driver is not aware if padding is being used or not, disable the over fetching along the border to avoid unexpected pixels being displayed. CRs-Fixed: 404918 Change-Id: I145f34bcaef76a88116b6803eeaf4a5ffd19592d Signed-off-by: Adrian Salido-Moreno commit 20f0af9200e416d4b2f7949e2ecfd81182a5edc6 Author: Asaf Penso Date: Tue Nov 13 17:34:12 2012 +0200 msm: mdss: fix enable/disable of gpio_panel_en in edp driver gpio_panel_en is always on even though driver is in suspend mode. The fix is setting gpio_panel_en value in edp_on/off function. Change-Id: Ib41681d31788b9a17a032e9b9e8dbe53eb9e4fa9 Signed-off-by: Asaf Penso commit 6db43b58111cfd39eaee0d694c223cbc7461d16c Author: Mayank Chopra Date: Fri Nov 2 15:25:37 2012 +0530 msm_fb: display: Create sysfs entries in mdp_probe for MDP3 targets vsync sysfs entries should be created in mdp_probe instead of creating in panel on. This avoids waiting for the first event control in framework Change-Id: I18b05b8d2a65d489afc6e3274ec8dc7a5b9a5f9a Signed-off-by: Mayank Chopra commit b5292f0df4e06db2272c92d575e255f310793e3c Author: Mayank Chopra Date: Fri Nov 2 13:54:39 2012 +0530 msm_fb: display: Create sysfs entries in mdp_probe for MDP4 targets vsync sysfs entries should be created in mdp_probe instead of creating in panel on. This avoids waiting for the first event control in framework Change-Id: I983731481ea89bb7666be5f2a9f75a1e04fd963f Signed-off-by: Mayank Chopra commit 39e3fecb80703313621b22d2a8b5667a816265bf Author: Adrian Salido-Moreno Date: Thu Nov 8 13:51:00 2012 -0800 msm: mdss: disable overlay operations while suspended When display is suspended all overlay operations coming from userspace should be ignored to avoid programming MDP when it's completely powered down. Change-Id: If43436915de33f89016ee2c85eb70bd57fdd2118 Signed-off-by: Adrian Salido-Moreno commit b6d7e48e777e99e28dea95cb93debfd9d15d849c Author: Adrian Salido-Moreno Date: Mon Nov 5 12:08:27 2012 -0800 msm: mdss: enable dithering for panels with reduced color depth In order to avoid banding caused by using reduced color depth as panel output format, dither can be enabled to produce an image which gives better representation of original image. Change-Id: I88a1be747332070d2b8b00dcbeb7e97936a47092 Signed-off-by: Adrian Salido-Moreno commit 6829d179d9ae8f3646a7a7204571ce15d35a997c Author: Huaibin Yang Date: Fri Aug 31 17:06:52 2012 -0700 msm_fb: display: add option to switch mdp operating mode Currently, mdp switch operating mode without turning off timing generator. This patch adds option to have mdp switch operating mode (direct out and writeback) with timing generator turned off based on configuration of panel file. CRs-fixed: 405987 Change-Id: I92057757863218222d8647d33d57f6de9b3b3765 Signed-off-by: Kuogee Hsieh commit a4567ac320abe5d74b3c7decdbddba4bd8c57463 Author: Huaibin Yang Date: Fri Oct 5 11:02:40 2012 -0700 msm_fb: display: skip one vsync event after enabling mdp and vsync clk Both mdp and mdp_vsync clks are disabled for command mode panel when no new frames are being played. When they are re-enabled if new requests come in, the first vsync event which is signaled by read pointer interrupt arrives in a random time due to the sync between mdp and panel, so skip it to maintain correct vsync timing. Change-Id: I683b765e4a16d3d152b9270f5982234b94921f1e Signed-off-by: Huaibin Yang commit 9bc28cf89a1619218fc1193409c4f614d1f826f6 Author: Huaibin Yang Date: Mon Nov 5 16:18:53 2012 -0800 msm_fb: display: add config of wb_mux_sel during update To make sure for each writeback play the reg is configured and avoid mdp hang. Change-Id: I29bdc31f27accca84e7add126c1c1e3c8a78fa15 Signed-off-by: Huaibin Yang commit ec8922ceea49cfd2e13a3c1ddab9f51e2f13394f Author: Huaibin Yang Date: Fri Nov 2 17:30:46 2012 -0700 msm_fb: display: empty pending queue during suspend for wfd Add the logic for wfd writeback interface. It already presents on other display interfaces. Change-Id: I389be77ec18041e260d0e71940586e86f1841ff8 Signed-off-by: Huaibin Yang commit 8befe49ddcd2952cfd60634153dc5caf440acb27 Author: Ujwal Patel Date: Mon Nov 5 18:34:13 2012 -0800 msm: mdss: Add support for disabling HDMI while cable is connected Send disconnect and/or offline event to user-space when user explicitly asks to stop listening to hpd only if HDMI mirroring is going on. Upon receiving this event, user-space will trigger power off and HDMI mirroring will be turned off until user explicitly asks to start listening to HDMI cable connect. CRs-Fixed: 409880 Change-Id: I509a9a7ba04066e571b5f762be4804c7dd39c655 Signed-off-by: Ujwal Patel commit 84639ef623c0f3301bda4893bae9eaa83454c222 Author: Adrian Salido-Moreno Date: Mon Nov 5 14:48:03 2012 -0800 msm: mdss: correctly handle panel power on failure Check panel power on return code and correctly revert any interface initialization if any error occurs. CRs-Fixed: 417959 Change-Id: I4ad644b16efd51e5e8b3be1393c39195687feb8a Signed-off-by: Adrian Salido-Moreno commit 074de641de0fab973a9efd9c3d57498453ef28ef Author: Ujwal Patel Date: Fri Nov 2 20:18:47 2012 -0700 msm: mdss: Serve HDMI Tx power off in a separate context HDMI Tx core should not be powered down until the audio engine has shutdown transmitting packets to the HDMI Tx core. This change moves the power off sequence to a separate thread so that framebuffer close system call does not get blocked. Change-Id: I011c6612ec1b6be047e4adb39c1af48f6a105bed Signed-off-by: Ujwal Patel commit 2816e20c94fd5ee23c9784b3dbc3ac690fe1e88d Author: Ujwal Patel Date: Fri Nov 2 20:17:27 2012 -0700 msm: mdss: Clean-up hpd debouncing logic of HDMI Tx controller Implement hot-plug detect (HPD) software debouncing by disabling the HPD interrupt until we finish processing a previous HPD interrupt. Change-Id: I434a223a3d340d5759346e071d5350d412de2c20 Signed-off-by: Ujwal Patel commit 3ca6a5691a83819c1b8c7123089cb85f5b4a58ef Author: Ujwal Patel Date: Mon Nov 5 14:58:28 2012 -0800 msm: mdss: Add error checking for incorrect state during HDMI power on/off HDMI power on should not be permitted if hpd is not initialized. Similarly HDMI power off should be skipped if power is not on. Add proper checking for above state conditions. CRs-Fixed: 417959 Change-Id: I9470c6d818adc403de05c25a7e96c8ab1c8a43fd Signed-off-by: Ujwal Patel commit 1073b45c0b120f2ebbe1b5034d4088f9294b54af Author: Kuogee Hsieh Date: Tue Oct 30 18:26:00 2012 -0700 msm_fb: display: fix frame buffer's ref count leak This patch clear MDP_MEMORY_ID_TYPE_FB from pipe's flag so that fput_light() and fget_light() can be applied to frame buffer evenly at end of pipe operation. Otherwise there has kernel unable to handle NULL pointer panic caused by frame buffer's ref count leak. CRs-fixed: 411394 Change-Id: Ib2b72e6277480b5ace23cda554be485d9d477b3d Signed-off-by: Kuogee Hsieh commit 4f4796e811c00082db0414d4ad211aa3fcefd3a9 Author: Ujwal Patel Date: Mon Nov 5 08:41:49 2012 -0800 msm: mdss: Fix returning incorrect error number Instead of returning actual error number, current code returns boolean value of error present. Fix this issue by using PTR_RET macro instead of IS_ERR during error check. Change-Id: I61f0e57dd918c98ae4699993fa526e31654bebb3 Signed-off-by: Ujwal Patel commit c30090ea5c28fce50a7c0ac829b9effd809f41e8 Author: Adrian Salido-Moreno Date: Thu Oct 11 15:30:58 2012 -0700 msm: mdss: add interlace video display support Interlace video contains two frames interleaved within same buffer. Since there is no hw support in MDP5 to display interlace content, support interlace video by taking even fields only for display. Change-Id: I92718d13eb7711d0c4252adf8751384719c862f1 Signed-off-by: Adrian Salido-Moreno commit 04d097801cc94a121751c9d5fde2ea458f3ae76f Author: Ajay Singh Parmar Date: Sat Nov 3 02:39:20 2012 +0530 msm_fb: hdmi: black out pipes on unset For HDMI as primary case, we need to blackout the pipes when they are unset so that any residue is not visible on the DTV during suspend. Change-Id: I2bf36f1002dd185c26fe6c4291977737daa73ae1 Signed-off-by: Ajay Singh Parmar commit a5611de5f7d754d538706949bfdc9b8aa36fd0f0 Author: Adrian Salido-Moreno Date: Fri Oct 19 13:39:52 2012 -0700 msm: mdss: fix bus calculations overflows With higher display resolutions the bus calculations being performed can be very high which may cause overflow and unwanted results. To avoid such situations modify logic to perform calculations in kb and use 64bit data type to call into bus scaling driver. Change-Id: I7b975d750e316c6e79bcdcd54a8194c8ae40c155 Signed-off-by: Adrian Salido-Moreno commit 7fb9c21f04a8a87d2bf2e45ad1a5c9cd374f65be Author: Adrian Salido-Moreno Date: Fri Oct 19 11:58:29 2012 -0700 msm: mdss: replace disable irq with no sync to avoid potential deadlock Potential deadlock can happen when disabling irq after receiving vsync complete event in display if at the same time MDSS irq is triggered, at this point disable irq will hold spin lock which irq tries to get and will not release because it's waiting on irq to be disabled. This scenario can be avoided by using disable_irq_nosync instead to avoid locking on irq to be disabled while holding spinlock. CRs-Fixed: 416304 Change-Id: I1e367ac2b5d7b0ed7d1c15efc8d29a6ffa9fea5e Signed-off-by: Adrian Salido-Moreno commit 5328e4976369d5b4fc76183720168b58bdffd6c7 Author: Siddhartha Agrawal Date: Tue Oct 2 15:03:44 2012 -0700 msm_fb: display: Enable scaling bit while setting x-flip bit To enable left-right flip x-scaling bit should be set for MDP 4.2 and above versions. This fixes the issue when RGB layer pipes are not properly rotated. Change-Id: I0afae4aecde39ce3ac4dcbefc0bda93510e7d18a Signed-off-by: Siddhartha Agrawal commit d8bad5aaad6a19d65ae8d63451044455aceca46a Author: Siddhartha Agrawal Date: Mon Aug 20 11:58:42 2012 -0700 msm_fb: Correctly setup splash screen flag in MDP probe The continuous splash screen flag was sometimes not correctly setup during MDP probe causing corrupted grey screen on resets. Crs-fixed: 389531 Change-Id: Id88d8a239ccfd1cbb5ce0f4f3db68756182f5ff9 Signed-off-by: Siddhartha Agrawal commit 6ced23c4d1863316a72d7143a60ccfb547282940 Author: Huaibin Yang Date: Thu Oct 25 16:24:54 2012 -0700 msm_fb: display: adjust refx100 parameter to avoid tearing refx100 is used to calculate how many mdp_vsync clocks to complete one line in the panel. This info is used by mdp h/w to sync data transfer between mdp h/w and command mode panel to avoid tearing. CRs-fixed: 379223 Change-Id: I3880a350b77cb8165745ea343b1525e84100a62d Signed-off-by: Huaibin Yang commit 66744e7a76bfa3f56818bcaa2d430468e50a1922 Author: Kuogee Hsieh Date: Wed Oct 31 13:29:48 2012 -0700 msm_fb: display: force mdp clock off at suspend At suspend, turn off mdp related clocks off if clocks are not turned off by vsync disable request. Change-Id: I0949b00b9ee0aee05b9b553ac7318b647052d94d Signed-off-by: Kuogee Hsieh commit ef5abb017cee4c6bbacb6d064764bda8b4a1a0c5 Author: Ajay Singh Parmar Date: Wed Oct 31 20:40:17 2012 +0530 msm_fb: display: Correct dtv pipe black out This change corrects the register values to black out the dtv base pipe. Change-Id: I80fefab3cc6dd006edbb673f41ccfe983af2cc3a Signed-off-by: Ajay Singh Parmar commit 19a4f321dca81cbee29c934a9584412614a444c0 Author: Ujwal Patel Date: Tue Sep 25 16:48:18 2012 -0700 msm: mdss: Enable stereo audio through HDMI Tx Add support for Stereo Audio in HDMI Tx driver which sends HDMI stream on/off notifcations to audio userspace using hdmi_audio switch node. Change-Id: I2c8e756adbbe2f9230dfb7735774ee194e32e446 Signed-off-by: Ujwal Patel commit e2c2859bac8fcf41d39ba9cc614d028f0e1573ef Author: Adrian Salido-Moreno Date: Tue Oct 30 16:01:15 2012 -0700 msm: mdss: add smp specific lock SSPP lock is shared between pipe allocations and smp block allocations, this can cause possible circular lock dependency since usage is different for these cases: - During pipe allocation SSPP is held when acquiring pipe lock - During SMP allocation pipe lock is held when acquiring SSPP lock For this reason, splitting SSPP lock, and since pipes and smp locks manage separate resources sharing is not needed. Change-Id: I54a0997fddef893b99a4b01d3e3f62382e1e0ecf Signed-off-by: Adrian Salido-Moreno commit ec339e96700b98faa170b06f73678f203c237291 Author: Huaibin Yang Date: Mon Oct 29 16:19:03 2012 -0700 msm_fb: display: change the location of wakeup timer call There are two pathes (pan display and overlay commit) to commit display buffer, so change the location of cpu timer wakup call to the common pipe_commit function to make sure cpu get waked up around vsync. Signed-off-by: Huaibin Yang Change-Id: Idbe6049d740a7e17a6a90e28566f7a9c74e348f2 commit b360fd40a5214595d7e9970431ef83653b76b13e Author: Ajay Singh Parmar Date: Sat Oct 27 13:14:11 2012 +0530 Revert "msm_fb: display: suspend-resume on HDMI" This reverts commit 30befc28305440f30770a6545839fe4b55ee2207. Revert early suspend implementation for MPQ. Change-Id: I028a7f0d6997d2d09d718d3b5072466d28a95b59 Signed-off-by: Ajay Singh Parmar commit 5f6d8314b2ad063da8a8ebf71fef8c713f76401b Author: Kuogee Hsieh Date: Sat Oct 13 17:27:55 2012 -0700 msm_fb: display: fix dsi_busy_wait race condition After pipe_commit() released mutex and before kickoff happens, There has possibility that dcs command may start transmitted. This patch add dsi_mdp_busy flag to fix this race condition. Change-Id: I0d9a81cd0719085c91c03386117261ad3bb6b182 Signed-off-by: Kuogee Hsieh commit 366ca5c34117fde6329ea81112068d1dc177ff70 Author: Kuogee Hsieh Date: Sat Oct 13 17:26:31 2012 -0700 msm_fb: display: add video mode dcs cmdlist support Add video mode dcs command list support. This patch make sure dcs commands committed while dsi video engine is busy so that dcs command will be transmitted at beginning of next BLLP. Change-Id: I11b0214ee10f3b1ef33b1da4c8e577800068cb06 Signed-off-by: Kuogee Hsieh commit c405afa88ef5139132795757a7446a7081d92c38 Author: Kuogee Hsieh Date: Sat Oct 13 17:23:10 2012 -0700 msm_fb: display: add sysfs and clock control to smart panel This patch allows both vsync enable and disable are controlled by framework. Driver reports vsync event to framework via sysfs. Meanwhile, mdp related clocks are enabled by framework at vsync enabled request and disabled by driver if there is no any display update within specifid vsync period. Change-Id: Ice5be3a6db5930b95bdd2f718d9256bf73936e23 Signed-off-by: Kuogee Hsieh commit 64892009d43ca724c5ee1be5f7db6ad1f00cda6c Author: Kuogee Hsieh Date: Thu Oct 25 09:07:58 2012 -0700 msm_fb: display: fix iommu leak during base layer swap Retain RGB1 iommu information during base layer swap so that iommu used by RGB1 can be freed back to pool later. CRs-fixed: 403277 Change-Id: Ibed85179284743dc8a9d1434f0c81626b0567e16 Signed-off-by: Kuogee Hsieh commit bbd754882e8ec1a52ebba237e02ba8c49b00f135 Author: Ujwal Patel Date: Thu Oct 25 19:30:33 2012 -0700 msm: mdss: Fix error roll back sequence during core on. When core power enable fails for some reason, current code disables hpd power in the roll back which is unnecessary. Correct this mistake. Change-Id: Ia5ed63edb017ade44950058c9d6071e8eb5d7884 Signed-off-by: Ujwal Patel commit 693e87a8e357add7444dbad12cb265deaa90d3e2 Author: Huaibin Yang Date: Tue Oct 2 15:08:56 2012 -0700 msm_fb: display: wake up system before vsync for cmd panel Add this feature for cmd mode panel. The feature is to avoid frame drops due to power collapse and it is already present for other display interfaces. Change-Id: Ic68f41cd59931294b592577475ed7480459f2cf8 Signed-off-by: Huaibin Yang commit 407e03a33eaa0880b87a2a6a7bf43e3516cb2562 Author: Asaf Penso Date: Thu Oct 25 15:03:21 2012 +0200 msm: mdss: add eDP backlight Add configuration for setting different brightness levels in edp driver. This is done according to lpg channel and period values from devicetree. Change-Id: I4e9074d777102193d7678f7aac565be3a5a551df Signed-off-by: Asaf Penso commit b640c29b8b3b4a0733924a6e4ad0665d5218a7dc Author: Carl Vanderlip Date: Thu Sep 20 14:14:40 2012 -0700 video: msm: Send ETIMEDOUT on update-notify timeout Send the ETIMEDOUT errno when the update-notify wait_for_completion times out. This is required to be able to properly handle the different failure cases in the functions that use the update notify ioctl. Change-Id: I0e46b0b0c89f6b2e5beb3fc0ed18ebbb75dfa434 Signed-off-by: Carl Vanderlip commit a3020ffbd3720f3aaba439b593db5a85dcb50bc0 Author: Carl Vanderlip Date: Mon Oct 22 11:33:23 2012 -0700 video: msm: Wait for latest histogram data Old histogram API introduced behavior that calls to collect histogram data would return a frame's histogram once, and would wait until new data was available if needed. Follow old histogram behavior by waiting when histogram has old/not ready data. Change-Id: Ia1b6b5b7a5b63a570a641b5460eb8e0d72c458c8 Signed-off-by: Carl Vanderlip commit a80d082eeb5ad6a024bea9992d8dc74406c37752 Author: Carl Vanderlip Date: Mon Oct 15 18:05:14 2012 -0700 video: msm: Ensure histogram is fully enabled before kicking off Histogram hardware needs to have histogram enabled before kicking off histogram collection. Add state variable to track if histogram is ready to collect. Change-Id: I71380e89de1a61f446802f791e917f57d14f10a2 Signed-off-by: Carl Vanderlip commit 6011950da33ac430c1c6b677c25423d07f8e8c95 Author: Carl Vanderlip Date: Tue Aug 28 12:03:28 2012 -0700 video: msm: MDSS: Add Update Notify Add update notify ioctl to MDSS driver. "Update notify" is able to signal userspace processes when there has been a screen update or if there has been a 22 second period without screen updates. Change-Id: I90cf7f7e6650236186452c1a9f86850731ad785d Signed-off-by: Carl Vanderlip commit 0af12fc4577d1dda6a0209d1a35cccaa716721b2 Author: Carl Vanderlip Date: Mon Aug 27 14:52:39 2012 -0700 video: msm: Add backlight scaling for MDSS Add backlight scaling functionality to the MDSS driver (includes the fixes with regards atomicity of backlight scale and level updates). Allow for power saving algorithms to modify the intensity of backlight without introducing race conditions caused by competition for backlight level. Change-Id: I97ae024055ca614648ffe2aeae09cc350d2577ec Signed-off-by: Carl Vanderlip commit 97ea71b93d1148c9127e59ba19a71f67b4808c2e Author: Kuogee Hsieh Date: Thu Sep 27 11:44:15 2012 -0700 msm_fb: display: check pipes queued before enter wait_for_completion Timing generator will not be turned on if there are no pipes queued. Therefore wait_for_completion may never be completed if there have no pipes queued. Change-Id: Iafba086e4ba20b31470c9fd385c4f5c474ecadcf Signed-off-by: Kuogee Hsieh commit d0edc1cb98a8af7a7c650c7f690e510e7c01b9b1 Author: Kalyan Thota Date: Mon Sep 24 19:52:16 2012 +0530 msm_fb: Enable H/W cursor for External Interface Add H/W cursor support for MPQ uses cases which use external interface. Change-Id: I5d1f71813769c7e86e576888463bceaa7ad37b68 Signed-off-by: Kalyan Thota commit c579c8770c6c0a9e823cc4a7d1349ea4e3d99d95 Author: Adrian Salido-Moreno Date: Mon Sep 24 17:36:38 2012 -0700 msm: mdss: fix rotator hang for xrgb formats XRGB formats require constant alpha to be setup when writing back to memory. Change-Id: Ie819b88578a85923d1cde7efe54ca0819c59a611 Signed-off-by: Adrian Salido-Moreno commit 6ba5f1fb067410d097f973f311bfcc9eded6a1bb Author: Kuogee Hsieh Date: Thu Oct 18 11:21:23 2012 -0700 msm_fb: display: add wait4dmae for hdmi as primary display When hdmi use as primary display, pan_display is used to update screen. This patch adds wait4dmae to pan_display to avoid source tearing on hdmi display. Change-Id: Ied31419590c51e4bc2218ee8dfdc7d5221c996dc Signed-off-by: Kuogee Hsieh commit 7ef177524d89ce9bbd84bf0a54c28c335c2a2b14 Author: Asaf Penso Date: Tue Oct 16 11:00:19 2012 +0200 msm: mdss: add support for different panel formats Some panels have different color format requirement such as RGB666 for EDP Panel. Add logic to detect panel resolution based on panel bpp set by panel driver. Change-Id: I4cad59033b8b4f807c2ed38b00451aab89737bb7 Signed-off-by: Asaf Penso Signed-off-by: Adrian Salido-Moreno commit b2372aeb5c33f7c49ad3133238b799ba9e60480b Author: Gagan Mac Date: Mon Aug 20 19:24:32 2012 -0600 msm: msm_bus: Add support for 64-bit bandwidth requests With 8974, bandwidth requests are exceeding integer size. Update ab and ib to ensure values over 4Gbps can be requested. For 64-bit support, there are four changes in this patch: Changes in the bus driver structures and functions to update ab and ib values to uint64. Updates in client drivers to ensure that the bus APIs are called with the right types. Updates to the device-tree. Device-tree nodes don't provide a clean mechanism to read a combination of u32 and u64 variables within the same property name. So, the ab and ib values must be specified in kbps instead of bytes/sec from the device tree. The bus driver function will convert the ab and ib values read from device-tree to Mbps. Change the existing property names to make them consistent with the convention used by the new property name, which abides to the Device Tree convention. Change-Id: Id37407c349a9cea17f6621d3bef2401b856f7b7d CRs-Fixed: 408786 Signed-off-by: Gagan Mac commit 327a968551e890838f471ce649748d03861465a3 Author: Kalyan Thota Date: Thu Aug 23 17:08:25 2012 +0530 msm_fb: ADD AVTimer info to the vsync event for DTV interface MPQPlayer requires Avtimer time stamp when every frame is rendered. This change enables sending AVtimer info with every vsync for DTV interface. Change-Id: Ib36c9a152bf3454be984fed765ad268f9435933b Signed-off-by: Kalyan Thota commit 523d93ac63dc5a0ae9b5c7d24278ca48fbb923d4 Author: Asaf Penso Date: Tue Oct 16 22:47:03 2012 +0200 msm_fb: mdss: Add EDP physical layer configuration support Add code to configure the enable/disable and PLL settings for the physical layer of EDP. Change-Id: I6e15e41fdd23cc5a4855a3addf85050ade802d8d Signed-off-by: Chandan Uddaraju Signed-off-by: Asaf Penso commit 68b3fc5593916dc6d4b47d2434776c9dd91f77a2 Author: Asaf Penso Date: Tue Oct 16 21:47:59 2012 +0200 msm_fb: mdss: Add eDP controller driver support eDP controller is one of the output interfaces for MDSS. Add support for eDP host controller driver which runs in Video mode only and eDP related changes for msm_fb panel driver. Change-Id: I0a150f8d712f57bdfaee9051b2893e2910195567 Signed-off-by: Kuogee Hsieh Signed-off-by: Ravishangar Kalyanam Signed-off-by: Asaf Penso Signed-off-by: Chandan Uddaraju commit 4fc9350b124ded06f90c43410c2c0b512681c0db Author: Kuogee Hsieh Date: Wed Sep 12 09:03:18 2012 -0700 msm_fb: display: return fail if pipe still staged Pipe is not un-staged from mixer when it is unset. It expects a pan_display() to un-stage it out of mixer. Return fail at overlay_set() if pipe was still stage at mixer. CRs-fixed: 399193, 393979 Change-Id: I562f6e133bb239b30f4f53669dbf1cc5ddf80d02 Signed-off-by: Kuogee Hsieh commit 4aa5b44e20ba129a98fedff1cc6ea4a9495f0ebe Author: Deva Ramasubramanian Date: Thu Jul 26 17:32:40 2012 -0700 msm: mdss: Use MDP_Y_CBCR_H2V2_VENUS as the output format for writeback For Wifi Display use case, the Venus variant of NV12 is required since the Venus core expects it in this format. Change-Id: I68ded4373212021486bc6b7b89514fdecf05d4da Signed-off-by: Deva Ramasubramanian commit 636779a7ddbe69a6f8be39cba9755e352fce39b4 Author: Ajay Singh Parmar Date: Fri Oct 12 19:06:16 2012 +0530 msm_fb: hdmi: Proper update of ACR CTRL Register While changing the audio sampling rate, the older data in the control register needs to cleaned before writing in new data to avoid mixed or wrong data writing. CRs-Fixed: 405772 Change-Id: I95d0807ea8cf544e4a0c8caed00de6cd60352efa Signed-off-by: Ajay Singh Parmar commit 35c724bf61ef9432cd467152dfeab25e517b50a7 Author: Kuogee Hsieh Date: Wed Oct 10 11:51:20 2012 -0700 msm_fb: display: add dtv base layer swap Add dtv base layer swap between border fill pipe and rgb pipe to support hdmi as primary display. Change-Id: I127a301385d5d83e5d06507869132c6e124cc94f Signed-off-by: Kuogee Hsieh commit 0e53b6627814d52e3cf5604e0793f4780ec4a9c1 Author: Mayank Chopra Date: Thu Oct 4 20:29:52 2012 +0530 msm_fb: display: Make sysfs read request interruptible Change blocking sysfs read request to be interruptible and protect vsync timestamp value to prevent corruption. Change-Id: I510d84134b0ab70d17729e8c53c91fa926035142 Signed-off-by: Mayank Chopra commit 97104cc8bf4881f41dfd79e6bdc31383c5ccabfc Author: Huaibin Yang Date: Wed Oct 3 17:50:39 2012 -0700 msm_fb: display: extend mutex protection for mdp pan display When mdp commits a buffer to play, functions inside pan display, e.g. mdp4_overlay_mdp_perf_upd are based on the current state of play, so extending mutex to the scope of pan display to avoid race conditions. Change-Id: I2e55567fd21de3738be066a2dee298d8122f12a3 Signed-off-by: Huaibin Yang commit 5b567514a5cebae7b6fdabd0b94c29efa4aef18f Author: Adrian Salido-Moreno Date: Mon Oct 1 18:50:16 2012 -0700 msm: mdss: fix rotator session not being closed correctly User space expects non-negative number as session id, update rotator mask to avoid making rotator session as negative. When rotator is closed, need to recalculate bus/mdp clock numbers. Change-Id: I6c0e3bfa5394fb64b78fb47be1f24462e320916d Signed-off-by: Adrian Salido-Moreno commit 6e923f52e81757c6fdb03fe4184f79be7b4068ee Author: Adrian Salido-Moreno Date: Tue Sep 11 18:30:03 2012 -0700 msm: mdss: update performance calculations to include border color Current clock and bus scaling calculations consider only source surface pipes to set clock rate and bus scaling factor, however since MDP also generates pixels for border color this area also needs to be considered for final clock and bus scaling factors for data paths that use layer mixer. Change-Id: I9463c01dfd0b7a301797bd036f563e15d5195dbd Signed-off-by: Adrian Salido-Moreno commit 35143f7156a7f651f2cfcc511b2ebbb12b2ceb02 Author: Adrian Salido-Moreno Date: Thu Sep 13 10:43:15 2012 -0700 msm: mdss: move unstaging of overlay surfaces to display commit Perform cleanup of surfaces destroyed with overlay unset until next display update. This enables a smooth transition in case multiple surfaces are unset before next frame update. CRs-Fixed: 406645 CRs-Fixed: 406553 Change-Id: I843c7f11fc943d8351b7408116101ba20f25d116 Signed-off-by: Adrian Salido-Moreno commit 70236f7a01bcb9278b99f2df7b8acd4d1cd323d2 Author: Adrian Salido-Moreno Date: Tue Oct 9 20:12:14 2012 -0700 msm: mdss: remove display commit during overlay play All display commits happen with pan display in order to have a single sync point when using multiple pipes, and avoid blinks that can happen when updating surfaces out of sync. Exception for this case is writeback where commit is still needed, keep this implementation until this exception is corrected from user space applications. CRs-Fixed: 408105 Change-Id: Ib40c4872f43e6a939c45624677b2ab1f64a3b31e Signed-off-by: Adrian Salido-Moreno commit 944b88e82e9baaaeb52a2ec38298ed2e48c33f1d Author: Adrian Salido-Moreno Date: Tue Oct 9 20:06:21 2012 -0700 msm: mdss: implement commit ioctl for display commit Commit ioctl is used to update contents on display while avoiding console_lock done through framebuffer pan_display path, which causes additional delay on display pipeline leading to flickers on HDMI. Change-Id: Id3522d322ba08b110d540e10214cadfbbb0bcc25 Signed-off-by: Adrian Salido-Moreno commit d74db5fcf24a223570137087aa5632593b315fcc Author: Kuogee Hsieh Date: Wed Sep 5 09:05:58 2012 -0700 msm_fb: display: wfd with vsync driven frame push To improve performance, hardware vsync event at mdp driver is passed to framework so that both composition and frame update are aligned at vsync event. This patch will upgrade wfd to incorporate vsync driven frame push in consistence with other interfaces. Change-Id: If088826ec387446301f1f6acc311d909edb04163 Signed-off-by: Kuogee Hsieh commit f0d08071a4e97c9018b8e8def498e07720201da8 Author: Kuogee Hsieh Date: Tue Sep 18 17:32:15 2012 -0700 msm_fb: display: add checking y direction for alpha drop Alpha is dropped when scaling with non repeat pixel method. Both x and y direction of scaling need to be cehcked for alpha dropped. Change-Id: Iba0df5a85011f179199c13ffdebac911e5c14c3c Signed-off-by: Kuogee Hsieh commit 6745082aec2b97f07dcfbc49ea7b8b79099f4d13 Author: Kalyan Thota Date: Tue Sep 11 18:04:34 2012 +0530 msm_fb: Use background alpha for all destination alpha enable cases Use background alpha for modulation in all the cases where source alpha is not available. CRs-fixed: 366834 Change-Id: I300c04181ee3fa4f305a26a3e17e7eac2572564c Signed-off-by: Kalyan Thota commit bd556dc51ccf32a7ddc8d435d31f39e981815f8f Author: Kuogee Hsieh Date: Fri Sep 21 14:11:30 2012 -0700 msm_fb: display: check base layer pipe at irq handler There is a corner case when overlay and dmap interrupts are fired before base layer pipe is allocated. Therefore Check for base layer pipe before performing any operations. Change-Id: Ib188d575044f5479672503508042c8c1e9c759c4 Signed-off-by: Kuogee Hsieh commit 7d136bef71281855cd224ccc967e4e95286f5356 Author: Kuogee Hsieh Date: Wed Sep 26 13:10:42 2012 -0700 msm_fb: display: add fput_light to frame buffer Frame buffer's (fb0) ref_count need to be balanced. overlay_play() increase fb0's ref_count (fget_light). This patch will decrease fb0's ref_count by calling fput_light after commit. Change-Id: I34ea738bf21d0858b7361ec8e289464a217a1231 Signed-off-by: Kuogee Hsieh commit f08f2387cdc5a2d365c33bef1fe2a87b6c5911c3 Author: Adrian Salido-Moreno Date: Thu Oct 4 16:21:33 2012 -0700 msm: mdss: remove pan display no memory warning There are some framebuffer devices that don't allocate any memory such as HDMI or WFD, warning for no memory is not necessary and it just floods kernel log hence removing it. Change-Id: I8f9ba1cda1f55c741b99d462adf74531d73aaeee Signed-off-by: Adrian Salido-Moreno commit a4c377fbf133bd53913d451b478c177c271ab365 Author: Huaibin Yang Date: Fri Sep 28 11:13:49 2012 -0700 msm_fb: display: remove background invert alpha option for alpha drop pipe When the blended background pipe has dropped alpha and it is going to be blended with foreground pipe on the next stage, MDP4_BLEND_BG_ALPHA_FG_CONST is taken. Foreground alpha constant is 0xFF, so we need to use this alpha value to show background, instead of its inverted value. Change-Id: I1fe0572f9bb54db6280bcc44117a21b8c0d8b07a Signed-off-by: Huaibin Yang commit 1ecd40f19ec16f6f5a8025ae49102b281fe016de Author: Kuogee Hsieh Date: Tue Sep 25 19:31:33 2012 -0700 msm_fb: display: empty pending queue during suspend Overlay_play() adds a pipe into pending queue and pan_display() will commit those pipes to hardware and empty queue. This patch will make sure queue is empty at suspend so that no unexpected pipes will be commited to hardware by pan_display() at resume. Otherwise, iommu page fault may happen. Change-Id: Iafdf469c6cdbf5d469c9dee114555a8d1adb9c66 Signed-off-by: Kuogee Hsieh commit a77eca6cee55531e81e21d83b474563f9c143e77 Author: Kuogee Hsieh Date: Thu Sep 13 13:22:04 2012 -0700 msm_fb: display: add pipe commit ioctl currently, pan display serves as pipe commit. However it may spend long time pending on cosole_lock() which cause flickering on HDMI. Add pipe commit ioctl to allow commit from overlay in addition to pan_display. CRs-fixed: 391564 Change-Id: I163b5d96f727b70b4d5693e9a414b59339818998 Signed-off-by: Kuogee Hsieh commit ee79b635fc78d5abe40e3918f2bf6f754f3516da Author: Adrian Salido-Moreno Date: Tue Sep 25 17:04:18 2012 -0700 msm: mdss: carve out memory for framebuffer Use carved out memory allocated exclusively for framebuffer instead of using up memory from ion pool. Change-Id: I4b248a21380a3ef737fe2fd8eed6de9747fe47c7 Signed-off-by: Adrian Salido-Moreno commit d7a09f0c134c61f3d3dd2239073c3363e4306858 Author: Adrian Salido-Moreno Date: Tue Oct 2 16:48:16 2012 -0700 msm: mdss: remove play_cnt reset in overlay set play_cnt is used to manage currently displayed buffer, this value is incremental and should be initialized only once for new pipe creation, but overlay set can be called after pipe creation to change params. Remove reset of play_cnt to avoid reset on subsequent overlay set calls. Change-Id: Idef90a6123c4e1a9e8b1ab963bf78330cdd912bf Signed-off-by: Adrian Salido-Moreno commit ac990ba5e32295c9efbffb56b7c659efa6cae6d0 Author: Adrian Salido-Moreno Date: Mon Oct 1 13:57:51 2012 -0700 msm: mdss: allow dynamic resolution change Modify initialization function to take changes in input paramaters including resolution and format instead of doing a one time initialization. Change-Id: I01c575fd1d957218296e658b3b4b8d72cd138614 Signed-off-by: Adrian Salido-Moreno commit 7b4b75a59b665c0d1b3aa14a41fd81f754d4f093 Author: Adrian Salido-Moreno Date: Mon Oct 1 18:25:22 2012 -0700 msm: mdss: use half of panel width when using dual pipe MDP layer mixer only supports up to 2048 width, if the panel resolution is greater than this dual mixer needs to be used. Setup each mixer width as half the panel width instead of allocating max width on left mixer and use left over for right mixer to have better load balancing. Change-Id: Ibc01591e2e6d5e5f98e81dfba766493abd9895a5 Signed-off-by: Adrian Salido-Moreno commit 6c6a597e45a2d7daafdfd2c63832cce638334d6f Author: Kuogee Hsieh Date: Mon Sep 24 10:51:13 2012 -0700 msm_fb: display: remove extra dmap irq disable Both irq enable and disable need to be called symmetrically. Remove an extra dmap irq disable call. Change-Id: Ic51003c50431ebe46a9fc540163cda77a1c91797 Signed-off-by: Kuogee Hsieh commit 6b453fc7adc6c02e0f23550c5703bf93f8f6bfea Author: Adrian Salido-Moreno Date: Fri Sep 28 15:22:37 2012 -0700 msm: mdss: disable framebuffer memory check when not allocated HDMI and WFD don't allocate any memory for framebuffer, in this case there is no need to check for available framebuffer memory. Change-Id: Id3fc6279e1b2a5d4b96d3b85e29ba6865a4dd38f Signed-off-by: Adrian Salido-Moreno commit 105ef65f2db0be51711a5d3fc293064da0a38e2b Author: Adrian Salido-Moreno Date: Mon Oct 1 18:26:05 2012 -0700 msm: mdss: fix height align for venus format Venus format expects luma height to be aligned to 32. Change-Id: I1ccd5ddb91d1067a68b576891ddf4d73360108ba Signed-off-by: Adrian Salido-Moreno commit c87b83203c2069c71a732e3164357b02649c12dd Author: Chandan Uddaraju Date: Fri Sep 28 18:48:15 2012 -0700 msm_fb: mdss: Fix dsi controller reset sequence during dsi initialization Move the dsi_sw_reset from panel ON sequence to controller initialization function. Enable clock lanes and disable controller before doing reset. Change-Id: I570615a931214021360070cd1cfea4ed3b6812d5 Signed-off-by: Chandan Uddaraju commit ed1430f0336a587a63729d2b698f9e23de46c95d Author: Aravind Venkateswaran Date: Wed Sep 12 17:00:27 2012 -0700 msm_fb: HDMI: Remove HDCP Kernelconfig Remove the kernel config parameter for HDCP since enabling or disabling HDCP will now be controlled using a corresponding module parameter. Change-Id: Iae23b8fa66ca75d99423547e77f850f3c86615ee Signed-off-by: Aravind Venkateswaran commit 16229f5a1ce7007eb44dc1d43482f85c03e07f57 Author: Aravind Venkateswaran Date: Fri Sep 7 16:08:10 2012 -0700 msm_fb: HDMI: Driver changes to support HDCP module parameter This change removes the need to use HDCP feature flags in the HDMI driver and adds the necessary support to configure HDCP feature based on a module parameter. Change-Id: Ie0eacc5b447230927cfdedfcb979c22d60e81981 Signed-off-by: Aravind Venkateswaran commit d8d660a6011c903fef1d9c1a58ea578e6a58e1ee Author: Aravind Venkateswaran Date: Tue Sep 11 18:10:33 2012 -0700 msm_fb: HDMI: Add module parameter to disable HDCP This change adds a module parameter that can be used to disable HDCP at runtime by specifying hdmi_msm.hdcp=0 on the fastboot command line. Change-Id: Ifad5da9fcb86fb4ed663a5ef2bb14fe4dafd241e Signed-off-by: Aravind Venkateswaran commit 51d631dd2b8a301828b4780f6496a6fe5490e454 Author: Mayank Chopra Date: Tue Sep 18 20:34:16 2012 +0530 msm_fb: display: Send vsync events using sysfs for MDP3 targets Replace sending of vsync timestamp using uevents with sysfs entry as uevent result in increase in power numbers due to broadcast in nature. Change-Id: I22cfbd68c8bcbe4a47e94074393f1cbf79920c58 Signed-off-by: Mayank Chopra Signed-off-by: Siddhartha Agrawal commit d473df4fba1417b4d7d429849af2a4243869e55a Author: Mayank Chopra Date: Fri Sep 7 00:37:24 2012 +0530 msm_fb: display: Send vsync events using sysfs for MDP4 targets Replace sending of vsync timestamp using uevents with sysfs entry as uevent result in increase in power numbers due to broadcast in nature. Also, for smart panel, wait4vsync is removed. Change-Id: I5219e85b837b8bab9d00a9f40c1048d2a2355194 Signed-off-by: Mayank Chopra Signed-off-by: Kuogee Hsieh Signed-off-by: Siddhartha Agrawal commit a8d45ced76c79333af546ad63ae31972aa00b109 Author: Ujwal Patel Date: Mon Sep 10 18:42:29 2012 -0700 msm: mdss: Enable hpd for HDMI Tx controller Enable hot-plug detect circuit of HDMI Tx controller to sense connect and disconnect events of HDMI cable. Change-Id: I4e5614d32f5c9885f23060d68ad5b6a72a045177 Signed-off-by: Ujwal Patel commit 4f56d21f84a2e2adea6e83b8c75501904feebf7c Author: Ujwal Patel Date: Tue Sep 18 15:17:07 2012 -0700 msm: mdss: Fix EDID read failures in HDMI Tx controller DDC data channel is used to read HDMI sink's EDID information. Fix the request length for this read transactions to prevent EDID read failures. Change-Id: I74b2ce344cdd08721a78641a7553c85927a96831 Signed-off-by: Ujwal Patel commit 1e88b6e0ecdb4485d21e94ad3e87c1caabdcde37 Author: Ujwal Patel Date: Mon Sep 10 15:54:25 2012 -0700 msm: mdss: HDMI Tx clock clean-up. Generalize and move HDMI Tx controller's clock access mechanism to mdss_io_util so that other mdss modules can reuse it. Also correct the name of iface clocks. Change-Id: If0ed2c4244a9a0fcdb819f63010555d968a0b036 Signed-off-by: Ujwal Patel commit 4e055b701f5600e391ed5d440b90fb1958924c49 Author: Ujwal Patel Date: Tue Sep 25 14:10:48 2012 -0700 msm: mdss: Debug enhancement for mdss modules Move debug log macros to mdss_io_util so that all mdss modules can use the same mechanism. Change-Id: I960fc394c60b74d694a81ad636b7055a224a2c6f Signed-off-by: Ujwal Patel commit 60a6b37db0caeb736291f0eccd99baa307d60a86 Author: Ujwal Patel Date: Fri Aug 31 18:20:45 2012 -0700 msm: mdss: Provide generic io access mechanism to all mdss modules Generalize and move HDMI Tx controller's io access mechanism to mdss_io_util so that other mdss modules can reuse it. Change-Id: I097af956706dcbf2e9fa1f6b5983a550a462fed1 Signed-off-by: Ujwal Patel commit e782ceab26e38590cd49a9bb273da1dbf1984ccd Author: Carl Vanderlip Date: Fri Sep 28 11:49:26 2012 -0700 video: msm: Enable mdp clock for histogram and histLUT Enable the mdp clock for histogram and histogram LUT to ensure that the clock remains enabled when they are being accessed. Change-Id: Ic744f2ee96b64442f23ba19aa1c38552c0dad83a Signed-off-by: Carl Vanderlip commit 61832135cad75ef082a905fedb30d835c85611b5 Author: Padmanabhan Komanduru Date: Thu Sep 13 17:41:46 2012 +0530 msm_fb: Return pan_display call on Vsync interrupt Till now, the pan_display call returns on DMA_P_DONE interrupt. For command mode panels, the DMA transfer starts only after the DMA engine receives a TE signal from the panel. Hence, return pan_display ioctl on vsync interrupt to improve performance. We still wait if the previous DMA transfer is not finished at the beginning of next pan_display. Change-Id: Ie92bc000a5842aa02a77a08b6bafdc8472bbebbd Signed-off-by: Padmanabhan Komanduru commit f6044334ee63fe9553f5cce8aa65c172c88e1175 Author: Kalyan Thota Date: Thu Sep 20 16:57:51 2012 +0530 msm_fb: configure LM1 and LM2 CSC coefficients with RGB2YUV for WFD 1) Initialise the LM1 and LM2 coefficients with RGB2YUV as WFD expects these coefficients to be programmed. 2) LM2 is available from MDP ver 4.3, fix conditions accordingly Change-Id: Ifad2be0fb5c3c96fa1515e114097a87d250fd62a Signed-off-by: Kalyan Thota commit ce328861aa1f4fa489e9abfc9d1e02b13af2ba47 Author: Carl Vanderlip Date: Tue Sep 25 18:52:00 2012 -0700 video: msm_fb: Ensure backlight is scaled atomically Ensure that when backlight scaling ratio or backlight level is being changed that the operation execute atomically. This prevents a backlight level change from being overwritten when it interrupts a backlight scale update. CRs-Fixed: 404017 Change-Id: I708513cfcec558c5d65f21f189dd52331fdf0f4f Signed-off-by: Carl Vanderlip commit 0f523bdb25b2af4f09e79eb58d3daee3775851d2 Author: Ken Zhang Date: Thu Aug 23 11:14:03 2012 -0400 msm: display: pp: histogram collection for mdss MSMFB_HISTOGRAM_START, MSMFB_HISTOGRAM_STOP and MSMFB_HISTOGRAM support Only read the histogram data when there is a new display commit Only generate the next histogram collection when there is a display commit Cache the histogram data in order to respond quickly Change-Id: I4532eca3bb8daa9e03ef78770c9e47d968c7c140 Signed-off-by: Ken Zhang commit bf5fb4c17c220a91160e48a2ca65e709c0a35511 Author: Ken Zhang Date: Sun Aug 19 14:41:01 2012 -0400 msm: display: pp: gamut mapping support Support gamut mapping via pp ioctl with logical display id. Allow changing processing order with pcc. Change-Id: Ia37afbe40b73c08fd8760bae84307889280368ce Signed-off-by: Ken Zhang commit 7fb85777173a3048765a52fc1ec4a3178c1fb2a9 Author: Ken Zhang Date: Sat Aug 18 14:51:33 2012 -0400 msm: display: pp: backend dithering support Dithering configuration from PP ioctl with logical display id for mdss. Change-Id: I4c8409b253dc1ab5625f342f45f61246d538691b Signed-off-by: Ken Zhang commit b9498c688a4a20d707233dda585a96b8e3681666 Author: Ken Zhang Date: Fri Aug 17 14:20:25 2012 -0400 msm: display: pp: enhance hist lut support Support histogram enhancement lut control for logical display for mdss. Change-Id: I915e1f1ca0ba1c53b8ce5b627a8d10cc15ebbf76 Signed-off-by: Ken Zhang commit 16e43d6c628bbfb14ba3a7e5024f60b9d216f9f4 Author: Ken Zhang Date: Wed Aug 22 17:14:19 2012 -0400 msm: display: postprocessing: argc lut support Area reduction gamma correction support for mdss. Support logical display id via PP ioctl for argc setting Change-Id: I8d1dedc016809f73de0605ea68e6a1bfda580648 Signed-off-by: Ken Zhang commit 824758e1c1d780014b4d404be9d7f85cb414fb46 Author: Ken Zhang Date: Wed Aug 15 11:02:21 2012 -0400 msm: display postprocessing:igc lut support Inverse gammam correction display support for 8974 Use logical display id via PP ioctl Change-Id: I9f1bec84a401f079690ecfd622a2e5f0f8307ff6 Signed-off-by: Ken Zhang commit ea6a09511a1d812f3b0f836dac9193900ccb9a3d Author: Ken Zhang Date: Tue Aug 14 15:11:39 2012 -0400 msm: display: pcc configuration Enable 8974 polynomial color correction support Cache the setting via logical display id, config hardware in the next display commit Change-Id: I11e3d2036c2ab8de881d394d53c6098932f810b5 Signed-off-by: Zhang Chang Ken commit ad6db3d66cb2f826f4f223898012d7d7aa6ca645 Author: Chandan Uddaraju Date: Wed Sep 26 17:57:34 2012 -0700 msm_fb: mdss: Remove spinlocks for set_rate and clk_enable APIs The clk_set_rate APIs should not be called in atomic context. clk_enable APIs doesn't need to be in atomic context. Add code to remove spinlocks for these clock APIs. Change-Id: If5e543135bda681ee8ddae35ab91288f535a9e9a Signed-off-by: Chandan Uddaraju commit aaacec6420069ba21992ddd39db991b3717d6436 Author: Chandan Uddaraju Date: Thu Sep 20 16:59:10 2012 -0700 msm_fb: Fix display corruption with continuous splash screen feature During boot up, we observe random lines on screen between the splash_screen image and the android animation. MDP clocks were turned off during bootup. Fix this issue by enabling the clocks when this feature is enabled. Add check to see that the video mode engine is not busy before turning off the dsi controller to avoid any underruns. CRs-Fixed: 399634 Change-Id: I8fdb50fa848362a548b8cdd53ee1817346b57716 Signed-off-by: Chandan Uddaraju commit b05e8b1ec779ab5cc94f0847a99baa4d97eb4e10 Author: Kuogee Hsieh Date: Tue Sep 25 13:16:05 2012 -0700 msm_fb: display: turn vsync irq off at suspend Turn off vsycn irq at suspend to prevent vsync irq firing before vsycn enabled ioctl called at resume. Change-Id: I2428cdeb5cf7008e50f6d8dabfad52416db2fff7 Signed-off-by: Kuogee Hsieh commit 911b4b702a63fbd241863966cad45909e40e4665 Author: Mitchel Humpherys Date: Wed Sep 12 14:42:50 2012 -0700 ion: change ion kernel map function to not take flags argument Buffer flags are going to be specified at allocation time rather than map time. This removes the flags argument from the ion kernel map function. Change-Id: I91589ca7b1ab142bb5ac8e6b0f4c06fa1305f23a Signed-off-by: Mitchel Humpherys commit 7d72bad55a0e03392d81eee77a9a8c9df6b73a9a Author: Hanumant Singh Date: Wed Aug 29 18:39:44 2012 -0700 ion: Port heap mask change to ion Heap mask field passes as argument at allocation time to specify ion heap. Change-Id: I8881dfc491dc0f8f70581ad97b35756a6a33dd6d Signed-off-by: Hanumant Singh Signed-off-by: Mitchel Humpherys commit 5e0fcdbf8b22bc9637413de9cd0592c159dd4e8f Author: Padmanabhan Komanduru Date: Wed Sep 12 11:10:26 2012 +0530 msm_fb: Make Vsync IOCTL during disable sequence as NO WAIT Change to make the vsync IOCTL no wait during the disable sequence. This is to increase the performance. Handle the synchronization of vsync interrupt using state variables in drivers from now. Change-Id: Ia5ec14493f233a95f21d01ea627200a6c278239f Signed-off-by: Padmanabhan Komanduru commit 57e2bed7fdf998d9dcb1a3bea98f43d75c7cf3a9 Author: Jeevan Shriram Date: Mon Sep 24 11:39:29 2012 +0530 msm_fb: display: Add support for vsync driven composition on 7x30 This patch will queue multiple surfaces and commit those surfaces into mdp at same instance so that surfaces will be blended and displayed at same time for 7x30. Hardware vsync event is delivered to the user space frame work via uevent. Both queue and commit are controlled by frame work and synchonized with vsync event. Therefore frame rate will match with vsync rate. Change-Id: I2acb83f871f16c2278dc10cb958580a2826efe70 Signed-off-by: Jeevan Shriram commit 3545573720822ce97ec37586f10fdf74a6d4f090 Author: Pradeep Jilagam Date: Mon Sep 24 22:07:47 2012 +0530 msm_fb : display : Block RGB downscale in MDP 4.0 and 4.1 Downscale is not allowed on RGB pipes in MDP 4.0 and 4.1. Hence, fail the OVERLAY_SET ioctl for such configurations. Change-Id: Ia18de77e78b84ec5f10a03fe9b48ef0821222e84 Signed-off-by: Pradeep Jilagam commit b54b6d4974f0a7c42e66502fca3644fe3ae406be Author: Ken Zhang Date: Mon Aug 13 14:49:52 2012 -0400 msm: display: csc configuration support via overlay Implement overlay pp csc configuration for mdss Reset the play cnt when MSMFB_OVERLAY_SET is called Change-Id: Ice2e3700a275c5375ee4939bd3484b7ee5def898 Signed-off-by: Ken Zhang commit 08065c0bd558140a26622f9bb15c8649a8333723 Author: Adrian Salido-Moreno Date: Fri Sep 21 15:48:31 2012 -0700 msm: mdss: implement early suspend api Use early suspend API for suspend/resume to allow display more room to turn panel off/on before system goes to suspend mode. Change-Id: I70b8b1055c30b940eda49ebad0db341259e903b4 Signed-off-by: Adrian Salido-Moreno commit e977b389d047b630be6178b6f2588dc339498b2d Author: Adrian Salido-Moreno Date: Fri Sep 21 16:28:16 2012 -0700 msm: mdss: cleanup suspend/resume logic Remove references to global variable by using driver data to access mdss global data. Change-Id: Icaedf0fffe22b6d375df8f87f555b415101c6628 Signed-off-by: Adrian Salido-Moreno commit 1121a7fab5548575f1a30388c5b1b0f5b773eb42 Author: Adrian Salido-Moreno Date: Mon Sep 17 18:52:56 2012 -0700 msm: mdss: fix vsync ctrl logic during suspend/resume Sometimes vsync ctrl ioctl can happen before panel is on after resume, in this case driver needs to remember state of vsync ctrl and apply after resume. Change-Id: Ia583bd9e3a858c5972623eae0512fa27da8452e1 Signed-off-by: Adrian Salido-Moreno commit 01b0d13ad1071385bb938ee69d268f799b7de6f5 Author: Adrian Salido-Moreno Date: Tue Sep 11 18:26:35 2012 -0700 msm: mdss: fix mdp suspend/resume sequence Free overlays used before panel off sequence to ensure source surface pipes are properly detached from layer mixer. Change-Id: I712bfc1961607e09dcb976e4888db1885de09871 Signed-off-by: Adrian Salido-Moreno commit 4a1fb9ce546b946a184601cbeb3a278dd351a0df Author: Chandan Uddaraju Date: Fri Aug 24 21:38:36 2012 -0700 msm_fb: mdss: Fix suspend/resume for panel driver Avoid disabling video mode while sending OFF commands. Add delay between the display reset line toggle mechanism and GPIO display enable API for proper reset of the panel. Modify the PHY regulator control configuration sequence for proper reset of the physical layer. Change-Id: I2c890d52d773faab6020267121ea4557a59bd108 Signed-off-by: Chandan Uddaraju commit 37e723cfad97be59d5a28e59220f9dcafe24ce32 Author: Ken Zhang Date: Wed Sep 5 15:43:02 2012 -0700 msm_fb: display: wake up system around vsync To avoid frame drops due to power collapse, wake up cpu right before vsync. Change-Id: I63385eb329ae5e74cbac5256823fd3a213e0a0e1 Signed-off-by: Ken Zhang commit 42f4dae926438b40ac3ba1a48f54c1fad31dc125 Author: Padmanabhan Komanduru Date: Tue Jun 26 22:31:06 2012 +0530 msm_fb: Reduce the display wake up time for NT35510 panel Reduce the display wake up time during resume by reducing the sleep values of the DCS commands during the panel initialization sequence for NT35510 panel. CRs-fixed: 392321 Change-Id: I6b55e48582a97adc451105802f5b2ca826767954 Signed-off-by: Padmanabhan Komanduru commit 7e73b56cb67779bc700938acbb226dd99d361882 Author: Kuogee Hsieh Date: Wed Sep 12 11:26:57 2012 -0700 msm_fb: display: free base layer pipe at adb stop Base layer pipe need to be freed at adb stop so that same pipe can be allocated at adb start. CRs-fixed: 390644 Change-Id: I948bb27687cfe1c96cc3b071b7bb9bb84b2c52c6 Signed-off-by: Kalyan Thota Signed-off-by: Kuogee Hsieh commit 5e5f3b4ff8a4a0d980e02fa38c2b70fec7095e79 Author: Carl Vanderlip Date: Mon Sep 10 09:40:44 2012 -0700 video: msm: Ensure idle state before enabling histogram Disable interrupt, set state flags to false, cancel histogram collection, and clear the workqueue before attempting to enable the histogram. This guarantees that this is the only configuration of the histogram running. Change-Id: I222932db40494724b3efdb2e5bea08a849095c1e Signed-off-by: Carl Vanderlip commit 2dd5234c094157bf77781b8646ac9ad114f819b0 Author: Carl Vanderlip Date: Thu Sep 6 12:03:29 2012 -0700 video: msm: Defer histogram reset to workqueue Currently, when an underrun occurs, a reset request is sent to the histogram hardware. This has been observed to cause a hang in the histogram collection cycle. The fix for this hang is to instead rely on the existing checks for histogram validity in the histgram read worker. When the underrun occurs, the histogram is invalidated, which in turn causes the histogram read worker to reset the histogram collection when it attempts to read its contents. Change-Id: I66d33ddedef76fdcb6c4a3d8095c0e8ca695e33d Signed-off-by: Carl Vanderlip commit 9218ac41cc42b55de227d7b967e15395feff89ca Author: Manoj Rao Date: Mon Sep 17 15:33:10 2012 -0700 msm_fb: MHL: add fwd declarations If MHL feature is enabled from kernel config compiler throws errors. This is due to the re-ordering of the function definition in some of the earlier patches. Need forward declarations of a few functions to fix compilation issues. Change-Id: I486b3d6efc33f6557b5ef301bd7037867bb8c562 Signed-off-by: Manoj Rao commit 1026832c51cbadeea9a717fa20fb42b6a7c5661f Author: Carl Vanderlip Date: Wed Aug 29 19:22:57 2012 -0700 video: msm: Dynamically toggle histogram interrupt Make histogram enable/disable functions also enable/disable the histogram "interrupt enabled" bit on the MDP enabled interrupts register. CRs-Fixed: 398556 Signed-off-by: Carl Vanderlip Change-Id: I56f811e88cf3fd44ae0a2df8a6e5de32ba9a0c1c commit bc79d49dacc9e416c7f9ea98fcff21eec3050fcc Author: Deva Ramasubramanian Date: Fri Sep 14 14:44:30 2012 -0700 msm: mdss: Return correct error value Return a proper value rather than 0 everytime. Change-Id: I0065a420c65e4800d114be4698618d66de89d105 Signed-off-by: Deva Ramasubramanian commit 8914c1ca05e90d80432c104a509eab129038de1c Author: Adrian Salido-Moreno Date: Wed Sep 12 17:32:21 2012 -0700 msm: mdss: increase bus scaling factor to improve performance Fix performance issues seen with different use cases such as HDMI and MDP composition by increasing bus scaling factor used. CRs-Fixed: 398503 Change-Id: I2391f81c0cba1fa7f5849ce55ec89762765d7575 Signed-off-by: Adrian Salido-Moreno commit ad3200279e62eff01fd1bb9136cc9c0d11e10380 Author: Ravishangar Kalyanam Date: Mon Jul 23 18:26:09 2012 -0700 msm: display: Add DSI clock control for MDP GDHS power collapse Enable DSI clock and regulator before enabling/disabling power collapse for MDP GDHS. Change-Id: I9effb5b4e9ca8033c51085260c8fb9f32c422dd3 Signed-off-by: Ravishangar Kalyanam Signed-off-by: Siddhartha Agrawal commit 6c7b2d322826aaf12b7682079cadb8ac9179fbce Author: Mitchel Humpherys Date: Thu Sep 6 10:33:12 2012 -0700 msm: display: include msm-specific ion header All msm_ion clients need to use instead of Change-Id: Id079277f1f5688f08c8dec7f20308315ab46a081 Signed-off-by: Mitchel Humpherys commit d635cad054f3860f8ca13a8cf79f3e46f8892ce6 Author: Pradeep Jilagam Date: Fri Aug 3 15:52:06 2012 +0530 msm_fb: display: Copy splash image to kernel memory The bootloader memory from which the splashscreen is shown gets reclaimed before frame update happens from framework. Hence, copy the splash image to a local buffer as soon as display is initialized. This will ensure proper continuous splashscreen functionality. CRs-Fixed: 378721 Change-Id: I55a7b97eeced56d2f108d34998d58966610c4305 Signed-off-by: Pradeep Jilagam commit 77ce0197185ba16c4cf6c2745065f339aa32ef46 Author: Ken Zhang Date: Fri Aug 10 11:27:19 2012 -0400 mdss: display: postprocessing: picture adjustment Support picture adjustment(hue, sat) for 8974 Use logical block id as input. Apply configuration at next display commit. Change-Id: I0e35e50aecdd346ec91373d0c304e21185f28502 Signed-off-by: Ken Zhang commit edd57ca52bd12fa42865557bc5cfcc70cbbb8e6f Author: Siddhartha Agrawal Date: Tue Sep 11 15:29:10 2012 -0700 msm_fb: display: Update mdp clocks based on perf patch MDP clock was not getting updated to the correct values causing underrun issues. Change-Id: I4902ede1a8dda7408384261ca352e1ca1057a69c Crs-Fixed: 395054, 395166 Signed-off-by: Siddhartha Agrawal commit 7c31ee7933fff437acfaa69cf443c81638a495de Author: Huaibin Yang Date: Tue Sep 4 17:20:36 2012 -0700 msm_fb: display: add wait after overlay kickoff MDP writeback overlay kick off needs to be a blocking call to avoid WFD tearing issues. Change-Id: I03ce16b1e11c458bc8602880f22f1aed536a2e5a Signed-off-by: Huaibin Yang commit a61ad91ac33d5ec756a39201ed4350f4af55f701 Author: Kuogee Hsieh Date: Thu Aug 30 16:21:32 2012 -0700 msm_fb: display: add blt condition check at video/lcdc off Blt mode may be enabled during system suspend. Need to make sure blt overlay done before turn off video/lcdc timig generator. Change-Id: Iad54ee544499213bb7c9cfe60d00919f819aacb1 Signed-off-by: Kuogee Hsieh commit 30e707acaba6cac235c86b84f9735ae1aa94b5cb Author: Ujwal Patel Date: Thu Sep 6 16:48:04 2012 -0700 msm: mdss: Move HDMI Tx controller's regulator get to probe Move HDMI Tx controller's regulator get to probe function in order to support deferred probe in case regulator in interest is not available or not successfully probed before HDMI Tx driver. Change-Id: If0a5cf97a86c39fcdf649997c18121cc500f08a8 Signed-off-by: Ujwal Patel commit 7bcecf0a6a6864accfa1318e33e85ad2cc23f535 Author: Mayank Chopra Date: Wed Aug 22 15:01:15 2012 +0530 msm_fb: display: Program source address registers correctly Scale filter FIR uses the adjacent pixels as part of the processing. Source address registers should be program such that they point to the first valid pixel so that non-ROI pixels are ignored. This is done by making source x,y offsets to zero and adding the computed offset to source address. CRs-Fixed: 380020 Change-Id: I998fdd46f39dc67f32c422ec209da59d1add2e95 Signed-off-by: Mayank Chopra commit f9bc16bf6dcb8beb7d5d6405ee5dc767e6decdff Author: Pradeep Jilagam Date: Tue Aug 21 15:15:13 2012 +0530 msm_fb : Add option to enable/disable mixer commit Adds support to enable or disable mixer commit during pipe staging operations. Depending on the current activity, this selection can be made. Change-Id: Ia2f5dbab58f73ef4de90abf7f278332d8d73df46 Signed-off-by: Pradeep Jilagam commit 8c13d2615b1c608f941137166efb649353cc0bdb Author: Padmanabhan Komanduru Date: Wed Jul 25 17:02:52 2012 +0530 msm_fb: Update backlight level on resume after first pan display Use shared workqueue to delay the update of backlight after a first valid frame is displayed on the panel. This avoids any transients being displayed during resume. CRs-fixed: 361002 Change-Id: Ia2c2e39aae62e9ddfebe3a26fb4dbc969d0892c2 Signed-off-by: Padmanabhan Komanduru commit c3c52ddda318fcf7e15bd0674c2ba1903fbfa49f Author: Chandan Uddaraju Date: Fri Aug 24 21:32:45 2012 -0700 msm_fb: mdss: DSI driver code clean-up Remove mmss_cc base variable. This is no more needed. Create new controller platform data. Move the needed variables as part of the controller pdata structure. Change-Id: Ic5c72911dbfe889e1f8ff6992d438b6631796507 Signed-off-by: Chandan Uddaraju commit 00baebf181e4dc29d128a2fd16422333b81a8e43 Author: Adrian Salido-Moreno Date: Fri Aug 3 10:23:20 2012 -0700 msm: mdss: display: Enable IOMMU for MDSS driver Implement all calls to iommu driver from MDSS driver to map all buffers to virtual address space instead of using physical addresses. Change-Id: Ia194bf53dd881e36c702bbe4c024b652ed34df13 Signed-off-by: Adrian Salido-Moreno commit 2fa3b134d43a6f9e47542fd25d288ed07205fa66 Author: Adrian Salido-Moreno Date: Wed Aug 15 16:02:25 2012 -0700 msm: mdss: expose panel frame rate to user space Some framebuffer clients expect panel frame rate within reserved[4] member of framebuffer info. Change-Id: Ie74950366372af7211ef1c743f26657e89cb7283 Signed-off-by: Adrian Salido-Moreno commit 5cf85c06bed6b7bb416093555d347d9eb221f58e Author: Ken Zhang Date: Thu Aug 23 19:32:52 2012 -0700 msm: display: fb blend setting via MSMFB_METADATA_SET ioctl MSMFB_METADATA_SET ioctl is added for the fb user to pass in additional infomation rather than using reserved fields. User can set pre-multiplied alpha for the frame buffer via this ioctl, overlay blend setting will take this into account. Change-Id: Ic2f6236d84691fb03174ec479874c6928489ea30 Signed-off-by: Ken Zhang commit cbd2a940d95056c51f6cef0a1641a716c8ed292e Author: Kuogee Hsieh Date: Wed Aug 29 10:46:31 2012 -0700 msm_fb: display: free iommu buffers for WFD Iommu buffers from overlay destinated for WFD (mixer2) are not freed after kickoff. This patch will free those iommu buffers. CRs-fixed: 394270 Change-Id: I6b58b5d1831e7c59c5107641b786730511803557 Signed-off-by: Kuogee Hsieh commit 1b6843a3a56e60e73305c66369f8ad806353e22d Author: Kinjal Bhavsar Date: Wed Aug 1 15:57:52 2012 -0700 msm_fb: display: Add timeout for waiting on update Content Adaptive BackLight userspace algo waits on UPDATE_NOTIFY to get the screen updates. When turning off CABL, this blocking ioctl causes the CABL threads to wait until next screen update, which may take indefinite time. Add timeout value to the wait_for_completion call, to make ioctl call blocking for at most timeout value. CRs-Fixed: 384026 Change-Id: I6715a36020c24ddd09823bd54d4321900429a6b9 Signed-off-by: Kinjal Bhavsar commit f947731692cb9480b53edfb6008a9ab2965fda2a Author: Nagamalleswararao Ganji Date: Fri Aug 31 03:08:52 2012 -0700 msm-fb: display: double the lvds pixel clock for dual lvds Lower MDP clock causing the underrun issues on dtv boards. To arrive at correct mdp clock pixel clock needs to be doubled for LVDS DUAL lane panel case Change-Id: I202f0d16896f88090a9f8407e067a31cc47eb4ea Signed-off-by: Nagamalleswararao Ganji commit 877932c6538689854e2b6a75ce24c8782fbe1fe0 Author: Padmanabhan Komanduru Date: Fri Sep 7 16:22:31 2012 +0530 msm_fb: Return ioctl on vsync interrupt disable Before the vsync interrupt gets disabled, initialize the completion structure and then disable the interrupt. This enables the ioctl to return successfully in all the cases. Change-Id: I6a7c233f818a773d00497502213d1ecf8fe9dc24 Signed-off-by: Padmanabhan Komanduru commit c5ac568e5050209ec2d2eb63995357cabfd43525 Author: Padmanabhan Komanduru Date: Thu Sep 6 19:12:40 2012 +0530 msm_fb: Enable MIPI video mode interface on 8x25 EVB/SKU5 Change to enable MIPI video mode on EVB/SKU5. Initialize the need_wait variable to zero to make sure that during suspend, we wait for MIPI_CMD_DONE interrupt only when the command mode engine is busy. Change-Id: I61a9132a9a9343d136ddc70ce76d8682f9ecf7bc Signed-off-by: Padmanabhan Komanduru commit eb868344503ed72b7a7a88913ab16250f934d9a2 Author: Ujwal Patel Date: Wed Aug 22 05:17:46 2012 -0700 msm: mdss: Add EDID support for HDMI Tx driver Extended Display Identification Data, EDID, provides support to read HDMI sink's various capabilities like resolutions supported, HDCP compliance status, Audio format supported etc. Add support for this in HDMI Tx driver. Change-Id: Id9367a2f64557c385082bbd528afc24b54b98514 Signed-off-by: Ujwal Patel commit e0a71b9705f4301c39e029f92c7e4c0ca3610f17 Author: Ujwal Patel Date: Mon Aug 13 17:25:10 2012 -0700 msm: mdss: Add DDC support for HDMI Tx driver Display Data Channel, DDC, is responsible for transmitting EDID and HDCP information between HDMI sink and HDMI Tx controller. Add support for this in HDMI Tx driver. Change-Id: I58d10c61277d36425d89a2270f0ad0495ffd3a1f Signed-off-by: Ujwal Patel commit 8bb5150587d79db7f60a5336f267666a7bf56bfd Author: Ujwal Patel Date: Wed Aug 22 05:14:17 2012 -0700 msm: mdss: Add power on/off support for HDMI TX driver Add support for HDMI panel power on and power off. Open and close of fb device associated with HDMI panel results in HDMI Tx's power on and power off respectively. Change-Id: I9becdffefe681ce104d631e798d196e23dae4995 Signed-off-by: Ujwal Patel commit 0b4ce9984ebbe740103568da1cc2db0d7648c4d9 Author: Ujwal Patel Date: Mon Aug 13 17:03:00 2012 -0700 msm: mdss: Add Hot Plug Detect support in HDMI TX driver Hot-plug-detect (HPD) circuitry is responsible for notifying HDMI sink's connect and disconnect events. Add support for this in HDMI Tx driver. Change-Id: I40fdc64007bffe063ce125ce2e819b06a49d0eb5 Signed-off-by: Ujwal Patel commit d49fe89aa7eb042947a64f1d5b5f12f54d2c033b Author: Huaibin Yang Date: Tue Sep 4 13:31:29 2012 -0700 msm_fb: display: fix division-by-zero bug Panel v_back_porch could be zero for virtual panels, so the check for zero is added to fix the bug. Change-Id: I6a29f3d8d771092bca2374cc9a1c11dd77ad569e Signed-off-by: Huaibin Yang commit 108090e77d90ff15da5ef94dd72b7aa6f18b5e94 Author: Padmanabhan Komanduru Date: Thu Sep 6 12:38:56 2012 +0530 msm_fb: Change refx100 value for NT35510 panel in command mode Change the refx100 value of NT35510 panel in command mode to bringup PVT command mode panel. Change-Id: I3e9a303a4f203bd7f2ca88f6cd2fe0b1134f8d65 Signed-off-by: Padmanabhan Komanduru commit d6770da3eb24a8d617145526a7f04398bf44b328 Author: Kuogee Hsieh Date: Wed Aug 8 19:35:57 2012 -0700 msm_fb: display: add support of mdp clocks controlled by vsync Mdp related clocks are controlled through vsync enable/disable ioctl from userspace frame work. Crs-fixed: 384482 Change-Id: I5999ad17955e0f862f64036a6390016ff3a6782f Signed-off-by: Kuogee Hsieh commit ffe9cf9b1f49bcd8b140cef21c4655d1b69bb1f9 Author: Kuogee Hsieh Date: Wed Aug 15 18:00:05 2012 -0700 msm_fb: display: add wait for overlay0 done Dcs command mode BLT involves both overlay0 done interrupt and dmap done interrupt. A transaction is start at kickoff and end with done interrupt. At some corner cases both overlay0 and dmap transaction need to be completed before kickoff of new transaction. Change-Id: I5a3cc6e8255acf2c61fc627d35f990182d226f63 Signed-off-by: Kuogee Hsieh commit ac37f42a6428b4a1a8bc964ea17902ea41772ba4 Author: Adrian Salido-Moreno Date: Fri Aug 3 10:23:20 2012 -0700 msm: mdss: improve mdp buffers management Currently buffers are unmapped as soon as it's queued to MDP, however the buffer still belongs to MDP until a new buffer is pushed. Change current buffer managment to track of buffers currently being displayed and properly unmap buffers after a new buffer is received. Change-Id: I6932191fc787f6f5b673edfb690ce1317e283587 Signed-off-by: Adrian Salido-Moreno commit f281368edca05e3171631b17c5767179bd0a77fc Author: Manoj Rao Date: Mon Aug 27 20:28:38 2012 -0700 msm_fb: MHL: Fix premature register access Until the information about the MHL feature through boot param percolates to the driver via probe we should refrain from accessing the registers or requesting irq. The init and probe functions are cleaned up with all the real initialization such as power, gpio and chip specific settings moving to probe functionality only if mhl is enabled from boot param. Change-Id: I68c0a2848493a7478f3046e439c42f8fb131f000 Signed-off-by: Manoj Rao commit e79dde6faab507c51994a8588bebd03dfc5fb57a Author: Pradeep Jilagam Date: Fri Aug 24 16:23:06 2012 +0530 msm_fb: display: Fix blend configuration for MDP4.1 MDP4.1 blend operation registers are not double buffered and take effect as soon as they are configured. Configuring these registers at any place other than between dma and vsync produce flickers as new blend values would get applied to previous mixer configurations. Configure blend operation registers just after dma is over, before vsync. Change-Id: I377c11222f7a0cd77e98e90edec6e2e1dc0c17ca Signed-off-by: Pradeep Jilagam commit e9d4bc826ca849b873f9e91bda68004aa7d78b25 Author: Huaibin Yang Date: Wed Aug 22 10:36:46 2012 -0700 msm_fb: display: add mdp clk rate calculation for low vbp For the panels that have low v_back_porch, if h/w FIR scaling is used, during vbp time, mdp clk should be fast enough to output a line from 4 input lines. MDP rate equation for very small scaling, e.g. 1 or 2 pixels' upscaling or downscaling cannot cover this case, where underruns are seen on those panels. Change-Id: I4f35f98c2c1bc4ef04dfee193427bd3ff674945d Signed-off-by: Huaibin Yang commit 5d3e219fd4e44d67fb122b99745e5e4d4637257e Author: Padmanabhan Komanduru Date: Fri Aug 24 17:43:31 2012 +0530 msm_fb: Keep LCDC timing generator enabled during boot up Keep the LCDC timing generator enabled during boot up on MDP 3.03 targets if continuous splash screen feature is enabled. Change-Id: I64276550f28e1f316c420f9cb158f7b8e938b8ea Signed-off-by: Padmanabhan Komanduru commit 5dcea9b4522d3bdc1a0fe38406881b264ce074b8 Author: Huaibin Yang Date: Tue Aug 28 15:28:12 2012 -0700 msm_fb: display: fix the underrun issue when playing interlaced videos Interlaced videos require higher mdp clk rate and the current code sets mdp clk to max and return. However mdp clk calculation may still give a result higher than max mdp clk, for this case the result is kept and used later to enable blt mode to avoid underrun. Change-Id: I185d0d15e5b79e94561e790e41713cdb405f8bf4 Signed-off-by: Huaibin Yang commit df6b645836bafcca027bd0820a477e86cf767823 Author: Ajay Singh Parmar Date: Mon Jul 30 20:12:34 2012 +0530 msm_fb: hdmi: Soft debouncing logic improvements Currently, HPD(Hot Plug Detection, a module used for detecting HDMI cable connection) soft debouncing logic implements around 1 sec mechanism to stabilize HPD event detection. In case of fast HPD connect/disconnect, it is missing a real HPD event. This change implements a new debouncing logic in driver which will make sure the first real HPD event is correctly processed and at the end of debouncing processing, if there is a change in HPD state, the changed state is also processed. This way we always process the change of HPD states. CRs-Fixed: 384513 Change-Id: I02d9814e4a55b7eec11a8e0d134c9ed9b5747422 Signed-off-by: Ajay Singh Parmar Signed-off-by: Aravind Venkateswaran commit 26d04f92047ce213301596f167d84fbc05019f7b Author: Ujwal Patel Date: Sun Aug 26 00:57:04 2012 -0700 msm: mdss: Correct HDMI interface polarity for different resolutions. For HDMI, hsync and vsync polarity for resolution height greater than or equal to 720 lines is active high. And for resolution height less than 720 lines is active low. Program the these settings correctly for mdp's hdmi interface. Change-Id: I1a8889662f55676c13dfa8b7172bf7bcf7351cf5 Signed-off-by: Ujwal Patel commit c678e139570f7c1c4560c19f284926b6149e7bbf Author: Mayank Chopra Date: Sat Mar 3 06:51:20 2012 +0530 msm_fb: display: Add pseudo-planar 422 H1V2 support in the MDP4 Rotator outputs pseudo-planar 422 H1V2 for interleaved inputs on 90 degree rotation. Add changes to support MDP_Y_CRCB_H1V2 in MDP4. CRs-Fixed: 371303 Change-Id: I8083bf44f9e2addf9e8732268147c1c3f6c0e2af Signed-off-by: Mayank Chopra commit 3c34bf24b6ba56d4a2633043d8be0c84d0f449f8 Author: Padmanabhan Komanduru Date: Sat Aug 25 18:07:27 2012 +0530 msm_fb: Handle vsync interrupt properly on MDP 3.03 targets Handle enabling/disabling the vsync interrupt and mdp clock enabling/disabling in a better way on MDP 3.03 targets. This will avoid target crashes due to unclocked register access. CRs-fixed: 388751 Change-Id: I5c4a409772464ce7d06869374dcba5ad7e335955 Signed-off-by: Padmanabhan Komanduru commit 330c0bf5f090f05395f0ae64994a6273853aa9e6 Author: Adrian Salido-Moreno Date: Wed Aug 22 14:15:33 2012 -0700 msm: mdss: add color format for venus core Venus output format expects luma and chroma components to be aligned to 32 bytes, add new color format to support this type of input. Change-Id: I1fc9a61a0c8cfa8244460105fdab02d019d31556 Signed-off-by: Adrian Salido-Moreno commit 248948310712bf710ba097a1d1ef8c840f17169f Author: Adrian Salido-Moreno Date: Wed Aug 22 19:34:43 2012 -0700 msm: mdss: implement vsync ctrl and events Allow users to enable vsync events to be sent as uevents to userspace applications. This allows applications to listen for and align composition to hardware vsync. Change-Id: Ice480659f8c2adda3b5fe3f2d5bcfb9bf779933c Signed-off-by: Adrian Salido-Moreno commit 7e1ec9ab4a865e57372d3536991770f1773af6fb Author: Adrian Salido-Moreno Date: Fri Aug 24 15:53:35 2012 -0700 msm: mdss: request bus bandwidth before panel on Panel on sequence requires access to bus, make sure bus clock is enabled before panel on by requesting bandwidth for panel commands. Change-Id: I2f92e81b20dba7875a8b1160d14e8fa1895c8f15 Signed-off-by: Adrian Salido-Moreno commit c40f9f9bc1e83ce521759f03b6fd01d9699cd39f Author: Kalyan Thota Date: Mon Aug 13 17:33:26 2012 +0530 msm_fb: Retain CSC values across suspend/resume sequence CSC values pertaining to various H/W blocks are stored in a global structure and will be re-applied during resume sequence. CRs-Fixed: 376159 Change-Id: Ieb151185efd106041e28feedf4fa271ae4ba2666 Signed-off-by: Kalyan Thota commit 9ed0ef8c7d126938c453aa52c7b69ac869613cc6 Author: Ujwal Patel Date: Wed Aug 22 05:12:03 2012 -0700 msm: mdss: Add support for HDMI Tx driver This patch adds the HDMI Tx driver in mdss domain. It uses device tree framework to get the platform data and then registers this device as dtv panel to mdss frame buffer domain. Change-Id: I55534919bacea5b044c1da5d44dda8db496e1528 Signed-off-by: Ujwal Patel commit 907b7e097f61fb5dfeacd23dfddb75b92737b1b2 Author: Manoj Rao Date: Wed Aug 8 18:47:12 2012 -0700 msm_fb: MHL: MSC cmd schedule to prevent overload MSC commands to be sent over the CBUS line need to be scheduled appropriately from the ISR. Reduce delay in any processing within the ISR. Schedule each command over a queue and handle them with a worker thread. Change-Id: I6cbde8ce9e4f8c69b7f0a40bcf12c5d3930d0b8b Signed-off-by: Manoj Rao commit f7110b8272c8b46c732f0cb9c9290ca9e7f688c3 Author: Manoj Rao Date: Sun Jul 29 22:29:02 2012 -0700 msm_fb: MHL: MSC, RCP/RAP feature implementation MHL implementation of handling CBUS interrupts to enable and handle MSC translation control packets. This change also includes implementation of RCP/RAP protocols with place holders in MHL driver. Change-Id: Icfc31ee1cf71a57cb9b3733d068ea4478b6c4e90 Signed-off-by: Manoj Rao Signed-off-by: Abhishek Kharbanda commit 83fba4a6a627923fb358fd445a96df5cf9eacbe6 Author: Kuogee Hsieh Date: Thu Aug 16 17:02:02 2012 -0700 msm_fb: display: add mutex on overlay_play to fix iommu page fault An iommu page fault may heppen When a pipe_commit is executed in between of frame dropped and pipe_queue during overlay play. An mutex is necessary to mutual exclusive between pipe_commit and overlay_play. Change-Id: I736e821c6c648a6ebd435303a1906a40e9b75791 Signed-off-by: Kuogee Hsieh commit 79e294bf767b12470d08b4300b286403cb40aaa9 Author: Adrian Salido-Moreno Date: Thu Aug 23 19:26:56 2012 -0700 msm: mdss: fix hang when down scaling video to more than half its size When down scaling video more than twice, PCMN filter scaling should be enabled for all components to avoid MDP errors which lead to hang or underrun on screen. Change-Id: I237bc3a16e4916c9270382f55ecae21b46743a5b Signed-off-by: Adrian Salido-Moreno commit e5612f210482d39d41966ebe003bc924f079db2f Author: Ajay Singh Parmar Date: Mon Aug 27 11:07:32 2012 +0530 msm_fb: hdmi: Correct checksum value This change writes the checksum value to registers after doing all the calculations so that the correct checksum value is transmitted. CRs-Fixed: 388272 Change-Id: Ia0543e458d5a11b148bd29e0d57ae355a051b2a9 Signed-off-by: Ajay Singh Parmar commit bef3d659b9f7538c4a208fe4b29f93d1a9795f76 Author: Kuogee Hsieh Date: Sun Aug 12 09:17:08 2012 -0700 msm_fb: display: alloc/free writeback buffer done at do_blt() To avoid double freeing writeback at end of blt mode, let both alloc and free writeback buffer done at do_blt(). Change-Id: Ida5d24589c19be8f6f655eca6add00badca356b2 Signed-off-by: Kuogee Hsieh Signed-off-by: Siddhartha Agrawal commit 580e37bbcb2334315cb9535cd4d1e30147f1142f Author: Aravind Venkateswaran Date: Thu Aug 2 17:38:12 2012 -0700 msm_fb: HDMI: HDCP: Start HDCP authentication as a work item HDCP authentication should be kicked off as a scheduled work item so as to ensure that MDP is already configured and frames are being transmitted over the HDMI channel prior to the start of the HDCP authentication procedure. Change-Id: I27cab44babfc24d91a318b0641674f85910cc33f Signed-off-by: Aravind Venkateswaran commit 73c7b2f7e9b25a3173aa00a5ea3d9d73484a5cf4 Author: Aravind Venkateswaran Date: Mon Aug 20 14:49:28 2012 -0700 msm_fb: HDMI: Driver changes to support MHL boot param Add necessary driver changes to support enabling MHL using a boot parameter. The MHL driver will now only be used if it is enabled using the boot parameter. If enabled, the default video resolution and available EDID modes will be set accordingly. Change-Id: I9c07a4bdd07ce1d9120296efb143e987390fa0a2 Signed-off-by: Aravind Venkateswaran commit ea0dcd3f4ad4fd3142bf081795c17d05c42957a7 Author: Adrian Salido-Moreno Date: Mon Aug 20 22:21:50 2012 -0700 msm: mdss: refactor overlay parameters validation Some checks done on parameters don't apply for rotation only mode where rotation is not limited by the bounds of panel resolution. Update overlay checks to perform correct validation depending on request type. Change-Id: Ic0cf9863231300f7190dd118b78fa753f77f217f Signed-off-by: Adrian Salido-Moreno commit 9d2c48e228631fefef2e5a2d9406447358d910f9 Author: Ujwal Patel Date: Fri Aug 10 22:53:40 2012 -0700 msm: mdss: Add support to make use of interrupt data pointer in an isr Add support to make use of interrupt data pointer during an isr such that mdss panel devices retrieve and use their private data to service an interrupt rather than using global variables. Change-Id: I51a6b1c2814a23b3297556e914ce9601ef266533 Signed-off-by: Ujwal Patel commit f502022c101dc1c6d6af35d112be76a88c874a3f Author: Adrian Salido-Moreno Date: Fri Jul 6 18:20:25 2012 -0700 msm: mdss: fix null dereference when using hardware cursor Null dereference kernel panic is seen when using hardware cursor because buffer for cursor is not allocated before using hardware cursor API. Allocate buffer once when API is first called to ensure buffer is available to hold cursor image. Change-Id: I2250c4dd93e54fa4e7122c2465fbaf1deef0fa1e Signed-off-by: Adrian Salido-Moreno commit 15177f038fc05e5de18c437fa8dce63327b42d17 Author: Kuogee Hsieh Date: Tue Aug 14 09:16:37 2012 -0700 msm_fb: display: fix mdp crash during overlay unset Check real_pipe address before refer to it. Change-Id: I2f8c6fa6f8e657801dc676f7d9887e7eb0f10e73 Signed-off-by: Kuogee Hsieh commit 9bfdbf0473204b0267dc86ac4b8cc351194c3ee2 Author: Chandan Uddaraju Date: Mon Aug 13 23:31:30 2012 -0700 msm_fb: mdss: Add DSI physical layer settings Add support for dsi clocks. Add support for DSI PLL configurations. Add strength, regulator and control settings for the DSI physical layer. Change-Id: I04a0eec869e40b4813cf5187e8eeef63ae2f5a1f Signed-off-by: Chandan Uddaraju commit 68b9675c9c5d889e3fcc550fa39fd23ea960ceb0 Author: Chandan Uddaraju Date: Mon Aug 13 23:23:11 2012 -0700 msm_fb: mdss: Add support for Backlight control and panel gpios Add code to support the WLED client interface to control backlight levels using led_trigger mechanism. Add support for msm gpio that maps to the lcd_enable line for the panel. Add support for pmic gpio that is mapped to the display reset line. Change-Id: Ie89692f1c0a38d7878271d4a91122d61fbba8c1b Signed-off-by: Chandan Uddaraju commit 90e71d1da087b5690eee35e5e88d8faa689c5f8e Author: Chandan Uddaraju Date: Mon Aug 13 22:57:11 2012 -0700 msm_fb: mdss: Add support for DSI specific regulators Add ldo2, ldo12 and ldo22 regulator support in dsi driver. Change-Id: Ia8e9907e87a293588688e7a47c74fecf155382af Signed-off-by: Chandan Uddaraju commit d7784e051a508a667a13d431b7d834725cef0379 Author: Siddhartha Agrawal Date: Tue Aug 21 19:16:27 2012 -0700 msm_fb: display: Removing clk_set_rate in atomic context clk_set_rate was getting called in an atomic context. This change is needed to comply with Phase 3 clock API's. Change-Id: If7fa9d624b07789803177da55e6c84c3686a2bde Signed-off-by: Siddhartha Agrawal commit 9cbd41158a2aabc9bc675fd8473bc1ed64251e82 Author: Kuogee Hsieh Date: Sat Aug 4 17:29:51 2012 -0700 msm_fb: display: add dcs command list for dsi command mode DSI dcs commands and mdp pixel stream share same dsi link. Add dcs command list to serialize sending dcs command and mdp pixel stream to avoid contention which may cause dsi controller to stall. Change-Id: Ie0e687f45be479d2137eb7b56b8d32040fba2044 Signed-off-by: Kuogee Hsieh commit 076901a58037d533840ce6b59c33796a96c2d56f Author: Kuogee Hsieh Date: Fri Aug 10 14:31:37 2012 -0700 msm_fb: display: fix page fault during supend/resume There has VG1 pipe commit (pan display) happen after system suspended. This left VG1 still staged up at mdp mixer. Once timing generator is enabled at resume, VG1 pipe start fetching contents from address 0 since VG1 has not yet be configured. This cause page fault. This patch has sanity check at system suspend to make sure no any pipe stage up at mixer after suspend. Change-Id: Idcf974ceb4afe2a3ec55b9603b700fa497f84045 Signed-off-by: Kuogee Hsieh commit d1fff85a0074e6caa8e6136f18644670d76d8f06 Author: Adrian Salido-Moreno Date: Thu Aug 16 20:57:38 2012 -0700 msm: mdss: fix MDP hang when using 2 or more layers Hang is seen when 2 or more overlapping layers are used in MDP, this is caused by problem with VBIF dynamic clock gating. Bypass VBIF dynamic clock gating and force clocks on to avoid MDP hang. Change-Id: I369d036aa059f79c48f3b2feec8ca2b0f49dd301 Signed-off-by: Adrian Salido-Moreno commit 452289427cbf054e7830770333f663ec866ca61d Author: Adrian Salido-Moreno Date: Mon Aug 13 16:19:18 2012 -0700 msm: mdss: add perf settings during hardware initialization Add MDSS initialization sequence, tuning for optimal performance. Change-Id: Icd44abf2707d74bbf29a8d095184067ae3a420d1 Signed-off-by: Adrian Salido-Moreno commit 21c74c4c8bda9a1d62c052f6b93355de6ce935fa Author: Adrian Salido-Moreno Date: Tue Aug 21 21:04:20 2012 -0700 msm: mdss: refactor mdp driver probe Remove references to global variables, remove untested support for board file in favor of device tree. Change-Id: If97536116f5b4ea64ade5938d713572c10415bfe Signed-off-by: Adrian Salido-Moreno commit 963bdc732baffeb24acc29d6e7e96460bc12ffdc Author: Adrian Salido-Moreno Date: Thu Aug 16 20:56:24 2012 -0700 msm: mdss: fix irq getting disabled when running concurrent displays Add check to make sure there are no other active interrupts before disabling MDP IRQ to avoid disable of interrupts. Change-Id: Ic2bb9398dfa67d2b210f988de6648d49fd8336ac Signed-off-by: Adrian Salido-Moreno commit d559ef1c0cfd13d3bef877692babab65a278bba1 Author: Adrian Salido-Moreno Date: Thu Jul 12 20:16:14 2012 -0700 msm: mdss: refactor mdss color formats Add missing color formats and reorganize color formats to have better code reuse and make it easy to add new formats if required. Change-Id: Ic7c6bb6f35a9c282d9ef99bd5e1d18b0b8033971 Signed-off-by: Adrian Salido-Moreno commit 114c07229fc6f166e0e14d6f6f5e601e192be8f6 Author: Adrian Salido-Moreno Date: Wed Aug 15 15:47:06 2012 -0700 msm: mdss: use framebuffer line length as base layer stride Adreno graphics core expects framebuffer to be aligned to 32 bytes, this alignment is observed in framebuffer and needs to be used for base layer. If not followed stride corruption can be seen for frames rendered by Adreno GPU. Change-Id: Iea5e729dc4e4613bd7270d7bcf616cff6377109a Signed-off-by: Adrian Salido-Moreno commit ae341d162288d796e0d205897df8d010e059c8d6 Author: Adrian Salido-Moreno Date: Mon Aug 6 11:22:46 2012 -0700 msm: mdss: fix suspend coming to MDP before panel drivers If suspend event is received by MDP before panels, MDP needs to ensure other panels are off before turning MDP clocks off. Remove handlers from framebuffer driver and handle all suspend logic within MDP driver to handle this scenario. Change-Id: Idcda2dd29b28a9993edca78b7e0778985e44b664 Signed-off-by: Adrian Salido-Moreno commit 05bb0b78d6eb80dfe1339f54fa24a4cec7529353 Author: Adrian Salido-Moreno Date: Fri Jun 8 18:12:43 2012 -0700 msm: mdss: improve clock and bus scaling logic Current clock logic only considers panel pixel clock to calculate mdp clock speed, MDP clock speed should also consider other factors such as surface scaling. Bus scaling should also consider surface scaling factor. Update logic to consider these new factors and perform these performance updates together. Change-Id: If274a7f40f496e1a730e1d0e8d7c35fa4384a832 Signed-off-by: Adrian Salido-Moreno commit a5a987a43f8a24592e0dcdd387dd5ae668f03410 Author: Adrian Salido-Moreno Date: Mon Aug 13 16:46:01 2012 -0700 msm: mdss: allocate framebuffer memory from ion pool When panel size is increased dma_alloc_coherent is not able to find a chunk of contiguous memory big enough to hold framebuffer, this causes framebuffer initialization to fail. Allocate buffer from ion pool which has reserved contiguous memory at earlier stage. Change-Id: Ibf7e3f7fc2c7ad991d69c106bbb6a9dd4c7f0e79 Signed-off-by: Adrian Salido-Moreno commit 67ddb9b38b1793c297ff431ef9f650f355c4abf2 Author: Carl Vanderlip Date: Tue Aug 14 19:00:22 2012 -0700 video: msm: Move histogram disable to before panel off Histogram expects the display to be on while running, thus moving its disable call to before disabling the panel timing generator ensures this assertion. Change-Id: I308b3e0c24f0111fb8549d0a0ae025910d649b75 Signed-off-by: Carl Vanderlip commit 41b206d0792724c3ee2e1d881dcaf6025cc200a8 Author: Huaibin Yang Date: Fri Aug 3 15:25:44 2012 -0700 msm_fb: display: commit mdp baselayer pipe When in resume or boot time, baselayer pipes need to be committed for mdp to play, otherwize underruns and blue screens are seen. The previous pipe stage up func has this commit which is removed now, so the commit calls have to be added for the cases where base pipe is initialized. Change-Id: I63a7d0ac3fb078b3d7f604eb646a0430326a478c Signed-off-by: Huaibin Yang Signed-off-by: Siddhartha Agrawal commit 496f928dd8cdd2b1b554c379d9336e2e902e0540 Author: Siddhartha Agrawal Date: Wed Aug 15 17:41:34 2012 -0700 msm_fb: display: change implementation of updating mdp_clk and blt mode Currently mdp clk and bw requests are predefined in a 4-entry table passed from the board file, and the logic to decide which level to use is mainly based on source resolution. This patch is intended to address several issues with this approach. One major issue is clk and bandwidth depends on seperate things, and need to be considered seperately. e.g. with mdp composition of multiple pipes, bw request may be high but clk requirement may still be low. The current approach that binds these two things together causes inefficiency of power. Another major issue is that there is no logic to calculate mdp clk requirement of a single pipe based upon panel clk and downscale parameters. Further the worst case of mdp clk should be determined by all pipe usage. Without proper logic, many underrun have been experienced, and blt mode may not be enalbed properly. Also mdp_clk or blt mode update must be on right timing especially between these two pathes: overlay play and pan display. In the situations of performance from high to low or from low to high clk and blt must be handled properly to avoid underruns. In a summary, to support many different panels and targets and complicated mdp pipe usage(mdp composition), mdp driver related to clk and bw needs to be implemented differently. This patch is to seperate clk and bw, and maily to deal with mdp clk and blt. Later increasing granuity of bw will be added. Change-Id: I678fbf86d6997ed7b602ce81cf2e0fff6164d129 Signed-off-by: Siddhartha Agrawal commit db0fb308df4830ce3586618c62e77fc157bb9e4d Author: Siddhartha Agrawal Date: Wed Aug 15 10:25:22 2012 -0700 msm_fb: display: Set timing generator after register flush Timing generator was getting started before the register flush. Stale values were sometimes causing IOMMU page faults on bootup. Signed-off-by: Siddhartha Agrawal Change-Id: Ia671c3603e383af94197a23a8e5e5f32274a9978 commit 36898359d3e8c21b8fa45ce24d3fe472a3813d4b Author: Adrian Salido-Moreno Date: Sat Aug 11 17:33:04 2012 -0700 msm: mdss: fix incorrect programming of timing generator setting Fix typo in code which is causing incorrect setting of vertical front porch on timing generator settings and incorrect output to panel. Change-Id: I4de61209443fcb284b7d4064a2039b5f546935d1 Signed-off-by: Adrian Salido-Moreno commit 34e216d7db0466fef4b9114ec18cf684275607a3 Author: Lei Zhou Date: Wed Jul 25 12:52:13 2012 -0400 msm_fb: display: Correct LVDS bitmap setting In case ASIC 1.1 is used on 8064 platform, LVDS bit mapping misalignment is fixed and no remapping is needed. LVDS bit mapping should comply with VESA format to get correct panel display. Data line #3's bit mapping should be coded in this sequence: DE + VS + HS + .... Change the original codes to go with this sequence. Change-Id: Iaebcfcea9c52207e16bac54ec37dc63e97286ff4 Signed-off-by: Lei Zhou commit 8f0326e19752f9b2b083a433621d3581f4e9a9da Author: Huaibin Yang Date: Fri Aug 3 16:00:03 2012 -0700 msm_fb: display: add dmap waiting before turn off timing generator Wait for dmap done to turn off TG to avoid underruns before base pipe setup and after constant splash during boot time. Change-Id: I64bc3935d996af1d2d54db4c11319301ea454ced Signed-off-by: Huaibin Yang commit 00c9a911ba43e3ddb4ea6ea1c843dc7101b3b1ab Author: Kuogee Hsieh Date: Sat Aug 4 17:35:16 2012 -0700 msm_fb: display: add stage commit before kickoff to WFD Since stage commit had been splited out of stage up fucnction, it needed to be called to stage pipes into mixer befroe kickoff mixer. Add this function into overlay writeback for WFD. Change-Id: I11e4486d92b89a15e58531033d474b3137b5935a Signed-off-by: Kuogee Hsieh commit 2a811f2a333ca0507eb98c35831af463f43fb011 Author: Chandan Uddaraju Date: Tue Jul 17 16:54:28 2012 -0700 msm_fb: Display: Fix Dithering issue for rgb565 format Using RGB888 as source format and rgb565 as destination pixel format, will cause image corruption on the display. Fix this issue by setting the destination format as RGB888 in MDP and DSI controller pixel format as RGB565 for DSI specific panels. CRs-Fixed: 377484 Change-Id: If58976ee9cd4825efb39437170e54796fa2213e0 Signed-off-by: Chandan Uddaraju commit 3c5ae1f883a8b6a7812d936c5f7e5bb4d0d3142b Author: Mayank Chopra Date: Mon Aug 6 19:43:42 2012 +0530 msm_fb: display: Update mdp clock counter for unsuccessful probes If a panel probe does not succeed, call mdp_clk_ctrl to maintain mdp_clk_cnt counter else mismatch in counter results in mdp clock to never go off in cases like suspend-resume. CRs-Fixed: 385560 Change-Id: I4ca54b051af98e823dc7f3ff7b9bcb960532c7e8 Signed-off-by: Mayank Chopra commit a28d1bb434e8505630fc5d03383a0ed6d4565885 Author: Kuogee Hsieh Date: Sun Jul 29 08:56:58 2012 -0700 msm_fb: display: Add BLT support to dsi command mode panel At run time, mdp BLT (writeback) mode is enabled and disabled base on performance level to avoid mdp underrun. Move BLT enabled/disabled logic to pan display so that enabled/disable is done per commit instead of per queue. Since all panels are shared same logic, dsi video mode and lcdc panel BLT logic have been changed accordingly. Change-Id: I6e04bf0f7bf1c13634e19b18d8ac4368affbc4d8 Signed-off-by: Kuogee Hsieh commit 1c15029f8551ca8f5ffa57973c4eabc471177333 Author: Kuogee Hsieh Date: Wed Aug 1 18:19:11 2012 -0700 msm_fb: display: retrieve correct base layer pipe Base layer pipe is cloned and cached at satge array. Retrive the real base layer pipe before used it. Change-Id: I6fc606559684156348a57b500083ed4089fc71b5 Signed-off-by: Kuogee Hsieh commit df5e3279961b1f43a38ba50f787d785a81ed1e36 Author: Kuogee Hsieh Date: Fri Aug 3 13:47:04 2012 -0700 msm_fb: display: free dtv iommu buffer Free iommu buffer after pipe is committed to hardware. Change-Id: I00506d6fd55d99fec7921c02953fd755a7536d3e Signed-off-by: Kuogee Hsieh commit 1bb4edf9242b0397975636a4442318713a53b5e6 Author: Pravin Tamkhane Date: Tue Jul 24 13:34:23 2012 -0700 video: msm_fb: Increase display timeout to 2 seconds One second time out for no frame update, as in current implementation, does not allow CABL to reach minimum backlight level possible because histograms dont get generated after one second. So increase time out period to two seconds which seem to be sufficient for complete black to complete white and vice versa transitions. CRs-Fixed: 370804 Change-Id: I0712924d669abcb820654cd6ca5f7da37bed57e6 Signed-off-by: Pravin Tamkhane Signed-off-by: Carl Vanderlip commit 5d7e5b30a98110dd138fddee58bc2a4f3ffdc715 Author: Pradeep Jilagam Date: Thu Aug 9 12:23:53 2012 +0530 msm_fb: Allow MDP hardware init for continuous splashscreen MDP hw init is getting avoided for MDP3.x targets to support continuous splashscreen. This avoids complete initialization of MDP and hence usecases are failing. This change allows the hw init. Change-Id: Ib0304b54bda4a62a20716bde85fe94b2dcfe6824 Signed-off-by: Pradeep Jilagam commit 5cb07af87572d44d74a2586dfffd1ee537f64941 Author: Huaibin Yang Date: Wed Aug 8 16:52:29 2012 -0700 msm_fb: display: clean pipe free or unlock calls A few places have unnecessary mutex unlock calls, and iommu pipe free depends on pipe parameters so move it before pipe is zeroed. Change-Id: I7ef39c66be611907b1b0c38675b15f8bc919d0c0 Signed-off-by: Huaibin Yang commit b50f747dee6db1d9413fe46cba3d7c42263b21b2 Author: Huaibin Yang Date: Sat Aug 4 17:04:18 2012 -0700 msm_fb: display: fix fake iommu buffer drop During pipe free, some content of pipe is backed up and then after pipe is zeroed out, the content get restored, in between there should be no actions to change the content since any change will be wiped out by the restore. Change-Id: Ia6da0162d1f9b614682e1fc36edab1db003b42ab Signed-off-by: Huaibin Yang commit 4a652002fecbd5d984d01fbe2f32515f1a98ba91 Author: Kuogee Hsieh Date: Wed Aug 1 17:38:07 2012 -0700 msm_fb: display: clear correct pending isr Clear correct pending isr during irq enable/disable to avoid unexpected side effects Change-Id: I5e7afc778cb8d5feda40f359ff2aae6493dc7cd2 Signed-off-by: Kuogee Hsieh commit 45301d3beb046201b8d4a54a2de274dabf1ebc46 Author: Kuogee Hsieh Date: Thu Aug 2 13:27:49 2012 -0700 msm_fb: display: fix iommu leaking Fixed iommu map buffer dropped after overlay unset by saving origianl iommu list before zero out overlay pipe structure. Change-Id: I498dd4cf62e93f4571883fe20a0298e9fad4ccab Signed-off-by: Kuogee Hsieh commit 8e2b559d1a1694e10bb2aa47826db24a8baceda6 Author: Ajay Singh Parmar Date: Tue Aug 7 13:23:23 2012 +0530 msm_fb: hdmi: Give proper buffer size Need to give proper buffer size for snprintf function calls. CRs-Fixed: 378343 Change-Id: Ia4df74c9871b26255572bb3ba226317c3076b5b6 Signed-off-by: Ajay Singh Parmar commit f3b0c231a85ceef488440ab02fba9b15e468faa0 Author: Padmanabhan Komanduru Date: Fri Jul 27 20:46:06 2012 +0530 msm_fb: Add support for Vsync driven composition on MDP 3.03 targets Add support for vsync notification to user space using user events. This is to trigger frame composition based on Vsync. Change-Id: Ie94edfcdb5e540dd2f9a4a5df4bc3b7c4eb9041c Signed-off-by: Padmanabhan Komanduru Signed-off-by: Jeevan Shriram commit c58fcce723e54466b85981bafe7179b717ff2371 Author: Chandan Uddaraju Date: Mon Apr 23 20:39:17 2012 -0700 msm_fb: MDSS: Add DSI driver support for MDSS Add the dsi driver implementation for DSI version 3.0. Use the panel information retrieved from the 'dts' to configure the interface parameters. Add the device tree binding file to specify the basic configuration and panel features. Change-Id: I6a3677401454ad1d2bc29b0b845b0366eb7842b7 Signed-off-by: Chandan Uddaraju commit 17182d61f4cfdc990706bcacfb1ab02f631fa154 Author: Ajay Singh Parmar Date: Fri Aug 3 11:14:36 2012 +0530 msm_fb: display: vsync support for HDMI as primary When HDMI is primary, dtv is associated with node 0. In this case, DTV vsync and ctrl need to be called for node 0. CRs-Fixed: 383877 Change-Id: I425cddf453dd159259883e71f92c32918ca8e6c7 Signed-off-by: Ajay Singh Parmar commit 378fed12479c91893acbc56124b7d69ab7bd8166 Author: Kuogee Hsieh Date: Wed Aug 1 18:40:51 2012 -0700 msm_fb: display: enable sending uevent as default Enable sending vsync uevent as default so that uevent will be sent to usersapce frame work when first request recevied Change-Id: If72248007d68cba8fc814d449b46a58d842544ba Signed-off-by: Kuogee Hsieh commit 68446e5773292eea8a7bb33e7240cf7a67c0194c Author: Huaibin Yang Date: Mon Jul 30 15:14:55 2012 -0700 msm_fb: display: add iommu mapping for mdp cursor buffer address The mdp h/w cursor buffer physical address needs to be mapped to an iommu virtual address when iommu domain is enabled. Change-Id: I73b4492fc4d63632117074136e4d908f5089eb93 Signed-off-by: Huaibin Yang commit dc5cfefb1bd5a30f8f1a611fca61cc9d7bc7bddc Author: Huaibin Yang Date: Thu Jul 12 11:19:20 2012 -0700 msm_fb: display: set pipe src and dst size same in solid fill mode When a mdp pipe is in solid fill mode, the pipe outputs constant color and pipe itself does not fetch data from memory, so pipe src size should not matter. However, when src size is greater than dst size in solid mode which means downscaling, underrun happens. In this situation, setting src size to be same as dst size can remove underrun. CRs-fixed: 368478 Change-Id: Ie3ffc34486129cddcc872fe6e5317873db985b97 Signed-off-by: Huaibin Yang commit efb6c143ea951dab6dc72586100999d5b94c1c8d Author: Huaibin Yang Date: Thu Jul 26 17:45:57 2012 -0700 msm_fb: display: no early suspend for writeback panel Writeback panel is not real physical panel and no power consumption concern, so it is removed from early suspend registration to avoid open fb2 error during suspend/resume. Change-Id: Ic61f69e069f2da8c73f2b5a13d103a2f20034d20 Signed-off-by: Huaibin Yang commit 98b3a61592b34d0f39ed2dd00ef56b3ad575e0d2 Author: Huaibin Yang Date: Mon Jul 16 21:12:33 2012 -0700 msm_fb: display: remove mdp_lut_enable call to avoid hang issue Calling this function is not necessary in mdp overlay2 writeback driver. If called, it causes command mode primary hang. CRs-fixed: 365332 Change-Id: Id7054c3e56224035ec5939d91f8ce152b038e858 Signed-off-by: Huaibin Yang commit f15aa8bcd2f3b4333e8f010c8af6be3a16cfb882 Author: Chandan Uddaraju Date: Fri Aug 3 11:52:31 2012 -0700 msm_fb: Increase the pixel clock range for DSI panels Increase the upper limit for the pixel clock that changed with the newer version of the DSI controller. CRs-Fixed: 380003 Change-Id: Ibbeaa478b4d12ae8f350be41f959d53a6ae6c923 Signed-off-by: Chandan Uddaraju commit cc3df57a918118a1b70a43921d0377fb2790fa1b Author: Ravishangar Kalyanam Date: Wed Jul 18 18:28:42 2012 -0700 Revert "msm_fb: display: Register MDP fault handler with IOMMU driver." This reverts commit 9f36ce34dc0e6f840c6198430adfb44142d91f4b. This enables the IOMMU page fault register dumps from default handler. Change-Id: Icddd2394f5aa337e1a4998247cc4e3201f752e84 Signed-off-by: Ravishangar Kalyanam commit 5f3807bcf41ae01b17a4140b010db6ed02899c18 Author: Padmanabhan Komanduru Date: Wed Jul 4 00:06:20 2012 +0530 msm_fb: Add "Continuous Splash Screen" support for LCDC panel Add changes to support continuous splash screen on 8x25 SKU7 for LCDC panel. Delay the MDP hardware initialisation, keep LCDC timing generator enable during boot up, do not disturb the GPIO/regulator configurations and skip the panel initialization sequence during boot up. Change-Id: Ied091b01ad2f26acdff73e3ffe158d844198923c Signed-off-by: Padmanabhan Komanduru commit 0a3699b368fd72a86fb293e37a420b9a34dbd5d0 Author: Padmanabhan Komanduru Date: Wed May 30 16:17:10 2012 +0530 msm_fb: Add support for "Continuous Splash Screen" on 8x25 EVB Add changes to support continuous splash screen on 8x25 for video and command mode panels. Delay the MDP hardware initialisation, keep video timing generator enable during boot up, do not disturb the GPIO/regulator configurations and skip the panel initialization sequence during boot up. Change-Id: Id5e635ca986e66abb3cbf7c5a174f952ea489708 Signed-off-by: Padmanabhan Komanduru commit 14baef8b22dee8e1d5019a9ac9c6e6cdb48fbbe5 Author: Deva Ramasubramanian Date: Thu Jul 26 17:32:40 2012 -0700 msm: mdss: Use YCrCb 420 as the output format for writeback Use YCrCb 420 (NV12) as the output format for writeback. For Wifi Display use case, NV12 is required as the encoder requires this as the output format. Change-Id: Ica8851073476b9c05f3b5b41232803c2d71f7a3e Signed-off-by: Deva Ramasubramanian commit dbb6355114354211a5bcc2ba9f120d601d7a4712 Author: Deva Ramasubramanian Date: Thu Jul 26 17:17:53 2012 -0700 msm: mdss: Return proper msmfb_data back to client For local clients, return the relevant msmfb_data which contains a cookie relevant to the client. Change-Id: I9b845c0cd7fde1bc8c53a5063ba331460d67427d Signed-off-by: Deva Ramasubramanian commit 3d36e64838fbd064ad4868e1a3770e27c183f83e Author: Mayank Chopra Date: Thu Jun 21 18:23:52 2012 +0530 msm_fb: display: Add pre-multiplied alpha support for MDP4. MDP4 blend logic differs from GPU blend implementation as MDP4 does not differentiate between pre-multiplied alpha layers and non pre-multiplied alpha layers. Check layers for pre-multiplied alpha and change blend logic accordingly. CRs-Fixed: 355755 CRs-Fixed: 361729 Change-Id: Id8253d3888f1ebbadba1b6bbd87e7d98bac22da7 Signed-off-by: Mayank Chopra commit 5a19b70f2846822228d0ae0ef56d14162812ff9e Author: Ravishangar Kalyanam Date: Wed Jul 25 11:15:20 2012 -0700 msm_fb: display: Map framebuffer region in Display Write Domain Framebuffer is currently mapped for Display read and rotator source domains. For MDP writeback mode, Display write domain requires framebuffer region and it is mapped at initialization time. CRs-Fixed: 382550 Signed-off-by: Ravishangar Kalyanam Change-Id: Iba6fd0201a48fe1864bf42e9576f063cd58646fd commit ec5b2ff6857134832d165b8c2db8174c0d0ef4a7 Author: Nagamalleswararao Ganji Date: Tue Jul 3 20:06:41 2012 -0700 msm: display: use the fb reserved fields same as kernel 3.0 Reserved fields of fb structure used for various use cases in qcom fb driver. Reducing the reserved fields caused lot of side effects and it will change the reserved fields same as kernel 3.0. Change-Id: I7bf82a9b5667cb5c84b54e428bbfcb6869157bd7 Signed-off-by: Nagamalleswararao Ganji commit 071280769e98128452ce8773e7ac2bc353f0cc93 Author: Adrian Salido-Moreno Date: Wed Jul 25 17:57:15 2012 -0700 mdss: display: expose panel parameters through framebuffer API Panel porch values and pixel clock can be used to calculate the refresh rate from user space. Assign these values with information from panel driver. Change-Id: I29995d27904e50892d72de5e8c7dd39285f9d421 Signed-off-by: Adrian Salido-Moreno commit 34c2b52441d968030b31841eda77a09d73b89b8b Author: Adrian Salido-Moreno Date: Thu Jun 28 15:48:10 2012 -0700 mdss: display: allocate buffer from ion when debug writeback enabled Debug writeback is used to output MDSS framebuffer contents to memory to for debugging of MDSS core. Use ion buffer allocation for debug writeback buffer instead of using memory from framebuffer base layer to allow entire framebuffer area to be used for composition. Change-Id: Ia1a91f5f14bed1d29691092142fc94f7a8b6f4d2 Signed-off-by: Adrian Salido-Moreno commit 686c70adef370bb5b60a116bdf326b2062c946d5 Author: Adrian Salido-Moreno Date: Fri Jun 15 11:28:12 2012 -0700 mdss: display: fix incorrect rotator programming Source format should indicate that source is to be rotated 90 degrees instead of indicating source has been rotated 90 degrees. This is needed for hardware to fetch source in correct order and generate correct 90 degree output image. Change-Id: If8d1e12ef3e7a291e67ec9763f5ca92ec6fa983c Signed-off-by: Adrian Salido-Moreno commit 38506ba57f21ea83fbb8adb6d6818e9f1611377a Author: Adrian Salido-Moreno Date: Wed Jul 18 10:26:56 2012 -0700 mdss: display: remove check for odd dst offsets MDSS does not support odd width, height or src offsets for YUV formats, however odd coordinates are acceptable for dst offsets. Remove odd check done for dst offsets CRs-Fixed: 372900 Change-Id: I69230640f94bf080a8be4ea6d79f0901a7fa72cd Signed-off-by: Adrian Salido-Moreno commit bff7356885b596340c9701fd1a6b18b08f8e75a5 Author: Kuogee Hsieh Date: Thu Jul 26 10:59:49 2012 -0700 msm_fb: display: free writeback buffer at correct time When mdp pipe is freed at end of video play back, Writeback buffer is freed while mdp still fetchs data from it. This cause system crashed and blue screen shows on screen. This patch will free writeback buffer at correct time. Change-Id: I46a5031c13d86f943d6604713e1841b482dffe96 Signed-off-by: Kuogee Hsieh commit 586fd1628cdd10468e0d6496a77a236f18eaf9c7 Author: Kuogee Hsieh Date: Tue Feb 14 15:24:16 2012 -0800 msm_fb: display: vsync driven screen update This patch will queue multiple surfaces and commit those surfaces into mdp at same instance so that surfaces will be blended and displayed at same time. Hardware vsync event is delivered to the user space frame work via uevent. Both queue and commit are controlled by frame work and synchonized with vsync event. Therefore frame rate will match with vsync rate. Change-Id: If630a6d94fd38483ee313f575b1a71ed8bd65a52 Signed-off-by: Kuogee Hsieh commit 1fe8e81ccadfb4ba621094c924f31f8c230daf63 Author: Ravishangar Kalyanam Date: Mon Jul 9 17:54:01 2012 -0700 msm_fb: display: Set LVDS Chimei panel frequency to run at 60 fps Modify LVDS Chimei panel pixel clock from 75 MHz to 79.4 MHz and update PLL settings to achieve refresh rate of 60 Hz for better user experience. CRs-Fixed: 375510 Change-Id: Ifb4036c790552b1c43d5a3c817ed05691f86c7f6 Signed-off-by: Ravishangar Kalyanam commit dfe5751941ef2478c57565f8ebca09623d83a8a4 Author: Carl Vanderlip Date: Mon Jul 23 12:34:47 2012 -0700 video: msm: Add CSC and QSEED support to Overlay API Add support for CSC and QSEED configuration through MSMFB_OVERLAY_SET and MSMFB_OVERLAY_PLAY ioctls. Provide better integration than previous attempt with the existing Overlay and PostProcessing APIs. CRs-Fixed: 380750 Change-Id: If895391074ef1e7d7a6824d289e1ed9da6a52180 Signed-off-by: Carl Vanderlip commit 3118cb077358e472adb0db8e207a63bd84fd267f Author: Carl Vanderlip Date: Fri Jun 22 18:15:18 2012 -0700 video: msm: Remove old post processing overlay integration Remove old implementation of HSIC and QSEED smoothing/sharpening overlay integration. Need to replace with new implementation that better integrates the existing functions of the two APIs. CRs-Fixed: 380750 Change-Id: Id3469fad16764ed88e74a8da75bb873f726ba366 Signed-off-by: Carl Vanderlip Signed-off-by: Pravin Tamkhane commit 382b00b9a664fa0bd9b8d8bee2dae3f4340d425d Author: Carl Vanderlip Date: Wed May 16 16:45:07 2012 -0700 video: msm: Add QSEED Table2 Support Add support for QSEED Table2 reads/writes. Table 2 is a table of coeffients for QSEED Table 1 to offset into. Table 2 is quite large, caution should be taken when writing into it. CRs-Fixed: 380315 Change-Id: I89be18c0047dcf1d9a3bcd538967b2bbe7b4efe1 Signed-off-by: Carl Vanderlip commit fbf467206a4b5d09f51268535364f0a1b462eef6 Author: Carl Vanderlip Date: Wed May 16 16:43:39 2012 -0700 video: msm: Add QSEED Table reading support Add support to read the tables of QSEED values. When the values of the QSEED tables are able to be written to, it is beneficial to be able to read what's there as well. CRs-Fixed: 380315 Change-Id: I3110721906424f70a12bf5736de7875dec03f4c6 Signed-off-by: Carl Vanderlip commit 43da18d00abc2a61834b6650a49bf7edcf4f4df0 Author: Huaibin Yang Date: Thu Apr 12 15:37:44 2012 -0700 msm_fb: display: switch blt mode on/off without turning off TG Turning off dtv TG may cause blink. MDP requires h/w idle to change blt mode, turning off TG can make sure mdp h/w is idle. If turning off TG is not desired, one way to do is to check busy bits of overlay and dmae and once they are both idle, the mode can be changed. CRs-Fixed: 363717 Change-Id: I2817d7751ed04fd9ed144974328c4518c54af3d6 Signed-off-by: Huaibin Yang Signed-off-by: Ajay Singh Parmar commit fccacdf4e72f8b39c3087628aee41bf94652e220 Author: Ajay Singh Parmar Date: Thu Jul 19 12:01:01 2012 +0530 msm_fb: hdmi: Proper switching of switch device Switch device used to tell userspace about HDMI connection needs to be enabled when: 1. HPD connect 2. Authentication successful And disable when: 1. HPD disconnect 2. Authentication failed Change-Id: I8d4529fa2335ec1b2dc1196e57e3c8bad7d6b657 Signed-off-by: Ajay Singh Parmar commit 53156f5794a1eb8625033cabe243bf35bde93d1f Author: Huaibin Yang Date: Tue Jul 24 10:13:05 2012 -0700 msm_fb: display: add out of range check for display sizes MDP pipe or mixer size registers have 12-bit number, so boundary checks are needed for those parameters. If not, input req sizes could be very large 32 bit unsigned numbers, e.g. 0xffffffff, unsigned operations may have overflow to pass all later checks, causing MDP underruns or hang issues. CRs-fixed: 380469 Change-Id: I096d7022ede21d54266b46a140782ab0348dd54b Signed-off-by: Huaibin Yang commit 6957fa026060675c197e2aad0762065a6aba7e31 Author: Siddhartha Agrawal Date: Wed Jul 11 21:08:50 2012 -0700 msm-fb: display: Tearing issue during video playback Tearing was observed while playing 1080p H264 videos in potrait mode. Enabled blt mode check for MIPI command mode panel as well. CRs-Fixed: 369365 Signed-off-by: Siddhartha Agrawal Change-Id: Iac980050e5966db4731240c11e89e1f68118f2b7 commit 62d4a8cb1a5a1a98b3a70988de9ff9e2c1368be6 Author: Jeevan Shriram Date: Tue Jul 17 11:44:25 2012 +0530 msm: HDMI: Re-initialize the scan details for every HPD After disconnecting the phone from TV which doesn't support underscan, and connected to TV which support underscan, underscan is not working due to non re-initialization of scan variables. Re-initialize the underscan variables for every HDP events. CRs-Fixed: 375862 Change-Id: I22b7b8785ec93f9cf226e9b646a851ffb3ceff62 Signed-off-by: Jeevan Shriram commit df67a26bb4e4eb274ef367ad67b10d1c845ef7f9 Author: Ajay Singh Parmar Date: Tue Jul 17 23:54:47 2012 +0530 msm_fb: display: Remove unnecessary dtv_pipe checks In case of PAN display, PAN update function would return without allocating dtv pipe resulting in no HDMI display. This change removes unnecessary checks and enable dtv pipe for PAN display as well. CRs-Fixed: 379625 Change-Id: I533392a1120a21e962fbbbf0c07a89997832406f Signed-off-by: Ajay Singh Parmar commit 30befc28305440f30770a6545839fe4b55ee2207 Author: Ajay Singh Parmar Date: Wed May 30 11:04:00 2012 +0530 msm_fb: display: suspend-resume on HDMI When HDMI is primary, suspend-resume is not happening. For HDMI as primary case, early suspend and resume can be used. This change implements early suspend and resume for hdmi as primary case. CRs-fixed: 381097 Change-Id: I7b83d07a8b109294f3606c60f58b760836b88685 Signed-off-by: Ajay Singh Parmar commit 6b82d2ba8296e956abcd4c0c2014138390439dee Author: Ajay Singh Parmar Date: Thu Jul 19 17:23:26 2012 +0530 msm_fb: hdmi: Boot param support for resolution change Boot param support for dynamic resolution change for HDMI as primary case like MPQ. With this change, MPQ can also be configured for different resolutions than the default 1080p@60Hz using boot parameters. CRs-Fixed: 373211 Change-Id: I2c8537724ddd1ece7e81e6022afb9315c5147aa2 Signed-off-by: Ajay Singh Parmar commit 2568be7b453fc06ac0ce2a293021f2309e3ebbfa Author: Nagamalleswararao Ganji Date: Tue Jul 3 21:20:58 2012 -0700 msm_fb: display: Configure MDP clock table based on DSI Video pixel clk To avoid display underrun issues, configure the MDP clock table's rate according to DSI Video mode panel's pixel clock frequency by 1.15 times. Change-Id: I9bc864a754c2d51c9d86ece79863820eb72cdae8 Signed-off-by: Nagamalleswararao Ganji commit 16c8ae2beba81d102bccd130ccf8cca06533cc28 Author: Abhishek Kharbanda Date: Mon May 21 11:31:15 2012 -0700 msm_fb: MHL: Adding MHL api's for USB interaction. Adding MHL api's for device discovery and registering callback mechanism.USB driver use these API's for synchronization with MHL driver. Change-Id: I0846951302e3b5f5d20d566c92c2f224528ca455 Signed-off-by: Manoj Rao Signed-off-by: Abhishek Kharbanda commit c8430bd159039340c5a50e6897b256631f5dc7bb Author: Padmanabhan Komanduru Date: Mon Jul 9 12:34:01 2012 +0530 msm_fb: Add histogram support for MPQ 8064 Currently, there is no support for histogram on MPQ 8064. Add support for histogram ioctls to support histogram testing. CRs-fixed: 375580 Change-Id: I24ccf73c6ea6d230da4624ea196cba2d8195f8b2 Signed-off-by: Padmanabhan Komanduru commit bc49e8330d32669aadc012585e3a2bcad0f34b85 Author: Ajay Singh Parmar Date: Sat Jul 14 16:18:02 2012 +0530 msm_fb: hdmi: Turn on switch dev when connect to HDMI Audio is not routed to TV after deep sleep and resume. Userspace is dependent on switch device to indentify audio route. When HDMI is turned on, this switch needs to be turned on as well. CRs-Fixed: 377159 Change-Id: I7faaad5ff772ad2045876cc084aa71d120b77139 Signed-off-by: Ajay Singh Parmar commit f0a3914b984c75b66ca7d96a479c08230928e2d1 Author: Matt Wagantall Date: Mon Jul 9 16:59:35 2012 -0700 msm_fb: Remove control of HDMI PLL regulator The regulators required by the HDMI PLL are now controlled within the clock driver. Remove the explicit control from mdp.c. Change-Id: Ia2975a5a83b77cd9e21fc43cabea754b7b040dd5 Signed-off-by: Matt Wagantall commit f0fd8e7323ea0f60539918528a4cfa1edb39b828 Author: Carl Vanderlip Date: Thu May 3 15:08:20 2012 -0700 video: msm: Add user-defined backlight scaling Add method for scaling backlight based off of a user provided ratio and minimum level for the scaling to be applied. Change-Id: I74c2329c842dd9cbbc9eddfff38cd56fd0e939a4 Signed-off-by: Carl Vanderlip commit 649ca22aba67cd429025ee026015b6082b38539f Author: Ravishangar Kalyanam Date: Sat Jun 9 18:19:18 2012 -0700 msm_fb: display: Configure DMA before Layer Mixer for writeback mode switch DMA addresses are configured after Layer Mixer is set to writeback mode. This leads to IOMMU page faults due to incorrect addresses read from DMA. Hence DMA is programmed before Mixer setting. Change-Id: I4c5e41a56f05e3fabb46b4cadde03168589eeb17 Signed-off-by: Ravishangar Kalyanam commit 3bb47a097c62b71c7f8f2be888a1f73c6cfb8142 Author: Aravind Venkateswaran Date: Fri Jul 13 11:51:24 2012 -0700 msm_fb: HDMI: Fix for high HDMI sleep current In certain cases, the HPD circuitry is not switched off when the device goes to suspend state, resulting in high sleep current on the HDMI power rail. This patch ensures that the HPD circuitry is always turned off during suspend operation by removing an unnecessary condition check. Change-Id: I5846255ff4405ff1f449158f4b2f0d5ed0cd96bb Signed-off-by: Aravind Venkateswaran commit 2f7f94cef2a64930e1476c09a5a402631bd39d99 Author: Ajay Singh Parmar Date: Tue Jul 10 16:08:30 2012 +0530 msm_fb: hdmi: Do not turn on HPD at boot HPD is getting turned on by userspace if HDMI is enabled. We don't need to turn on the HPD from HDMI driver. CRs-Fixed: 377899 Change-Id: I29af0ca6ba222c7af61b1a0e8b51be35dee6426c Signed-off-by: Ajay Singh Parmar commit 10bbb7da8663f44fd348d72fef24f08bbc789cd5 Author: Kuogee Hsieh Date: Sun Jun 3 07:56:23 2012 -0700 msm_fb: display: use spin_lock_bh() when turns on/off dsi_clk Since dsi clock is accessed by both thread and timer context, spin_lcok_bh()/spin_unlcok_bh() must be used to serialize accessing of dsi clock. Change-Id: Iac80400d871c90413dcbb10a12efc6bc6247e986 Signed-off-by: Kuogee Hsieh commit 97c332da161665e9ec31a222dcd919267889af1f Author: Ravishangar Kalyanam Date: Wed Jun 13 11:25:38 2012 -0700 msm_fb: display: Add DMA and Overlay blt mode address to MDP driver For handling split IOMMU domain cases, BLT mode requires DMA to map for reads and Overlay for writes. DMA and Overlay blt addresses are added to configure the respective registers to avoid page faults and normal operation of supported panel interfaces. Change-Id: Id007cf96588f817bcfe8559177abb073a9b00755 Signed-off-by: Ravishangar Kalyanam commit 3d297368b8199b07bda815915e94ecb5761561b0 Author: Padmanabhan Komanduru Date: Thu Jul 5 17:24:45 2012 +0530 video: msm: Fix corner cases of "read twice" error Fix several cases where histogram's completion structure is completed multiple times which causes the next histogram read to force the histogram software state machine into believing that the histogram is always being read by someone. When the timeout in mdp_do_histogram times out and then soon after the work that was being waited on completes, the next do_histogram call that is processed will not wait (and thus will not have its hist field set to NULL). This will cause all subsequent do_histograms to think that the histogram is currently being read, and will cause the "read twice" message to flood the kernel logs. This error is fixed by always initializing the completion structure before waiting for the histogram to complete. That way if the completion happens after the timeout, instead of causing the error, the completion's internal counter is reset to zero, which prevents the next histogram read from completing without waiting. Change-Id: Ic1bc4b8688cd191d226de1df15d389de09996106 Signed-off-by: Padmanabhan Komanduru Signed-off-by: Carl Vanderlip commit 18e97cde0f9875c41692139d30bce497df31b8fb Author: Manoj Rao Date: Fri Jun 22 00:33:51 2012 -0700 msm_fb: MHL: Driver changes for Integrated MHL Power up and GPIO functions have been moved to the driver MHL HPD event also triggers the HDMI HPD event since 8x30 FLUID device doesn't connect HPD line from 8334 to HPD line from MSM HDMI. The pull-up resistance in 8334 has been set to the recommended value so that the interrupts are sent over to MSM-USB driver. Change-Id: Ib8bb462c81706ff2dc027535ef766917bb7da39d Signed-off-by: Manoj Rao commit 9d7db4fd399109999f4ec0207651f335920f06db Author: Ravishangar Kalyanam Date: Sat Jun 23 18:49:59 2012 -0700 msm_fb: display: Wait for overlay done after DSI Video writeback switch After writeback mode is switched for DSI Video interface, wait for overlay done for prefill frame to avoid unnecessary fetches from previous buffers resulting in page faults. CRs-Fixed: 372389 Signed-off-by: Ravishangar Kalyanam Change-Id: Iacd3775a718fe8e08404b4d119d447a88b628617 commit ef95ae33a328426b45f502eeb86f2edc120faf30 Author: Olav Haugan Date: Tue May 15 09:50:30 2012 -0700 msm: iommu: Split rotator/mdp iommu domains Finer granularity is needed when mapping into the IOMMU's for rotator and mdp for secure playback. During secure playback HLOS will only have access to map into one context bank. The other context bank is secured and programmed by TrustZone. Divide DISPLAY_DOMAIN into DISPLAY_WRITE_DOMAIN and DISPLAY_READ_DOMAIN. Divide ROTATOR_DOMAIN into ROTATOR_SRC_DOMAIN and ROTATOR_DST_DOMAIN. Change-Id: I2d67525d6026b8a1fb2f2cb00e4bb118c8eb6f27 Signed-off-by: Olav Haugan commit 50f0f86034c97484081e1bbf4ea36253a21474f2 Author: Jeevan Shriram Date: Thu Jun 21 18:53:25 2012 +0530 msm_fb: display: Add ion support for PPP Add support for ion in MDP PPP drivers for accessing source images and destination images. Change-Id: I1ba07fb826447abb13ff73752089577cf9924ce5 Signed-off-by: Jeevan Shriram commit a43f44b44ee221df11ad84b8536c1c8d5373cbaf Author: Padmanabhan Komanduru Date: Thu Jun 28 20:00:42 2012 +0530 msm_fb: Handle multiple histogram reader errors during suspend/resume If a histogram reader waits for completion in the do_histogram ioctl and during this time the device is suspended, the complete for this gets called from mdp_histogram_ctrl_all() in the panel_next_off() sequence. This results in mgmt->hist not set to NULL. The subsequent do_histogram ioctls after device resume fail due to multiple reader failure condition since the histogram irq will be enabled now from the same mdp_histogram_ctrl_all() during panel_next_on() sequence and this by-passes mgmt->hist getting set to NULL that is present in histogram_start() ioctl. Handle this scenario. Change-Id: Ib0485da24c0f09a3f26768b75231903c8a2e0033 Signed-off-by: Padmanabhan Komanduru commit c45b820e3000c1c7f76cc1a3e1efcfaa33b75eba Author: Carl Vanderlip Date: Wed Jun 27 12:00:44 2012 -0700 Revert "Revert "video: msm: Always queue histogram work"" This reverts commit 2423ba8ae07458ec93efa07d777454f26d1d7c90. commit 2423ba8... will be refered to as commit X Commit X should have been listed as a parent of commit 56a123baaab84af584fbbf5cbb29955ec5c92f39 (i.e. video: msm: Always queue histogram work & lock histogram calls). commit 56a123b... will be refered to as commit Y Commit Y is composed of 3 commits that were squashed together after they caused errors when only one of them merged into mainline. Commit X was created to revert the first of these 3 commits, and thus resolve the errors. However, when updating commit Y, commit X was omitted as the parent commit. So when commit Y merged as a parent of commit X, commit X reverted part of commit Y. By reverting commit X, this commit restores commit Y. Change-Id: Ibfad464a2579354c92bc62d406672dcfc6a24009 Signed-off-by: Carl Vanderlip commit b14ed96f74b1258b1f102831a2b0ccd56f991132 Author: Laura Abbott Date: Mon Jan 30 14:18:08 2012 -0800 gpu: ion: Pull in patches for 3.4 Pull in Ion patches for 3.4 upgrade. Inclues the following patches from google: commit 7191e9ba2508ca6f1eaab251cf3f0a2318eebe26 Author: Rebecca Schultz Zavin Date: Mon Jan 30 14:18:08 2012 -0800 ion: Switch map/unmap dma api to sg_tables Switch these api's from scatterlists to sg_tables Signed-off-by: Rebecca Schultz Zavin commit 6f9e56945d4ee3a2621968caa72b135cb07e49c4 Author: Rebecca Schultz Zavin Date: Tue Jan 31 09:40:30 2012 -0800 ion: Add reserve function to ion Rather than requiring each platform call memblock_remove or reserve from the board file, add this to ion Signed-off-by: Rebecca Schultz Zavin commit 9ae7e01de1cf03c77054da44d135a7e85863fcb0 Author: KyongHo Cho Date: Wed Sep 7 11:27:07 2011 +0900 gpu: ion: several bugfixes and enhancements of ION 1. Verifying if the size of memory allocation in ion_alloc() is aligned by PAGE_SIZE at least. If it is not, this change makes the size to be aligned by PAGE_SIZE. 2. Unmaps all mappings to the kernel and DMA address spaces when destroying ion_buffer in ion_buffer_destroy(). This prevents leaks in those virtual address spaces. 3. Makes the return value of ion_alloc() to be explicit Linux error code when it fails to allocate a buffer. 4. Makes ion_alloc() implementation simpler. Removes 'goto' statement and relavant call to ion_buffer_put(). 5. Checks if the task is valid before calling put_task_struct() due to failure on creating a ion client in ion_client_create(). 6. Returns error when buffer allocation requested by userspace is failed. Signed-off-by: KyongHo Cho commit 043a61468f395dd6d4fc518299726955e9999c59 Author: Rebecca Schultz Zavin Date: Wed Feb 1 11:09:46 2012 -0800 ion: Switch ion to use dma-buf Ion now uses dma-buf file descriptors to share buffers with userspace. Ion becomes a dma-buf exporter and any driver that can import dma-bufs can now import ion file descriptors. Signed-off-by: Rebecca Schultz Zavin commit 0d1259b5f84969bd00811ff9faa1c44cdb9fdbb5 Author: Rebecca Schultz Zavin Date: Mon Apr 30 16:45:38 2012 -0700 gpu: ion: Use alloc_pages instead of vmalloc from the system heap With this change the ion_system_heap will only use kernel address space when the memory is mapped into the kernel (rare case). Signed-off-by: Rebecca Schultz Zavin commit be4a1ee79a89da3ca705aecc2ac92cbeedd032bd Author: Rebecca Schultz Zavin Date: Thu Apr 26 20:44:10 2012 -0700 gpu: ion: support begin/end and kmap/kunmap dma_buf ops These ops were added in the 3.4 kernel. This patch adds support for them to ion. Previous ion_map/unmap_kernel api is also retained in addition to this new api. Signed-off-by: Rebecca Schultz Zavin commit 46d71337f9aa84694e4e6cca7f3beb6b033bbf76 Author: Rebecca Schultz Zavin Date: Mon May 7 16:06:32 2012 -0700 gpu: ion: Allocate the sg_table at creation time rather than dynamically Rather than calling map_dma on the allocations dynamically, this patch switches to creating the sg_table at the time the buffer is created. This is necessary because in future updates the sg_table will be used for cache maintenance. Signed-off-by: Rebecca Schultz Zavin commit 903f6c716db3d4e26952aae9717f81dd5bc9e4ba Author: Rebecca Schultz Zavin Date: Wed May 23 12:55:55 2012 -0700 gpu: ion: Get an sg_table from an ion handle This patch adds an interface to return and sg_table given a valid ion handle. Signed-off-by: Rebecca Schultz Zavin The commit also includes fixups needed for MSM specific code. Change-Id: Idbcfa9d6af0febf06f56daaa6beaa59cc08e4351 Signed-off-by: Laura Abbott commit 24502cb2cfd176d72cc6884dbeb375c7fb054766 Author: Ravishangar Kalyanam Date: Mon Jun 25 18:58:45 2012 -0700 msm_fb: display: Enable MDP clock's overlay block during panel on MDP clock's overlay block is enabled during first update after panel on currently. This is now moved to panel on to keep clock enabled right from display on time. Signed-off-by: Ravishangar Kalyanam Change-Id: Ie201186c1471201874f2eff246486bc4a73b5872 commit 89dd8eb788bc97479a7c7bfbcafc25f1b63ceda0 Author: Stephen Boyd Date: Mon Jul 2 17:05:16 2012 -0700 msm_fb: HDMI: Fix lockdep warning Locks must always be taken in the same order to prevent AB-BA scenarios from occuring: ====================================================== [ INFO: possible circular locking dependency detected ] 3.4.0-g55e6e49-00052-g71783d6-dirty #3258 Tainted: G W ------------------------------------------------------- kworker/0:1/15 is trying to acquire lock: (hdmi_msm_state_mutex){+.+...}, at: [] hdmi_msm_hpd_state_work+0x78/0x2d8 but task is already holding lock: (external_common_state_hpd_mutex){+.+...}, at: [] hdmi_msm_hpd_state_work+0x6c/0x2d8 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (external_common_state_hpd_mutex){+.+...}: [] __lock_acquire+0x950/0xa10 [] lock_acquire+0x18c/0x1e8 [] mutex_lock_nested+0x68/0x3c4 [] hdmi_msm_hpd_on.clone.0+0x230/0x2c4 [] hdmi_msm_probe+0x378/0x588 [] platform_drv_probe+0x18/0x1c [] driver_probe_device+0x148/0x334 [] bus_for_each_drv+0x48/0x84 [] device_attach+0x78/0xa4 [] bus_probe_device+0x28/0x9c [] device_add+0x438/0x5e0 [] platform_device_add+0x13c/0x1a0 [] hdmi_msm_init+0x218/0x2d0 [] do_one_initcall+0x94/0x168 [] kernel_init+0xe4/0x1b8 [] kernel_thread_exit+0x0/0x8 -> #0 (hdmi_msm_state_mutex){+.+...}: [] validate_chain+0x944/0x1080 [] __lock_acquire+0x950/0xa10 [] lock_acquire+0x18c/0x1e8 [] mutex_lock_nested+0x68/0x3c4 [] hdmi_msm_hpd_state_work+0x78/0x2d8 [] process_one_work+0x37c/0x694 [] worker_thread+0x22c/0x3bc [] kthread+0x8c/0x9c [] kernel_thread_exit+0x0/0x8 other info that might help us debug this: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(external_common_state_hpd_mutex); lock(hdmi_msm_state_mutex); lock(external_common_state_hpd_mutex); lock(hdmi_msm_state_mutex); *** DEADLOCK *** 3 locks held by kworker/0:1/15: #0: (hdmi_hdcp){.+.+..}, at: [] process_one_work+0x214/0x694 #1: ((&hdmi_msm_state->hpd_state_work)){+.+...}, at: [] process_one_work+0x214/0x694 #2: (external_common_state_hpd_mutex){+.+...}, at: [] hdmi_msm_hpd_state_work+0x6c/0x2d8 stack backtrace: [] (unwind_backtrace+0x0/0x12c) from [] (print_circular_bug+0x288/0x2d4) [] (print_circular_bug+0x288/0x2d4) from [] (validate_chain+0x944/0x1080) [] (validate_chain+0x944/0x1080) from [] (__lock_acquire+0x950/0xa10) [] (__lock_acquire+0x950/0xa10) from [] (lock_acquire+0x18c/0x1e8) [] (lock_acquire+0x18c/0x1e8) from [] (mutex_lock_nested+0x68/0x3c4) [] (mutex_lock_nested+0x68/0x3c4) from [] (hdmi_msm_hpd_state_work+0x78/0x2d8) [] (hdmi_msm_hpd_state_work+0x78/0x2d8) from [] (process_one_work+0x37c/0x694) [] (process_one_work+0x37c/0x694) from [] (worker_thread+0x22c/0x3bc) [] (worker_thread+0x22c/0x3bc) from [] (kthread+0x8c/0x9c) [] (kthread+0x8c/0x9c) from [] (kernel_thread_exit+0x0/0x8) Change-Id: I251049edbc97a5fe0e6c67801cf472fdc48722a7 Signed-off-by: Stephen Boyd commit dbbca9b8710704bd0ae37acd40e30b6aba6d1462 Author: Ravishangar Kalyanam Date: Fri Jun 29 19:04:08 2012 -0700 msm_fb: display: Attach IOMMU for DSI cmd mode in kickoff call Attach IOMMU call is currently done from DSI cmd mode DMA update method. Move the attach call to kickoff which enables it from restore and video paths Signed-off-by: Ravishangar Kalyanam Change-Id: I06d39e31b3ab1cf797fb655e7e558c1cabd98ebf commit 07876121525c631cbf914c8777e01875c293d0ed Author: Ravishangar Kalyanam Date: Fri Jun 29 12:27:49 2012 -0700 msm_fb: display: Set HDMI PLL footswitch regulator to 1.8V after get() After regulator_get call for HDMI PLL footswitch purpose, set output voltage to 1.8 V to ensure proper state while enabling and disabling regulator. Signed-off-by: Ravishangar Kalyanam Change-Id: Ifdd0cdbf614524b53038074b943cca65b71bbd24 commit 3ac0c174b21293d50773bb8b2bc5ad9ee2aedf23 Author: Ravishangar Kalyanam Date: Fri Jun 22 18:46:33 2012 -0700 msm_fb: display: Fix Toshiba WSVGA panel porch and timing settings Fix the porch and timing settings for DSI Toshiba WSVGA panel to enable writeback mode switch efficiently. Signed-off-by: Ravishangar Kalyanam Change-Id: Ib768d13617470f75ae027970c6ca4779d6b5a367 commit 254d6740cfa0a32afe9bb66762199ea5931f53d0 Author: Ravishangar Kalyanam Date: Wed May 30 22:12:09 2012 -0700 msm_fb: display: Flush pipe registers before staging for Mixer 0 or 1 For Mixer 2, register flush need not be called. Flushing is done only for pipes on mixer 0 and 1. Signed-off-by: Ravishangar Kalyanam Change-Id: I54758f79552790de2ad936703ba6140ac57b76c4 commit 37320fb657169e39aef13afb468ae551481658f4 Author: Matt Wagantall Date: Tue Jun 26 14:50:28 2012 -0700 mdss: display: Correct regulator API usage A device pointer should be passed to regulator_get() as the first argument, and the regulator mapped to the MDSS device in the device tree. Do this. This also resolves the following message seen in debugfs, which is present when regulator_get() is called with a NULL device: <4>[ 1.145507] gdsc_mdss: Failed to create debugfs directory Change-Id: I70a5137a31dbf82ae1e6634249f274cb16fe7a71 Signed-off-by: Matt Wagantall commit b5085c57a43b2ba6cded7b4adeb646ed3c8ad095 Author: Ajay Singh Parmar Date: Wed Jun 20 11:43:54 2012 +0530 msm_fb: display: Increase wait for VSYNC Wait time for VSYNC needs to be increased to accomodate 1080p 24HZ resolution which requires around 41ms. CRs-Fixed: 368521 Change-Id: Ideda24bb83e32a6d5035c6193ef3dfd5e0c947fc Signed-off-by: Ajay Singh Parmar commit 4a4f2d591cebc94b179e58cc6418f4598146f3c8 Author: Ravishangar Kalyanam Date: Wed Jun 20 18:30:05 2012 -0700 msm: display: Add MDP footswitch regulator control for HDMI PLL Add support for enabling HDMI PLL regulator along with footswitch enable/disable to avoid PLL lock detection failures during suspend/resume Change-Id: I9b161cab50d2b6c39de39b588e326f5ff97cbc65 Signed-off-by: Ravishangar Kalyanam commit 9c4743fd7d5e5230b4f05564432bd6d6b51b4a88 Author: Mayank Chopra Date: Wed Jun 27 15:31:43 2012 +0530 Revert "msm: iommu: Split rotator/mdp iommu domains" This reverts commit 9ae9beaf0a79f929c4f9928b8daed5a9ed131d6a. Change-Id: Ie93cbb23eaa1e35bfbacc53cd18f05b345acea4b Signed-off-by: Mayank Chopra commit fd233093130a8b11519630cf3b38f02491e634a3 Author: Mayank Chopra Date: Wed Jun 27 15:30:49 2012 +0530 Revert "msm_fb: display: Add DMA and Overlay blt mode address to MDP driver" This reverts commit 5f979254a80b7a844df3d9c1f49e16427f2477cc. Change-Id: I595afa529d96e8378d00e75bd836cfa191ab5135 Signed-off-by: Mayank Chopra commit ef5b150ffa574ec1aac76618e2cfd1d94ee626ba Author: Abhishek Kharbanda Date: Wed Jun 6 13:08:06 2012 -0700 msm_fb: HDMI: Removing unnecessary HPD detection code. HPD read work is used to detect HPD at bootup which is not required as HPD detection is taken care at bootup by toggling the HPD circuit. So we can safely remove this redundant code. CRs-Fixed: 368865 Change-Id: I8eed00c4f5af2ed2ca37e86da622ab518e5eb887 Signed-off-by: Aravind Venkateswaran Signed-off-by: Ajay Singh Parmar commit 2423ba8ae07458ec93efa07d777454f26d1d7c90 Author: Carl Vanderlip Date: Tue Jun 19 18:09:36 2012 -0700 Revert "video: msm: Always queue histogram work" This reverts commit c0d815c2a4118d1ba51e316c6cb59bee4d68eb9b. Revert patch that is causing excessive histogram logging. Will merge original patch with fix when issue is resolved and tested. Change-Id: I99b04362f6acd4f75a72e4b3ca52406907971e67 Signed-off-by: Carl Vanderlip commit 14c5e7a160faee03393994b064a093019aca9333 Author: Adrian Salido-Moreno Date: Tue May 29 14:02:58 2012 -0700 mdss: display: Add writeback support for WFD - Implement APIs used to support wifi display (WFD) based on ioctls and functions declared in linux/msm_mdp.h. - Restructure writeback interface file to support custom output formats and take buffers from WFD APIs. Change-Id: I3e6b75bd8b7d73eb20c97899de1891bbd85e9fa4 Signed-off-by: Adrian Salido-Moreno commit 20684ab9fdf25602872a602d89a3d3eda1b15102 Author: Adrian Salido-Moreno Date: Wed May 9 19:16:40 2012 -0700 mdss: display: implement common irq handler for different mdss blocks All of MDSS blocks (mdp, dsi, edp, hdmi) share same irq line. Implement function to manage MDSS irq line with common API with support for irq callback handler for each of block. Also fix incorrect calculation of MDP interface interrupts. Change-Id: I1271f7e1065aac95175b6e92504917264f4043a5 Signed-off-by: Adrian Salido-Moreno commit 2dca5a058c622a7bd0803285b10ec081b8f8e3ef Author: Adrian Salido-Moreno Date: Tue May 29 19:00:54 2012 -0700 mdss: display: add video display interface support Video mode display interface is used by DSI, HDMI and EDP controllers. Implement MDP support in order to setup data path to these controllers. Change-Id: Ibc766a1d10a55bcf64a3ab693db034a378afe4ee Signed-off-by: Adrian Salido-Moreno commit 4e584a304cdf03c4ed7cc28a6457ac22e5d4c688 Author: Adrian Salido-Moreno Date: Tue May 29 18:25:01 2012 -0700 mdss: display: implement csc matrix programming Implement color conversion matrix programming to support YUV surfaces. Also add dspp initialization stub function. Change-Id: I7ba57eca24e15acffbddf7b81fac6b8a6ce3bba5 Signed-off-by: Adrian Salido-Moreno commit 1857f06647e420c97f9b0e24bb1b77da710d858a Author: Adrian Salido-Moreno Date: Tue May 29 17:57:28 2012 -0700 mdss: display: add rotator interface to mdss driver Add rotator session management support with overlay interface using MDP flag MDSS_MDP_ROT_ONLY. Overlay interface can only support overlay surface or rotator (written back to memory) but not both. Change-Id: Ib2f494683b2e6c2fd8c67818df2b57afb82a3df3 Signed-off-by: Adrian Salido-Moreno commit 96a1e9e9a778f0729b7073f20a0fbd9a63c9ba8b Author: Adrian Salido-Moreno Date: Tue May 29 18:36:57 2012 -0700 mdss: display: add clock and bus scaling logic MDSS hardware supports different bus bandwidth and clock frequencies depending on the load on the hardware. Add support to driver to calculate the bus bandwidth and clock frequency requirements and activate changes before the load on hardware changes. Change-Id: I9bb5bbc7b3e18fb1a738f527b875506dfa0c5c81 Signed-off-by: Adrian Salido-Moreno commit 5ef3ac01347acd86ea5a3f7a7b44cbe88bb90221 Author: Adrian Salido-Moreno Date: Mon May 14 18:40:47 2012 -0700 msm: copper: add device nodes and clock information for mdss Copper uses Mobile Display SubSystem, add device tree and clock information to be used in mdss driver. Change-Id: I67397a28168407b3268f4f026f35d69a04062995 Signed-off-by: Nagamalleswararao Ganji Signed-off-by: Adrian Salido-Moreno commit 5f979254a80b7a844df3d9c1f49e16427f2477cc Author: Ravishangar Kalyanam Date: Wed Jun 13 11:25:38 2012 -0700 msm_fb: display: Add DMA and Overlay blt mode address to MDP driver For handling split IOMMU domain cases, BLT mode requires DMA to map for reads and Overlay for writes. DMA and Overlay blt addresses are added to configure the respective registers to avoid page faults and normal operation of supported panel interfaces. Change-Id: I522944b804fe65925df428d6bb312262328a11d7 Signed-off-by: Ravishangar Kalyanam commit 9ae9beaf0a79f929c4f9928b8daed5a9ed131d6a Author: Olav Haugan Date: Tue May 15 09:50:30 2012 -0700 msm: iommu: Split rotator/mdp iommu domains Finer granularity is needed when mapping into the IOMMU's for rotator and mdp for secure playback. During secure playback HLOS will only have access to map into one context bank. The other context bank is secured and programmed by TrustZone. Divide DISPLAY_DOMAIN into DISPLAY_WRITE_DOMAIN and DISPLAY_READ_DOMAIN. Divide ROTATOR_DOMAIN into ROTATOR_SRC_DOMAIN and ROTATOR_DST_DOMAIN. Change-Id: If3e556171645e8ea02deb12ca543df36233db5f2 Signed-off-by: Olav Haugan commit 56a123baaab84af584fbbf5cbb29955ec5c92f39 Author: Carl Vanderlip Date: Tue Jun 12 16:55:14 2012 -0700 video: msm: Always queue histogram work & lock histogram calls Always queue histogram read worker in order to gain concurrency protection from the histogram management mutex (move previous checks/calls into worker itself). Lock the mdp_histogram_start and mdp_histogram_stop calls with the same lock used currently by mdp_do_histogram to maintain that every do_histogram called between a start and stop will be completed. Add a timeout to do_histogram wait_for_completion so that it will unlock and yield to other histogram calls if it waits for longer than 33 msec. CRs-fixed: 363763 Change-Id: Icc503aed4e60dd01941682003ca3dbc844aed8d9 Signed-off-by: Padmanabhan Komanduru Signed-off-by: Carl Vanderlip commit 41cdae666312bdc248a8e707a2d8f9ca568178cf Author: Ajay Singh Parmar Date: Mon Jun 11 17:18:42 2012 +0530 Revert "msm_fb: display: Fix for HDMI bootup issue" This reverts commit a369ce03ca048fb511642ac1cb73c1f652d70c50. The change is no more required as pan_update is not being called and overlay set is now being used instead. Change-Id: I7b25c256ab57e620f319058638371e079642c448 CRs-Fixed: 367233 Signed-off-by: Ajay Singh Parmar commit d60ac323a1e3e7086ef2d77c866d5ed482d2a4e9 Author: Carl Vanderlip Date: Thu May 31 18:16:31 2012 -0700 video: msm: Resolve post processing memory leaks Allocate memory for post processing only once. Free post processing memory when MDP is removed. CRs-fixed: 366325 Change-Id: I244f4e10a6933e2acaf69a83d8b91ee5f6e27557 Signed-off-by: Carl Vanderlip commit cc91399843c5ffb5a57d890c0ca835cd7f5a6e8c Author: Padmanabhan Komanduru Date: Wed May 9 14:57:28 2012 +0530 msm_fb: Add backlight support using both GPIO 96 and PWM Add support for backlight control on EVB using both the LCD_BACKLIGHT GPIO and also the PWM approach on 8x25 EVB. Also increase the backlight levels supported on 7x27A from 100 levels to 256 levels. CRs-fixed: 365523 Change-Id: I4806644783cc98e01192a3101bc852487bb3b592 Signed-off-by: Padmanabhan Komanduru commit 691524c2e330592b2561df4c0fb6e7d2a741a924 Author: Abhishek Kharbanda Date: Wed Jun 6 12:44:46 2012 -0700 msm_fb: HDMI: Do not add HPD state timer during probe Currently all HDMI timers are initialized in the driver's probe function with a maximum possible expiration value. However, the 32-bit jiffies value is initialized in the kernel so as to wrap 5 minutes after boot. This results in the HPD timer being fired 5 minutes after boot even though cable is not connected. This change fixes this issue by not starting the HPD timer during probe. Change-Id: I9eeb8b892be2476e8debdd4ec5897a103cc34665 Signed-off-by: Aravind Venkateswaran Signed-off-by: Abhishek Kharbanda Signed-off-by: Manoj Rao Signed-off-by: Ajay Singh Parmar commit df694561ecc3105707af6bf323cd42f988293e3a Author: Ajay Singh Parmar Date: Tue Jun 5 15:06:21 2012 +0530 msm_fb: display: Fix compilation error for non-HDMI builds HDMI dependent functions need to be guarded under HDMI panel macro to avoid non HDMI builds complilation errors. CRs-Fixed: 366864 Change-Id: Ib2a9f6db4eb511b2a170fcc7ac979f6c41046baf Signed-off-by: Ajay Singh Parmar commit 3db0ca75238989ad2b5860c48901952bb15483a3 Author: Adrian Salido-Moreno Date: Tue May 29 17:32:43 2012 -0700 mdss: display: add overlay ioctl apis to mdss driver - Add support for overlay IOCTL APIs defined in linux/msm_mdp.h - Support for ion client buffers and framebuffer memory Change-Id: I0418ecab9aacf826d900f82f179fa20688fc763e Signed-off-by: Adrian Salido-Moreno commit d6d2863519c2351ef790758ed134e012d4563c4e Author: Adrian Salido-Moreno Date: Tue May 29 16:52:09 2012 -0700 mdss: display: implement writeback interface for mdss Add writeback interface support, using one page of framebuffer memory for writeback output. Change-Id: I0a44c6907cbc10d97c78642f45dc018dfb2d1750 Signed-off-by: Adrian Salido-Moreno commit e55fa120321f49385973b37f8b258bf78163743b Author: Adrian Salido-Moreno Date: Tue May 29 15:36:08 2012 -0700 mdss: display: Add Mobile Display SubSystem driver - Implements Linux frame buffer interface to interact with userspace libraries and applications, based on msm_fb frame buffer. - Implement MDP driver which handles MDP core data path setup and hardware blocks programming. - Support for UI through Linux frame buffer FBIOPAN_DISPLAY ioctl. Change-Id: Ib98677b8d81d74283b27dea08a9f1a705c101bce Signed-off-by: Adrian Salido-Moreno commit 75692782e15de0990247e2d6252fbd26ca849278 Author: Siddhartha Agrawal Date: Thu Jun 14 14:56:11 2012 -0700 msm: display: reduce pwm frquency to fix the broswer blank issue screen goes completely blank while loading a webpage at low back light value. reducing the pwm frequency range to fix the issue. Signed-off-by: Siddhartha Agrawal Change-Id: I44018b9f19d2dd3c8731d94588c606cd081fa3cb CRs-fixed: 362987 commit 14db6b404f2b1627791dada77ea303ef970910a6 Author: Aravind Venkateswaran Date: Wed May 23 17:22:15 2012 -0700 msm_fb: HDMI: Start HDCP authentication only on device open Currently HDCP authentication is started for a default resolution upon HPD connection event. With this change, HDCP authentication is only triggered after the HDMI interface has been configured for an appropriate resolution following the call to open the HDMI device. CRs-Fixed: 368865 Change-Id: I7b9ce85aed989b78b448bff6a545a194dfed5b1d Signed-off-by: Aravind Venkateswaran Signed-off-by: Ajay Singh Parmar commit 56672d222b15602826d0200a6baee5ca02a450c6 Author: Ajay Singh Parmar Date: Fri Jun 8 15:57:29 2012 +0530 msm_fb: display: HPD rework for cleaner approach Currently HPD is turned on and off with HDMI turn on and off and turned on again after HDMI off so as to detect the cable plugin. With this change, HPD will be turned on when HDMI drvier is initialized and turned off and on with suspend - resume. The HPD handling during HDMI turn on and off has been removed. CRs-Fixed: 368865 Change-Id: I1fb42b4587e58086d643b87a1600ecf09754423d Signed-off-by: Aravind Venkateswaran Signed-off-by: Ajay Singh Parmar commit 7d11c271b2ca399783975d3b6ef3199cd937a2e0 Author: Ajay Singh Parmar Date: Thu Jun 7 12:25:31 2012 +0530 msm_fb: HDMI: Update HPD logic to address HDMI PLL related issues In the current implementation, the regulators pertaining to the HDMI core are turned off/on as part of the configuration of the HDP circuitry. As a result, the regulator that powers the HDMI PLL is turned off before the HDMI clocks on the PLL are disabled. This might lead to the PLL not getting locked when it is re-enabled. This change turns on and off the regulators and clocks in proper sequence. CRs-Fixed: 360135 CRs-Fixed: 358598 Change-Id: Ie3630b543e78e83dc565edc32239935135ca4ca5 Signed-off-by: Aravind Venkateswaran Signed-off-by: Ajay Singh Parmar commit 66c3c2d50b970ee5f2275d89945271677018ddb3 Author: Jeevan Shriram Date: Tue Jun 12 17:46:53 2012 +0530 msm_fb: display: Add support for command mode on 8x25 SKU5 1. Make command mode default on 8x25 SKU5 devices 2. Add command to change panel scan direction to have proper display Change-Id: I9440ed01541a18ddabe2029c37565dda1181ac2f Signed-off-by: Jeevan Shriram commit 1c2bee0158437f485c32f6750e8df3314ae9168b Author: Huaibin Yang Date: Wed May 23 11:30:28 2012 -0700 msm_fb: display: detect if timing generator is on when do dma waiting If the timing generator is not on, dma waiting won't return and system crashes. So add TG on detection to avoid the issue. CRs-fixed: 362503 Change-Id: Ic472e7b75be1fd8960e5ac18929181513085212e Signed-off-by: Huaibin Yang commit c0d815c2a4118d1ba51e316c6cb59bee4d68eb9b Author: Carl Vanderlip Date: Tue Jun 12 16:55:14 2012 -0700 video: msm: Always queue histogram work Always queue histogram read worker in order to gain concurrency protection from the histogram management mutex (move previous checks/calls into worker itself). CRs-fixed: 363763 Change-Id: If9e3c13b5e4005f81fd1b5d2664af206b1decf5b Signed-off-by: Carl Vanderlip commit ba2fa104b3d51b24ccceb168b6bae96fcc851080 Author: Laura Abbott Date: Fri Jun 15 07:43:20 2012 -0700 video: msm: Don't make the framebuffer cached The video framebuffer should not be cached when mapping into the rotator or video domains. Change it. Change-Id: I407c68ac21a030aff801ebfae01d360bb6bf338c Signed-off-by: Laura Abbott commit aadc14e2ef6a6a84681233ba8020b72b38b98819 Author: Huaibin Yang Date: Tue Apr 10 15:28:50 2012 -0700 msm_fb: display: change ion memory map for mdp mixer2 writeback One way that mdp mixer2 gets writeback address is to get ion memory fd from userspace, then mdp driver maps this fd in kernel. When mdp iommu domain was not enabled, this maps to a physical address. Now after mdp iommu domain is enabled, the map is changed to an iommu virtual addr. Change-Id: I461a00cc93169de586565834af4fb9a43949cf95 Signed-off-by: Huaibin Yang commit 9acbfb0eb688bac6a35f12b58e2e9c3de4d2d3b8 Author: Zhang Chang Ken Date: Wed Jun 6 10:00:43 2012 -0400 msm_fb: display: add support for frc Frame rate converter(frc) is treated as LVDS 1080p panel Its configuration is based on HDMI 1080p60 mode LVDS dual channel mode will be used Change-Id: Id3a17f107c8398ddb47105d064be2743a150a3b3 Signed-off-by: Ken Zhang commit 94fea065072fc6afd61bd7e2c05f0e552dd1e578 Author: Amir Samuelov Date: Tue Jun 12 17:52:12 2012 +0300 msm_fb: display: Fix D2L register I2C driver more than once Fix error message seen on kernel log after suspend/resume Change-Id: I908efec9fde6e9de838e28d2c778fa4b3567e4f6 Signed-off-by: Amir Samuelov commit 913cf20260442f1335ec6ad82549bdae65b120c0 Author: Nagamalleswararao Ganji Date: Fri Jun 8 22:12:38 2012 -0700 Revert "msm_fb: display: Attach and detach MDP IOMMU on suspend/resume" This reverts commit aaf74ca34581feb8be797a6d8793824e73fecf67. Conflicts: drivers/video/msm/mdp4_overlay.c Change-Id: If9ec76cd040b0e834301d3d9ddbbab04b38b7a7e Signed-off-by: Nagamalleswararao Ganji Signed-off-by: Shruthi Krishna commit f6ef081fb7c9d779401b88c00314127333f9df83 Author: Nagamalleswararao Ganji Date: Fri Jun 8 22:05:30 2012 -0700 Revert "msm_fb: display: Add MDP IOMMU detach support for DTV" This reverts commit fa853b91ddfe4ac5eb9c77f9c409223d9b3cc0e4. Change-Id: Id1d127080040962c1ad33c9d4bca5005415283da Signed-off-by: Nagamalleswararao Ganji Signed-off-by: Shruthi Krishna commit 1ce7e4c2f39c787fa82aa10a5189df7d0c41b3fe Author: kuogee hsieh Date: Fri Jan 13 14:05:54 2012 -0800 msm_fb: display: Add support for 4 layer MDP composition Add 4 layers composition support to MDP by allowing borderfill pipe to be used as base layer of mdp blending. This releases RGB1 base pipe which can be used as a general purpose pipe. Change-Id:I517485d738e8bb555a263b3ea885d78d5e4f4396 Signed-off-by: Kuogee Hsieh commit 12d6b1f102f45566a0d3089d4e5eeb46a328cf00 Author: Padmanabhan Komanduru Date: Mon Jun 4 11:18:11 2012 +0530 msm_fb: Correct the chroma offset calculations for Yamato format In the PPP blit operations, when the source image format is Yamato, there is chroma offset calculations going wrong in the case when a frame is split into parts and blit is done separately. Correct the chroma offset calculations in this case. CRs-fixed: 366908 Change-Id: I867024632fda9f64a569150e0b6389d55614cd3a Signed-off-by: Padmanabhan Komanduru commit a382195e358eebc39640ba8e7f2fe7a3d583aaec Author: Padmanabhan Komanduru Date: Tue Jun 5 17:06:10 2012 +0530 msm_fb: display: Set the minimal sleep time for DSI PHY Initialisation On 7x27A/8x25, set the minimal sleep time required for DSI PHY hardware to get initialized and for the display to come up. CRs-fixed: 367652 Change-Id: If040a5ac37f694e83b819ecf08fc80f2afb7afaa Signed-off-by: Padmanabhan Komanduru commit 2fcabf92eea31cad2ec4852dcab563f2c93e4294 Author: Stephen Boyd Date: Wed May 30 10:41:11 2012 -0700 msm: Replace idle wakelocks with pm_qos Idle wakelocks are being removed so replace them with pm_qos. Since we don't know every driver's latency requirements we maintain one-to-one compatabilty with the idle wakelock API by replacing the wakelock with a pm_qos request of the correct latency. Once we determine the actual latency requirements of each driver we can replace the latency used with the correct latency for the device. Change-Id: Icc40f1642218e0de8fc2f56eaf9e8f92914d142f Signed-off-by: Stephen Boyd commit 33a7d7226c7ab243fe6f3192b5f007435c451c5b Author: Mayank Chopra Date: Wed Feb 29 12:25:31 2012 +0530 msm_fb: display: add writeback mode for mddi on 7x30 Add support for BLT mode in the MDP4.0 overlay architecture while downscaling to more than half of the source dimensions to avoid underrun issues. CRs-Fixed: 313524 Change-Id: I3ead5329edbef36697c26d55e6cf8d8cd316fdbc Signed-off-by: Jeevan Shriram Signed-off-by: Mayank Chopra commit ef9ccdb031e1fc3c80067cfad59fc5c2d9db77be Author: Siddhartha Agrawal Date: Tue May 15 10:52:00 2012 -0700 msm: display: Change DSI escape clock to byte clock Changing DSI escape clock source from PXO to byte clock to add more flexibility. Change-Id: Ia78093f8b8be6a27c86f3e8db68fa1f4a4d85086 CRs-Fixed: 361022 Signed-off-by: Siddhartha Agrawal commit f98c498b5ef8827afb24bad495f4e175f0829807 Author: Ravishangar Kalyanam Date: Thu May 31 15:15:29 2012 -0700 msm_fb: display: Wait for external vsync before DTV IOMMU unmap In play wait call for DTV, software waits for overlay1 done before unmapping IOMMU buffers. This is replaced by external vsync wait to avoid page faults. Change-Id: I67d3615121e9eda3a4378553049a41e32860a520 Signed-off-by: Ravishangar Kalyanam commit c0399fc8064b7e09bf41b9213faabc448ea95707 Author: Mayank Chopra Date: Wed Feb 29 11:43:49 2012 +0530 msm_fb: display: Remove chicken bit config during video playback Remove the chicket bit configuration and overlay status check for MDP 4.0 v2.1 hardware version CRs-Fixed: 313524 Change-Id: I0fd2db72a25a628398c9f794676d2178cdca78df Signed-off-by: Jeevan Shriram Signed-off-by: Mayank Chopra commit b411a253ea37acbe8cc817bf004ae08d877d9bd1 Author: Nagamalleswararao Ganji Date: Wed May 16 00:47:38 2012 -0700 msm-fb: display: lm2 writeback support on mpq platfroms lm2 writeback has broken on mpq platfroms as lm1 and lm2 are selecting the same axi writeback path. It adds the support to select the right axi writeback path based the availability of the write master Change-Id: Ia6b868ff13de5edc641e4795794286893c063e66 Signed-off-by: Nagamalleswararao Ganji commit 140748fe6442df1cc95dc1a2519ad8db2190b2b3 Author: Nagamalleswararao Ganji Date: Thu May 24 20:44:07 2012 -0700 msm_fb: display: Disable LVDS phy & pll during panel off LVDS phy pll power rail is consuming power in suspend state. Hence phy & pll are disabled during panel off cases on suspend and device release cases. Change-Id: I390a1d774587a108edc2e5f7319e431c14132cb8 Signed-off-by: Nagamalleswararao Ganji commit ff42a9a426ab9a76d75a29464412807dd72ceb13 Author: Jeevan Shriram Date: Tue May 29 11:03:00 2012 +0530 msm_fb: Check for Histogram NULL while queuing work Don't queue the work if the user hasn't requested for the histogram data CRs-Fixed: 365729 Change-Id: I0b28097fa00f13a836c2ee9d35e8e4557f1c70f0 Signed-off-by: Jeevan Shriram commit adf8fef78bf5f77f6c378d8889a35844278148e3 Author: Laura Abbott Date: Fri May 11 14:13:05 2012 -0700 video: msm: Migrate away from subsystem map APIs The subsystem map APIs are no longer the preferred method for mapping into the the IOMMU. Migrate away from those APIs to the newer map_contig_buffer APIs. Change-Id: I29608bd1cf7f9fb8c5584952826b6f3ae56bc3d8 Signed-off-by: Laura Abbott commit a2afa0dbade27d11382e2486c079d20532a5d73c Author: Chandan Uddaraju Date: Wed May 23 15:38:50 2012 -0700 msm_fb: Display: Add additional settings to improve DSI signal strength. Modify/add new Physical layer settings for Lane, BIST and PHY strength to improve the rise/fall time of the DSI clock waveform. CRs-Fixed: 364037 Change-Id: Ie2503100eebdf9d4c82d457c187ab8fa903778c6 Signed-off-by: Chandan Uddaraju commit 493c38628f7288d0c9ef384517b0eda3b76d50a8 Author: Nagamalleswararao Ganji Date: Mon Apr 23 17:18:18 2012 -0700 msm-fb: display: Perf changes for mdp composition Display under-run issues are observed with mdp composition. Fix underrun issues by changing perf level. CRs-Fixed: 354377 Change-Id: I82346e65af173d7592506f1cee7f90f40ee01485 Signed-off-by: Siddhartha Agrawal commit 7a77c7ca07bbcc390967552d0973238ac48b5597 Author: Anitha Anand Date: Tue Apr 24 15:46:36 2012 -0700 msm_fb : Disable power collapse before VSync to negate wake up latencies. For a 16ms frame period the CPU may go into deep power collapse. Based on the power collapse exit latency for that low power mode, the frame period gets extended by the latency to wake up the CPU at the next VSYNC. This results in a user experience glitch. Adding an hrtimer to wake up the CPU few ms before the Vsync and disabling power collapse compensates for the extra time spent in waking up the CPU out of deep sleep. On timer expiry, set wakelock to veto idle power collapse till the next VSync. The wakelock is released on the next VSYNC occurrence. Change-Id: I3e013cc54c36d3015d6fafa4b9ccd435cb5532ab Signed-off-by: Anitha Anand commit 9f36ce34dc0e6f840c6198430adfb44142d91f4b Author: Ravishangar Kalyanam Date: Fri May 25 15:15:16 2012 -0700 msm_fb: display: Register MDP fault handler with IOMMU driver. MDP fault handler will print minimum information on display related page faults and its registered with the IOMMU driver handler. This is to minimize logging when a series of faults are seen to cause watchdog bark. Change-Id: I7728e8265cad8f2b506f1ec7f71309ccdcb804a2 Signed-off-by: Ravishangar Kalyanam commit 1c96bc441e59d6f0439671c85bc41a3507f232e8 Author: Ravishangar Kalyanam Date: Fri May 25 12:31:31 2012 -0700 msm_fb: display: Free staged foreground pipes during suspend During suspend, some foreground pipes might still be staged and have to be removed before disabling timing generator. So, these pipes are staged down and freed before timing generator is switched off. Change-Id: I3f2376cac43464c64cd1c9e2f16f3d801298c25d Signed-off-by: Ravishangar Kalyanam commit fa853b91ddfe4ac5eb9c77f9c409223d9b3cc0e4 Author: Ravishangar Kalyanam Date: Fri May 25 13:24:52 2012 -0700 msm_fb: display: Add MDP IOMMU detach support for DTV IOMMU detach support on suspend is currently meant for DSI Video and LCDC modes. The detach call is moved to early suspend for primary display and external DTV to avoid page faults related to suspend/resume cases. Change-Id: Ia45071c44c20b951a328f39a033bdd83ff77d8f8 Signed-off-by: Ravishangar Kalyanam commit 6877b7fc326cd18bbf6c83b418005f7cffbffb9c Author: Amara Venkata Mastan Manoj Kumar Date: Thu May 24 12:30:35 2012 -0700 msm_fb: display: Flush background pipe after solid fill configuration For is_fg support on a foreground pipe, the background pipe is currently set to Solid Fill mode without being flushed. Add flush after enabling Solid Fill on background pipe. CRs-fixed: 352855 Change-Id: I91c4e391c9577a9198d048d2b369369d348efeab Signed-off-by: Amara Venkata Mastan Manoj Kumar commit 10a9758c95a68e11f27c9f6452ac9b5b978a8ca8 Author: Adrian Salido-Moreno Date: Mon May 21 17:32:07 2012 -0700 msm_fb: display: Fix invalid x offset programming for YUV444 fmt Source x offset adjustment is not properly programmed for YUV444 format, it is always programmed as 0. Add support for correct x offset adjustment. Change-Id: I73e87f961bda60670cc764c66be955e48ccf2734 Signed-off-by: Adrian Salido-Moreno commit aaf74ca34581feb8be797a6d8793824e73fecf67 Author: Ravishangar Kalyanam Date: Wed May 23 18:37:20 2012 -0700 msm_fb: display: Attach and detach MDP IOMMU on suspend/resume MDP IOMMU is not in a clean state on suspend/resume with page faults seen with video playback after resume. Hence, IOMMU is detached during suspend and attached on every resume call. Change-Id: I906cd7fa79ab67fd69eb1974d06d3521d42bf55b Signed-off-by: Ravishangar Kalyanam commit 9ef70852238212e6df24584426ad263291df1bf4 Author: Deva Ramasubramanian Date: Tue May 1 19:19:40 2012 -0700 video: msm_fb: Wait for dma to finish before terminating If writeback takes too long to finish, after calling _stop() writeback client might deallocate buffers during the DMA causing faults. To prevent this situation, make _stop() a blocking call that waits for the writeback to finish before returning. Change-Id: Ia710095a55d705589a81aa9bc29c41d536c2a42d CRs-Fixed: 351773 Signed-off-by: Deva Ramasubramanian commit 20c1b5887a5ba7bae742225bfceaa2268e0e7549 Author: Manoj Rao Date: Mon Mar 12 13:58:07 2012 -0700 msm_fb: HDMI: Video Quantization Ranges changed Quantization settings applied based on default range for source format for 480p. If a non-zero value is sent then it must correspond to transmitted video format as per the standard. Setting RGB Quantization values in AVI Infoframe for 480p to default range (0x0). Change-Id: I01fc263c9406fe80a4b3c73628f265bb733ff90c CRs-Fixed: 349246 Signed-off-by: Manoj Rao commit 77f82aec5a4785f89cb2ab968dcde1452f3073c6 Author: Ravishangar Kalyanam Date: Wed May 23 09:42:25 2012 -0700 msm_fb: display: Flush MDP registers before staging up any pipe Add flush calls to MDP's pipe and mixer registers before staging up any pipe to a mixer. Change-Id: I36f5aa04634bae43a38e57cd97bd2aafe9631eda Signed-off-by: Ravishangar Kalyanam commit c9fa6999ad8b2f10ec4e807ee3dae621f8c6d4fe Author: Nagamalleswararao Ganji Date: Sun Apr 29 22:39:48 2012 -0700 msm-fb: display: Reducing the display wake up time 100 msec sleep in phy init delays system wake up. Using usleep instead of msleep to optimize it. Change-Id: Ibdbb771145210c9462aa68543024be2ae797be4f Signed-off-by: Siddhartha Agrawal commit aa356f6c4d44965233c79d68bd293a258730d8c1 Author: Ajay Singh Parmar Date: Thu May 24 12:25:27 2012 +0530 msm_fb: display: Keep fb1 for MDP version < 4.0.2 For better memory usage, fb1 memory allocation is removed for targets like 8960 which support BF pipe and true mirroring but required for targets like 7x30 and 8660 which still needs fb1 for border fill. CRs-fixed: 364669 Change-Id: Id741223a0107e356b9164b582aa1f901caa21988 Signed-off-by: Ajay Singh Parmar commit e9658eb364860826d3924b3d45ba74a2a6c2a2e6 Author: Ravishangar Kalyanam Date: Tue May 15 14:58:55 2012 -0700 msm_fb: display: Rename MDP IOMMU context bank names MDP IOMMU context banks do not correspond to the input processing pipes like RGB and VG. So the context banks are renamed based on port and number. Change-Id: I39a6b1a66226aeaaf48fb3697f90ab55b67a592c Signed-off-by: Ravishangar Kalyanam commit d995a89cd61bb7295f0226420c4752dc0a9a8fe1 Author: Mayank Chopra Date: Tue Apr 10 12:18:58 2012 +0530 msm_fb: display: Move mipi dsi clock enable before dsi soft reset mipi_dsi_clk_enable() is called after dsi soft reset. Move mipi dsi clock enable before dsi soft reset as per mipi dsi hardware design document. Change-Id: Ie1cfdf53bc74b87b5a0e0679ab26bc513205673d Signed-off-by: Mayank Chopra commit ca61dbb1d9f0d8fe2c4d5871d9934379708c1091 Author: Huaibin Yang Date: Tue May 8 15:04:27 2012 -0700 msm_fb: display: disable pan display and memory access to fb1 and fb2 The native fb1 and fb2 framebuffer memory is not used and not allocated on the board file. So on the driver side, pan display ioctl or other operations on fb1 or fb2 framebuffer memory is checked and invalidated. CRs-fixed: 357242 Change-Id: I2883926251a0465f69f18c442d5867556a4651bf Signed-off-by: Huaibin Yang commit 0dc81db9cf48d869987e8fa8ab8914fcec964bda Author: Carl Vanderlip Date: Tue May 15 13:38:45 2012 -0700 video: msm: Avoid waking readers on failed histogram copy Avoid waking up the waiting histogram reader when the current histogram has failed to copy. Additionally, clean up initialization of histogram workqueue (was initialized twice). CRs-Fixed: 361640 Change-Id: I376c0193b8e34aba5b0aef54feb9504f450ffff4 Signed-off-by: Carl Vanderlip commit 71cf95bf1100ab5de55bf3858d40996be7dc445e Author: Carl Vanderlip Date: Mon May 7 11:30:52 2012 -0700 video: msm: Check for multiple readers of histogram Check to ensure that only one reader attempts to read one frame's worth of data from a histogram block. Prevent the case where two readers attempt to get data, but end up causing a loop where neither of them do. CRs-Fixed: 361640 Change-Id: I48878d9fe02d96f306894ed9acc47bf41cd9984b Signed-off-by: Carl Vanderlip commit 19e4b71f617e307cacf0be077e08bec5c37df290 Author: Carl Vanderlip Date: Mon May 14 12:01:04 2012 -0700 video: msm: Clear previous histogram data on next startup Clear the pointer to the userspace histogram struct when histogram is started. Previously, when the histogram was stopped while a histogram read was in progress, the pointer was not cleared, causing the next histogram read to think that someone was already using the histogram. CRs-Fixed: 361640 Change-Id: If09017149e98b35c49603372c554aa4c97f2de82 Signed-off-by: Carl Vanderlip commit ee888e34e20ec3bb4c2c385f3967ecaa9e97f49c Author: Huaibin Yang Date: Tue May 15 16:39:10 2012 -0700 msm_fb: display: add blt mode enable and disable for lvds panel The check for lvds panel is missing, so blt mode can never be enabled for lvds panel. blt mode is critical to avoid underrun issues. Change-Id: I3cd74bcd978a73997df638f10cd2126ba9ab6577 Signed-off-by: Huaibin Yang commit 8f7c96dc7ee42acd71ea962cf0580f0a9480d5af Author: Jeevan Shriram Date: Tue May 15 12:42:57 2012 +0530 msm_fb: display: Add support for MIPI NT35510 client on SKU5 Panel is 180 degrees rotated on SKU5 devices. This change fixes the 180 rotation on SKU5 devices in video mode. Change-Id: I9c7ff12de9e19534f8df8ebd9215d74ff0e429f3 Signed-off-by: Jeevan Shriram commit 9f1453ec3eb2b22160d25148a45f1731a23d4c95 Author: Pravin Tamkhane Date: Mon Apr 16 13:25:00 2012 -0700 msm_fb: Increase PWM granularity to 255 levels for 8960 fluid Currently 8960 fluid display panel only supports 100 levels for backlight. Content Adaptive Backlight Control requires 255 levels of backlight for optimal user experience with CABL turned on. CRs-fixed: 342485 Change-Id: I02226a7790f2dd0144c1eb623c8177724e33a715 Signed-off-by: Pravin Tamkhane commit fee56a86ba3582e2985b2f5a0e535743381544ff Author: Pankaj Kumar Date: Tue Apr 17 14:26:49 2012 +0530 msm: Add support for 7x25AB MSM 7x25AB is new msm which can go upto 1GHz. Add required cpu checks to add support for this new device. Change-Id: I0be886d471fe0c70b8afd4da87b9991862a8571f Signed-off-by: Pankaj Kumar commit 1b92af6e05320b6f5858a0e4b5c9aa40e54a9b54 Author: Siddhartha Date: Mon May 7 18:58:56 2012 -0700 msm_fb: display: Update video format on fps change Added check for frame rate change. Corner case if there is no change in xres,yres and pixclock. Change-Id: I0ff5eb65364d2a370e0973da7e84f738bd042a20 CRs-Fixed: 356328 Signed-off-by: Siddhartha Agrawal commit 514b1c651a33b7b73fb6f654d04355eac5ecb146 Author: Ajay Singh Parmar Date: Thu Apr 19 11:17:26 2012 +0530 msm_fb: hdmi: 3D configurations in HDMI 3D configurations using Generic0 packets need to be done after enabling HDMI Control to take these configurations into effect. CRs-fixed: 349578 Change-Id: I8d658ddf4f2ccb2ae47015fe411e8c1a5a55e4df Signed-off-by: Ajay Singh Parmar commit ca15287e50fe00dd6526fdc166cb526298099fb2 Author: Aravind Venkateswaran Date: Fri May 4 12:56:36 2012 -0700 msm_fb: HDMI: Do not add HDCP reauth timer during probe Currently all HDMI/HDCP timers are initialized in the driver's probe function with a maximum possible expiration value. However, the 32-bit jiffies value is initialized in the kernel so as to wrap 5 minutes after boot. This results in the HDCP timer being fired 5 minutes after boot even though reauthentication is not necessary. This change fixes this issue by not starting the HDCP reauth timer during probe. The timer is only started when an authentication failure is detected from an existing valid HDCP session. Change-Id: I0a28437daa2e95d24a02131322305f3b21a6445c CRs-Fixed: 352080 Signed-off-by: Aravind Venkateswaran commit d4aab1eb15aa7f9452f1e40688732815b39d4182 Author: Matt Wagantall Date: Thu May 3 20:26:56 2012 -0700 msm_fb: Pass device pointers to regulator_get() Passing a device pointer instead of NULL as the first argument to regulator_get() allows the device to be taken into account when finding a matching regulator. Change-Id: Idc9990eff2c6c78fc9fc9a36d638eef4fd1b632a Signed-off-by: Matt Wagantall commit 275f94daff0211c145526ee6d45bf48454b13afa Author: Huaibin Yang Date: Wed Apr 25 15:46:01 2012 -0700 msm_fb: display: add mdp version info for later mdp h/w fbtest needs to get the correct mdp version number, but now only the version up to mdp4.0 is returned. Add the latest mdp version up to 4.4. Change-Id: If1ff302bb4a02ed13bb4dcabcb933fd5adfbec6d Signed-off-by: Huaibin Yang commit cfd004fa326a6dc4c7e80da707248b5bddaa39b8 Author: Ravishangar Kalyanam Date: Mon May 7 12:02:41 2012 -0700 msm_fb: display: Flush pipe registers before staging the pipe Flush pipe registers before staging the pipe for the Mixer with pull mode panel interfaces. This fixes the IOMMU page fault/underrun caused by pipe fetching previously unmapped buffers due to missing flush calls CRs-Fixed: 356484 Change-Id: I6bc2e49746a7c3773708796bc1709c75a8afaa4b Signed-off-by: Ravishangar Kalyanam commit eee66c6ffa18c954fa2583fdda66526f90bad40b Author: Pravin Tamkhane Date: Wed Mar 28 16:07:08 2012 -0700 msm_fb: Increase backlight granularity from 15 to 255 levels Currently number of backlight levels are set to 15, which causes noticeable flicker when backlight level is changed from CABL functionality in userspace. So to improve visual performance, increase backlight granularity from current 15 levels to 255 levels. This change is for msm8960 & apq8064 liquids which use Chimei panels. CRs-fixed: 342485 Change-Id: I204f881d45fbcd4a419cc8e61c3bcb1f4d520f7e Signed-off-by: Pravin Tamkhane commit 134786b7bbcb3c8b07b4f56b4421842b75e8471a Author: Huaibin Yang Date: Thu May 3 14:44:39 2012 -0700 msm_fb: display: add dtv wait for vsync when in blt mode Currently dtv is waiting for overlay done when in blt mode. When dtv frame rate is low, this return may be too soon. So before dmae finishes updating buffer, the buffer may be overwritten by userspace. Add dtv wait4vsync after overlay done to lock the buffer untill the next vsync to avoid tearing or flicking. Change-Id: Ic57544a5305fdf9081bfeeccd8d364395faaf602 Signed-off-by: Huaibin Yang commit 6f043415300f58c5868e02050b15c8aa21c26342 Author: Nagamalleswararao Ganji Date: Fri May 4 01:16:06 2012 -0700 msm_fb: display: Correct LVDS Phy mux settings Fix the display color issue in 1.1 chips due to wrong mux settings in LVDS Phy Change-Id: Ia51500e15e0ffb3e4cc056073985cdeed5751652 Signed-off-by: Nagamalleswararao Ganji commit 29c5fb0392a1bf36ac385f5e8790999d70f6d2a6 Author: Ravishangar Kalyanam Date: Fri Apr 27 13:50:44 2012 -0700 msm_fb: display: Clear background solid fill on closing video pipe Clear background pipe's solid fill setting on closing Video pipe to avoid blink issues in display Change-Id: Iac3c884334f38580fb5c9dbfb260dd6940ef5019 Signed-off-by: Ravishangar Kalyanam commit b2bdae8ee4262a4e1d8e8e7f9c91b80790bdff27 Author: Huaibin Yang Date: Fri Apr 6 16:05:05 2012 -0700 msm_fb: display: remove mixer1 waiting4vsync when staging down the pipe dtv_pipe is the base layer pipe for mixer1. Waiting for vsync when staging down this pipe (it happens when we unplug HDMI cable) causes mixer1 under run because at the vsync moment dtv_pipe is disconnected to mixer1. CRs-fixed: 349765 Change-Id: I3a09159c3ae2dfea963e5ad064076f5a9452ec1b Signed-off-by: Huaibin Yang commit e534683723654af2a904e6dec3a646a2d9542408 Author: Matt Wagantall Date: Fri Apr 27 22:27:31 2012 -0700 msm_fb: Correct mdp_iommu array size to avoid scribbling The mdp_iommu array was undersized. This resulted in scribbling of nearby data structures which, through a long series of events, lead to invalid pointer dereferences in the workqueue framework's process_one_work() function on (at least) the 8930 SoC. CRs-Fixed: 357011 Change-Id: Ia8027ba8714bb90b336ee79d43920a7f71a8091b Signed-off-by: Matt Wagantall commit 59508db9d5cec32ff59c2ff5a689288db2b027d4 Author: Huaibin Yang Date: Fri Mar 30 16:30:29 2012 -0700 msm_fb: display: increase mdp upscaling range The old range is x8. Acturally mdp rgb or vg pipes can scale up more than that. The max up to x20 is verified. CRs-fixed: 340747 Change-Id: Ief7ee936e39de2ada87d47b14872bca0c3cf36a7 Signed-off-by: Huaibin Yang commit b18c9e29486f574bc6353243e1c0116956ba712c Author: Pravin Tamkhane Date: Fri Apr 13 18:29:34 2012 -0700 msm_fb: Provide support for ARGC and CSC for layer mixer 2 MDP 4.4 supports additional layer mixer (LM2) with ARGC and CSC blocks. Extend existing ARGC and CSC functionality to additional layer mixer (LM2). Change-Id: Id9e5d0a80fcd9a6e3b6132b083d8a43450c0efa1 Signed-off-by: Pravin Tamkhane commit 0ae152b929dfc538bbb2c72f01b5f3bf14c3c6bf Author: Huaibin Yang Date: Wed Apr 25 14:17:39 2012 -0700 msm_fb: display: update dtv panel info clk rate dtv panel clk rate is dynamically changed with the HDMI resolution. s/w panel info needs to keep its clk rate updated. CRs-fixed: 355110 Change-Id: I9365d67820158afb2bc520736df9152864a2a962 Signed-off-by: Huaibin Yang commit e01bb5a4944eea27e87ca00a869105185c13664d Author: Carl Vanderlip Date: Tue Apr 24 15:14:26 2012 -0700 video: msm: Add QSEED API to MDP_PP IOCTL Add the ability to program the QSEED Table 1 coefficients to the features supported by the MSMFB_MDP_PP IOCTL Doesn't support table2 writes currently, however, the code to write to them is already present. QSEED support is currently only configurable via a tuneable parameter that maps to a small subset of possible QSEED settings. By moving to the MSMFB_MDP_PP IOCTL, QSEEDs tables will be able to programmed to any value requested by userspace. This also allows for future expasion of the QSEED feature by allowing dynamic loading of the table2 coefficients (rather than only configuring them at init). Change-Id: I7394e211169efb0e677391e2c150a6a6b8d0477c Signed-off-by: Carl Vanderlip commit 28ffb9c964d8d303c38f90b6c4bc8bf313356a54 Author: Huaibin Yang Date: Wed Apr 11 23:37:15 2012 -0700 msm_fb: display: add dtv_pipe null check before dereferenc it There are chances that a null dtv_pipe pointer is dereferenced and system crashes. One such case is unplug HDMI cable while playing video. So a null check is needed for each dtv_pipe dereference. CRs-fixed: 355238 Change-Id: I1ff57b00169e217fc5ed98574db7fd49b9319d0a Signed-off-by: Huaibin Yang commit 14648740d17ca1f154222aba29a1f2946609f460 Author: Manoj Rao Date: Fri Mar 30 19:42:12 2012 -0700 msm_fb: MHL Driver for SI-8334 Transmitter The device driver for SI8334 Silicon Image's Mobile High-definition Link (MHL) Transmitter implements wake-up, discovery and communication with MHL sink. The MHL-8334 Tx is attached to MSM as an I2C-client. Change-Id: I845bc1b30dc799183357224a296215ecc1d44893 Signed-off-by: Manoj Rao Signed-off-by: Abhishek Kharbanda commit 2b41048b637d4341e24f8f36b68b127fe600f6a1 Author: Adrian Salido-Moreno Date: Mon Aug 15 10:40:40 2011 -0700 msm_fb: display: add YUV444 interleave format support to mdp Add support for H1V1 interleave (YUV444) to mdp Change-Id: I86b76831ad87dede90ddd8d8f5ae64e51fa28c27 Signed-off-by: Kyong Hwa Bae Signed-off-by: Adrian Salido-Moreno commit 6098eee975076350586eb3010edda8b96ac998d5 Author: Ravishangar Kalyanam Date: Thu Apr 19 10:35:01 2012 -0700 msm_fb: display: Unstage video from primary mixer H/W on unset Resolve video playback suspend/resume IOMMU page fault by unstaging video layer on VG pipes from primary mixer H/W during overlay_unset calls immediately at the next vsync boundary CRs-Fixed: 350371 Signed-off-by: Ravishangar Kalyanam Change-Id: Ia1b2369005db500b5042d3226cf8d43027783fe3 commit 5ff2cb661c0575a45e8cf70384dd6c1d2dc8e7ba Author: Kuogee Hsieh Date: Wed Apr 11 10:43:07 2012 -0700 msm_fb: display: switch mdp mode without turning off timing generator MDP need to be in idle state before switching to different mode. Dmap_done interrupt is delivered when the last line of frame is clocked out. Therefore mdp is in idle state during dmap_done ISR. This patch execute mdp mode switching inside dmap_done ISR. Therefore timing generator is not necessary to be turned off since mdp is in idle state already. CRs-fixed: 350154 Change-Id: Ib10557bde90856ffd5284a0a76dddbe92f2abc0e Signed-off-by: Kuogee Hsieh commit d94b7d4d0c67a9bcdbb4ab1929ce70f4b6ec7136 Author: Huaibin Yang Date: Mon Apr 23 16:02:08 2012 -0700 msm_fb: display: remove mdp writeback2 overlay kickoff waiting Before overlay2 kickoff, there is already a dma busy waiting, so once overlay is kicked off, mdp driver can safely return to userspace. Then if there is another request while ovlay2 is still busy, dma busy can take care of it. Change-Id: Ibb45a8b306a393c8e240fc64b5857e8700afcaba Signed-off-by: Huaibin Yang commit 012a8e79ebc3cd375f501a862e7b401b99c53054 Author: Mayank Chopra Date: Wed Apr 11 10:41:13 2012 +0530 msm_fb: display: Fix color swap issues in MDP4 and Rotator drivers Many of MDP input formats don't have correct unpack pattern, so image displayed on screen is not in the actual format set. Also,Some rotator output formats differ from input, these mappings used to be handled in userspace, but to avoid issues this is now done in driver. For YCrCb planar inputs chrominance order is dependent on rotator hardware version. Add hardware check to swap Cb and Cr for 7x30 and 8x60 rotators. CRs-fixed: 339114 CRs-fixed: 337040 Change-Id: I55691aa7c9d38e83e4fc63a162ffb23959ba30c1 Signed-off-by: Mayank Chopra commit 7a62a68bfa68cf9767b9cb6432c05a47e296067b Author: Manoj Rao Date: Wed Mar 14 15:56:13 2012 -0700 msm_fb: HDMI: Compile error when HDMI is disbaled Resolve compilation error when HDMI is disabled through kernel config. Change-Id: Ie89ac666fe4db83294cce07f59f61790b200d463 CRs-Fixed: 341412 Signed-off-by: Manoj Rao commit 87dd72e286299134b5783cb90f61e7eaec7d2788 Author: Ravishangar Kalyanam Date: Mon Apr 16 19:07:36 2012 -0700 msm: display: Clean DSI state on continuous splash disabled cases Reset the DSI clock control, disable controller and PLL to resolve boot issues for DSI command mode for continuous splash feature disabled/unspported cases Change-Id: I1e5e9a9d2d548c518d2620bf6d9e125d5efc8fd4 Signed-off-by: Ravishangar Kalyanam commit 0769dbd1fabe600bf6a8bd1d563c9e31b8d7c122 Author: Padmanabhan Komanduru Date: Thu Apr 19 16:54:09 2012 +0530 msm_fb: display: Update clock prepare changes for MIPI DSI Update the clock prepare/unprepare changes for MIPI DSI clocks and update the clock lookup table for ebi_lcdc_clk for MIPI DSI interface. Change-Id: Ic31e2e1b169894e633849573eb54325457080b53 Signed-off-by: Padmanabhan Komanduru commit 60d51beb9dd5db3f1adeb203728b1d7ccdec8e0c Author: Padmanabhan Komanduru Date: Wed Apr 18 17:18:31 2012 +0530 msm_fb: display: Change panel init command for NT35510 for proper display On NT35510 panel, the display is 180 degree rotated right now for video mode. Change panel init command in the init sequence for Video mode for proper display. Change-Id: I90f9c3e8e689a141c7c606be756c319bb7de1b3f Signed-off-by: Padmanabhan Komanduru commit d16485de65e9e7d611293f5b6174b3a3efa7a3d2 Author: Ravishangar Kalyanam Date: Wed Mar 21 16:51:26 2012 -0700 msm_fb: display: Add clk prepare changes to MDP and rotator Use clk_prepare_enable and clk_disable_unprepare instead of clk_enable and clk_disable respectively. CRs-Fixed: 351340 Change-Id: Ifb2a9405b8f445a90277d2fade9ab33f5becbd6e Signed-off-by: Ravishangar Kalyanam commit 0f0000abcba6f99593dab94ca869c3d865a73e29 Author: Padmanabhan Komanduru Date: Thu Apr 12 10:23:02 2012 +0530 msm: display: Backlight control on 8x25 EVB for qHD panel Add support for backlight control on 8x25 EVB for qHD panel Change-Id: I488786b45b844df776952fed4d23b9a4fb337107 Signed-off-by: Padmanabhan Komanduru commit 5479cc16a03c6b791daa5eac8f45018ea873cfc1 Author: Aravind Venkateswaran Date: Fri Mar 16 15:40:40 2012 -0700 msm_fb: HDMI: Enhance EDID Parser to read supported 3D formats EDID Vendor Specific Data Block (VSDB) contains information regarding all the 3D video formats that are supported by a sink. This change enhances the EDID parser to read this data. Change-Id: I61ca8adbff8f4662e437bab42786149c39ea78da Signed-off-by: Aravind Venkateswaran commit 8b25b2a0b5910befcf0668dc76294f83dccc080f Author: Aravind Venkateswaran Date: Thu Apr 12 14:19:12 2012 -0700 msm_fb: HDMI: Fix EDID parsing logic for multiple data blocks This change fixes a bug in EDID parsing logic when there are more than one data blocks of the same type in the EDID data. With this change, the starting offset used to scan for the next data block, is computed correctly. Change-Id: I5d09fe61be9f7c749197991f54e430ae3aaddbcb Signed-off-by: Aravind Venkateswaran commit 45ce501383ee71df0072b4e5426f9daa7941636a Author: Huaibin Yang Date: Mon Apr 9 11:19:07 2012 -0700 msm_fb: display: add mixer1 writeback buf init call mdp4_init_writeback_buf call is missing for mixer1 interface. And blt_addr should be nulled when dtv interface is initialized, otherwise, mixer1 writeback mode may be false enabled which causes system crashes or garbage display on TV. Change-Id: Idbf5fe90eb50f0a68b434f2c76012c64a38553a4 Signed-off-by: Huaibin Yang commit 7b8b64075ee4b61c15e28f3042672b26674e0b45 Author: Carl Vanderlip Date: Thu Mar 1 10:58:03 2012 -0800 video: msm: Add Histogram collection framework for MDP blocks Expand the previous histogram collection implementation to support the addition of other MDP blocks that allow for histogram data collection. Support the VG1, VG2, DMA-P, and DMA-S histograms using this new framework (VG pipes only supplying the histogram of luminance). Change-Id: I94088c1f714fa5d91256ae7b0f5548f8a0b81763 Signed-off-by: Carl Vanderlip commit 20582a5cf3fad8e9fda7ded6478ed8a32b376b97 Author: Carl Vanderlip Date: Wed Apr 11 10:57:22 2012 -0700 video: msm: Remove an ifndef from mdp_isr Remove ifndef so later patch does not require adding more ifndefs. Change-Id: Ia06e844f42086ad76019f66b575ed78a40ebafc4 Signed-off-by: Carl Vanderlip commit 65fe6e713f7ca6b662c2cf4ce7335e22ca371118 Author: Carl Vanderlip Date: Thu Apr 5 19:09:40 2012 -0700 video: msm: PCC/GC config register protection PCC/GC configuration registers are shared with other features. This patch makes sure that the other features implementations don't overwrite the existing settings for PCC/GC. CRs-Fixed: 345395 Change-Id: I5467a4c50eae214181d67a7976eee92c0ae26fe5 Signed-off-by: Carl Vanderlip commit 97e2fcf862d913feff157f536ee14cfc5f3197f7 Author: Ajay Singh Parmar Date: Tue Apr 10 14:11:22 2012 +0530 msm_fb: hdmi: Disable 1.1_FEATURE Some displays support Enhanced Link Verfications(1.1_FEATURE) which makes HDMI Tx to verify Pj on every 16th frame. Three consecutive Pj mismatch will result in HDCP authentication failure. If 1.1_FEATURE is supported(this can be detected by reading BCAPS), it needs to be enabled by writing into AInfo of display. Default is disbaled. This change sets HDMI Tx core to disable 1.1_FEATURE by default so that we don't see Pj mismatch error unless the feature is enabled. CRs-fixed: 348752 Change-Id: I996f60b852a7e867e8e13e700beecbac8190a59e Signed-off-by: Ajay Singh Parmar commit b52a25139f7b14bb3b9e052d1af3def2fff5d25d Author: Ravishangar Kalyanam Date: Tue Apr 10 18:27:23 2012 -0700 msm_fb: display: Fix HDMI as primary issue with continuous splash support Fix HDMI as primary boot failure with continuous splash support by resetting MDP hardware and disabling splash feature flag in board data Avoid flickering issue for HDMI as primary display with composition bypass updates Change-Id: I9620062f10b24072ea23b7e712e24aba533f044b Signed-off-by: Ravishangar Kalyanam commit 6b7005caf369caf819c1bc3e29a633893b9ebcc4 Author: Ravishangar Kalyanam Date: Fri Apr 6 18:58:44 2012 -0700 msm_fb: display: Allocate writeback buffers of panel resolution sizes Allocate MDP writeback buffers based on panel resolution size dynamically Signed-off-by: Ravishangar Kalyanam Change-Id: I4a456199a05850f35c204edfa7ae3679036138a9 commit 8c23e070b04aa6160681203bf431db60eb7e2e9a Author: Jeevan Shriram Date: Wed Mar 14 11:35:49 2012 +0530 msm_fb: display: Enable 32bpp framebuffer format. Enable 32bpp framebuffer format for 7x27a and 8x25. Change-Id: I38deabca45ea849710bd2edb2b6847c5309a0c9e Signed-off-by: Jeevan Shriram commit 2e931122a4bab690ed345730d7733904eb97d5b8 Author: Padmanabhan Komanduru Date: Wed Apr 11 11:05:39 2012 +0530 msm: display: Reset BG_alpha register while alpha blending Reset BG_alpha register when pre-multiplied alpha is not set for a layer during blit request. CRs-fixed: 351158 Change-Id: If103af384d59c3349cb2ef556a497c709d9280a2 Signed-off-by: Padmanabhan Komanduru commit 1b064f5e1e5a7426fad6ab8ada8e47dbb091937e Author: Ravishangar Kalyanam Date: Thu Mar 15 18:17:54 2012 -0700 msm: display: Add device pointer with clk_get for retrieving clocks clk_get requires device pointer to return appropriate clocks for display subsystem. Rename the names of display related clocks in the lookup table based on functionality. CRs-Fixed: 336925 Change-Id: I784bc4e650d779d1422a9ff1b9a75e36d669e551 Signed-off-by: Ravishangar Kalyanam commit 59e7b0e47eaee57850157361f31c230b3e1c8a8f Author: Carl Vanderlip Date: Fri Apr 6 15:51:44 2012 -0700 video: msm: Allow PCC/GC to be disabled/select bins Current implementation would not set enable/disable bits to PCC/GC nor be able to select the zero'th bin after selecting the first. Change-Id: I0f52beb8914cdaecbabe913455c00fb9ea6100db Signed-off-by: Carl Vanderlip commit fff7a7d207a8791a68706bf8fac3838884981204 Author: Aravind Venkateswaran Date: Fri Mar 16 15:27:19 2012 -0700 msm_fb: HDMI: Enable SPD InfoFrame transmission Sinks use the information in the SPD InfoFrame to get the vendor name and the product information of the source device. This change adds the ability to specify this information and transmit the data as part of the SPD InfoFrame. Change-Id: Iff3db2e21cc30cdcc18787de5fd83c6a0790794e Signed-off-by: Aravind Venkateswaran commit b64b8dee8c93cb806a906440ef8a4aa72486df75 Author: Mayank Chopra Date: Tue Apr 3 23:04:35 2012 +0530 msm_fb: display: Unstage mixer staging on next commit for video use case Unstage of mixer occurs on single vsync. For video playback case on 8660 it is observed that sometime unstage does not complete due to which flicker is seen during unset. Unstage of mixer is now done on next commit only for video use case to avoid flicker. Change-Id: I4939148989d49b3190142f858a40d2cf7617c7ba Signed-off-by: Mayank Chopra commit bea9c06d44800da4c7cbc75e25731a75bd9f84ae Author: Padmanabhan Komanduru Date: Mon Apr 9 10:33:48 2012 +0530 Revert "Revert "msm: display: Backlight control on 8x25 EVB"" Enable backlight control on 8x25 EVB for WVGA panel. This reverts commit 75cf6b84b36b054cb7b8074af165cb082112c7d7. CRs-fixed: 339158 Change-Id: Ice8426442c9d82a7316dfd4d812e9f6301a97850 Signed-off-by: Padmanabhan Komanduru commit c55856c548e0cec8b29e415a08a353a0ab1ac4c8 Author: Alhad Purnapatre Date: Tue Feb 28 13:24:57 2012 -0800 msm_fb: display: MSM V4l2 video overlay driver Provides a V4L2 device that uses the MDP overlay pipes (on MDP4), or the PPP interface (MDP3) to overlay frames on top of display framebuffer. Signed-off-by: Alhad Purnapatre Change-Id: Iab69d0a5acfe993d13cb7a585e292b9a87eb90ee commit aabbf2b21c415c226b680df7ee61b565f47d8603 Author: Ajay Singh Parmar Date: Wed Mar 7 10:50:19 2012 +0530 msm_fb: hdmi: CEC re-transmission improvements. Adding some improvements to HDMI CEC code flow to reduce the risk of system crash and compliance failure by proper CEC resiters settings and positions in code flow. CRs-fixed: 336541 Change-Id: I8fb3510190e5c4ff83b3785c51bade139f20692c Signed-off-by: Ajay Singh Parmar commit 6fdf4becd5fe50e52d587d35d1ee047385351f83 Author: Ravishangar Kalyanam Date: Fri Mar 30 18:34:05 2012 -0700 msm_fb: display: Create hdmi_as_primary node for boot parameter case Create hdmi_as_primary node for both boot parameter and compile-time cases when HDMI is set as primary display Change-Id: Ib170637e3792477e46ae0fb6044b298bf8de875c Signed-off-by: Ravishangar Kalyanam commit f0bd4cd4ca4114298fba41f18db9babe0533e075 Author: Zhang Chang Ken Date: Sat Mar 31 14:35:50 2012 -0400 msm_fb: display: Epson ebi2 panel support Support fb with ebi2 only(without mdp) Add Epson ebi2 qvga panel support Change-Id: If61b2c522a102133f98f27b21dcc18d057b7ef25 Signed-off-by: Zhang Chang Ken commit 226b429d026195ff93b7de8066d8943b58dc65a5 Author: Aravind Venkateswaran Date: Fri Mar 16 15:35:31 2012 -0700 msm_fb: HDMI: Enhance EDID parser to read physical address This change adds the support for reading the physical address field in Vendor Specific Data Block (VSDB) of the EDID data of a sink. Change-Id: I435705a7709ea26cff71121a2c37fd630b267ae5 Signed-off-by: Aravind Venkateswaran commit d89c0e7712dd5cf13769b4d0facfecb93028538c Author: Carl Vanderlip Date: Wed Mar 28 10:17:20 2012 -0700 video: msm: Load correct default values to QSEED at init The previous QSEED Table 1 values are not suitable values (would end up smoothing and sharpening content which can lead to artifacts). The values loaded by this patch are the suggested default values for QSEED since they do not smooth or sharpen most content (bi-cubic filter), but will slightly smooth low frequency components of the image (i.e. helps reduce artifacts that produce sharp edges on content that is supposed to be a constant color; often introduced by some video encoding algorithms). Change-Id: Ic4c0ca4719141bf52123ad239fcca5d3767a2c2b Signed-off-by: Carl Vanderlip commit 5066a5f662d0d88ad4c94158fe392bb0fbd61cb4 Author: Aravind Venkateswaran Date: Fri Mar 16 15:29:32 2012 -0700 msm_fb: HDMI: Support VCDB parsing of EDID data This change enhances the EDID parser to read the Video Capability Data Block (VCDB) in order to check whether a sink supports underscan mode. Change-Id: Id4e48db4ff7f54fd72d40a413e2f03b692b662c1 Signed-off-by: Aravind Venkateswaran commit 6e73f0a25171e3e5d2d520da99a02f74c5646592 Author: Chandan Uddaraju Date: Thu Mar 8 17:32:55 2012 -0800 msm: Display: Add support for backlight control on 8930 chipset. Register the PMIC WLED trigger driver to control the backlight level on 8930 chipset. CRs-fixed: 339310 Change-Id: Ia73625cfeaa18f2515c81a4c128f98f9fb5c0b32 Signed-off-by: Chandan Uddaraju commit b7c45f42b50b609bb632a0f1f1b2e404af38329a Author: Ajay Singh Parmar Date: Tue Apr 3 11:39:39 2012 +0530 msm_fb: display: Enable pre-multiplied alpha for MDP303 For images which are pre-multiplied with alpha, driver support is now added to blend them properly. CRs-fixed: 347803 Change-Id: I859c26c5f52fa0886c106928ef338bd9d0db4462 Signed-off-by: Ajay Singh Parmar commit 18e249a842a459c14624354f00ef3434d3b6c643 Author: Stephen Boyd Date: Tue Feb 21 01:10:56 2012 -0800 msm_fb: lvds: Fix uninitialized variable warnings The compiler doesn't know that there are only two values for mfd->panel_info.bpp. Add an else arm to catch the unknown third value as a BUG() so that we avoid writing initialized variables to registers. Change-Id: I643df7e256cda59a4af73571e1cc5eef610d781f Signed-off-by: Stephen Boyd commit 2d19103b77ae63fe127304b9c3ceeb1f399c756a Author: Olav Haugan Date: Tue Feb 28 09:46:31 2012 -0800 msm: Enable all IOMMU's Enable video, camera, display, and rotator IOMMU's so that virtual contigious memory can be used by these devices. Physical contigious carveout regions can be reduced so that more memory is available to the rest of the system when not in use by multimedia. Change-Id: Ibfad7d6a55e04490be9e39a5539780657f6727e0 Signed-off-by: Olav Haugan commit 70b866b2ca1d92ee632b5f3eb591d7ae09fab492 Author: Aravind Venkateswaran Date: Tue Mar 27 14:50:25 2012 -0700 msm_fb: HDMI: Disable HDCP interrupts when starting deauthentication All HDCP interrupts should be disabled at the beginning of HDCP deauthentication process so that we do not process any redundant HDCP failure interrupts while deauthentication is underway. Change-Id: Ib5149460446b6073122a8249807918d5ad06492c CRs-Fixed: 341921 Signed-off-by: Aravind Venkateswaran commit 92e58bb7966bbaf8b4c73bf98a5d55dde9980b37 Author: Adrian Salido-Moreno Date: Tue Mar 6 13:49:19 2012 -0800 msm_fb: display: flush base layer pipe when solid fill is enabled Need to flush bgpipe with solid fill format to avoid fetching from bg pipe when its contents are not displayed. Also add other missing flushes. CRs-Fixed: 342961 Change-Id: I03e517e02c02d9abc26fd9365e7b67025fa59657 Signed-off-by: Adrian Salido-Moreno commit c0852b7c3a9d08f8d80ad2bb01316f7252f23ced Author: Adrian Salido-Moreno Date: Tue Mar 6 13:49:19 2012 -0800 msm_fb: display: perform data flush for each data path separately Performing data flush on stage commit causes some frame updates to be missed waiting for stage commit, this can lead to old data being overwritten while it's being displayed causing visible corruption. Change flush to happen on each frame update to avoid corruptions. CRs-Fixed: 341597 Change-Id: If91800068d2bfd5a2e43fe3e2a96c457e173763d Signed-off-by: Adrian Salido-Moreno commit d46e8d072e432c19eec0e7a2b04a9b6967906242 Author: Huaibin Yang Date: Tue Mar 27 16:22:11 2012 -0700 msm_fb: display: remove #if 0 Cleanup all #if 0s in display driver. Change-Id: I32473b33ad4dff3e5d3d91aae42d70955836cd52 Signed-off-by: Huaibin Yang commit aabb74cb030c086ca67f51b3d56deb678d4f040a Author: Mayank Chopra Date: Thu Mar 15 14:25:32 2012 +0530 msm_fb: display: Enable mixer1 writeback for video downscale use cases Underrun occurs while downscaling video data on 8x60. Enable writeback if video downscale is required. CRs-fixed: 329630 Change-Id: Ief4b002efd6f4ad9fcfd844325c05de619d47719 Signed-off-by: Mayank Chopra commit 07c82d6ca63c6be28ab897fdb3ccfc1a448c342f Author: Jeevan Shriram Date: Mon Apr 2 10:20:48 2012 +0530 msm_fb: display: Assign proper destination rectangles to mdp blit Add check for (90 + Flip Horizontal) and Flip Vertical cases to assign proper destination rectangle parameters to avoid corrupted frame buffer content. CRs-Fixed: 344807 Change-Id: I7e7b0b8d26f08f63a6f9c55eedd37f31cf0348d7 Signed-off-by: Jeevan Shriram commit fd0df3ccda02dd1fad680735333bea7ac025abc5 Author: Zhang Chang Ken Date: Fri Mar 30 17:03:51 2012 -0400 msm_fb:display: add display support for mdm platform add setting for no mdp hw case add ebi2 epson qvga panel setting Change-Id: I91b9ef1890a66eb95c14f8a393b89baa757904a5 Signed-off-by: Zhang Chang Ken commit 687b109b5f46caf68efde0a1c3a1084a5576a997 Author: Pradeep Jilagam Date: Sat Mar 31 15:45:21 2012 +0530 msm_fb : display : Add 60fps support for NT35516 qHD panel This change adds the required support for 60fps using h/w vsync in Command mode on NT35516 DSI Client. Panel Init comamnd has been modified accordingly. Also, since the panel gives 59 to 61 TE signals per second, refx100 has also been modified to indicate the maximum possible refresh rate with this panel. This will ensure smooth operation of DMA Tear Check algorithm. Change-Id: Ib2c03e61509946b7929c3cd21b497a972359fee3 Signed-off-by: Pradeep Jilagam commit ff6bfa8e6f2a62ebb19aabd9ed499ee7efa0e006 Author: Ravishangar Kalyanam Date: Fri Mar 23 17:48:47 2012 -0700 msm: display: Attach MDP IOMMU during first update after boot For continuous splash support to work properly, attach the MDP IOMMU device at a later point during boot to allow display use the splash image from bootloader Signed-off-by: Ravishangar Kalyanam Change-Id: Ife9a2afae1e9b9140ee74af0cc7dcf7ad945d4de commit 3ef84a5ab70bbd65799dbf72b3375b0bc764140d Author: Chandan Uddaraju Date: Thu Mar 22 22:14:41 2012 -0700 msm: Display: Fix reference count for DSI clocks for DSI command mode. For MIPI DSI command mode panels, clock enable for DSI clocks is called more than needed. Fix the reference count for these clocks to turn off the clocks during suspend state. Change-Id: Ife061eec6af9f5fb106bfaf608e222fabec1e9dc CRs-fixed: 339125 Signed-off-by: Chandan Uddaraju commit 75cf6b84b36b054cb7b8074af165cb082112c7d7 Author: Padmanabhan Komanduru Date: Fri Mar 30 15:04:52 2012 +0530 Revert "msm: display: Backlight control on 8x25 EVB" Waiting for the vendor approval/permission letter. This reverts commit 224d5fa264c38a529fc41f5cfd0ed2792181fcbd. Change-Id: I83e45776c37ea08c6daf0a529c411e67bd5a7719 Signed-off-by: Padmanabhan Komanduru commit d85b55446992dd36bb9b8ee56f7e95be97278425 Author: Aravind Venkateswaran Date: Mon Mar 26 15:59:58 2012 -0700 msm_fb: HDMI: Fix bug in mutex handling The code for HDCP authenticaton has a bug where a mutex is not freed when the code follows an error path. This change fixes this issue by correctly handling the mutex. Change-Id: I4b141a313830cc09e11a5db4b8e464fa4439efd6 CRs-Fixed: 341922 Signed-off-by: Aravind Venkateswaran commit 5b5f2188eb7f6c774b435263284f6179cb35c508 Author: Mayank Chopra Date: Wed Mar 21 13:43:55 2012 +0530 msm_fb: display: Unstage pipe from Mixer0 H/W on each unset call for 8660 During unset call, mixer0 staging is cleared using stage down logic which makes the staging update to happen in next vsync for 8660 platforms. Clearing of mixer0 stage now is done on a single vsync for 8660 as well. Change-Id: Ib6b11728944be89ee6ba5b5d58c470c05cb9f41b Signed-off-by: Mayank Chopra commit 6bc448aefa897a1e08a6c817280809afc189faa7 Author: Ravishangar Kalyanam Date: Wed Mar 14 11:31:52 2012 -0700 msm_fb: display: Add IOMMU support to MDP and rotator driver Add IOMMU support to MDP and rotator driver for operating with virtual addresses instead of physical addresses Change-Id: Ia5afcf33220e0e75e92948649c2bd4d7ef32917d Signed-off-by: Ravishangar Kalyanam commit 87260cdaef95054474e97fab85e3fb691f03a035 Author: Ravishangar Kalyanam Date: Mon Mar 26 12:00:45 2012 -0700 msm_fb: display: Wait for external vsync before turning off DTV Wait for external vsync interrupt before turning off the timing generator for DTV display CRs-Fixed: 341400 Change-Id: Ibd380f8e20a7ebb250669fcabf4233e9e526d22f Signed-off-by: Ravishangar Kalyanam commit 4a9d3382873adb7aecab07345f3d253eefd150cb Author: Ravishangar Kalyanam Date: Mon Mar 19 16:10:42 2012 -0700 msm_fb: display: Enable timing generator during first update During first display update through pan_display or overlay_play, enable the timing generator for pull modes like LCDC, DSI Video and DTV interfaces Change-Id: Icec5b28f0df04a1223119222a1aad5129111f676 Signed-off-by: Ravishangar Kalyanam commit 2aa111c008157070e871aa5788e9c3664935847a Author: Jeevan Shriram Date: Tue Mar 20 11:58:44 2012 +0530 msm_fb: display: Initialize work queue for MIPI command mode panels Initialize workqueue for MIPI command mode panels for s/w refresher mechanism to work in x-window type architectures. Change-Id: Id67c54452aa0b02a39f480709fc4bcd6c7bde2eb Signed-off-by: Jeevan Shriram commit 224d5fa264c38a529fc41f5cfd0ed2792181fcbd Author: Padmanabhan Komanduru Date: Tue Mar 6 18:23:50 2012 +0530 msm: display: Backlight control on 8x25 EVB Enable backlight control on 8x25 EVB for WVGA panel. Change-Id: Ib293440829c39e2230cc5a288037e2d5d7806dc3 Signed-off-by: Padmanabhan Komanduru commit 14e8c40443d2c2891c232c2becda9073a1a44186 Author: Chandan Uddaraju Date: Mon Mar 5 14:57:09 2012 -0800 msm: Display: Fix the reference count for MDP and DSI clocks The clk_enable() call for MDP and DSI clocks are called more than necessary. These clocks were not turning off during suspend mode for "continuous Splash screen feature" and dtv. Fix this by calling clk_disable() functions whereever needed. Change-Id: I05469ad08497bead6171478413623da15fe49182 Signed-off-by: Chandan Uddaraju commit 042cd63a1b7674feaf70e41a44550678ae338bbc Author: Chandan Uddaraju Date: Thu Jan 19 12:51:37 2012 -0800 msm: Display: Add support for "Continuous Splash Screen" feature. The image displayed on the screen by the android bootloader driver should continue till the android animation shows up. Delay the display initialization for MDP, display dependent clocks and panel power on functions. Change-Id: Iaec53879def6f4a9d2f6b7b8090f572e64e55d87 Signed-off-by: Kuogee Hsieh Signed-off-by: Chandan Uddaraju commit 033ee132dd50dfb4ca11f8c87d1a3f1c988b0a74 Author: Jeevan Shriram Date: Tue Feb 28 12:24:39 2012 +0530 msm_fb: display: Report correct fps to user space There are only 30 pan updates per second due to MDDI Type 1 interface bandwidth limitation. Hence, 30 fps needs to reported to user space for MDDI Type 1 Panels though the panel refreshes at 60Hz. Make change to all type 1 panels to report only 30 fps to userspace. CRs-fixed: 330584 Change-Id: I07784060ef7a3f37ac13cdecf8138afb6c27ee51 Signed-off-by: Jeevan Shriram commit a3b168b4d1f6b32f17a3498940cf198fdfba0722 Author: Ravishangar Kalyanam Date: Mon Mar 26 11:13:11 2012 -0700 msm: display: Add proper flags for secure/non-secure writeback buffers For MDP writeback buffer allocations, use appropriate heap id flags for secure and non-secure sessions Change-Id: I05e897d5d90ab03b17ccddbda764f39b963192ef Signed-off-by: Ravishangar Kalyanam commit e350d9bcee496c06f79a6490f108f77ed73f66e3 Author: Kuogee Hsieh Date: Mon Mar 26 08:29:54 2012 -0700 msm_fb: display: fix dsi_irq race condition There has race condition that mipi_dsi_disable_irq_nosync() is called from isr context at one core while mipi_dsi_irq_enable() is called from thread context at other core. Serialize mipi_dsi_disable_irq_nosync() with mipi_dsi_irq_enable() by putting mipi_dsi_disable_irq_nosync() inside scope of spin_lock(&dsi_mdp_lock). CRs-fixed: 345837 Change-Id: Ibd2ff3194890b671983142fdb7b5a62cc009cae2 Signed-off-by: Kuogee Hsieh commit 28338aebe08832ba8a01c28b290615d60c023128 Author: Ravishangar Kalyanam Date: Mon Mar 26 13:31:28 2012 -0700 msm_fb: display: Call footswitch control from overlay dtv on/off Instead of dtv on and off, call footswitch control during overlay dtv timing generator on and off calls Change-Id: Iffe47e12ce99e1fc7a080daef7b220c4f010ccda Signed-off-by: Ravishangar Kalyanam commit 8d3b0fce866e5f05f18a47bc0cd8f60356dbeb23 Author: Adrian Salido-Moreno Date: Wed Mar 14 20:18:30 2012 -0700 msm_fb: display: fix underrun when conecting wifi display When connecting wifi display underrun can happen if there is no frame update in other mixers before pipe in mixer2 is staged up. Add logic to make sure that any pipes that are going to be staged up to mixer2 are staged down from other mixers first. Change-Id: I84ce8d0fcd392639d470ba4161be36212bcefce1 Signed-off-by: Adrian Salido-Moreno commit 88ad8a7be06a86104169cf2739c18c7d4409dde6 Author: Ajay Singh Parmar Date: Wed Mar 14 14:19:18 2012 +0530 msm_fb: display: HDMI power reduction at suspend During suspend, HDMI clocks are still running and power consumption is high. Usually HPD module is kept on even when the cable is not connected to sense the cable re-connect. But cable connect sense is not required when the device is suspended. This change makes sure that HPD, along with other HDMI modules, are totally shutdown during suspend and there is no power consumption by HDMI. CRs-fixed: 335821 Change-Id: I90c6ec6ca99a9396609028fda9f1768324e7d3da Signed-off-by: Ajay Singh Parmar commit a1f9df15e005241ecf23069f7d345f9a943c06ef Author: Jeevan Shriram Date: Fri Mar 9 19:48:18 2012 +0530 msm_fb: display: Add panel driver for Truly IPS3P2335 client Add panel driver for TRULY IPS3P2335 client Change-Id: Ibf37f7c292593898e237329f3021f1eed8f8728d Signed-off-by: Jeevan Shriram commit 56dfb682a5bf274842140716333c791d010e38ef Author: Ajay Singh Parmar Date: Wed Mar 21 16:23:54 2012 +0530 msm_fb: hdmi: HDMI high sleep current High current is observed during sleep. HDMI PHY needs to be reset before going into sleep. CRs-fixed: 336972 Change-Id: If79f1fb5bcb88d649b2545362eb853d3699e41bf Signed-off-by: Ajay Singh Parmar commit 16f27dc68e406e181c306cc1fb924dca43fb1080 Author: Deva Ramasubramanian Date: Wed Mar 7 17:04:24 2012 -0800 video: msm: writeback: Stop providing buffers to mdp in stopping state After writeback_stop() is called, we continue providing buffers to mdp until the free queue is completely exhausted. However, client can deallocate buffers immediately after writeback_stop() is called, this will trigger page faults from mdp accessing invalid buffers. Change-Id: Ibe3c8435a5f84eeb61b92ec3277f0dc27f008b02 Signed-off-by: Deva Ramasubramanian commit fa530308e1fa485a39e35ed17879b6ab1e665c37 Author: Ravishangar Kalyanam Date: Mon Mar 12 15:03:10 2012 -0700 msm_fb: display: Remove base layer for DSI command mode during suspend Remove RGB base layer pipe for DSI command mode during suspend to unstage all pipes in Mixer 0 properly CRs-Fixed: 343233 Change-Id: Icce46ad0969536ed9819d10c0e7e01c63aed147d Signed-off-by: Ravishangar Kalyanam commit 5c1fa46367d021fc3e457df2bf5b6331c41ad189 Author: Pravin Tamkhane Date: Wed Mar 7 17:49:09 2012 -0800 msm_fb: Handle flags for updating AR GC lookup table (LUT) In current implementation of area reduced gamma correction (AR-GC) LUT configuration,flags for read/write AR-GC LUT and enable/disable AR-GC LUT functionality are not handled even though the IOCTL accepts these flags as part of arguments. So in current implementation by default updates the AR-GC LUT which may not be expected always. So, handle flags for read/write AR-GC LUT and enable/disable updating area reduced gamma correction (AR GC) functionality Change-Id: Idd19dd86ec2b8a4b6f22674e522b2f7e06fb63fc Signed-off-by: Pravin Tamkhane commit 225152437092241cb3f6ff5b97896684d856f844 Author: Pravin Tamkhane Date: Thu Mar 1 17:45:52 2012 -0800 msm_fb: Restructure PCC and AR-GC code for clean implementation Current PCC & AR-GC implementation uses macros for base addresses, while other post processing features use mdp_block2base() function. Also, in current implementation check for feature supported for MDP version in device is not performed, currently function which implements AR-GC, is named as mdp4_pgc_cfg() which is bit misnomer. This change uses uniform method for calculating block base using mdp_block2base(). For checking MDP version and feature supported using mdp_pp_block2pcc() and mdp_pp_block2argc() functions. This change also renames mdp4_pgc_cfg() to mdp4_argc_cfg() to correctly indicate the functionality it implements. Change-Id: I99a9948c987e3270c246aa44e569f94e35026c2f Signed-off-by: Pravin Tamkhane commit 917ed6837ea5a43fe61b39ba0b966ae642fd9c4d Author: Huaibin Yang Date: Mon Mar 12 14:55:04 2012 -0700 msm_fb: display: disable mdp flip when enabling mdp solid fill If both solid fill and flip mode are enabled, MDP underruns. So for any pipe, if solid fill bit is set, flip operation modes including left/right or/and up/done are disabled. CRs-fixed: 334782 Change-Id: I879231d03c6aab6f82d80bde65c9f01c34f1fa6c Signed-off-by: Huaibin Yang commit 2bd101d5bed1729b317114456360605e86289c15 Author: Padmanabhan Komanduru Date: Fri Mar 16 11:32:23 2012 +0530 msm_fb: Clean up the fix for error in y-offset check in FB driver There is a failure observed in yres_virtual offset check and every third frame gets skipped without an error message. Due to this high fps is noticed in the test applications. Correct the yres_virtual offset check. Change-Id: Iddce0b75e0a9c466adad6eb5726203ae0586c27b Signed-off-by: Padmanabhan Komanduru commit 56daa2d8864d4de16d131b943af5f5fb3ce50b24 Author: Mayank Chopra Date: Mon Mar 12 19:43:41 2012 +0530 msm_fb: display: Change perf level for VGA video Change perf level to 3 from 4 for VGA and less resolution video usecases. This avoids underruns seen with camera/camcorder usecases on 8660 and older platforms. CRs-fixed: 338044 Change-Id: I12fa81f10dc6d02caed44c5b7e6f5732a57bb095 Signed-off-by: Mayank Chopra commit 60b26064afb48a5f82c2d0a0a135e0a63d32910c Author: Ajay Singh Parmar Date: Thu Mar 15 14:40:11 2012 +0530 msm_fb: hdmi: CEC Message queue flush CEC message queue should be flushed when CEC function is enabled. If there are residue CEC message, they might cause collision at message queue. CRs-fixed: 338811 Change-Id: I6268528417d660fab48818ae67e94e169abbb217 Signed-off-by: Ajay Singh Parmar commit a950365ed12ab0d66367b06bd1c3236cbcf695a1 Author: Kuogee Hsieh Date: Mon Mar 12 16:17:23 2012 -0700 msm_fb: display: check dtv_pipe before unset it Dtv_pipe is the base layer pipe for HDMI and it is normally populated before overlay_unset() called to free a mdp pipe. However at wireless application, there has possibility that overlay_unset() is called to free a pipe even before dtv_pipe is populated which cause system crashed. Therefore check dtv_pipe before free fore ground pipe. CRs-fixed: 340884 Change-Id: I32b69e937f21646204c7fd7275988ee12e439655 Signed-off-by: Kuogee Hsieh commit e5c9f6e5f9fe550e228cc5b34dbde086b151a613 Author: Huaibin Yang Date: Wed Feb 22 15:09:07 2012 -0800 msm_fb: display: initialize is_flag variable This local variable needs to have init value, otherwize it is always true, possible for mdp4_overlay_perf_level to return incorrect value. CRs-fixed: 338543 Change-Id: Icbb665773545e866c7f48edaf3ecf11272713d19 Signed-off-by: Huaibin Yang commit 0473d05091f0df4d85e4f6a162f55a9af8d3307b Author: Padmanabhan Komanduru Date: Tue Feb 21 12:00:12 2012 +0530 msm_fb: Clean up of frame buffer 4KB alignment changes Remove redundant code from the 4 KB alignment patch and reduce the overhead of calculation of the hole size by using bitwise operators in its calculation. CRs-fixed: 325134 Change-Id: Ie2e3ea7cbb2a815ae4f50cb97e6c5be1bd72fe27 Signed-off-by: Padmanabhan Komanduru commit 9d76704c8dac8f9e0794834cc4d62c17fd9cdf63 Author: Kuogee Hsieh Date: Fri Feb 10 08:40:51 2012 -0800 msm_fb: display: clean dsi fifo during dsi_off During suspend, wait until dsi controller's fifo is cleaned before disabling dsi controller. This will prevent pixels that were left over in the fifo from being displayed during next resume. CRs-fixed: 336049 Change-Id: If5b80d0c3a9b5edd21ae6651321572c2fdcac951 Signed-off-by: Kuogee Hsieh commit 0507c8cefa525a89df9b9e2a305e2bd7c4f6d7b2 Author: Aravind Venkateswaran Date: Thu Feb 16 17:16:05 2012 -0800 msm_fb: HDMI: Add support for HDMI on APQ8064 Configure necessary PMIC regulators, GPIO, clocks and parameters related to external display to enable HDMI on APQ8064 target. Change-Id: Ia2741fc13c6a640ebc610461ad4242929383b611 Signed-off-by: Aravind Venkateswaran commit 5245ec886f6e282b8f3c1b0e3f7aecbfae9ed85a Author: Huaibin Yang Date: Fri Mar 2 13:49:53 2012 -0800 msm_fb: display: change pixel sequence on lvds lanes This is a s/w workaround to fix lvds phy h/w bug. On the rising edge of lvds phy clk the phy transimits d0d1..d6 sequence, however, lvds panel from the manufacture expects d6d5d0...d4. So s/w adjusts the sequence on the phy side to meet panel spec. CRs-fixed: 338715 Change-Id: If852ba29954b363911d04cd08d3784ce7d385c2f Signed-off-by: Huaibin Yang commit 416878307740e2d475511ed0f12ebbd50db8c156 Author: Pradeep Jilagam Date: Wed Feb 22 09:15:28 2012 +0530 msm_fb : display : Add support for NT35516 qHD panel This change adds the drivers for NT35516 DSI Client and Truly qHD panel. Change-Id: Ifb7e02300a8e42d7097845638b77e311e92f69d6 Signed-off-by: Pradeep Jilagam commit d37b52404236bf4cadf530a238cafc5d6499d32a Author: Padmanabhan Komanduru Date: Fri Mar 9 20:16:21 2012 +0530 msm_fb: Fix error in y-offset check logic in FB driver After 4 KB alignment changes, the frame from 3rd buffer doesn't get updated since during PUT_VSCREEN_INFO ioctl, the driver returns -1 to userspace due to error in logic because the hole size is not considered in calculating the logic for validity of the y-offset. Change fixes this error. Change-Id: Ib151970eacab4df36fb8274be0079bc814e93efe Signed-off-by: Padmanabhan Komanduru commit fff132dffafe129620475a51c34309b4fff08dce Author: Aravind Venkateswaran Date: Wed Mar 7 13:22:30 2012 -0800 msm_fb: HDMI: Enable HDMI on 8930 target Register HDMI device and enable HDMI driver initialization for 8930 target. Change-Id: Ia3d1f0963de079e7af3cd683a498897cd677e97a Signed-off-by: Aravind Venkateswaran commit fd3a0274fc30e8f795365e8cd8c90d2b0b3df2d7 Author: Chandan Uddaraju Date: Mon Sep 26 17:29:37 2011 -0700 msm_fb: display: Add MIPI DSI 720P Orise panel driver support Add support to run 720p MIPI DSI Orise panel in both cmd and video modes Change-Id: Iefd5594ba2fafe7797378f3297d169ebbce9b963 Signed-off-by: Chandan Uddaraju commit a6f72edcca16dbed1e345fe472df32f08f5548ca Author: Chandan Uddaraju Date: Fri Mar 2 16:51:57 2012 -0800 msm_fb: Display: Change the VCO frequency range for 8960. The DSI PHY PLL is not stable for VCO frequency between 500 MHz to 600 MHz on 8960. Fix this issue by changing the VCO range from 500 Mhz - 1 GHz range to 600 MHz - 1.2 GHz range. CRs-fixed: 340956 Change-Id: If09ac96455e16c5c2ca219c74e7ee0c758d55851 Signed-off-by: Chandan Uddaraju commit 0bb7fe942f5e655d1ac1b10398ccda73ce83550e Author: Ravishangar Kalyanam Date: Thu Oct 27 16:06:30 2011 -0700 msm_fb: display: Dynamic boot support for HDMI as primary display Move boot parameter to board display file as early_param for proper allocation of PMEM and ION sizes. Change-Id: Icfb163f572e8e010550747ec83787b6da6e86ee2 Signed-off-by: Ravishangar Kalyanam commit beaa9356713db6949eefa32ed329bf87a3461842 Author: Kuogee Hsieh Date: Fri Feb 24 16:59:26 2012 -0800 msm_fb: display: decrease file->f_count when play Frame buffer's (fb0) f_count needed to be decreased after both overlay play and rotation so that fb0 can be closed and display will be blanked out after system suspended. CRs-fixed: 336254 Change-Id: I966e7b2bb4def0c9c09580be12048933723e2c2e Signed-off-by: Kuogee Hsieh commit 8d19d0d22e03dba3b2b08356bc18ed1b2987e70c Author: Kuogee Hsieh Date: Fri Feb 24 12:50:37 2012 -0800 msm_fb: display: call mdp_pipe_ctrl() with correct block name Mdp_pipe_ctrl() needs to be called symmetrically within same block name for both ON and OFF operation so that mdp clock will be turned off after OFF operation. CRs-fixed: 338802 Change-Id: Idda450a32c0c897327c17dda70fc05e9fb74d510 Signed-off-by: Kuogee Hsieh commit a5649bcea56c8aecbf88fb97a2a88d7142f5ca1f Author: Aravind Venkateswaran Date: Wed Dec 7 18:23:32 2011 -0800 msm_fb: HDMI: Fix for HW reset issue on HDCP Reauth On HDCP reauthentication, the HDCP link status register does not get cleared unless the HDMI app clock is deasserted and asserted. Stale values in the link status registers can potentially lead to the HDCP HW block getting locked up resulting in a device reset. Change-Id: I4952c64d4087e4303cbc75dbb61f66510b0a0798 Signed-off-by: Aravind Venkateswaran commit 682888654f146d6c34c76b9db435c9c6fe58eeea Author: Huaibin Yang Date: Wed Jan 18 16:08:55 2012 -0800 msm_fb: display: add overlay1 writeback enable and disable This logic is used to enable mdp overlay1 writeback mode when downscaling in any pipe for mixer1 requires a mdp clk rate more than its max, and disable it when no pipe requires more than max mdp clk rate. CRs-fixed: 330895 Change-Id: I67632fdc2cf4c357753603fee293817bb87581ca Signed-off-by: Huaibin Yang commit 4c7ccb31068e6b606520722279fc8add740d7578 Author: Ajay Singh Parmar Date: Tue Feb 21 12:56:04 2012 +0530 msm_fb: display: Use FIR (QSEED) for upscaling. Low resolution UI is observed on HDTV connected with HDMI. FIR (QSEED) algorithm needs to be used instead of pixel repetition to improve the performance in case the BYPASS composition is not used. CRs-fixed: 332123 Change-Id: Ib4c2b107b4ae1300458cccc7e8066d31aee50a0d Signed-off-by: Ajay Singh Parmar commit 38eac1aef2250181f1a2f9d75529f0961257740b Author: Adrian Salido-Moreno Date: Tue Feb 28 16:24:06 2012 -0800 msm_fb: display: set max clk level when more than 2 pipes used Correct logic to take all pipes into account and increase clk perf level to max when more than 2 pipes are used. Change-Id: Ibe6594e23a95e72c113b98c8f08b33395677d212 Signed-off-by: Adrian Salido-Moreno commit c246a1bd2edbf1607e5437ee46c0f7a043d6bd5d Author: Adrian Salido-Moreno Date: Wed Feb 22 20:38:43 2012 -0800 msm_fb: display: perform bus scaling updates when idle Move bus scaling updates to same place where MDP clock is changed which happens when MDP is idle. This allows MDP sufficient time to finish fetching buffers before commiting unstaging changes. Change-Id: Id6e04522928b0f815091e17054fff94e0e111ff1 Signed-off-by: Adrian Salido-Moreno commit 3e9ca08c34561167db0e7aa7179b224d8e10a1e5 Author: Ravishangar Kalyanam Date: Tue Dec 13 12:14:59 2011 -0800 msm_fb: display: Remove boot parameter parse support Remove boot parameter parse support from framebuffer driver. This is done as a part of moving this to board-display file. Instead of detecting the panel in msm_fb file, the detection is now handled in individual board file. Change-Id: I722cc6964a815bd99b1cf0856ef9c1a4481898d4 Signed-off-by: Ravishangar Kalyanam commit b88ffd3484ecddbfe7a24ae9a8438b0d3792d116 Author: Adrian Salido-Moreno Date: Wed Feb 22 19:42:44 2012 -0800 msm_fb: display: enable unstage caching for command panel Enable support for caching of overlay unsets for command panel to flickers between frame updates. Change-Id: Ide9a165cfddb33a5cd0756b9cd469b0c3374f2ae Signed-off-by: Adrian Salido-Moreno commit d60dff3ca61bbdc6881b9aaf34baea570c25fa32 Author: Adrian Salido-Moreno Date: Fri Feb 10 14:01:09 2012 -0800 msm_fb: display: wait for vsync staging down in overlay unset Need to wait for vsync so registers are properly flushed when commiting stage down changes in overlay unset Change-Id: I56bfdf56c2a32f109f3d9264c8cc4a086ef2c356 Signed-off-by: Adrian Salido-Moreno commit acde4b6510b352b97ca1dc7d3386c6696e8f10fb Author: Carl Vanderlip Date: Fri Dec 16 15:50:56 2011 -0800 video:msm: Add IGC LUT functionality to PP IOCTL This patch adds the functionality to write to the IGC Look Up Tables (LUTs) in the MDP. Change-Id: I4789820a56748b1a5e33ee4ca979e418170695a3 Signed-off-by: Carl Vanderlip commit 330b4ae84d423bee684af24a2e52b4d81831a37f Author: Carl Vanderlip Date: Mon Feb 20 19:24:56 2012 -0800 video:msm: Add support for updating Histogram LUT using MDP_PP ioctl This adds the ability to write to the Histogram LUTs in the VG pipes, DMA_P and DMA_S. Change-Id: I548140d01aee5c2fd437aa218a307b4d1364dade Signed-off-by: Carl Vanderlip commit 14b56ad8f78a974de534aa02523624304983acfc Author: Ajay Singh Parmar Date: Wed Feb 22 14:56:21 2012 +0530 msm_fb: hdmi: check for multiple hpd on/off calls HPD on/off may be called from userspace and from kernel asynchronously which may result in system crash or reset. Returning in case HPD is already on/off. Change-Id: Ic6233925e02e6070e3ebc3fa40a87717e7b2ad1e Signed-off-by: Ajay Singh Parmar commit 6cc11c405ae51f50436f48160faf302b8b29d486 Author: Carl Vanderlip Date: Tue Feb 7 15:25:46 2012 -0800 video:msm: Move histogram reads to workqueue Histogram must be read after each histogram completion in order to clear the histogram registers; this patch reorganizes the histogram code to use a deferred workqueue task to read the histogram registers out of the interrupt context. As well, this re-organizes the histogram start-up to clear, using the same new workqueue, the first histogram that is read because it is often incorrect (too many or too few bins filled). CRs-Fixed: 328214 Change-Id: I4088028fc805113e74b5b763c6458183e75421cf Signed-off-by: Carl Vanderlip commit ff10d072f13a0845fc4e6dc0f82d2f51d9209e6e Author: Carl Vanderlip Date: Wed Feb 15 15:19:29 2012 -0800 video: msm: Allow Enabling of DMA P Hist LUT Histogram LUT enabling was accidentally disabled by a previous patch. This patch allows it to be enabled again, while not conflicting with the patch that previously disabled it. CRs-Fixed: 336128 Change-Id: I5106999d79b5fdee255e23d31e5bc7de5d59b937 Signed-off-by: Carl Vanderlip commit e063a05cb7b869853ac7968c29acc0891b0d70f9 Author: Huaibin Yang Date: Mon Jan 30 16:26:57 2012 -0800 msm_fb: display: change perf level for 720p landscape video New perf level 3 (128M mdp clk) is used to play 720p landscape video, changed from previous perf level 2 (160M mdp clk), to save power. Change-Id: Ie27de4d2e407513eeb4cfb8fba6dd535a45c1364 Signed-off-by: Huaibin Yang commit 20bd54d7d64317f2c9e3b1384133a1c550454948 Author: Saurabh Shah Date: Wed Feb 22 10:22:36 2012 -0800 msm_fb: HDMI: Create hdmi_as_primary switch node If HDMI is used as primary, rather than external, create a switch node named "hdmi_as_primary". Change-Id: I694a12c1b8d223417090183b9d57913dca4df5be Signed-off-by: Saurabh Shah commit c7a7cc6dc79a6f60b0468efd0fb3964b1ebc7a70 Author: Pravin Tamkhane Date: Thu Dec 15 16:25:45 2011 -0800 msm_fb: Add support for Area Reduced Gamma Correction (AR GC) Provide API for programming Area Reduced Gamma Correction parameters. AR GC is used for adjusting panel gamma behavior for R, G and B channels. Tested using dummy AR-GC data from panel calibration and fbtest Change-Id: I64e9f81510160ffaacb6927de1812dfd2a3e5436 Signed-off-by: Pravin Tamkhane commit 85153bdf335804c526746ab8d930087b658f3d50 Author: Pravin Tamkhane Date: Tue Dec 13 13:56:46 2011 -0800 msm_fb: Add support for Polynomial Color Correction (PCC) Add support for programming Polynomial Color Correction (PCC) parameters on MDP. PCC is used for enhancing colors on display panel by programming the display panel calibration parameters Tested using fbtest and dummy calibration data Change-Id: I57dae828365f02d560e932ed0f26aa76c819fd31 Signed-off-by: Pravin Tamkhane commit 0056791344518f90c5708a5d3233373bb4e4cca6 Author: Amir Samuelov Date: Tue Feb 21 18:27:42 2012 +0200 msm_fb: display: Add I2C interface to Toshiba DSI-to-LVDS driver. The Toshiba bridge has both DSI and I2C interfaces. The DSI interface is used for configuring the bridge registers during setup. However, when video is running via the DSI interface then the I2C interface is used for read/write the Toshiba bridge registers. Change-Id: I6e90244948e09710fb9f55f1d828e73e1218e266 Signed-off-by: Amir Samuelov commit ac5337bb28f81c29b7449626f442e84742186574 Author: Amir Samuelov Date: Tue Feb 21 03:26:00 2012 +0200 msm_fb: display: Fix Chimei WUXGA panel driver for 60 fps. Fix front porch blanking according to the panel EDID for 60 frames per seconds. Change-Id: I3de0a238f5d08e14073a409bfcf2ec20002048b7 Signed-off-by: Amir Samuelov commit 91e4135c0f44697891b7ea933a8dacfac375a1e3 Author: Padmanabhan Komanduru Date: Fri Feb 10 18:23:04 2012 +0530 hdmi_msm: Power down PHY register during suspend Add change to power down phy register to save current when device goes to suspend state. CRs-fixed: 333739 Change-Id: I5c1c4202637cc8391d1dba03071a246e4f891307 Signed-off-by: Padmanabhan Komanduru commit 5f4b579b68fdc6f50ba20a50e31814a7ec2bc45d Author: Padmanabhan Komanduru Date: Wed Dec 7 17:14:10 2011 +0530 msm_fb: Change the sequence of backlight control for Gordon panel During Resume, backlight control settings are getting set before the Gordon panel has been initialized. This change corrects the sequence and ensures that display is proper after resume operation Change-Id: I22a6c857da3cb011404198b94e4347f76292a77e Signed-off-by: Padmanabhan Komanduru commit ede0a63aaa49024ac4a0a304bd5e32f34f6b6180 Author: Padmanabhan Komanduru Date: Wed Jan 25 12:01:28 2012 +0530 msm_fb: Make buffers aligned to 4K page boundary This change makes the frame buffers aligned to the page boundary. Improves GPU performance since accessing the frame buffer from page boundary is faster. CRs-fixed: 325134 Change-Id: I6ce4477f62536a3cd81064e26dc08f2b199e181b Signed-off-by: Padmanabhan Komanduru commit 1573599adbb42c606d8b91854c76461b3f212c3e Author: Manoj Rao Date: Thu Jan 26 17:15:09 2012 -0800 msm_fb: HDMI-CEC: Line latch patch The CEC hardware latches upon reading a corrupt bit in bit 7 of any bytes due various timing issues. If the driver detects this latch up then we call CEC reset to release the lacthed up line. Change-Id: Ia5a2e09372129a4358a46a623e6880095da4f0b4 CRs-Fixed: 329507 Signed-off-by: Manoj Rao commit 9919b7e5503bc078720337da27a421ec3833e528 Author: Adrian Salido-Moreno Date: Fri Feb 10 15:57:39 2012 -0800 msm_fb: display: perform mixer flush on every commit Mixer needs to be flushed on every commit instead of just when mixer cfg changes to flush changes in blending configuration CRs-Fixed: 336655 Change-Id: Ia56380eac1bd9dfb0795d930dc97a85dd30ba8a8 Signed-off-by: Adrian Salido-Moreno commit a369ce03ca048fb511642ac1cb73c1f652d70c50 Author: Ajay Singh Parmar Date: Fri Jan 20 16:13:43 2012 +0530 msm_fb: display: Fix for HDMI bootup issue If the device is booted up with HDMI cable connected, HDTV would go blank unless the HDMI cable is removed and inserted again. This is happening because the dtv pipe is initialized after HDMI core is initialized. The dtv pipe needs to be allocated at the bootup time when dtv is turned on to syncronize the HDMI core and DTV overlay. CRs-fixed: 331867 Change-Id: I90f6434e8440548391a6846b47bb5539f2e436b7 Signed-off-by: Ajay Singh Parmar commit 3b9595f629805408d572892227091cd1b42560fd Author: Ajay Singh Parmar Date: Wed Feb 8 16:36:03 2012 +0530 msm_fb: hdmi: Fix for EDID parser error. For an older TV, which doesn't contain Data Block Collection, the EDID parser was parsing wrong supported video resolutions. As per EDID standard, if EDID block 1 byte 2 is 0x04, it means there is no DBC available in EDID so the supported video resolutions should be read from DTDs of block0 and block1 instead of SVD of DBC. Reading DTDs for supported video resolutions instead of DBC for byte 2 being 0x04 case, fixed the issue. CRs-fixed: 332148 Change-Id: I637b91059952b63029cf4f05f750c340bdfa37a6 Signed-off-by: Ajay Singh Parmar commit 36d8ccd620799d2ad224f22a4c4c34c0256e1d08 Author: Ravishangar Kalyanam Date: Fri Feb 10 11:53:49 2012 -0800 msm_fb: display: Add DSI Video Toshiba WUXGA(1920x1200) panel support Add DSI Video Toshiba WUXGA(1920x1200) panel support using DSI Toshiba WSVGA bridge chip for controlling panel Change-Id: I36de195a0f86acd5415f2c6a0c4f0cfe050512bb Signed-off-by: Ravishangar Kalyanam commit 23fa9e7a958be09f9d6743cea026a4f56b84a48f Author: Huaibin Yang Date: Tue Jan 31 10:31:53 2012 -0800 msm_fb: display: set mdp perf_level to low level after playing video This bug fix sets mdp clk rate back to the rate for UI after playing video to save power. Change-Id: I73a0db158536b27a4a50d25b7737db4327210b8f Signed-off-by: Huaibin Yang commit 3b6551e3642301c92a1c96a70c4905da87b268ec Author: Ravishangar Kalyanam Date: Wed Feb 15 16:11:39 2012 -0800 msm_fb: display: Add supported MIPI panels to LVDS/MIPI detect config Add supported MIPI panels to LVDS/MIPI panel detect config for backward compatibility with old targets Change-Id: I31048cd51c8e8d09e7a16c5f81eb3e6dc9c59259 Signed-off-by: Ravishangar Kalyanam commit 55648fc2ab536294f7d549c822df8f17317b91c9 Author: Jeevan Shriram Date: Mon Dec 19 13:43:44 2011 +0530 msm_fb: display: Add mutex during display turn off There is a possibility that suspend operation trigger during a display update. Add mutex to serialize suspend and display update operations Change-Id: I52dea1bd718e8c54d894ae3830e86105f951efab Signed-off-by: Jeevan Shriram commit 13c5b2aa0116ee7859eb9331efd111e535db335d Author: Jeevan Shriram Date: Tue Dec 27 12:32:37 2011 +0530 msm_fb: display: protect dma status for video mode panel There is a possibility of race condition between dma update in ioctl context and isr context, hence add spinlock to protect the dma status in video mode type panel for safety in dual core environment. Change-Id: I85a2d76d62816ad92a7b0d60f7788f6c551f8dfb Signed-off-by: Jeevan Shriram commit 7716ef8c6180714d9948ecc008fb82ffef5628d7 Author: Ajay Singh Parmar Date: Thu Feb 2 19:04:18 2012 +0530 msm_fb: hdmi: Fix for different resolution TV switch hang. On connecting 1080p TV, then connecting 720p TV and then connecting 1080p TV again results in system hang. Hardware is waiting for reading AN in hdcp authentication part1 and then the resolution switch happens, which clears all the registers and we are in lost state. We need to protect the reading of AN bits in link status register and the reset core from muliple access. CRs-fixed: 334143 Change-Id: Ic5399a79a37a4285b1d10998cb1ffb4913c39f51 Signed-off-by: Ajay Singh Parmar commit d7185f60b02879c6b07293380a505791add19752 Author: Huaibin Yang Date: Sat Feb 11 01:36:41 2012 -0800 msm_fb: display: add mixer2 writeback userspace support Apps, e.g. fbtest can access mixer2 writeback functionality in userspace by providing ion writeback buffers. Change-Id: Ia56ac5275854231f1f28066f78db6dda97bb7b85 Signed-off-by: Huaibin Yang commit 1af8a35b8700d507016d6c05488401dbf6af0431 Author: Adrian Salido-Moreno Date: Thu Feb 9 14:34:23 2012 -0800 msm_fb: display: fix underrun seen due to scaling accuracy When making scale phase step ratio calculation, accuracy is lost when sizes are big since calculation is done in 32 bit and some truncation happens; this leads to underrun in mdp hw since scaling ratio doesn't match the src/dst rectangle. Increase accuracy by performing division again on remainder and appending to lsb of ratio. Change-Id: I6baa69a70a55e402c8924b51cab86afa6d0e9b5c Signed-off-by: Adrian Salido-Moreno commit 57e30678c19f540108d99e81fb03fdaa86105d95 Author: Jeevan Shriram Date: Mon Jan 30 16:58:12 2012 +0530 msm_fb: display: Featurize pm operations for external display Featurize suspend/resume operation of the external display to resolve compilation error in cases where external display features are not defined. Change-Id: Ifae276f514b67314a22e50fd80237e2168482d3f Signed-off-by: Jeevan Shriram commit b0d8321014da0ff547e8386d09a6bb3146320834 Author: Ajay Singh Parmar Date: Mon Feb 13 13:51:47 2012 +0530 msm_fb: display: Fix for compilation error with HDMI as primary Proper variable is now used to avoid the compilation error. The function where this error is seen is compiled only when the HDMI is configured as PRMIARY. Change-Id: I74a9693ceef49143412101a6a8360d2241f75e91 Signed-off-by: Ajay Singh Parmar commit ab05f94b75a40fdd70f018a12fef1d8e0b972175 Author: Ravishangar Kalyanam Date: Thu Feb 9 19:18:45 2012 -0800 msm_fb: display: Add LVDS display & LVDS/DSI panel auto detect support Add LVDS display PHY/PLL configuration and panel backlight support. Enable auto-detect support for LVDS/DSI panels Change-Id: I36a1a3c4cee9e015ae6fd03257bd10efa81450d8 Signed-off-by: Ravishangar Kalyanam commit 94f25dcbd137d139e31be55c461a95b39f730cbe Author: Kiran Kandi Date: Tue Jan 31 00:18:33 2012 -0800 msm_fb: HDMI: Export interface for setting Audio info frame The Audio InfoFrame contains information that allows for the format of the digital audio streams to be identified more quickly via out-of-band information and, for multi-channel uncompressed audio provides channel allocation information for the sink device's speakers. Currently audio info frame is hard coded to support 2-ch PCM. To Support Multi channel PCM, correct channel allocation information has to be sent to HDMI sink. So export the interface for setting audio info frame to HDMI audio driver. Change-Id: I7d0d5cf9f8792250bfd6e5eb003a8360ccb9707a Signed-off-by: Kiran Kandi commit 56499ed9d52ec2adfab9d8d48fa1495698fbbb75 Author: Jeevan Shriram Date: Thu Feb 9 16:12:00 2012 +0530 msm_fb: Display: Update panel initialization sequence Update the panel initialization sequence to avoid tearing effect on the panel Change-Id: I933ba5cadf1d2620bc571bd3a307494d838c2b38 Signed-off-by: Jeevan Shriram commit 5cef5f4de20c409e8e1ba31bd97aca111677f49d Author: Jeevan Shriram Date: Tue Dec 27 11:39:16 2011 +0530 msm_fb: display: add spinlock to protect dma status. During dma transfer to interface host the status of the dma needs to be protected in the smp environment. Change-Id: I02b4f046de7f693bb098343b7345c4aa6ca395bd Signed-off-by: Jeevan Shriram commit 7f4205b6487f81a3c504726263ffeddbc74df833 Author: Pradeep Jilagam Date: Mon Dec 19 12:29:52 2011 +0530 msm_fb: display: Add SMP-safety for PPP Operations Adds protection using spinlock for the variable used in controlling the PPP operations Change-Id: Iba6ef5e32d38668bd110ed23ee9631aa40de79e0 Signed-off-by: Pradeep Jilagam commit 5978cd2b581df55aa0c23a1478239b2e7bf7942d Author: Jeevan Shriram Date: Mon Dec 26 11:10:46 2011 +0530 msm_fb: display: remove while loop in mdp ISR As mdp interrupt is enabled on-demand, there is no need to have a while loop to handle interrupts at random time. There is possibility that mdp clock is turned off at first loop and ISR handler try to read mdp status register again at second loop which cause system to reset. Change-Id: I3716638974d8e24eda4a5146421d026b0ca85b4c Signed-off-by: Jeevan Shriram commit 1e6fcce3a2382b6af0c02aaed6bb503ac5d53b5d Author: Adrian Salido-Moreno Date: Wed Feb 8 16:24:22 2012 -0800 msm_fb: display: fix primary not resuming after suspend when hdmi connected Update bl_updated variable only after succesfully changing backlight, otherwise it can be set on hdmi play which doesn't really update backlight so primary remains blank. Change-Id: Ia08713ff0fbc88a98acd004a909c995fcd5726c6 Signed-off-by: Adrian Salido-Moreno commit d3a2993f02636b865bb59b075b12586513c7ba9f Author: Adrian Salido-Moreno Date: Wed Feb 8 12:26:39 2012 -0800 msm_fb: display: fix no resume after suspend for cmd mode panels Base layer pipe is updated only on ui kickoff, in bypass mode ui kickoff might not happen and that is why panel won't resume. Perform base layer restore on resume to allow panel to resume. Change-Id: I6031569077731fae0a716175d62fe4c0c85c6c36 Signed-off-by: Adrian Salido-Moreno commit 540124b79dd7b3bc25651935999f6fe422152fa4 Author: Amir Samuelov Date: Wed Feb 8 18:18:51 2012 +0200 msm_fb: display: Add write permission for 3D barrier file. Allow user space application to write to 3D barrier for control. Change-Id: Ia58597ad3707faa3f2d89de5f53fc77cfd97530a Signed-off-by: Amir Samuelov commit d9f38b0c3bcb8cb16e5b8d433caea647f9c875a3 Author: Padmanabhan Komanduru Date: Thu Feb 2 18:57:03 2012 +0530 msm_fb : Add support for Yamato format Changes to support Yamato format as a source format. Change-Id: I334fd059d2a06ea2796eb24f4a69fdb4be4e9789 Signed-off-by: Padmanabhan Komanduru commit 0cfba7b42b33cc0712d81d3ea917a235b3cd8d7c Author: Amir Samuelov Date: Mon Feb 6 11:02:12 2012 +0200 msm_fb: display: Add Chimei MIPI-DSI WUXGA panel driver. Add Chimei MIPI-DSI WUXGA (1920x1200) panel driver. Change-Id: Ie5d55309efa81e237215de4d79b0bc84ce5072ef Signed-off-by: Amir Samuelov commit 4b3395e1e6441673fb41c8fea58ea3e1422c3590 Author: Ravishangar Kalyanam Date: Sat Jan 28 21:45:03 2012 -0800 msm_fb: display: Read DSI platform's data lane swap for Novatek panel Read DSI platform's data lane swap setting for Novatek panel and set it in panel info for programming internal lane control register Change-Id: I762ed4a526e205803ff64c8eb92ce7758ab1d946 Signed-off-by: Ravishangar Kalyanam commit 2664ca29cca2ba9a46b0a992ba4f529e5208bab7 Author: Kuogee Hsieh Date: Tue Feb 7 15:31:42 2012 -0800 msm_fb: display: clear mixer blending cache during resume Clear mixer blending cache so that new blending value can be committed during system resume. Change-Id: Ie4e8399cdbbdb2153417c19e7f8019f38a294dd6 Signed-off-by: Kuogee Hsieh commit 18044ce96c01a440a2ade3711aba776aa1fea64a Author: Pradeep Jilagam Date: Tue Dec 13 23:22:48 2011 +0530 msm_fb: display: Add support for MIPI NT35510 WVGA panel. Adds DSI client and panel driver files to support Command and Video modes with NT35510 client and Truly WVGA panel Change-Id: Ia41bf282d070fa5fc5e0afeb24366a540c7ca9f5 Signed-off-by: Pradeep Jilagam Signed-off-by: Jeevan Shriram commit e6f182a1d4d1e186ae75f3a73cc496d94f983761 Author: Amir Samuelov Date: Tue Feb 7 09:14:03 2012 +0200 msm_fb: display: Update Toshiba DSI-to-LVDS to support WUXGA panel. Add 1920x1200 WUXGA panel support to the Toshiba DSI-to-LVDS driver. Change-Id: I2de71377f83de9847ef6b25b89dc5ae563279d1b Signed-off-by: Amir Samuelov commit 9705d1ebd4e39d0428a950589da9f5963d22ab74 Author: kuogee hsieh Date: Tue Jan 17 15:29:57 2012 -0800 msm_fb: display: increase timeout value to 2 vsync wait_for_completion_timeout() may timeout before overlay1_done interrupt when one vsync timeout is specified. This cause mdp4_overlay_dtv_ wait4_ov_done() to return prematurely which causes a falsely increased FPS. This patch increases the timeout value to 2 vsync to prevent premature timeout. Crs-fixed: 330723 Change-Id: Iac516525f328be01cf81ce3f4e95e5d6a4ab80ca Signed-off-by: kuogee hsieh commit bbcf4477c7e7d8ba7208e179f55bc8e550de08a7 Author: kuogee hsieh Date: Fri Jan 20 11:35:24 2012 -0800 msm_fb: display: enable MDP interrupts base on panel interface Enable necessary MDP interrupts base on panel to avoid triggering dma_s isr handler. Crs-fixed: 331668 Change-Id: I139a6193338a1b0a7c9cc7869e3ea1b3f9a65c4d Signed-off-by: kuogee hsieh commit 94c8a2c7f32371057f094cac19aa1bb905e714f6 Author: Adrian Salido-Moreno Date: Fri Jan 6 12:35:14 2012 -0800 msm_fb: display: perform staging updates on a single vsync Store all staging updates locally and write to hw on a single vsync only when changes are detected, this allows a smooth transition from using multiple overlays to framebuffer for UI Change-Id: I2cd61d858e74d450b8ad515b75008518274bd15e Signed-off-by: Adrian Salido-Moreno commit 9cb0ead92fa1188c99ee9bcdc1148dab17b48a36 Author: Jeff Ohlstein Date: Fri Dec 16 13:30:08 2011 -0800 video: msm: change normal operation prints to pr_debug There is no need to print every time an mdp4 overlay pipe is allocated or freed. Change these prints to pr_debugs so they can still be used for debugging if necessary. Change-Id: I91ba245ce54ab8a963539cfdea6d8d92efaf52a4 Signed-off-by: Jeff Ohlstein commit 207b565179fe95d9537ad1d8172ba9de91a3fbaf Author: Padmanabhan Komanduru Date: Wed Jan 18 21:21:15 2012 +0530 msm_fb : Check the validity of Histogram start/stop ioctls. Histogram start/stop ioctls are called now without checking if the panel is on or not. Add check to validate the ioctl calls in this aspect. CRs-fixed: 327910 Change-Id: Idc110408841c1b813dd2331a63cafe80243baeac Signed-off-by: Padmanabhan Komanduru commit 62f887ce4c6a52be4a4b846606768c19487742b7 Author: Ravishangar Kalyanam Date: Tue Oct 11 22:56:59 2011 -0700 msm_fb: display: Add LVDS display driver support for Chimei WXGA Add LVDS display driver support for Chimei WXGA LVDS display panel Signed-off-by: Ravishangar Kalyanam Change-Id: If8830295814d0e27f49dfffdeb96db63f73809ba commit 79d05a646f8af2658ad8f0aadb73c47cb277cc95 Author: Saurabh Shah Date: Mon Jan 9 15:18:33 2012 -0800 msm_fb: HDMI: Switch device node for HDMI Add switch device node for HDMI on initialization. Final node path will be /devices/virtual/switch/hdmi Set the node state to 1 on HDMI cable connect event, and successful HDCP authentication, if applicable. Set the node state to 0 on HDMI cable disconnect, HPD off events and HDCP authentication failure. Change-Id: I3496169f73a768a7908e8c633ab4dfb70c42f940 Signed-off-by: Saurabh Shah commit cb6b2e9c9ecb6884f556456b3d1ce4d877570534 Author: Ravishangar Kalyanam Date: Thu Jan 19 16:05:27 2012 -0800 msm_fb: display: Add external display PM suspend support Remove PM suspend registration from HDMI driver and add it in MSM framebuffer driver Change-Id: Ibd15ce1de541d2fe4dae24fc0d2f580328915fc0 Signed-off-by: Ravishangar Kalyanam commit 8562e7893e41969f1fe15839b7020b75401f6d72 Author: Ravishangar Kalyanam Date: Tue Jan 24 18:34:29 2012 -0800 msm_fb: display: Remove HDMI PHY power settings for proper PLL locking Remove HDMI PHY power settings for controlling PHY along with HDMI PLL in clock driver for avoiding random PLL lock detect failures Change-Id: I4016d5711b06785be3dd47782a187196d61445de Signed-off-by: Ravishangar Kalyanam commit 175d1281a5c1635cffc911dac261efc67d807c9d Author: Ravishangar Kalyanam Date: Fri Jan 20 16:57:23 2012 -0800 msm_fb: display: Cleanup log messages for ION buffer management Cleanup log messages for ION buffer allocation and de-allocation functions Signed-off-by: Ravishangar Kalyanam Change-Id: I87f44273a9de1899fdb7c30e90a8a1a5715c4dc5 commit 0bd48279653be46c7b91648e1ae0d93c7131e425 Author: Padmanabhan Komanduru Date: Tue Jan 24 11:59:50 2012 +0530 msm_fb : Check validity of histogram bin collection When CABL is disabled from UI, wait for completion gets killed. Histogram bin collection is invalid in this case. Add checks to handle this scenario. CRs-fixed: 331527 Change-Id: I0c25417672ee44a63011f76f2c998cbef9ae95f5 Signed-off-by: Padmanabhan Komanduru commit fa1de67dbadc084aa9fd6afa5ab4fae335089334 Author: Carl Vanderlip Date: Mon Dec 5 12:37:59 2011 -0800 video: msm: Adding CSC support for other MDP blocks Adding support for VG1, VG2, DMA_S and Overlay Mixer 1. Change-Id: I95a5832a70fd893970e82dadcec1e11ed608d79c Signed-off-by: Carl Vanderlip commit c7d7aa888a33818f278bdce86fa6c349561e05ea Author: Padmanabhan Komanduru Date: Sat Jan 21 17:17:06 2012 +0530 Revert "msm_fb: Handle static screen update case in CABL for MDP3.0.3" This reverts commit ff77f57b5bb1cd55bfdd3a14430470829e360822. Patch causes histogram ioctl to fail after there is no UI update for 50 ms. Abl-daemon handles static screen update case in CABL from now. Change-Id: Iddcd5b4fe0b2f99fe7b8f6b296649eee2f1f0c6e Signed-off-by: Padmanabhan Komanduru commit 3ab14ddf6e9fa157c292ba7442550628f090b5a5 Author: Rajesh Sastrula Date: Fri Jan 20 22:40:52 2012 -0800 msm_fb: display: increase wfd resolution to 720p Wi-fi display can support upto 720p resolution. CRs-Fixed: 332226 Change-Id: Idd4f293d364bb52ff5e85c58a713fc1d36b29c1b Signed-off-by: Rajesh Sastrula commit 228895ae217589ca71aa464f7c22bc4cedd06f77 Author: Aravind Venkateswaran Date: Fri Jan 13 12:47:08 2012 -0800 msm_fb: HDMI: Correct order for BKSV read operation During HDCP authentication, the BKSV read operation should be issued after writing AKSV as per the HDCP specification. This change fixes this issue. Change-Id: If5de484fe19dd3e949107d5b0d72f9594ee2e76f CRs-Fixed: 327845 Signed-off-by: Aravind Venkateswaran commit 0da46929eb69a01fa4b1d26a317e8fcc60a024ac Author: Huaibin Yang Date: Tue Nov 29 15:08:04 2011 -0800 msm_fb: display: add mdp overlay1 writeback This feature is enabled to avoid underrun on the display external interface (HDMI). For example, if 1080p to 720p downscaling is required, and mdp clk rate already is in its max, writeback is the only solution for this situation. Change-Id: I2323272a90730da45601f1d4c7dfc2bf06337b59 Signed-off-by: Huaibin Yang commit 3a895fd04105cb1a1db3ae51d051ea6b6d9ef980 Author: Mayank Chopra Date: Thu Jan 5 10:36:31 2012 +0530 msm_fb: display: prefill two writeback frames for lcdc. Pre-fill two writeback frames before enable writeback mode to avoid flickering for lcdc. CRs-fixed: 325327 Change-Id: I2ae6edea4578441f2027cc7657c851cf9646a28c Signed-off-by: Mayank Chopra commit 284fc85908c31b7424cc600083c2499d4188bdfd Author: Rajesh Sastrula Date: Sat Jan 14 14:45:23 2012 -0800 msm_fb: display: Fix incorrect goto call During the probe for writeback panel, for MDP hardware versions earlier than 4.3 an incorrect goto call un registers the bus scale handle that primary panel uses. This is causing the boot failures because the primary panel turn on sequence triggers the bus scale update request on already unregistered handle. Change-Id: Ie604b0ba5606d9664d2aeff28b8bea131965de61 Signed-off-by: Rajesh Sastrula commit fa559f6cb6c9a75beb48b594f952ccfe213c4234 Author: Adrian Salido-Moreno Date: Fri Jan 13 16:28:54 2012 -0800 msm_fb: display: fix underrun seen with big src coordinates MDP underrun happens if combination of x + w or y + h exceeds 2048. To handle such use cases add an offset to the source address instead. Change-Id: I36a8b687c4e21cac9915b5bf71211c97f6b44ddd Signed-off-by: Adrian Salido-Moreno commit da2f3cc0003c55cd18d6f052ecb9530fe2acea9a Author: Adrian Salido-Moreno Date: Thu Jan 5 15:32:57 2012 -0800 msm_fb: display: perform backlight updates on overlay play Perform pending backlight requests on overlay play to handle cases in which framebuffer updates are not happening to update backlight. Change-Id: I97a39c8fc9405f308ed684041b171bccc917154d Signed-off-by: Adrian Salido-Moreno commit ff77f57b5bb1cd55bfdd3a14430470829e360822 Author: Padmanabhan Komanduru Date: Fri Jan 13 16:32:31 2012 +0530 msm_fb: Handle static screen update case in CABL for MDP3.0.3 Avoid histogram bin collection and copy during static screen update. Histogram ioctls are also returned early in this case. Change-Id: Id75a2a61e018f683e2ec2d23c0fb78e1c7605a7d Signed-off-by: Padmanabhan Komanduru commit daa069f0949391f7b6fa7dcc26d854b790c14906 Author: Carl Vanderlip Date: Mon Nov 28 14:09:24 2011 -0800 video: msm: Adding CSC configuration for DMA P This enables the ability for the MSMFB_MDP_PP ioctl to configure the DMA P CSC registers. Change-Id: I1e18646decdd26641592bbc2a2dc0a4aa74e5f8a Signed-off-by: Carl Vanderlip commit ff85b428535a84bc00648e4a097332aeaebd676c Author: Rajesh Sastrula Date: Mon Jan 9 00:07:05 2012 -0800 msm_fb:display: Fix compilation errors when DTV is disabled Change-Id: I33b6426a202b60fe2f3d2fd007e05ce839283c0a Signed-off-by: Rajesh Sastrula commit ca82bd65223f61c193fd2600479bd18c09f7b1dc Author: Aravind Venkateswaran Date: Tue Jan 10 15:57:53 2012 -0800 msm_fb: hdmi: Correct logical clock rate for 480p We need to keep the logical pixel clock rate for 480p video resolution to be 27.03 MHz even though the hardware internally only generates 27.027 MHz. Change-Id: Idc653062e0a155e69753a8b58b9abf6106cfb8e0 Signed-off-by: Aravind Venkateswaran commit 4f4b108a0931736c2b3d5d0b577f1f557247167c Author: Carl Vanderlip Date: Wed Jan 11 10:02:34 2012 -0800 video:msm: Fix histogram error check logic Current error check logic is incorrect. Starting the histogram should throw an error if the histogram current state (mdp_is_hist_data) is already true. Similarly, stopping the histogram should only throw an error if the histogram current state has already been set to false. In the cases of suspend/resume the mdp_histogram_ctrl calls should only be allowed when the histogram desired state (mdp_is_hist_start) is true. Change-Id: Idef307293a7e4fb70807e9cea53078bf3cc67f15 Signed-off-by: Carl Vanderlip commit 061c8d1b5097067a2348431f26ad193a37ae02c8 Author: Adrian Salido-Moreno Date: Tue Jan 10 18:37:36 2012 -0800 msm_fb: display: fix underrun seen for some YV12 format input Underruns seen on display because source rectangle width is aligned to 16 before being passed to MDP. Only ystride should be aligned, source rectangle should be passed as received. CRs-Fixed: 329453 Change-Id: Ibb71ad316023d21ebad4c5db37fdc5e5c8acb02b Signed-off-by: Adrian Salido-Moreno commit e1ba2705ea4c9960f4349c57d115f4a79482f3a0 Author: Vinay Kalia Date: Wed Dec 21 16:24:52 2011 -0800 msm: wfd: Adds writeback start/stop functionality. Removes register/unregister calls and replaces them with start/stop. No need to pre-register the buffers anymore. Change-Id: I2f12c3a5791252ad09032cc628d93fb1dc50fee0 Signed-off-by: Vinay Kalia commit e240c2f738e6b3c4bc754442a8da3a351a0d68cf Author: Huaibin Yang Date: Tue Jan 3 15:43:29 2012 -0800 msm_fb: display: fix mdp clk rate settings If the video resolution is changed from higher to lower, mdp clk rate cannot be changed before overlay_play. Otherwise, underrun may happen because of a lower mdp clk rate for current higher resolution frames. On the other hand, if the res is changed from lower to higher, mdp clk rate must be changed before overlay_play to avoid underrun. CRs-fixed: 327811 Change-Id: Ieac4d2e1644e5687e3506b37799c56e19a17b991 Signed-off-by: Huaibin Yang commit bf300479078611dc528cd0e2decc4fdb3c282c4e Author: Adrian Salido-Moreno Date: Tue Jan 10 12:33:13 2012 -0800 msm_fb: display: fix hdmi connection crash on 8660 Crash happens because RGB pipe is not completely setup when initializing the base layer pipe. HDMI crash no longer happens after initializing RGB pipe correctly. Change-Id: Iff2e989db95b86fd81afc7e04d12d3d8f099acd7 Signed-off-by: Adrian Salido-Moreno commit 06237550f191c8d218030a231a9fefe0d7bd3f76 Author: Adrian Salido-Moreno Date: Wed Jan 4 16:35:26 2012 -0800 msm_fb: display: Move debug messages to debug statistics Move some debug messages that were shown as errors in display driver to debug statistics to avoid excesive prints in kernel log. CRs-Fixed: 326925 Change-Id: I529586f0e79baf27e2ae17f08fac203ba28bf416 Signed-off-by: Adrian Salido-Moreno commit 9add8a944993cb6bf90b12344731bb279fb366c9 Author: Nagamalleswararao Ganji Date: Mon Nov 21 12:51:36 2011 -0800 msmfb: display: fix the issue with overlay wait api calling overlay wait api asynchronous to the other overlay apis results in race condition in protection flags. this case is observed with HDMI true mirroring feature. it modifies the protection logic to fix the race condition Change-Id: Ib933055a395c2fc743f018aee96090defde33d37 Signed-off-by: Nagamalleswararao Ganji commit ca0aeaa65f7d4c2896e881e20e2b1892e5f96dab Author: Carl Vanderlip Date: Mon Nov 28 14:08:03 2011 -0800 video:msm: Adding stub for MSMFB_MDP_PP ioctls Basic handling of invalid copy_from_user and op from an invalid range. Change-Id: I788b28d3804e7312ee18310011c75d11287c4c6c Signed-off-by: Carl Vanderlip commit 880f847f5daf4517a4090e62ea1345ed69ff05fc Author: Nagamalleswararao Ganji Date: Wed Dec 14 03:52:28 2011 -0800 msm-fb: display: ION based allocation for writeback buffers ION based allocation is added for the writeback support for content security. Change-Id: Iaa7ec07a7cbc05c818af6f26a2c42c8c36b9bcb5 Signed-off-by: Nagamalleswararao Ganji commit 285745f9b9cf52a4f69711a3737ca185e0e699ec Author: Nagamalleswararao Ganji Date: Thu Dec 29 18:31:46 2011 -0800 msmfb: display: clean up of the writeback buffer variables clean up of the writeback variables to change the write back allocation for ion support Change-Id: I4999e43cb2f7111853e9c4a17852b2d5a351204e Signed-off-by: Nagamalleswararao Ganji commit a4f48cd3a16243671b42c6ef6437c0df77c9f1f9 Author: Aravind Venkateswaran Date: Wed Jan 4 16:24:19 2012 -0800 msm_fb: [HDMI_COMPLIANCE] Update audio ARCs for 480p As per HDMI specification, the correct pixel clock rate for 480p should be 27.027 MHz. In the code, we are currently using 27.03 MHz and thus the audio constants corresponding to this clock rate seem to be incorrect. This change updates these constants as per the HDMI and the CEA-861D spec. Change-Id: I526ce7bb5e6894e07040cc409c8a700e4a78a9fd CRs-Fixed: 328553 Signed-off-by: Aravind Venkateswaran commit 304248c9d5bfa96e965a2a08c134cb5b20aac00a Author: Adrian Salido-Moreno Date: Thu Dec 29 14:04:27 2011 -0800 msm_fb: display: fix mdp blending logic Handle case where blending downscaled VG pipe with alpha channel since alpha channel will be dropped by MDP hw. Also propagate framebuffer pipe alpha to top layers only if they are opaque to avoid picking up from layers which contain alpha. CRs-Fixed: 326178 Change-Id: I73cfc0716d1f5f8a803a645bdc09b97f909e593d Signed-off-by: Adrian Salido-Moreno commit 276bdaa5717d379e072137f004dd79133058d70d Author: Eugene Yasman Date: Thu Dec 29 18:44:53 2011 +0200 video: msm: Update CONFIG_MHL condition Replace generic CONFIG_MHL by a specific define CONFIG_FB_MSM_HDMI_MHL.implemented in Kconfig Change-Id: I3a8393518ca4f3adc1d74a62cb615ca629269af2 Signed-off-by: Eugene Yasman commit 819b257a51108b3833256804030c522dc7059cb0 Author: Eugene Yasman Date: Thu Dec 29 18:36:56 2011 +0200 video: msm: Add FB_MSM_HDMI_MHL to Kconfig Add FB_MSM_HDMI_MHL config to enable/disable the HDMI to MHL conversion support Change-Id: I51b58e9ca687e244c5b818a3aefb211e605c8e2a Signed-off-by: Eugene Yasman commit b52368bee31a047be045687253e3805c008bd4e6 Author: Rajesh Sastrula Date: Thu Dec 22 12:09:17 2011 -0800 msm_fb:display: Enable Layermixer2 for nv12 writeback enabling the layermixer2 for new MDP hardware so that it can be used to writeback the output in nv12 format for wi-fi display usecase Change-Id: I70322e722d8382102077db2d94a9320c2f2bb175 Signed-off-by: Rajesh Sastrula commit d0de5f990ab738a8b9c67fefc63b67e31d457f89 Author: Eugene Yasman Date: Tue Dec 20 13:57:28 2011 +0200 video: msm: Add support for Sii9244 MHL video modes. Currently the HDMI driver reads the video modes of the external panel using EDID and matches those modes with the HDMI TX Core supported modes. If the HDMI signal is routed via the Sii9244 MHL chip, its video modes should be also taken into account. Change-Id: I841071c47dde94d9a91727d5f31b0ec43a957689 Signed-off-by: Eugene Yasman commit 6a75b86e9f0707f46f0fd161481da25235bd037c Author: Ravishangar Kalyanam Date: Thu Dec 15 10:33:39 2011 -0800 msm_fb: display: Add backlight with first pan display after resume Add backlight call with first pan display after resume operation of framebuffer driver CRs-Fixed: 323682 Signed-off-by: Ravishangar Kalyanam Change-Id: Ic27c2c9fe37b622bbd9ab5933ca45626decd53ae commit 48d8f219004677ead97d6a5a0b89b54625c2f15d Author: Abhishek Kharbanda Date: Fri Nov 11 18:22:29 2011 -0800 msm_fb: Power saving for enabling HPD feature. Don't initialize HDMI PHY while enabling HPD feature. CRs-Fixed: 310913 Change-Id: Ib18f93dfa848218e0a6a1fdf06944e6696e08bbc Signed-off-by: Abhishek Kharbanda commit 402adc6142598abcb2a41a941895003f57f289a5 Author: Abhishek Kharbanda Date: Thu Dec 15 12:21:29 2011 -0800 msm_fb: Fixing Aspect Ratio Non-standard resolution, like 531*398, is treated as 720*480 instead of 640*480 , as it has non 4:3 aspect ratio.Chanding aspect ration calculation to be in a range , rather than absolute. CRs-Fixed: 320022 Change-Id: Ie3b1ebefe48ef648720f06336239af907c3468d2 Signed-off-by: Abhishek Kharbanda Signed-off-by: Aravind Venkateswaran commit e88f8f552a6102b8622ca6f88e78f2a244531746 Author: Aravind Venkateswaran Date: Tue Dec 13 19:07:20 2011 -0800 msm_fb: HDMI: Fix Coding Style Warnings This change takes care of all the coding style warnings reported by the checkpatch script. Change-Id: I31506132176f269ce2971dc45ffaf6e8b4b9dab5 Signed-off-by: Aravind Venkateswaran commit 39cf209c7f8ac4843c8b10223af15d0afdbe96ce Author: Abhishek Kharbanda Date: Thu Dec 15 11:37:57 2011 -0800 msm_fb: Removing HDCP timedout error. DEBUG mode added delay after writing RO's to RCVPORT, leading to HDCP AUthentication Sucess Interrupt coming before INIT_COMPLETION call. Re-arranging INIT_COMPLETION code before writng RO's resolved the issue. CRs-Fixed: 325564 Change-Id: I6d21103d049bf22d3a09aeeafab1a50119597d7e Signed-off-by: Abhishek Kharbanda Signed-off-by: Aravind Venkateswaran commit b7b13f07b1b7f3c721752163f8b0279042636a02 Author: Abhishek Kharbanda Date: Fri Nov 18 11:20:08 2011 -0800 msm_fb: HDMI_COMPLIANCE: Disable Encryption on NON HDCP builds. HDMI Compliance require non HDCP builds to work on HDCP SURF's. Do not set HDCP flag for NON-HDCP builds, so that encryption enable bit is never set. Change-Id: I6f2df598fe2ed4d9ae3673fcec74b76c30e3c0dd Signed-off-by: Abhishek Kharbanda commit 910183691eb3d8c06f6344cfd57ae4e30716ff94 Author: Huaibin Yang Date: Tue Nov 29 14:57:43 2011 -0800 msm_fb: display: allocate mdp writeback memory The writeback buffer is already reserved on the board side. This allocation separate writeback buffer from framebuffer. Change-Id: I312be3e0dfcf4c5b611cd06cd68d2baae7e2add8 Signed-off-by: Huaibin Yang commit c174d301d899a3242efc5d30d549c9fde8270b78 Author: Adrian Salido-Moreno Date: Tue Dec 13 15:38:26 2011 -0800 msm_fb: display: enable pixel repeat on VG pipe only for alpha upscaling VG pipe doesn't support pixel repeat/drop to avoid alpha channel drop during downscaling. Keep pixel repeat only for upscaling. Change-Id: Id400d0f823bc0054a94330600d5085778a65b936 Signed-off-by: Adrian Salido-Moreno commit 7b879b66c84b849ea78bcdd2400bacd7e0311561 Author: Ravishangar Kalyanam Date: Fri Dec 16 16:04:09 2011 -0800 msm_fb: display: Add MDP 4.2 footswitch ctrl at suspend Add MDP 4.2 footswitch ctrl at suspend/resume for non-HDMI cases Change-Id: I1071c0106ffc52c7f337e9f612a6ec9eb4746edd Signed-off-by: Ravishangar Kalyanam commit 52e88234977cd598e4902841869207b670f1321b Author: Ajay Dudani Date: Tue Dec 13 13:33:10 2011 -0800 msm8930: Temporarily disable HDMI by default On some 8930 variant boards, we see a kernel panic on HDMI core power on. Disable HDMI temporarily until this is root caused. Change-Id: Ibfa1d851897c6f38c8f17cde8d3529a373203f1e Signed-off-by: Ajay Dudani commit 89d519ca92ba2f8c70d595f1950691170c577486 Author: Ravishangar Kalyanam Date: Thu Dec 15 17:31:35 2011 -0800 msm_fb: display: Fix DSI cmd mode color swap issue for MDP rev <= 4.1 Fix DSI cmd mode color swap issue for MDP rev <= 4.1 CRs-Fixed: 323479 Signed-off-by: Ravishangar Kalyanam Change-Id: Ic9841f0eb89df7afea7ec1c9486e8cb0e6bbb58d commit 6a601cdc35501835a0b19718329be70f696a34ee Author: Adrian Salido-Moreno Date: Tue Dec 13 18:16:25 2011 -0800 msm_fb: display: fix mdp underrun on disabling writeback Writeback fallback for mdp underflow can be enabled/disabled dynamically based on parameters; if writeback is disabled while displaying previous frame it can can cause underrun. Disable writeback after programming new frame to avoid underrun. Change-Id: I6c73887043f19596cb3611c83c51c1aeac907ff0 Signed-off-by: Adrian Salido-Moreno commit 8e3cb69445244c620d5742b8f3cb57c3a8bef5c4 Author: Aravind Venkateswaran Date: Tue Dec 13 17:35:51 2011 -0800 msm_fb: HDMI: Remove Audio Packet Ctrl Reg Setup With a recent change we do not set the Audio Packet Control Setup register (offset 0x0020) on HPD connect event. In addition, we should not reset the value of this register whenever HDMI is powered off. CRs-Fixed: 323928 Change-Id: I1ecbb9c87470b5cedc7351198cf73c5d7406ceb6 Signed-off-by: Aravind Venkateswaran commit db7007f5a6697cd5239f433b010440bf5a5650e7 Author: Ajay Singh Parmar Date: Wed Dec 14 02:17:58 2011 +0530 msm_fb: hdmi: Add DVI sysfs node For DVI mode, audio should not be routed. This routing happens through HDMI daemon in usespace after confirming the mode from HDMI core. This change gives HDMI daemon a way to determine if the mode is DVI or HDMI, based on that HDMI Daemon can decide on routing the audio. Change-Id: I4afa746d6195b02046305a33a2b6a8b693510ba6 Signed-off-by: Ajay Singh Parmar commit a9c4e3cb9f29ced98b82ea073e7814668abf56a9 Author: Padmanabhan Komanduru Date: Mon Nov 21 10:35:35 2011 +0530 msm_fb: display: Change the timing values of MDDI toshiba panel. Adjusts the porch values and refx100 to prevent tearing effect on MDDI toshiba panel. CRs-Fixed: 309691 Change-Id: I304bb088ef1147e562fdeb6f7eb02ed570aba627 Signed-off-by: Padmanabhan Komanduru commit 88426ca238a783acf165f8b4e0958cd3cced6cf9 Author: Eugene Yasman Date: Tue Dec 13 13:31:41 2011 +0200 video: msm: Add mhl api header file MHL API defines an interface for HDMI driver. The API provides the information of the MHL connection state for HDMI to transmit the MHL supported video format. Change-Id: If19e497b7a238eb0465f9fb13b5586d3b9043360 Signed-off-by: Eugene Yasman commit a35b234783de0a3dd4e21d784081d35309592e51 Author: Vinay Kalia Date: Thu Dec 1 17:38:01 2011 -0800 msm: wfd: Fix compilation error. Changes function call to match the new API signature. Change-Id: I6b1cadca697c5b7431ee2648a4d34df21b46ce52 Signed-off-by: Vinay Kalia commit b240803778c9d2c9788bd33587c9c63edb7d6801 Author: Carl Vanderlip Date: Thu Oct 27 10:52:48 2011 -0700 video: msm: Track validity of and synchronize histogram Adding mutex to more thoroughly lock histogram calls; additionally, adding a flag to track histogram data validity. Together they ensure that the histogram is not started, stopped, or read out of order. CRs-Fixed: 310429 Change-Id: I276974811a5e673b05c68b41f5fbff5b178165cb Signed-off-by: Carl Vanderlip commit 562c58fbf58a55b9dc8cde472361cb8d3cb6a1e5 Author: kuogee hsieh Date: Thu Dec 8 08:47:33 2011 -0800 Revert "msm_fb: display: decrease mdp_timer_duration" This reverts commit 9a1fb1c65ad421178dea65e8cdc0796c9ace3b00. Change-Id: I3312c878370ce72a611423085c8cefe42028d21e Signed-off-by: kuogee hsieh commit fc6be921eeb73aea9bd625189f225d199908b685 Author: Adrian Salido-Moreno Date: Tue Oct 4 15:22:39 2011 -0700 msm_fb: display: enable border color fill on external display Enable border color fill feature on external display. This avoids usage of RGB pipe for background border fill and can now be used as overlay layer for UI display. Change-Id: I652ab3ffe2c43260590e4e5a2ffc986340c4a8c0 Signed-off-by: Adrian Salido-Moreno commit d2fb0bd826f83b6bc3fc2d0819773f25bd2b049f Author: Aravind Venkateswaran Date: Wed Nov 30 18:38:14 2011 -0800 msm_fb: [HDMI_COMPLIANCE] Reset DDC control logic upon failure This change toggles the HDCP_DDC_CTRL_0 register to reset the DDC control logic, in effect enabling the DDC controller logic to continue to function after hitting a DDC failure. This is needed to pass HDCP compliance on MSM8960. Change-Id: Ic11a4d4de375aab9b3948cbde7eda5aca7aefbd6 CRs-Fixed: 321221 Signed-off-by: Aravind Venkateswaran commit daf5e17901e7519de3bfc5752dbd95093aeb2527 Author: Aravind Venkateswaran Date: Wed Nov 30 18:34:40 2011 -0800 msm_fb: [HDMI_COMPLIANCE] Disable HDCP interrupts on de-authenticaiton This change disables all the HDCP interrupts upon de-authentication. In addition, we also clear the HDCP AUTH_FAIL_INFO register upon processing the AUTH_FAIL_INT interrupt. This is required for passing HDCP compliance for MSM8960 Change-Id: Iefe544c8c972e4d3b5fa4ccdd513c411d1781b3d CRs-Fixed: 321221 Signed-off-by: Aravind Venkateswaran commit 34c5f958890c8881e92a05e05ac6f95b5a48eaf1 Author: Huaibin Yang Date: Tue Nov 29 13:56:59 2011 -0800 msm_fb: display: cleanup overlay0 writeback funcs and config flags The writeback blt mode is controlled by assignment of blt_base (NULL or not), only the #ifdef in board file is effective. Those flags and funcs on the driver side is cleaned up. Change-Id: Idc9a7fbb5525071bf3cf68e5182bc7f6a5693932 Signed-off-by: Huaibin Yang commit a12cc95a7e8b5f4882307f0ec7516f62ef8ab21e Author: Matt Wagantall Date: Tue Nov 8 18:14:50 2011 -0800 msm_fb: Discontinue use of clk_set_min_rate() This proprietary API will soon be removed. Replace use of it with a combination of clk_round_rate() and clk_set_rate() where appropriate. Calls to clk_set_min_rate() with a rate of 0Hz followed immediately by a clk_disable() served no purpose and are removed entirely. Change-Id: I56d680ee36cc6292dcc436eeec7acdc57f3c243a Signed-off-by: Matt Wagantall commit 2aab6fd9b00955b2e836a873cd5a27bddd2f3644 Author: Ajay Singh Parmar Date: Wed Dec 7 07:23:34 2011 +0530 msm_fb: hdmi_msm: No HDMI for 8627 The HDMI driver should not register for 8627 target. Change-Id: I3ef882e76d374eabc15ed5c3121ac7d6f618f616 Signed-off-by: Ajay Singh Parmar commit e8943499da4389b9f32658f19da0ced6b7ff565f Author: Nagamalleswararao Ganji Date: Tue Nov 1 13:04:10 2011 -0700 msmfb: display: enable the blt mode for bigger line length blt mode is enabled for bigger line length to avoid the underun on qt devices Change-Id: I6055f494034b1e64fbf6fb083442f9513634659c CRs-Fixed: 316327 Signed-off-by: Nagamalleswararao Ganji commit 954620c40355894763ea1aeff4646b2adb30a594 Author: Aravind Venkateswaran Date: Wed Nov 30 14:50:48 2011 -0800 msm_fb: [HDMI_COMPLIANCE] HW reset on HDCP reauthentication We need to add a small delay before reading the AN0 and AN1 registers once they are ready, in order to avoid hardware reset. Change-Id: Iba9465ee83dce66ae99ab5885015d977d54c0612 CRs-fixed: 319542 Signed-off-by: Aravind Venkateswaran commit 9a2673aca6aae756ef36b35e981c7c349845edf1 Author: kuogee hsieh Date: Mon Nov 28 09:03:25 2011 -0800 msm_fb: display: fix invalid receving length bug Since expected receiving length need to be divided by 4 evenly, it need to be &= ~0x03 instead of &=0x03. Change-Id: I68912245c6fc499bdb652ed327d60bcf60487d40 Signed-off-by: kuogee hsieh commit e22c42d680cfa7abedb0b29431bbbd83451f19c1 Author: Huaibin Yang Date: Wed Nov 30 17:35:51 2011 -0800 msm_fb: display: move the prefill function inside the config flag There is a compilation error if the config flag is not set, so the func has to be moved inside the #ifdef. Change-Id: I6163606c389e8e4767239cf74eb8260fca728728 Signed-off-by: Huaibin Yang commit ebefc805a139e8222061b32cbf7686d76122de5f Author: Manoj Rao Date: Wed Oct 19 11:16:08 2011 -0700 msm_fb: HDMI: EDID > 2 blocks, params not set. Currently the driver discards one byte from DDC buffer. In cases where EDID exceeds two block in length we need to discard a total of 3 bytes before reading from EDID seg. Change-Id: I60ff039cbc3ff4bbc81ec61de696d25c3ddca92e CRs-Fixed: 307706 Signed-off-by: Manoj Rao Signed-off-by: Abhishek Kharbanda commit 9a1fb1c65ad421178dea65e8cdc0796c9ace3b00 Author: kuogee hsieh Date: Sun Oct 30 09:15:12 2011 -0700 msm_fb: display: decrease mdp_timer_duration mdp_timer_duration decides when both mdp and vsync clocks be turned off after last screen updated. Decrease mdp_timer_duration to 20ms to have clocks be turned off sooner. CRs-fixed: 315271 Change-Id: Icf7f0a64ab38dd5184a12242cfc190efa31016a9 Signed-off-by: kuogee hsieh commit edcb9567783846d292410c14fc4b99612ef1caff Author: kuogee hsieh Date: Mon Nov 28 09:02:50 2011 -0800 msm_fb: display: remove mutex from mipi d2l register read/write Mutex had been acquired at dsi_on() already. Hence no need to acquire same mutex at mipi d2l registers read/write function again. Change-Id: Ie47590771c287a8e7c42aae568c1703a7e9107a4 Signed-off-by: kuogee hsieh commit fa14cb039938c7a60007b6e5f1c4db2541faa18e Author: Aravind Venkateswaran Date: Wed Oct 19 13:00:16 2011 -0700 msm_fb: HDMI_HDCP Compliance: Fix for test case 1B-01a In the case where there are many downstream receivers connected to a repeater, we need to poll for HDCP_SHA_BLOCK_DONE bit everytime after writing 64 bytes of the KSV fifo. Change-Id: Ic304250a73ad6573c43b4eb910a7eb7eb2b4dee9 Signed-off-by: Aravind Venkateswaran commit 8863118c485d2dff94dfa259a95d069d15994b29 Author: Ajay Singh Parmar Date: Mon Nov 28 23:55:53 2011 +0530 msm_fb: hdmi_msm: dynamic sample rate change for non-hdcp Adding support for other modules to dynamically change the sampling rate in HDMI core for audio which is supported by NON-HDCP surf/FFA as well. Change-Id: I2e4f239e43251b2dc5f8529b7c352a94456ad974 Signed-off-by: Ajay Singh Parmar commit 0948c68fe35913119f2d025168b381e6ca1d2db7 Author: kuogee hsieh Date: Mon Oct 31 16:50:43 2011 -0700 msm_fb: display: update mdp statistics Update mdp4 statistic information so that it becomes more useful during debug session. Change-Id: I0b88428bc692c28284f9091e143f0cf10079225d Signed-off-by: kuogee hsieh commit 0fc5d36176b8feaa360bff9c5d46c481cea8a42b Author: Ajay Singh Parmar Date: Wed Nov 16 05:48:33 2011 +0530 msm_fb: hdmi_msm: Add support for audio sample rate change. This patch provides the support for changing the sample rate dynamically. Change-Id: I973e5240e6f545b85ab2872aa0786b2d80ee2d2f Signed-off-by: Ajay Singh Parmar commit a077d0063dfb8a39a869f56099dd0ffe85301180 Author: Abhishek Kharbanda Date: Fri Nov 4 14:25:48 2011 -0700 msm_fb: Check for ACP and ACFG register before reset core. Check for Bit[0] of Audio Packet Control Register and Audio Configuration Register before resetting HDMI core. Even after sending OFFLINE event, QDSP take time to switch between stereo and hdmi audio mode. HDMI reset core should not be called untill that switch happens. Change-Id: Iee8d5d019b74edd675b23ac8dd34535766714eb2 CRs-Fixed: 310700 Signed-off-by: Abhishek Kharbanda commit 6b2d8af94b0fc441eefb65e87a964208783dac3c Author: kuogee hsieh Date: Wed Nov 16 10:02:01 2011 -0800 msm_fb: display: commit BLT to mdp register during video kickoff BLT (writeback mode) need to be committed to mdp register before kickoff. Normally, UI kickoff will follow immediatly after BLT enabled/disabled. However sometimes video overlay play happen before UI's pan display after BLT enabled/disabled. In this case, video kickoff need to commit BLT to mdp register too. Change-Id: I7b085f516f869009e7fc4b443f7858a61fce5ba3 Signed-off-by: kuogee hsieh commit 3875379164cd350591eb8a1f4ea06994004a21ce Author: Aravind Venkateswaran Date: Fri Nov 18 13:14:08 2011 -0800 msm_fb: HDMI: Support for 576p 4:3 in HDMI Driver The firmware upgrade for the QD 882EA box requries us to have support for 720x576p 4:3 aspect ratio. Until now, we have only supported 720x576p 16:9 aspect ratio. This change adds the appropriate values to the AVI Info-frame lookup table. Change-Id: Ibc1165ab2445977e7b253a20b0d9396e1ae88ce1 Signed-off-by: Aravind Venkateswaran commit 4b910f252587e25699eaa4daa5036ab3bfb73c3f Author: kuogee hsieh Date: Tue Nov 15 09:43:04 2011 -0800 msm_fb: display: enable mdp chip select controller Enable mdp chip select controller so that CS signal is asserted or de-asserted by MDP according to activities of memory access on both read and write to save power. Change-Id: Ic0acc1c8cbe06c5f3cf25627af209abadeb1350c Signed-off-by: kuogee hsieh commit 465c15903f44453a235d7eb9be4b6bde51368370 Author: Abhishek Kharbanda Date: Fri Nov 4 14:06:15 2011 -0700 msm_fb: Remove Audio Packet Control Register setup Donot set Audio Packet Control Register (0x0020) on HPD connect event. This register should be set by QDSP6 core on start of dumping Audio Data. CRs-Fixed: 316588 Change-Id: I9ab9bf2b6c02d73e40cd1a28241ffb20cdd69516 Signed-off-by: Abhishek Kharbanda commit 2b16b8f13507e9ea078b2f612d74b024a11afd13 Author: Matt Wagantall Date: Tue Nov 8 16:58:21 2011 -0800 msm_fb: Use clk_set_rate() to vote on ebi_clk rates clk_set_rate() and clk_set_min_rate() share a common implementation for ebi_clk, but the clk_set_min_rate() API will soon be eliminated. Remove its use in preparation for this. Change-Id: I5a4a4a2f5e2e0ba4989bc7c1f9423653bec0af0f Signed-off-by: Matt Wagantall commit cb8fbbcbe0630451ba582a0747987c48b2c603f1 Author: Adrian Salido-Moreno Date: Wed Oct 26 13:00:18 2011 -0700 msm_fb: display: cleanup usage of shared pipes in overlay Remove usage of shared pipes. Shared pipes are used to allow VG pipes to play both video and rgb formats. This can now be handled by calling overlay set ioctl with new format, that means shared pipes are no longer needed and can cause instabilities if not used properly. CRs-Fixed: 312209 Change-Id: If723802d9405001baa69f132a143d21c8aa85613 Signed-off-by: Adrian Salido-Moreno commit 0f0ab64f56cbc31cd2fda46ff4790ae86f89ad5f Author: Manoj Rao Date: Tue Nov 1 12:28:24 2011 -0700 msm: HDMI: CEC: Hardware FSM reset. Hardware requires a FSM reset toggle under frame write/read scenarios. This enables every transaction/feature to have a fresh start. CEC CTS requires this patch to pass a subset of test cases in sections 8, 9. Hardware and VI teams have confirmed this as a necessity for compliance tests to pass. Change-Id: Id79795dd4c17c3a75337a4c3818219ba6d87ff25 Signed-off-by: Manoj Rao commit d973663b4a2086c7fe1bf0264f16d413673c36c3 Author: Liyuan Li Date: Fri Nov 11 13:47:59 2011 -0800 video: msm: Adding support for MDP4 HSIC controls Adding support for users to adjust Hue, Saturation, Intensity and Contrast of the display. Change-Id: I79cb69c871686ccba115798f635f768b9a50affc Signed-off-by: Liyuan Li commit 4b1bde4cd20b889b3fc49972d3210c5308044ca1 Author: kuogee hsieh Date: Tue Nov 8 15:26:26 2011 -0800 msm_fb: display: add mutex to dsi_on During resume, backlight dcs commands to client may be issued before dsi_on completed. Add mutex to dsi_on and check dsi state to make sure dsi_on is completed before sending backlight command to panel to avoid conflict on dsi link. Otherwise screen will stay blank if confliction happened. Change-Id: Icfba079b228f02aeb89949befb10cca29bf6d744 Signed-off-by: kuogee hsieh commit e69bed86ffa5b7cc05545fd986a21ebef5123775 Author: Nagamalleswararao Ganji Date: Mon Oct 17 16:21:42 2011 -0700 msm-fb: display: ion framework support Add support for the ION memory manager to the framebuffer driver Change-Id: If012dcdbbc71eb0f7d4d429ad4789b3276d34a58 Signed-off-by: Nagamalleswararao Ganji Signed-off-by: Naseer Ahmed commit 6a3a01ae8eca6d615ead5be9ed28720bc0c79dab Author: Deepa Madiregama Date: Fri Oct 28 06:34:17 2011 +0530 msm: 8660: audio: HDMI: Fix the HDMI DMA stop issue LPA_IF dma channel is disabled without checking the per count value. Because of this dma channel is not functional after few iterations of continuous playback. Fix this issue by checking the dma per count value to stop before disabling the LPA_IF dma channel. Change-Id: Ie9e9a9337ca2c4b76cebd99cd3eb98137be85b89 Signed-off-by: Deepa Madiregama commit 81be67988ef149f601064a9e8e5d91705e636ff5 Author: kuogee hsieh Date: Mon Nov 7 14:18:51 2011 -0800 msm_fb: display: update busy flag before check blt_addr dma_busy flag is set to TRUE on every vsycn push and set it to FALSE at overlay0_done ISR. When blt disable, dma_busy need to be set to FALSE before return due to blt_addr == NULL at overlay0_done ISR. Change-Id: If2622631a7cd03276ae7fbd8326155d0e9c7b66b Signed-off-by: kuogee hsieh commit 27020d1b5db194e11b08dc46dd7b89078895b6eb Author: Vinay Kalia Date: Fri Oct 14 17:50:29 2011 -0700 video: msm: Writeback support in mdp for WFD. Adds writeback mode in mdp for wifi-display(WFD). This mode can be used to get the captured frames from mdp. This is added to support wifi-display capture device. Change-Id: Iae30cac65af181d8df4b514a128cd876fe7dda1c Signed-off-by: Vinay Kalia commit 584b96a4a3b0f5842178fb8fd1b1235501cf7ef0 Author: kuogee hsieh Date: Mon Oct 31 10:33:30 2011 -0700 msm_fb: display: add no_max_pkt_size flag Add no_max_pkt_size flag to allow toshiba dcs to lvds bridege chip work. Change-Id: Icaed4bc749dec96f12e3e0e78c098294658a2c46 Signed-off-by: kuogee hsieh commit 4c4c286176e91b24f2399309ce9f379902be58d2 Author: Carl Vanderlip Date: Thu Oct 27 11:28:55 2011 -0700 video: msm: Clear and disable histogram interrupt When the histogram is disabled, its interrupt should also be disabled and cleared. Note: only applicable to MDP4.0 onwards as earlier versions of the MDP expect the histogram interrupt to be left enabled after running mdp_histogram_ctrl. CRs-Fixed: 310429 Change-Id: I5a8df4fdcc41520e1ed0af970a8628479a4645a6 Signed-off-by: Carl Vanderlip commit e19a2869b3db914e93335746ef80878103d5c0cd Author: Carl Vanderlip Date: Thu Oct 27 11:26:24 2011 -0700 video: msm: Remove redundant code in histogram collection Rewrites start and stop histogram functions to better use the existing mdp_histogram_ctrl function. CRs-Fixed: 310429 Change-Id: Iecc97c1376319021f99dd00eee6fb154bf7a5740 Signed-off-by: Carl Vanderlip commit 13f48ed4a9141772385eb44bd8c1923668ae32df Author: Carl Vanderlip Date: Thu Oct 27 13:44:31 2011 -0700 video: msm: Remove ifdef from mdp_histogram_ctrl Replace the mdp revision specific code with reference to mdp_rev global var. CRs-Fixed: 310429 Change-Id: I09fe3707bc9926af89874966e7d640c5862cffa0 Signed-off-by: Carl Vanderlip commit 7484515be07eebc3a12a087921416f1b373decde Author: Carl Vanderlip Date: Tue Oct 11 10:24:32 2011 -0700 video: msm: Block histogram requests with powered down panel This causes MSMFB_HISTOGRAM ioctls to return an error when they are called after the panel has entered a powered down state. CRs-Fixed: 310429 Change-Id: I39c768c62a37ca83df2db2309230971cb6492bab Signed-off-by: Carl Vanderlip commit 40a43409804073a0442d2a1ea09293c0b95fdab1 Author: kuogee hsieh Date: Tue Oct 4 08:48:18 2011 -0700 msm_fb: display: check BLT mode within overlay_done isr At dsi video mode, overlay_done isr return immediately if blt mode was not enabled. Aslo, since time between overlay_done interrupt and dmap_done interrupt is very close, both may be serviced within same ISR. In this case overlay_done is serviced first. CRs-fixed: 310918 Change-Id: If8b6220c26ea8d08857f87f33609b1673238b2ec Signed-off-by: kuogee hsieh commit 0737d65bb7faf91f3dbf87c32a86c5e7cb9e454e Author: Nagamalleswararao Ganji Date: Fri Oct 14 02:02:33 2011 -0700 msmfb: display: support for overlay wait ioctl this adds supports for overlay wait ioctl and it allows the userapce start overlay play and HDMI and can call wait later point of the time Change-Id: I8000cc52a497861e0a5fdfe58c0c049219724ab6 Signed-off-by: Nagamalleswararao Ganji commit d1b9d7ab0c98fe2bb8d6ab3f6dbd489dd17b3c5a Author: Adrian Salido-Moreno Date: Fri Oct 14 18:18:51 2011 -0700 msm_fb: display: enable hw cursor for dsi video panel fix hw cursor updates not coming for dsi video panel defining callback during driver setup. CRs-Fixed: 309515 Change-Id: I12586e813c19ff4dbe1e3877eaf14b5a396b273a Signed-off-by: Adrian Salido-Moreno commit dee95105fdbc21ca2cecad26403e7c6a9942f445 Author: Abhishek Kharbanda Date: Mon Sep 19 14:08:33 2011 -0700 msm_fb: HDMI: Support for clock stretching HDMI Sink may hold off the DDC transaction by stretching the SCL line during the SCL-low period following the Acknowledge bit as permitted by the I2C specification. All HDMI Sources shall delay the DDC transaction while the SCL line is being held low. HDMI_DDC_SETUP register field should be set. Change-Id: If58ee3f81b5f89ab22c5e74104ba5ad07ff6094d CRs-Fixed: 296256 Signed-off-by: Manoj Rao Signed-off-by: Ramakrishna Prasad N commit df021cf202ea5f026c9d8862a06997e43346b2aa Author: Ravishangar Kalyanam Date: Thu Oct 20 12:53:27 2011 -0700 msm_fb: display: Fix suspend/resume for HDMI as primary display Fix suspend/resume for HDMI as primary display by setting solid fill for RGB pipe connected to DTV Change-Id: I2f6bf1892137ef40c55e26498c03cfb7a439219b CRs-Fixed: 310198 Signed-off-by: Ravishangar Kalyanam commit d893034f3c7b3bc9435cd0cba78f220349b484ae Author: Taniya Das Date: Tue Aug 23 18:47:05 2011 +0530 msm_fb: display: Add support for MIPI DSI Truly panel Change-Id: I499f050622e72c9f1daafa251b16ac67c35a7991 Signed-off-by: Taniya Das commit 959fd6fc48da46199ac1faf8b7d8be18d50af253 Author: Pradeep Jilagam Date: Wed Oct 5 21:19:46 2011 +0530 msm_fb: display: Add YV12 support in the MDP Added changes to support YV12 input format in the MDP. Change-Id: Id8344af1a1607cbf4a6c01ad35441bbdd4fcbd49 Signed-off-by: Pradeep Jilagam commit 4b99172a1df8b1ad2b48343bead39685f294e680 Author: Nagamalleswararao Ganji Date: Fri Jan 28 13:24:34 2011 -0800 msm_fb: display: CSC Matrix update support is added CSC Matrix update support is added for MDP4 VG pipes to convert Ycbcr -> RGB format CRs-fixed: 313601 Change-Id: Ib6fb8f2eab4b1e871a406a3a2d7274fcfdcdd9d1 Signed-off-by: Nagamalleswararao Ganji commit 8611e05dc5cb4b3ce155c04ab4e851dff1438582 Author: Amir Samuelov Date: Tue Oct 11 17:44:32 2011 +0200 msm_fb: display: Change the backlight PWM freq to 66 KHZ for LiQUID Change the backlight PWM to 66 KHZ, according to the backlight driver HW spec. Change-Id: I67bc02b7863d7e8721841edfb4cfe3a4414a1bab Signed-off-by: Amir Samuelov commit a2c2767ee7fa7e55d9cb30873739dc42311d60f4 Author: Manoj Rao Date: Tue Aug 30 17:19:39 2011 -0700 msm: display: HDMI: Driver support for CEC feature Driver implementation of HDMI CEC feature. Support includes CEC frame send and frame receive. Support added for sysfs interface for CEC daemon to interact with the driver for reading and writing frames. sysfs interface /sys/class/graphics/fb1/cec Read: CEC block state. Write: Enable/Disable CEC block. /sys/class/graphics/fb1/cec_logical_addr Read: Print CEC logical address Write: Set CEC logical address which is used for addressing CEC messages to and from MSM /sys/class/graphics/fb1/cec_rd_frame Read: Read rcvd CEC message from message queue. If queue is empty -EBUSY. If CEC block is disabled -EPERM. Write: N/A /sys/class/graphics/fb1/cec_wr_frame Read: N/A Write: Write to send CEC message. If CEC line arbitration fault/no ack -EINVAL. If CEC block is disabled -EPERM. Change-Id: I62ce418b7f1e887550319081cc4b78fbd564a6f5 Signed-off-by: Manoj Rao commit 5e48f5f6701a3cf0f8c325d252037bb49be67fc1 Author: Ravishangar Kalyanam Date: Fri Sep 23 18:56:59 2011 -0700 msm_fb: display: Fix DSI WSVGA Toshiba panel PLL control settings Fix DSI WSVGA Toshiba panel PLL control settings to avoid over-write on reset values from phy table Change-Id: Ia4b3a4a409a4601a3a2c9132ff66c164f1f8c9fd Signed-off-by: Ravishangar Kalyanam commit 7a95a8f6a93bbca3f1664cd12d516041f6d926cf Author: Amir Samuelov Date: Mon Oct 17 15:20:11 2011 +0200 msm_fb: display: Fix dsi read packet size for LiQUID The toshiba DSI-to-LVDS bridge supports only packet size of 4 for reading its registers. The DSI host should avoid changing the bridge packet size. Change-Id: I08a4cb5921c90e9fa07db62e0310fcdb6155f131 Signed-off-by: Amir Samuelov commit 051489246f2a6a4538e7dad2b985837fa06d567a Author: Praveena Pachipulusu Date: Mon Oct 17 10:42:36 2011 +0530 msm: Change the permission of 3d barrier sysfs entry Change-Id: I64f7e028701d65d864d9ed30499bf0bfc00c8ab6 CRs-Fixed: 308897 Signed-off-by: Praveena Pachipulusu commit 898f4bd8a9e7027e2fd9e50000e34abb41834e19 Author: Ravishangar Kalyanam Date: Fri Jul 15 18:25:47 2011 -0700 msm_fb: display: Add support for HDMI as primary Add support for using HDMI as primary. Includes changing number of framebuffers to 2, using RGBA format, enabling HPD by default. Change-Id: I7a01ee3cf981b08d05eed13cd0fb7a41983211b5 Signed-off-by: Ravishangar Kalyanam commit 09ab565589a8a1409c222ce79b6885aa9e96d33d Author: Manoj Rao Date: Mon Oct 10 17:36:15 2011 -0700 mm: display: hdmi: QDSP_OFF evt with OFFLINE evt Every OFFLINE event should be accompanied by QDSP OFF event. This makes sure that QDSP DMA operations occur smoothly before HDMI is powered down. Change-Id: If9797a3b8490ecba05969d546fc70a80c0f76dd0 Signed-off-by: Manoj Rao commit 53ac99d0bb8cdeb0d519b27b1159953447a7a7c7 Author: Manoj Rao Date: Mon Oct 10 17:32:28 2011 -0700 mm: display: hdmi: HPD fix multiple reconnects HDMI display remained blank after multiple reconnect of hdmi cable. Setting the trigger handler to TRUE in hdmi_hpd_on. CRs-Fixed: 291547 Change-Id: I77e660f4b9843991a6948532eea4199b7377a6b9 Signed-off-by: Manoj Rao commit 1c8fc4ae526f9ea79952a8dfd967ba3d11b7dc87 Author: Nagamalleswararao Ganji Date: Mon Oct 10 20:51:31 2011 -0700 msmfb: display: Fix for the 3D stride corruption issue adding the src_x offset to the address causing the stride corruption issue for tile buffer, as the it is changing the alignment Signed-off-by: Nagamalleswararao Ganji Change-Id: I46139c2126b47ac6e1b33135b792ef702cc04446 CRs-fixed: 302409 commit a27bde25b4efd43946c19f1e672554ce0bce63c8 Author: kuogee hsieh Date: Sun Sep 25 13:31:37 2011 -0700 msm_fb: display: add dcs read parser Parser byte stream responsed back from dcs client base on the dcs command type. CRs-fixed: 306936 Change-Id: I0e3776c7ca86f7c4a0f0d090da108599753b9997 Signed-off-by: kuogee hsieh commit 8717a17a1a5555e53d2f8f8160462417105dda6c Author: kuogee hsieh Date: Mon Sep 5 09:57:58 2011 -0700 msm_fb: display: configure dsi control as free run Configure DSI controller as free run instead of software trigger. At free run, DSI controller is triggered by MDP directly when output of blending is ready. No extra register write to trigger DSI controller is necessary. Therefore it reduce latency during MDP kickoff. Change-Id: I630cc47be806a8de383648aa80804b4d65210d4d Signed-off-by: Kuogee Hsieh commit c430223b113ff533ef34c5acb0de6a6ccc3a1b51 Author: Adrian Salido-Moreno Date: Mon Sep 26 12:54:03 2011 -0700 msm_fb: display: avoid staging up two pipes at same mixer_stage staging two pipes at same mixer stage can cause blue screen, adding additional check to avoid this. CRs-Fixed: 304278 Signed-off-by: Adrian Salido-Moreno commit 5a7f32c088bda86c7f0de08d06c8176920b28439 Author: kuogee hsieh Date: Wed Aug 31 17:51:34 2011 -0700 msm_fb: display: received writeback offset from board file Writeback offset need to be passed from board file to avoid hard code value used by MDP. Signed-off-by: Kuogee Hsieh commit e17a2ddc109e0691a25c69acd3ee16de354f5a82 Author: Ravishangar Kalyanam Date: Fri Sep 30 15:04:39 2011 -0700 msm_fb: display: Fix display driver init calls for auto-detection Fix display driver init calls for auto-detection logic to avoid initialization of panel drivers that are not selected for loading through fastboot Signed-off-by: Ravishangar Kalyanam commit e1ed1ae1d4c6d17ddb2a027ced9524c23e878d72 Author: kuogee hsieh Date: Fri Sep 2 08:53:36 2011 -0700 msm_fb: display: vg pipe shared by both rgb and yuv format VG pipe can carry both RGB and YUV format. This patch will allow VG pipe to switch between RGB and YUV format. Signed-off-by: Kuogee Hsieh commit c719c541d8ec1c9a036002a80725457aab10e54f Author: Ravishangar Kalyanam Date: Thu Jul 28 16:49:25 2011 -0700 msm_fb: display: Add boot param LCDC/MIPI panel detection support Add boot param LCDC/MIPI panel detection support for automatically loading selected panels through fastboot command Signed-off-by: Ravishangar Kalyanam commit e2833e9f0a24e1f1d3dc1a912977884920bc5487 Author: Carl Vanderlip Date: Tue Sep 27 13:26:01 2011 -0700 video:msm: Reset histogram when not read Reset the histogram collection if there is no one waiting for it when it is completed. CRs-Fixed: 308367 CRs-Fixed: 305674 Change-Id: I76de44f237f842a1163d8b9f0783bf3457ff1d3d Signed-off-by: Carl Vanderlip commit 5a4f1ba19d0172fe3566f3df5bc78844d84c485b Author: Matt Wagantall Date: Thu Aug 18 18:13:03 2011 -0700 msm: hdmi: Register device with clock driver and rename clocks Rename the clocks per the new naming convention under which similarly named clocks are distinguished between using their associated device's name and ID. Change-Id: I35f164e902003b1c3cd7243bc08d00b4c5d37b0c Signed-off-by: Matt Wagantall commit 1429568ba55646240d551e8f8f9bdd25e4cb249f Author: kuogee hsieh Date: Thu Sep 29 15:57:04 2011 -0700 msm_fb: display: prefill two writeback frames Pre-fill two writeback frames before enable writeback mode to avoid flicking. CRs-fixed: 310076 Signed-off-by: Kuogee Hsieh commit aff429ae7d2d1b272d98935907ddfbf43ff4aaeb Author: kuogee hsieh Date: Thu Sep 22 17:50:05 2011 -0700 msm_fb: display: wait for vsync instead of dmap_done At both lcdc and dsi video mode panel, wait for vsync interrupt instead of dmap_done interrupt to make sure a single frame updated during every vsync period. CRs-fixed: 305599 Signed-off-by: Kuogee Hsieh commit d48737e7b42e51a73d8084cc37d7c1b63fcdefc0 Author: kuogee hsieh Date: Mon Sep 26 09:12:11 2011 -0700 Revert "msm_fb: display: fix behavior of NO_WAIT flag during writeback" This reverts commit 96fbbf3272449febc1a33861af1d275200563965. NO_WAIT frame push need to be followed by a WAIT frame push so that only a MDP kickoff necessary. Therefore this fix should be done at user space program instead at driver. Signed-off-by: Kuogee Hsieh commit a591110794daf54865c88f3f3fcfa8b5b4ab45c2 Author: Jeevan Shriram Date: Fri Sep 23 11:54:21 2011 +0530 msm_fb: display: Fix compilation error for 7x27a target Fix compilation error when CONFIG_FB_MSM_MIPI_PANEL_DETECT is enabled. This is required for auto detections of the mipi dsi panel. Signed-off-by: Jeevan Shriram commit a7c9891a83bb0dbb6729173b0e7a204f20220849 Author: Ravishangar Kalyanam Date: Thu Sep 22 12:44:15 2011 -0700 msm_fb: display: Avoid footswitch control for MDP versions <= 4.2 Avoid footswitch control for MDP versions <= 4.2 to prevent any side effects with video playback and HDMI use cases Signed-off-by: Ravishangar Kalyanam commit 95169f2d316397b15f2666591951c937bdd3de4e Author: Adrian Salido-Moreno Date: Wed Sep 14 19:17:33 2011 -0700 msm_fb: display: fix behavior of NO_WAIT flag during writeback if NO_WAIT flag, overlay buffer should be set and wait for dma_p done should only be done if flag is not enabled. Signed-off-by: Adrian Salido-Moreno commit a1b240fc59964122076812ea4c2f2ebcda99f4f2 Author: kuogee hsieh Date: Mon Sep 19 09:00:07 2011 -0700 msm_fb: display: remove yield with pan display It is more proper to have USER space thread to decide when yield be called. This patch remove yield() from pan display. CRs-fixed: 307344 Signed-off-by: Kuogee Hsieh commit c2f19595abd7e55f302f6b50f39ed81a67cdbee6 Author: Manoj Rao Date: Fri Aug 5 17:54:25 2011 -0700 msm: display: HDMI: Remove audio packet setup for ACP, ISRC In HDMI driver we are setting audio packet with ACP, ISRC by default. Removing this setting until end-to-end feature has been supported. CRs-Fixed: 297272 Signed-off-by: Manoj Rao commit daf1d2101d21f27ed21dbc8e9afe9e82f24083c2 Author: Chandan Uddaraju Date: Tue Aug 30 17:16:07 2011 -0700 msm_fb: Display: Enable novatek sharp panel for 8960 target. Add code to provide DSI PHY settings from board file. Remove chipset dependent changes in panel file. Add fpga register access support for 8960 chipset to enable 3D barrier Signed-off-by: Chandan Uddaraju commit 1dcb24860f556c8e60b333ffbfa26f22773560c1 Author: Manoj Rao Date: Mon Jun 13 22:14:57 2011 -0700 msm: fb: HDMI: Sending AVI Info Frame even if HDCP is disabled AVI_INFO_FRAME was not getting sent if CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT is enabled Getting rid of the #ifdef checks around the function call/defn Signed-off-by: Manoj Rao commit 83eac3cec4e5957abd90a7a73a645f91d477a603 Author: Chandan Uddaraju Date: Sun Sep 11 18:32:23 2011 -0700 msm: Add MIPI DSI novatek panel for 8960 target. Add code to support DSI novatek panel for 8960 target. Add support to provide DSI PHY settings from the board file. Add code to provide FPGA access interface information from the booard file. Signed-off-by: Chandan Uddaraju commit c6ecb836e9afb41bc9475b2a4c39dad8888f5e5f Author: Nagamalleswararao Ganji Date: Wed Sep 14 10:00:18 2011 -0700 msm-fb: display: Fix for the green patch issue in rotation cases always programming the tile_size register has side affect in rotation case. the issue is fixed by programming the tile_size register only in case of tile buffer Signed-off-by: Nagamalleswararao Ganji commit 419051b1b98b5f86ef72a6299ee9d73d039ce09e Author: Ravishangar Kalyanam Date: Wed Aug 31 19:07:53 2011 -0700 msm_fb: display: Move MDP footswitch control to early suspend/resume Move MDP footswitch control from pipe_ctrl to early suspend/resume and fix boot related DSI command mode. This patch resolves the side effects caused by 716e97e704c6591f05f5b88743fca7770f0c61cd on 7x30 CRs-Fixed: 306221 Signed-off-by: Ravishangar Kalyanam commit 18f63087971116fc2af33f90ed42fd764d8ae7c0 Author: Carl Vanderlip Date: Fri Jul 22 12:32:33 2011 -0700 video: msm: Defining functions for MIPI CMD panel Defining do_histogram and lut_update functions for MIPI CMD panel CRs-Fixed: 294029 Signed-off-by: Carl Vanderlip commit c42862ab0b4149d6264b39d849aaf70b3de7a1fe Author: Ravishangar Kalyanam Date: Wed Sep 14 11:42:34 2011 -0700 msm_fb: display: Fix division by zero error in MDP downscale check Fix division by zero error in MDP downscale validation by rejecting destination rectangle width and height params with 0 Signed-off-by: Ravishangar Kalyanam commit 054dc107f98f31b2941489bd37e647e8be7b34e6 Author: kuogee hsieh Date: Fri Sep 9 10:02:58 2011 -0700 msm_fb: display: add mutex during lcdc off There has possibility that suspend operation and screen update happen simultaneously. There mutex at lcdc_off is necessary to serialize both lcdc off and pan display. CRs-fixed: 302527 Signed-off-by: Khsieh commit 7a7e46f6c1b48a5e2a3234bf0bb0e0ccfcd90323 Author: Ravishangar Kalyanam Date: Mon Sep 12 12:45:29 2011 -0700 msm_fb: display: Set DSI Video mode dest type as DISPLAY_LCDC Set DSI Video mode dest type as DISPLAY_LCDC to return correct fps to userspace in reserved[4] CRs-Fixed: 302910 Signed-off-by: Ravishangar Kalyanam commit bbf9a472c9484c9e7a0b6ec15995a29afa0dfaeb Author: Manoj Rao Date: Tue Jun 14 21:05:18 2011 -0700 msm_fb: HDMI: Support for 480p 16:9 in HDMI Driver Requirement for customer (Samsung) to have support for 720x480p 16:9 aspect ratio, prior to this we supported only 4:3 aspect ratio for 720x480p. Adding the appropriate Lookup Table changes. Signed-off-by: Manoj Rao commit 9e4491612de7c7a322d061b85c8d42ee42ea831a Author: Ajay Singh Parmar Date: Fri Sep 9 11:57:41 2011 +0530 msm_fb: display: Re-arrange the reference clock enabling. Reference clock needs to be enabled before DSI PHY Ctrl enabling. Signed-off-by: Ajay Singh Parmar commit 3d4d275bd9442307af9f0ffb36660114e842e529 Author: Ajay Singh Parmar Date: Fri Sep 9 09:01:55 2011 +0530 msm_fb: Display: Set ebi1 clock during lcdc on and off. Set EBI1 clock to 0 during lcdc off and to 65MHz during on. Signed-off-by: Ajay Singh Parmar commit 5c6cfbf2a4f8e76a0d14e37453c31561bca41019 Author: kuogee hsieh Date: Tue Sep 6 19:01:31 2011 -0700 msm_fb: display: no wait for vsync after suspend There has possibility that overlay_unset() is called after suspend had been done. In this case no wait_for_vsync is needed for pulling mode interface (lcdc and dsi video mode) since timing generator was turned off and hence no vsync interrupt will be delivered. This will cause thread to hang up. Signed-off-by: kuogee Hsieh commit 074ee02cd301d9831de59b55d34e2ab5625cc983 Author: Nagamalleswararao Ganji Date: Fri Sep 2 12:06:37 2011 -0700 msm-fb: display: mdp clock scaling clean up clean up of clock scaling code to organize it better Signed-off-by: Nagamalleswararao Ganji commit 07d19c35fd414757f4535f721522ed6379286b47 Author: Ravishangar Kalyanam Date: Thu Sep 1 11:22:35 2011 -0700 msm_fb: display: Synchronize DSI CMD Mode MDP & DMA cmd triggers Synchronize DSI CMD Mode MDP & DMA cmd triggers by handling DSI IRQ enable/disable properly Signed-off-by: Ravishangar Kalyanam commit 668d6d5e3e38f9aa55e78333fb8d200a83f32be8 Author: Manoj Rao Date: Tue Aug 16 19:12:31 2011 -0700 msm:display:hdmi: Fix for EDID read/parse block[1] HDCP enabled DVI monitors with block 0 and block 1 EDID always switched to 640x480 even though they supported higher resolutions. This patch reads DTD data from the correct offset from block[1] and reads correct bits for interlaced format recognition. CRs-Fixed: 290391 Signed-off-by: Manoj Rao commit b84120b47e318d5144604e7249e0e0bc119e1301 Author: Amir Samuelov Date: Sat Sep 3 17:49:43 2011 +0300 msm_fb: display: Add Chimei MIPI-DSI WXGA panel driver. Add Chimei MIPI-DSI WXGA (1366x768) panel driver. Signed-off-by: Amir Samuelov commit 21ef2feb1cddfa15f0a88c0838e3c941a84e9c7e Author: kuogee hsieh Date: Thu Aug 18 17:12:42 2011 -0700 msm_fb: display: use blt mode to implement MDP writeback MDP frame buffer mode was used to implement writeback for pulling interface (lcdc and dsi video). However frame buffer mode is not recommanded by hardware engineer due to lacking of verification. This patch will replace frame buffer mode with BLT mode to implement MDP writeback. Signed-off-by: Kuogee Hsieh commit 073f1221221adb52039bc49f79c81e06335f9c7a Author: kuogee hsieh Date: Fri Sep 2 09:44:22 2011 -0700 msm_fb: display: Add panel vertical porches into TE logic Panel vertical porches are not considered into tear check logic which cause TE can not tolerate panel vsync frequency variation after panel heating up. This cause mdp to hang up and no screen updated after that. This patch will have panel vertical porches considered in during configure TE registers. Signed-off-by: Kuogee Hsieh commit 5e91203dfd1bb3dda16c712a4accde6b2040e437 Author: Adrian Salido-Moreno Date: Mon Aug 29 11:15:47 2011 -0700 msm_fb: display: wait for vsync and change perf level only if needed since overlay_set can be called multiple times to change some parameters, there is no need to wait on vsync to change clock for each call to overlay_set unless there is a change in performance level. Signed-off-by: Adrian Salido-Moreno commit 8fef09a792fe01ec564d09a2b0b29d2bfa55fd21 Author: Ravishangar Kalyanam Date: Tue Aug 9 17:36:23 2011 -0700 msm_fb: display: Remove histogram memcpy from MDP Interrupt handler CRs-Fixed: 300666 Signed-off-by: Ravishangar Kalyanam commit 33dc7b93d4fd73307bb8f68f8067cbe481c5bbcb Author: Adrian Salido-Moreno Date: Thu Aug 18 16:16:12 2011 -0700 msm_fb: display: fix YCrCb planar input format support in mdp MDP hardware expects source addresses to be in YCbCr order, in order to support YCrCb, need to swap chroma planes addresses. CRs-Fixed: 302408 Signed-off-by: Adrian Salido-Moreno commit 2ca30356bd3e2db7de9df06670ff9ba2f6dfafe4 Author: Nagamalleswararao Ganji Date: Fri Jun 24 18:16:23 2011 -0700 msm_fb: display: Fix DSI PLL/clock warnings CRs-Fixed: 300073 Signed-off-by: Nagamalleswararao Ganji commit 57dcfff1206da4b1f6e3cdbbc63b5c27d57ded24 Author: kuogee hsieh Date: Wed Aug 24 14:34:46 2011 -0700 msm_fb: display: synchronous UI and Video thread Use mutex to synchronous between UI and Video thread. Meanwhile, add yield() when at end of frame push of UI thread to prevent UI thread from dominating cpu times. CRs-fixed: 303246 Signed-off-by: Kuogee Hsieh commit bea4783bcd4a65f11a6c5c00995a04dcea72c002 Author: Nagamalleswararao Ganji Date: Mon Aug 15 10:49:59 2011 -0700 msm-fb : display: foot switch control for the mdp driver adds the support for disable/enable the mdp foot switch at suspend/resume boundaries Signed-off-by: Nagamalleswararao Ganji commit 3a8b8514533d94af2e9fcb4b215f968f07d14253 Author: Zhang Chang Ken Date: Thu Aug 4 18:41:39 2011 -0400 msm:8060: lcdc nt35582 panel support Signed-off-by: Zhang Chang Ken commit d5315bd98102b8a2f8e36bbd69b15b679dc43e84 Author: Abhishek Kharbanda Date: Wed Aug 10 19:45:53 2011 -0700 msm_fb: [HDMI_COMPLIANCE] Enable Audio for HDMI Compliance Enable Audio event for NON-HDCP builds required for HDMI Compliance Cases. Signed-off-by: Abhishek Kharbanda commit e52976fc8742c1734c3fda80735d0dfd21c61826 Author: kuogee hsieh Date: Fri Aug 12 15:32:52 2011 -0700 msm_fb: display: use mutex instead of spin lock to avoid deadlock There has deadlock between mdp4_isr() and disable_irq() called by LCDC thread. Disable_irq() will wait for mdp4_isr() to complete before return. Meanwhile mdp4_isr() will try to acquire mdp_spin_lock which had been acquired by lcdc thread before call disable_irq(). This patch replace spin lock with mutex to avoid deadlock from happening. CRs-fixed: 301276 Signed-off-by: kuogee hsieh commit 48aef6d5c2dbe622a0c44440809f4860ff7a5770 Author: Pradeep Jilagam Date: Thu Aug 18 18:58:50 2011 +0530 msm_fb: display: Vote for AXI Clock for DSI on 7x27A Vote for a minimum rate of 65 MHz for AXI Clock while using DSI interface on 7x27A Signed-off-by: Pradeep Jilagam commit 0a3249ebfc2d474378fb2a3e49dad2140fd6b042 Author: Matt Wagantall Date: Tue Aug 16 12:16:19 2011 -0700 msm-fb: display: Remove explicit control of mdp_axi_clk This clock is already enabled and disabled implicitly along with mdp_clk and should not be controlled directly by the MDP driver. Signed-off-by: Matt Wagantall commit 4d3c779eb9d906b381225be5065976703d91872a Author: kuogee hsieh Date: Mon Jul 25 11:02:24 2011 -0700 msm_fb: display: disable timing generator before enable writeback mode At pulling mode (lcdc and dsi video mode), timing generator need to be turned off before enable wriback mode and turn it back on after enabled. CRs-fixed: 298593 Signed-off-by: kuogee Hsieh commit 1833754d1f71e8b52e3ac0fcfb4602048763f39c Author: Ravishangar Kalyanam Date: Fri Aug 12 10:26:35 2011 -0700 msm_fb: display: Fix HDMI clock control during suspend/resume Fix HDMI clock control during suspend/resume to avoid incorrect reference counts CRs-Fixed: 293818 Signed-off-by: Ravishangar Kalyanam commit 9452ecb5b57e5bde9b880a2a1ddcd0f210ce9dea Author: kuogee hsieh Date: Mon Aug 1 18:26:23 2011 -0700 msm_fb: display: change mdp clock while mdp is idle at overlay_set() MDP clock is adjusted base on run time perfomance level. This patch will change MDP clock while mdp is in idle state at overlay_set() when performance level changed to avoid MDP from underrun. Signed-off-by: Kuogee Hsieh commit 01d682803053d294ef11da8bef3e88b073c43cc8 Author: Ravishangar Kalyanam Date: Mon Jul 18 18:45:06 2011 -0700 msm_fb: display: Adjust overlay VG pipe src params for non-zero x_offset Adjust overlay VG pipe src params for non-zero x_offset to avoid overfetching of pixels from the left of x_offset CRs-Fixed: 296185 Signed-off-by: Ravishangar Kalyanam commit 115d7975e66ab3e5f9c03d9660413a940517ddeb Author: Ravishangar Kalyanam Date: Tue Aug 9 12:52:14 2011 -0700 msm_fb: display: Add mb() before reading MDP histogram data Signed-off-by: Ravishangar Kalyanam commit 164fe8a429e39cad3f03d56dfa4dce85ff90a0b3 Author: Stepan Moskovchenko Date: Fri Aug 5 18:10:54 2011 -0700 msm: hdmi: Disable the HDMI driver on APQ8064 Prevent HDMI initialization from running on APQ8064. Signed-off-by: Stepan Moskovchenko commit 120232e5eed881f12c9d6196f2f5567106c2c98a Author: Ravishangar Kalyanam Date: Fri Aug 5 19:13:55 2011 -0700 msm_fb: display: Enable tv_enc_clk for 7x30 to avoid HDMI freeze Signed-off-by: Ravishangar Kalyanam commit 48551552f956565389a760cd46fd6db8ad79a044 Author: Ravishangar Kalyanam Date: Mon Aug 8 15:33:42 2011 -0700 msm_fb: display: Fix vsync GPIO for DSI command mode Fix vsync GPIO 0 condition check for DSI command mode to enable Tear check logic CRs-Fixed: 298596 Signed-off-by: Ravishangar Kalyanam commit 3436daeb9f5e1216c827a85252b4c35a6d8380e6 Author: Adrian Salido-Moreno Date: Mon Aug 8 12:13:07 2011 -0700 msm_fb: display: increase mdp max burst size increase mdp dma and pipes max burst size, to avoid mdp underruns (blue frames shown on display). Signed-off-by: Adrian Salido-Moreno commit 3a76ccb3dff876cea6494d777c24c232c5964c4e Author: kuogee hsieh Date: Fri Aug 5 13:30:28 2011 -0700 msm_fb: display: use spin_lock_irqsave before call disable_irq disable_irq() will wait for irq handle to complete before disable the specified irq. Therefore use spin_lock_irqsave() instead of spin_lock() before call disable_irq() to avoid deadlock on same spin lock. CRs-fixed: 299938 Signed-off-by: Kuogee Hsieh commit ed016bedc8c2af80b10a9d0558b537cf5e396636 Author: Nagamalleswararao Ganji Date: Sat Jul 23 17:58:43 2011 -0700 msm-fb: display: back light support for mipi driver back light control logic is added to mipi driver. it supports 100 levels Signed-off-by: Nagamalleswararao Ganji commit e7833e230a3843070f4628532e5902442eeed2c4 Author: Ravishangar Kalyanam Date: Fri Jul 22 16:20:19 2011 -0700 msm_fb: display: Add MDP 4.2 histogram support for DSI Video Signed-off-by: Ravishangar Kalyanam commit 58b5555b7d19272e43732364b68e5d7c74b30870 Author: Ajay Singh Parmar Date: Tue Aug 2 10:28:01 2011 +0530 msm_fb: display: Avoid BTA requests during panel init. BTA requests may fail during panel initialization if the DSI Client is not stabilized yet. Hence, avoid them during initialization. CRs-Fixed: 298789 Signed-off-by: Ajay Singh Parmar commit bb3d48517f5d590cb66cee5b2fe418abf4eb69d1 Author: Adrian Salido-Moreno Date: Mon Aug 1 15:57:52 2011 -0700 msm_fb: display: disable fill screen with blank on early suspend Disable logic to fill framebuffer with black screen before early suspend, this is causing slugish wipe off from top to bottom animation on screen. This logic is still needed for MDP3 because of hardware limitation. CRs-Fixed: 298050 Signed-off-by: Adrian Salido-Moreno commit 492049ec4f59bf04275878a9d16ae20528159636 Author: Adrian Salido-Moreno Date: Mon Aug 1 14:06:21 2011 -0700 msm_fb: display: clear interrupt flag to properly wait for vsync need to properly clear vsync interrupt flag so that subsequent waits for vsync are handled properly, otherwise wait will return before next vsync happens CRs-Fixed: 299043 Signed-off-by: Adrian Salido-Moreno commit e546d48310bbb1b62e56a4f361af923c8814de54 Author: Ajay Singh Parmar Date: Fri Jul 29 15:43:52 2011 +0530 msm_fb: display: Modify panel init commands for HVGA on 7x25A Modify panel init commands to send the video timing values for HVGA resolution on 7x25A. CRs-Fixed: 297154 Signed-off-by: Ajay Singh Parmar commit b91fa71c588a9785f639193c49295b88031971d7 Author: Manoj Rao Date: Wed Jun 29 09:07:55 2011 -0700 msm: display: HDMI: VG2 pipe solid fill color causes MDP to hang During 3D video playback both VG pipes are used, solid color fill into VG2 pipe for HDCP compliance purpose causes MDP to hang instead, we enable Encryption on HDMI TMDS Output By setting BIT[2] of HDMI_CTRL register to enable encryption on HDMI TMDS Output. Signed-off-by: Manoj Rao commit 7b57bb815b5287b0c8ef618459d989475aa2f071 Author: Ravishangar Kalyanam Date: Tue Jul 19 19:14:23 2011 -0700 msm_fb: display: Use __va instead of ioremap for framebuffer memory map Signed-off-by: Ravishangar Kalyanam commit 405dc3051b06637b6a38aa6b1f4da1660cff37d0 Author: kuogee hsieh Date: Thu Jul 21 15:06:59 2011 -0700 msm_fb: display: add ioctl for mixer info Add new ioctl to allow user to query mdp mixer detail configuration. Signed-off-by: Kuogee Hsieh commit c4b8b2fb9d783be26b85381b3618bbe253a75b89 Author: kuogee hsieh Date: Tue Jul 12 13:32:14 2011 -0700 msm_fb: display: change mdp clock while mdp is idle Mdp clock need to be adjusted at run time base on the performance level. However mdp clock can only be changed when mdp blending/dma engine is idle. Signed-off-by: Kuogee Hsieh commit f74d2edd791b3fddaf147c5e358a8f41463dc1f9 Author: Manoj Rao Date: Mon Jul 18 14:25:38 2011 -0700 msm: display: HDMI: ISR not triggered when HPD occurs during power_off During power off we disable 5v, power down core, by turning off the TX channels one by one. When a HPD is triggered the driver has a software debouncing timer during which interrupts are disabled to be able to read stable HPD status from the register. When HPD is detected while the core is being turned off/powered down the driver's software disables the interrupt and this was making the core to go into off state. So the fix was to keep the interrupt bit enabled through the register even during the debounce timeout (this doesn't trigger unnecessary interrupts due to appropriate clearing and masking of HPD interrupt bits). Signed-off-by: Manoj Rao commit 49a83b2caa9718d35fab9a9fa9ad2d9436040ffd Author: Ravishangar Kalyanam Date: Wed Jul 20 15:28:44 2011 -0700 msm_fb: display: Fix 8960 HDMI resolution switch issue Fix 8960 HDMI resolution switch issue by removing core reset via clock branches. This helps in retaining the HDMI PLL register values for subsequent cable disconnect/connect scenarios. CRs-Fixed: 296879 Signed-off-by: Ravishangar Kalyanam commit a411f7e5195777253d4c3c94430787b4f19ea068 Author: Stepan Moskovchenko Date: Wed Jul 20 13:21:08 2011 -0700 video: Kconfig: Remove extraneous dots from help text Clean up the help text by removing extraneous punctuation. Signed-off-by: Stepan Moskovchenko commit 4aea274b69eeee685d87e159107f0d0eb9b35b70 Author: kuogee hsieh Date: Wed Jul 6 11:05:05 2011 -0700 msm_fb: display: add 3D support at DSI video mode Currently, only DSI command mode have 3D capability. Add 3D support for DSI video mode also. CRs-fixed: 294082 Signed-off-by: Kuogee Hsieh commit 8d1f8724f0d89d474a283f2ba6f51801d14daaee Author: Ravishangar Kalyanam Date: Thu Jul 14 18:45:07 2011 -0700 msm_fb: display: Fix writeback offset with correct fbnum Fix writeback offset with correct fbnum value to avoid any memory corruption with image buffers in use CRs-Fixed: 290324 Signed-off-by: Ravishangar Kalyanam commit bdc7bbba1cc1202166a45b479b1cb7b0e54eec8f Author: Matt Wagantall Date: Fri Jul 15 12:26:19 2011 -0700 msm: Remove last references to NPA-related code for AXI rate management The NPA driver was removed some time ago, but wrapper code and some of its driver hooks persisted in the tree, despite not being compiled (or even compilable). Remove these now. Signed-off-by: Matt Wagantall commit ebca0c796cb22947a224c1afea9b7950886804e1 Author: kuogee hsieh Date: Thu Jul 14 13:30:33 2011 -0700 msm_fb: display: set flush bit at overlay_unset set flush bit at overlay_unset to notify mdp blending engine to pick up new configuration changes. Signed-off-by: KUogee Hiseh commit 3de11f35c77c7239a51c64254b00e400abaf93f1 Author: kuogee hsieh Date: Fri Jul 8 14:09:11 2011 -0700 msm_fb: display: add spinlock to synchronize mdp irq enable/disable To improve performance, UI push thread release mutex before blocked at waiting for vsync to allow Video thread to be updated at same vsycn. This also cause contention to enable/disable mdp irq. Add spinlock to synchronize both threads and irq context. Signed-off-by: Kuogee Hsieh commit 9d28c3e809aac17dc2e3f6923e730293ae4aa977 Author: Jeevan Shriram Date: Fri Jul 8 17:59:18 2011 +0530 msm_fb: display: Enable H/W vsync in msm7x27a Enable tearing effect control in msm7x27a using gpio. CRs-Fixed: 289024 Signed-off-by: Jeevan Shriram commit 759a8cf14ce1c2f0d6551a090fac84ec7f4705f2 Author: Ravishangar Kalyanam Date: Fri Jul 8 11:50:33 2011 -0700 msm_fb: display: Use spinlock instead of mutex in vsync timer handler Use spinlock instead of mutex in vsync timer handler to avoid sleeping from timer context through mutex locks Signed-off-by: Ravishangar Kalyanam commit 3f2bc4d6eb5a4fada842462ba22bb6bbb41d00c7 Author: Bryan Huntsman Date: Tue Aug 16 17:27:22 2011 -0700 Initial Contribution msm-2.6.38: tag AU_LINUX_ANDROID_GINGERBREAD.02.03.04.00.142 Signed-off-by: Bryan Huntsman commit 39fff5a3899f8d95886ba2e50d70001602b279c0 Author: Adrian Salido-Moreno Date: Mon Sep 26 12:54:03 2011 -0700 msm_fb: display: avoid staging up two pipes at same mixer_stage staging two pipes at same mixer stage can cause blue screen, adding additional check to avoid this. CRs-Fixed: 304278 Change-Id: Id270b97eba6d01583dac3091cce0403a6aa96be7 Signed-off-by: Adrian Salido-Moreno commit cb472111d93fa119c52d56c102b90cc3ad2c8030 Author: kuogee hsieh Date: Fri Sep 2 08:53:36 2011 -0700 msm_fb: display: vg pipe shared by both rgb and yuv format VG pipe can carry both RGB and YUV format. This patch will allow VG pipe to switch between RGB and YUV format. Change-Id: Ib64ddaf9d887ac3250b40451fab70d7ca9df081e Signed-off-by: Kuogee Hsieh commit 3b9047132b38c211d4d8a26896ceb4e151bf618a Author: Ravishangar Kalyanam Date: Fri Sep 30 15:04:39 2011 -0700 msm_fb: display: Fix display driver init calls for auto-detection Fix display driver init calls for auto-detection logic to avoid initialization of panel drivers that are not selected for loading through fastboot Change-Id: I32a7c220efd33f748a7b46fb1006e5f0a59dc4dd Signed-off-by: Ravishangar Kalyanam commit 91be717084e45121fc1232e8309343c605603928 Author: Ravishangar Kalyanam Date: Thu Jul 28 16:49:25 2011 -0700 msm_fb: display: Add boot param LCDC/MIPI panel detection support Add boot param LCDC/MIPI panel detection support for automatically loading selected panels through fastboot command Change-Id: I5f5167411ac2e5bbc4287148d22608a7e1f2af35 Signed-off-by: Ravishangar Kalyanam commit d8a25911705d1baef68f3accf2bdcb4327152705 Author: Matt Wagantall Date: Thu Aug 18 18:13:03 2011 -0700 msm: hdmi: Register device with clock driver and rename clocks Rename the clocks per the new naming convention under which similarly named clocks are distinguished between using their associated device's name and ID. Change-Id: I35f164e902003b1c3cd7243bc08d00b4c5d37b0c Signed-off-by: Matt Wagantall commit a2e6ec896e8d2e10965d6f8df6f0affdf162a489 Author: kuogee hsieh Date: Wed Aug 31 17:51:34 2011 -0700 msm_fb: display: received writeback offset from board file Writeback offset need to be passed from board file to avoid hard code value used by MDP. Change-Id: Iff123c6046eb69b5d26e632ad507605774f6562f Signed-off-by: Kuogee Hsieh commit 5a95ccd976434514d06384c2684c187daf3925ea Author: kuogee hsieh Date: Thu Sep 29 15:57:04 2011 -0700 msm_fb: display: prefill two writeback frames Pre-fill two writeback frames before enable writeback mode to avoid flicking. CRs-fixed: 310076 Change-Id: Ifb4f6d16967cb98a25a253c99a8af2da2a22404d Signed-off-by: Kuogee Hsieh commit 2f7ff25ba93f7f6485b1a878f08a58040ee7ee57 Author: kuogee hsieh Date: Thu Sep 22 17:50:05 2011 -0700 msm_fb: display: wait for vsync instead of dmap_done At both lcdc and dsi video mode panel, wait for vsync interrupt instead of dmap_done interrupt to make sure a single frame updated during every vsync period. CRs-fixed: 305599 Change-Id: I1795bb154fcee4813b4a1e5e935ed7c9863cd849 Signed-off-by: Kuogee Hsieh commit 6e4e76632b3e8e109da4b63fdf653af246dcde1e Author: kuogee hsieh Date: Mon Sep 26 09:12:11 2011 -0700 Revert "msm_fb: display: fix behavior of NO_WAIT flag during writeback" This reverts commit 96fbbf3272449febc1a33861af1d275200563965. NO_WAIT frame push need to be followed by a WAIT frame push so that only a MDP kickoff necessary. Therefore this fix should be done at user space program instead at driver. Change-Id: I39f263a8e0263aa04274d95fa43e2bd4b5815185 Signed-off-by: Kuogee Hsieh commit 46e3767f9ec607dddb2fa6ac8f41a0c0e455a479 Author: Jeevan Shriram Date: Fri Sep 23 11:54:21 2011 +0530 msm_fb: display: Fix compilation error for 7x27a target Fix compilation error when CONFIG_FB_MSM_MIPI_PANEL_DETECT is enabled. This is required for auto detections of the mipi dsi panel. Change-Id: I2f0ab81c2432d7d04fd685f0d104858b8342bd9c Signed-off-by: Jeevan Shriram commit f076525d4ed93b77ca5a4cad20771e34dd5cbea1 Author: Ravishangar Kalyanam Date: Thu Sep 22 12:44:15 2011 -0700 msm_fb: display: Avoid footswitch control for MDP versions <= 4.2 Avoid footswitch control for MDP versions <= 4.2 to prevent any side effects with video playback and HDMI use cases Change-Id: I75d46e16564c4a7d1486f1ac59f79b8b218290c3 Signed-off-by: Ravishangar Kalyanam commit 96fbbf3272449febc1a33861af1d275200563965 Author: Adrian Salido-Moreno Date: Wed Sep 14 19:17:33 2011 -0700 msm_fb: display: fix behavior of NO_WAIT flag during writeback if NO_WAIT flag, overlay buffer should be set and wait for dma_p done should only be done if flag is not enabled. Change-Id: Ic007306a019956f565b0336d966cec7fdeefe918 Signed-off-by: Adrian Salido-Moreno commit 5ecbf18f5513f653847d83c8f24aae6c5a184eee Author: Manoj Rao Date: Fri Aug 5 17:54:25 2011 -0700 msm: display: HDMI: Remove audio packet setup for ACP, ISRC In HDMI driver we are setting audio packet with ACP, ISRC by default. Removing this setting until end-to-end feature has been supported. CRs-Fixed: 297272 Change-Id: Ibbdbdaedf4ad5000e3f44d1e80888d68e23ff842 Signed-off-by: Manoj Rao commit a7ec6eccf30ef970ec47444058f490530ac92600 Author: Chandan Uddaraju Date: Tue Aug 30 17:16:07 2011 -0700 msm_fb: Display: Enable novatek sharp panel for 8960 target. Add code to provide DSI PHY settings from board file. Remove chipset dependent changes in panel file. Add fpga register access support for 8960 chipset to enable 3D barrier Change-Id: I89a8dce29c1ea41894eebdfd3bdb5ad7178aa8ee Signed-off-by: Chandan Uddaraju commit 7e65d5e31f62a20ae919e0e70f04d000a353bd52 Author: Chandan Uddaraju Date: Sun Sep 11 18:32:23 2011 -0700 msm: Add MIPI DSI novatek panel for 8960 target. Add code to support DSI novatek panel for 8960 target. Add support to provide DSI PHY settings from the board file. Add code to provide FPGA access interface information from the booard file. Change-Id: I03ae784750eb4763569cf8faca43ecd46f995638 Signed-off-by: Chandan Uddaraju commit c2177245161614a0302380d0eca57deae0cb10b5 Author: Nagamalleswararao Ganji Date: Wed Sep 14 10:00:18 2011 -0700 msm-fb: display: Fix for the green patch issue in rotation cases always programming the tile_size register has side affect in rotation case. the issue is fixed by programming the tile_size register only in case of tile buffer Change-Id: I2012cc3cd9a69b7d5eadb690fee4faa1857ee059 Signed-off-by: Nagamalleswararao Ganji commit 4d28b63ec5ca47e074ae87551911d6a5f8c289d0 Author: Manoj Rao Date: Mon Jun 13 22:14:57 2011 -0700 msm: fb: HDMI: Sending AVI Info Frame even if HDCP is disabled AVI_INFO_FRAME was not getting sent if CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT is enabled Getting rid of the #ifdef checks around the function call/defn Change-Id: I462422e4b0d17013d61e841f66fd155db4b7ea00 Signed-off-by: Manoj Rao commit a7cb9d450cc6aa03df1f18191c2b36c8222bbe32 Author: kuogee hsieh Date: Mon Sep 19 09:00:07 2011 -0700 msm_fb: display: remove yield with pan display It is more proper to have USER space thread to decide when yield be called. This patch remove yield() from pan display. CRs-fixed: 307344 Change-Id: I00ab1fa277a86d721a78ea2d2c9d8139c92e0719 Signed-off-by: Kuogee Hsieh commit 9955cf6062327857c43947cc7ec78649619c8735 Author: Ravishangar Kalyanam Date: Wed Aug 31 19:07:53 2011 -0700 msm_fb: display: Move MDP footswitch control to early suspend/resume Move MDP footswitch control from pipe_ctrl to early suspend/resume and fix boot related DSI command mode. This patch resolves the side effects caused by 716e97e704c6591f05f5b88743fca7770f0c61cd on 7x30 CRs-Fixed: 306221 Change-Id: Ie179e0281bff19ea69ec60fdabcf18190c390660 Signed-off-by: Ravishangar Kalyanam commit 7b31a46e449747c2ca79605450f57658c855c756 Author: Carl Vanderlip Date: Fri Jul 22 12:32:33 2011 -0700 video: msm: Defining functions for MIPI CMD panel Defining do_histogram and lut_update functions for MIPI CMD panel Change-Id: I47a4a55d85f4fe2555628d833220b7e72c69cbf5 CRs-Fixed: 294029 Signed-off-by: Carl Vanderlip commit 313e9c47ee295bff714ca1a535fe6681945d5421 Author: Ravishangar Kalyanam Date: Wed Sep 14 11:42:34 2011 -0700 msm_fb: display: Fix division by zero error in MDP downscale check Fix division by zero error in MDP downscale validation by rejecting destination rectangle width and height params with 0 Change-Id: Ia7054e7f1d05740b765a6c9b88f8f844cb605bbb Signed-off-by: Ravishangar Kalyanam commit 4e6e7ed6081dc0a6877a99f734928e9831ecfd4b Author: kuogee hsieh Date: Fri Sep 9 10:02:58 2011 -0700 msm_fb: display: add mutex during lcdc off There has possibility that suspend operation and screen update happen simultaneously. There mutex at lcdc_off is necessary to serialize both lcdc off and pan display. CRs-fixed: 302527 Change-Id: I5b4f8e11262c60d286d98c79f0c32e0104a7d57b Signed-off-by: Khsieh commit 64ee60e185dd7c5b2b6d08f3c81fcdd9a7a5e178 Author: Manoj Rao Date: Tue Jun 14 21:05:18 2011 -0700 msm_fb: HDMI: Support for 480p 16:9 in HDMI Driver Requirement for customer (Samsung) to have support for 720x480p 16:9 aspect ratio, prior to this we supported only 4:3 aspect ratio for 720x480p. Adding the appropriate Lookup Table changes. Change-Id: I5c0804854cb33d1fb875bf1f6c52acd0a0e0940c Signed-off-by: Manoj Rao commit a8d17b9e9d8c1f980002994c81c9ae1ff25dca8f Author: Ravishangar Kalyanam Date: Mon Sep 12 12:45:29 2011 -0700 msm_fb: display: Set DSI Video mode dest type as DISPLAY_LCDC Set DSI Video mode dest type as DISPLAY_LCDC to return correct fps to userspace in reserved[4] CRs-Fixed: 302910 Change-Id: I0ef69645fa08e8c756aa25be95ac5a9d038a3910 Signed-off-by: Ravishangar Kalyanam commit 1c60d7efe10dd5b2824464d3187bb8262ee25d2f Author: Ajay Singh Parmar Date: Fri Sep 9 09:01:55 2011 +0530 msm_fb: Display: Set ebi1 clock during lcdc on and off. Set EBI1 clock to 0 during lcdc off and to 65MHz during on. Change-Id: Ia81a8d52c6f9a24f8107d62596eed3cdc966e4dd Signed-off-by: Ajay Singh Parmar commit 9f1bb9925e9d0ea9eb505695601941f48f8aed7e Author: Ajay Singh Parmar Date: Fri Sep 9 11:57:41 2011 +0530 msm_fb: display: Re-arrange the reference clock enabling. Reference clock needs to be enabled before DSI PHY Ctrl enabling. Change-Id: I754a23592901225f3f52772b7ff4666f5b6d429f Signed-off-by: Ajay Singh Parmar commit 743f162911247ba260445deb01b5406d0067daf3 Author: kuogee hsieh Date: Tue Sep 6 19:01:31 2011 -0700 msm_fb: display: no wait for vsync after suspend There has possibility that overlay_unset() is called after suspend had been done. In this case no wait_for_vsync is needed for pulling mode interface (lcdc and dsi video mode) since timing generator was turned off and hence no vsync interrupt will be delivered. This will cause thread to hang up. Change-Id: I107af5cc0c1a914c53a22558085123798ca2b5f2 Signed-off-by: kuogee Hsieh commit b8c3aa8bdd5974b75a8782cab641936bfa7eb3f6 Author: Nagamalleswararao Ganji Date: Fri Sep 2 12:06:37 2011 -0700 msm-fb: display: mdp clock scaling clean up clean up of clock scaling code to organize it better Change-Id: I056c15de115367a33209c876a0d64cea85a02655 Signed-off-by: Nagamalleswararao Ganji commit 446d22d4641f699b741d16ea6086ce570c49dd7c Author: Ravishangar Kalyanam Date: Thu Sep 1 11:22:35 2011 -0700 msm_fb: display: Synchronize DSI CMD Mode MDP & DMA cmd triggers Synchronize DSI CMD Mode MDP & DMA cmd triggers by handling DSI IRQ enable/disable properly Signed-off-by: Ravishangar Kalyanam Change-Id: I7f493f1b850d40156b505cf88da308844ee34b42 commit 4f7e10164fc8f8477a0929cb910a849772620bc9 Author: Amir Samuelov Date: Sat Sep 3 17:49:43 2011 +0300 msm_fb: display: Add Chimei MIPI-DSI WXGA panel driver. Add Chimei MIPI-DSI WXGA (1366x768) panel driver. Change-Id: I0409909ea6f24db3da6ebf4d92233e45da93c2a4 Signed-off-by: Amir Samuelov commit 9c08f6850dbd998adf7956887060eec599a8f26f Author: kuogee hsieh Date: Thu Aug 18 17:12:42 2011 -0700 msm_fb: display: use blt mode to implement MDP writeback MDP frame buffer mode was used to implement writeback for pulling interface (lcdc and dsi video). However frame buffer mode is not recommanded by hardware engineer due to lacking of verification. This patch will replace frame buffer mode with BLT mode to implement MDP writeback. Change-Id: I5cf94a2523c453cf4e82f68f3167c3c2442d9c82 Signed-off-by: Kuogee Hsieh commit 4d93d76ca62d758fa6f584a5a6f86ed92b0ea845 Author: kuogee hsieh Date: Fri Sep 2 09:44:22 2011 -0700 msm_fb: display: Add panel vertical porches into TE logic Panel vertical porches are not considered into tear check logic which cause TE can not tolerate panel vsync frequency variation after panel heating up. This cause mdp to hang up and no screen updated after that. This patch will have panel vertical porches considered in during configure TE registers. Change-Id: I3ede2a9fa25adc62c85b5514c1bb1600ec7ce460 Signed-off-by: Kuogee Hsieh commit 8ee9289450d530ab1fdec2379859fca5845a7808 Author: Adrian Salido-Moreno Date: Mon Aug 29 11:15:47 2011 -0700 msm_fb: display: wait for vsync and change perf level only if needed since overlay_set can be called multiple times to change some parameters, there is no need to wait on vsync to change clock for each call to overlay_set unless there is a change in performance level. Change-Id: I6f03e957983c4161499a26cfe2f9008a997a04c5 Signed-off-by: Adrian Salido-Moreno commit 4d8813b4fd6fe7588c411e90a2603b23a772f738 Author: Manoj Rao Date: Tue Aug 16 19:12:31 2011 -0700 msm:display:hdmi: Fix for EDID read/parse block[1] HDCP enabled DVI monitors with block 0 and block 1 EDID always switched to 640x480 even though they supported higher resolutions. This patch reads DTD data from the correct offset from block[1] and reads correct bits for interlaced format recognition. Change-Id: I252df99c085bf3e9ada117aa7c08f3a1f3023475 CRs-Fixed: 290391 Signed-off-by: Manoj Rao commit c429f0a0d694ee7ef3471c1b5172b050bf17a1f4 Author: Ravishangar Kalyanam Date: Tue Aug 9 17:36:23 2011 -0700 msm_fb: display: Remove histogram memcpy from MDP Interrupt handler CRs-Fixed: 300666 Change-Id: I8b054f61ae907735064da549e493964176ed3090 Signed-off-by: Ravishangar Kalyanam commit bca2a2055432cdf78380ac070ba0ede9c5893083 Author: Nagamalleswararao Ganji Date: Fri Jun 24 18:16:23 2011 -0700 msm_fb: display: Fix DSI PLL/clock warnings CRs-Fixed: 300073 Change-Id: I6a0793ff049017785b75624d30d0fe862e41b210 Signed-off-by: Nagamalleswararao Ganji commit 871edcfd5a801feed587b6c7f72aa4e1387d245f Author: kuogee hsieh Date: Wed Aug 24 14:34:46 2011 -0700 msm_fb: display: synchronous UI and Video thread Use mutex to synchronous between UI and Video thread. Meanwhile, add yield() when at end of frame push of UI thread to prevent UI thread from dominating cpu times. CRs-fixed: 303246 Change-Id: I06c21a6fb480e119ad4ec75e993203124b97f4b2 Signed-off-by: Kuogee Hsieh commit ede104a0244a04ca6fa6ce8fe9fc98008462df9e Author: Zhang Chang Ken Date: Thu Aug 4 18:41:39 2011 -0400 msm:8060: lcdc nt35582 panel support Change-Id: Ic5714dad929cf56505569cba14722a20dee12c15 Signed-off-by: Zhang Chang Ken commit 716e97e704c6591f05f5b88743fca7770f0c61cd Author: Nagamalleswararao Ganji Date: Mon Aug 15 10:49:59 2011 -0700 msm-fb : display: foot switch control for the mdp driver adds the support for disable/enable the mdp foot switch at suspend/resume boundaries Change-Id: I3c80e4307f84d32b02872e977858fb0adc293b94 Signed-off-by: Nagamalleswararao Ganji commit 64b4b03461e39a715b33a2ea1ab97f5b27850535 Author: Adrian Salido-Moreno Date: Thu Aug 18 16:16:12 2011 -0700 msm_fb: display: fix YCrCb planar input format support in mdp MDP hardware expects source addresses to be in YCbCr order, in order to support YCrCb, need to swap chroma planes addresses. Change-Id: Ie2a0785d490dc92f7f14f64aa3c2e28e6a231202 CRs-Fixed: 302408 Signed-off-by: Adrian Salido-Moreno commit cd1ebfb22a41e9c3c84c7c7a1e5e0b91fc1fcc8c Author: Abhishek Kharbanda Date: Wed Aug 10 19:45:53 2011 -0700 msm_fb: [HDMI_COMPLIANCE] Enable Audio for HDMI Compliance Enable Audio event for NON-HDCP builds required for HDMI Compliance Cases. Change-Id: I94ba3457311c58415ba29bccdc2d146891b17897 Signed-off-by: Abhishek Kharbanda commit f4e2e01971ffc096a98fb42a8a1f1db13e0b2be5 Author: kuogee hsieh Date: Fri Aug 12 15:32:52 2011 -0700 msm_fb: display: use mutex instead of spin lock to avoid deadlock There has deadlock between mdp4_isr() and disable_irq() called by LCDC thread. Disable_irq() will wait for mdp4_isr() to complete before return. Meanwhile mdp4_isr() will try to acquire mdp_spin_lock which had been acquired by lcdc thread before call disable_irq(). This patch replace spin lock with mutex to avoid deadlock from happening. CRs-fixed: 301276 Change-Id: I0ce9cf2a7eefd785ad161b10204e56285248661f Signed-off-by: kuogee hsieh commit cfb68532d8d09c54564590fb8eeaa83383004472 Author: Pradeep Jilagam Date: Thu Aug 18 18:58:50 2011 +0530 msm_fb: display: Vote for AXI Clock for DSI on 7x27A Vote for a minimum rate of 65 MHz for AXI Clock while using DSI interface on 7x27A Change-Id: Ie3e020394492fdb0209b7eec2ab2303b4f2a9ebb Signed-off-by: Pradeep Jilagam commit ea9be62c230d982d6122b16b8717131f0df6f215 Author: Matt Wagantall Date: Tue Aug 16 12:16:19 2011 -0700 msm-fb: display: Remove explicit control of mdp_axi_clk This clock is already enabled and disabled implicitly along with mdp_clk and should not be controlled directly by the MDP driver. Change-Id: I47d68ddb2565be4f3d131061a21c5d921142e933 Signed-off-by: Matt Wagantall commit 60dc151a43093fad5f68d02323570d5efd58ee4a Author: kuogee hsieh Date: Mon Jul 25 11:02:24 2011 -0700 msm_fb: display: disable timing generator before enable writeback mode At pulling mode (lcdc and dsi video mode), timing generator need to be turned off before enable wriback mode and turn it back on after enabled. CRs-fixed: 298593 Change-Id: I98bd1a4547bb7e310b0df2311aa41ed4115cf8cf Signed-off-by: kuogee Hsieh commit e6613b38e178e67f441936e6820c966f553074ec Author: Ravishangar Kalyanam Date: Fri Aug 12 10:26:35 2011 -0700 msm_fb: display: Fix HDMI clock control during suspend/resume Fix HDMI clock control during suspend/resume to avoid incorrect reference counts Change-Id: I032883b9de9e51c6844cc66e3d1945a14ca05e19 CRs-Fixed: 293818 Signed-off-by: Ravishangar Kalyanam commit ddc23bd81a174843ee09fe464e0afafa62bc7126 Author: kuogee hsieh Date: Mon Aug 1 18:26:23 2011 -0700 msm_fb: display: change mdp clock while mdp is idle at overlay_set() MDP clock is adjusted base on run time perfomance level. This patch will change MDP clock while mdp is in idle state at overlay_set() when performance level changed to avoid MDP from underrun. Change-Id: I7188e5dac6d4eb2f4ca6a7833c84e1fb1251b1b5 Signed-off-by: Kuogee Hsieh commit 0b3fa05890d038428d0faebcda7fc2cdc9aab4f0 Author: Ravishangar Kalyanam Date: Mon Jul 18 18:45:06 2011 -0700 msm_fb: display: Adjust overlay VG pipe src params for non-zero x_offset Adjust overlay VG pipe src params for non-zero x_offset to avoid overfetching of pixels from the left of x_offset Change-Id: Id2eb0be74e72c8982a2def8e333032174ec1d23c CRs-Fixed: 296185 Signed-off-by: Ravishangar Kalyanam commit 14db758bfd64c473185b369b311e2cca443d01a6 Author: Ravishangar Kalyanam Date: Tue Aug 9 12:52:14 2011 -0700 msm_fb: display: Add mb() before reading MDP histogram data Change-Id: I960e441210deaf7edba38b2409954f938160e875 Signed-off-by: Ravishangar Kalyanam commit a41b7a628978951a3d2b58409eaa131a65707f4d Author: Stepan Moskovchenko Date: Fri Aug 5 18:10:54 2011 -0700 msm: hdmi: Disable the HDMI driver on APQ8064 Prevent HDMI initialization from running on APQ8064. Change-Id: I37e0cc6394ffa8dce8aa8a4cc5fde61402f44334 Signed-off-by: Stepan Moskovchenko commit fb8a7f9d09f3c068fdcdb7e880fd11688db2df95 Author: Ravishangar Kalyanam Date: Fri Aug 5 19:13:55 2011 -0700 msm_fb: display: Enable tv_enc_clk for 7x30 to avoid HDMI freeze Signed-off-by: Ravishangar Kalyanam Change-Id: I39cdcb78455e07332351b7312ba149aa4f8c2f07 commit aa3c63a48f18740c0f90f2d85218891b0b3899b5 Author: Ravishangar Kalyanam Date: Mon Aug 8 15:33:42 2011 -0700 msm_fb: display: Fix vsync GPIO for DSI command mode Fix vsync GPIO 0 condition check for DSI command mode to enable Tear check logic CRs-Fixed: 298596 Change-Id: Ide2beb306ed09e4b5478877d2f000eb00f1c317b Signed-off-by: Ravishangar Kalyanam commit 48d2bf5e9ac5d927775c5aedbde817c192cb2aeb Author: Adrian Salido-Moreno Date: Mon Aug 8 12:13:07 2011 -0700 msm_fb: display: increase mdp max burst size increase mdp dma and pipes max burst size, to avoid mdp underruns (blue frames shown on display). Change-Id: I5fc29a314eb6eeb9a88ff7cca5779e95ca954ede Signed-off-by: Adrian Salido-Moreno commit 2920965c1443096f1707888d2fe311cb79dd68dc Author: kuogee hsieh Date: Fri Aug 5 13:30:28 2011 -0700 msm_fb: display: use spin_lock_irqsave before call disable_irq disable_irq() will wait for irq handle to complete before disable the specified irq. Therefore use spin_lock_irqsave() instead of spin_lock() before call disable_irq() to avoid deadlock on same spin lock. CRs-fixed: 299938 Change-Id: Ie55ac18e6b196276023d7f28f291e5410d309217 Signed-off-by: Kuogee Hsieh commit 6935ec9e55cb488fbbb377cc49697b6d37b254f6 Author: Nagamalleswararao Ganji Date: Sat Jul 23 17:58:43 2011 -0700 msm-fb: display: back light support for mipi driver back light control logic is added to mipi driver. it supports 100 levels Change-Id: I0c30f41a5d46f357110b619ba90d16d95d9576af Signed-off-by: Nagamalleswararao Ganji commit 733443cb29774d7c4adb1dd0c15a897bdee47fd3 Author: Adrian Salido-Moreno Date: Mon Aug 1 15:57:52 2011 -0700 msm_fb: display: disable fill screen with blank on early suspend Disable logic to fill framebuffer with black screen before early suspend, this is causing slugish wipe off from top to bottom animation on screen. This logic is still needed for MDP3 because of hardware limitation. Change-Id: I1b9e562c257fac563934b5b1477e58e5382b45be CRs-Fixed: 298050 Signed-off-by: Adrian Salido-Moreno commit 69a5a9854608a2ee856dffb5df7780f3d9bd5ed0 Author: Adrian Salido-Moreno Date: Mon Aug 1 14:06:21 2011 -0700 msm_fb: display: clear interrupt flag to properly wait for vsync need to properly clear vsync interrupt flag so that subsequent waits for vsync are handled properly, otherwise wait will return before next vsync happens Change-Id: I7448525e9f11638c4505e0ce39fa9da05813f5d9 CRs-Fixed: 299043 Signed-off-by: Adrian Salido-Moreno commit bf2d82ddc93d20097fa1021b1c7629b9d9986384 Author: Ajay Singh Parmar Date: Tue Aug 2 10:28:01 2011 +0530 msm_fb: display: Avoid BTA requests during panel init. BTA requests may fail during panel initialization if the DSI Client is not stabilized yet. Hence, avoid them during initialization. CRs-Fixed: 298789 Change-Id: Ib794b76cc7b9e1a8e9ce53ff9ede57108f0eca88 Signed-off-by: Ajay Singh Parmar commit 38bae35c81f7eee8605d854cda9f3854c3be2051 Author: Ravishangar Kalyanam Date: Fri Jul 22 16:20:19 2011 -0700 msm_fb: display: Add MDP 4.2 histogram support for DSI Video Change-Id: I555cf7871da84a91806cb5b1c269e7ed79080009 Signed-off-by: Ravishangar Kalyanam commit bdf8e676b81924ee689bbf43cb7343ea3d5e77ce Author: Manoj Rao Date: Wed Jun 29 09:07:55 2011 -0700 msm: display: HDMI: VG2 pipe solid fill color causes MDP to hang During 3D video playback both VG pipes are used, solid color fill into VG2 pipe for HDCP compliance purpose causes MDP to hang instead, we enable Encryption on HDMI TMDS Output By setting BIT[2] of HDMI_CTRL register to enable encryption on HDMI TMDS Output. Change-Id: Id6fdb3249825405fae058d54772a86145de9d8e8 Signed-off-by: Manoj Rao commit bb597c0640d5f87aadec33d29c03eaa0d3718a4b Author: Ravishangar Kalyanam Date: Tue Jul 19 19:14:23 2011 -0700 msm_fb: display: Use __va instead of ioremap for framebuffer memory map Change-Id: Ie2e3bd1df66b5cb944cd0e28d97227c408cfcaa2 Signed-off-by: Ravishangar Kalyanam commit 2be87760e94044f23ffefc7a753f9abaf14134ba Author: Ajay Singh Parmar Date: Fri Jul 29 15:43:52 2011 +0530 msm_fb: display: Modify panel init commands for HVGA on 7x25A Modify panel init commands to send the video timing values for HVGA resolution on 7x25A. Change-Id: Ic691103e5d1de894f81d90ff1eb4c1a0f9830ecf CRs-Fixed: 297154 Signed-off-by: Ajay Singh Parmar commit 51159ca5df7bb860abdda9e09eba8cb39e2e5d15 Author: kuogee hsieh Date: Thu Jul 21 15:06:59 2011 -0700 msm_fb: display: add ioctl for mixer info Add new ioctl to allow user to query mdp mixer detail configuration. Change-Id: I0057bb34c6bb90ba3c13861978c5cf71ac620ef2 Signed-off-by: Kuogee Hsieh commit 30ea94f26e085154b974d1abeb3f1300fd5dcf83 Author: kuogee hsieh Date: Tue Jul 12 13:32:14 2011 -0700 msm_fb: display: change mdp clock while mdp is idle Mdp clock need to be adjusted at run time base on the performance level. However mdp clock can only be changed when mdp blending/dma engine is idle. Change-Id: I23c6ee2a6802baa98af495320f6bee94915ecfa5 Signed-off-by: Kuogee Hsieh commit 4d4aea2e4f489fcc8a5d2eacb528d3bd8c274374 Author: Manoj Rao Date: Mon Jul 18 14:25:38 2011 -0700 msm: display: HDMI: ISR not triggered when HPD occurs during power_off During power off we disable 5v, power down core, by turning off the TX channels one by one. When a HPD is triggered the driver has a software debouncing timer during which interrupts are disabled to be able to read stable HPD status from the register. When HPD is detected while the core is being turned off/powered down the driver's software disables the interrupt and this was making the core to go into off state. So the fix was to keep the interrupt bit enabled through the register even during the debounce timeout (this doesn't trigger unnecessary interrupts due to appropriate clearing and masking of HPD interrupt bits). Change-Id: I8f6374ed2e27529215a7d66dc32e65e7b4a79983 Signed-off-by: Manoj Rao commit 1532e778ce5b8c30e8261f2b73bc78819f99ea3d Author: Ravishangar Kalyanam Date: Wed Jul 20 15:28:44 2011 -0700 msm_fb: display: Fix 8960 HDMI resolution switch issue Fix 8960 HDMI resolution switch issue by removing core reset via clock branches. This helps in retaining the HDMI PLL register values for subsequent cable disconnect/connect scenarios. CRs-Fixed: 296879 Change-Id: Ie052e986bf21277685d4f52205d3401a5d85c3bc Signed-off-by: Ravishangar Kalyanam commit f711ac25a68e521ce2bbb450d34f46eb76d39a20 Author: kuogee hsieh Date: Wed Jul 6 11:05:05 2011 -0700 msm_fb: display: add 3D support at DSI video mode Currently, only DSI command mode have 3D capability. Add 3D support for DSI video mode also. CRs-fixed: 294082 Change-Id: I0ea1d8797ae850fcfd21b8964ee967282b23910e Signed-off-by: Kuogee Hsieh commit a34b0bc9e1e66f9e9c6ef6063bf3c858bca2e2f4 Author: Stepan Moskovchenko Date: Wed Jul 20 13:21:08 2011 -0700 video: Kconfig: Remove extraneous dots from help text Clean up the help text by removing extraneous punctuation. Change-Id: I043abaf33ce6a5f926a3b27551a517e829b30af9 Signed-off-by: Stepan Moskovchenko commit 917fee282ae07cc98541a54204069bf7955e352d Author: Ravishangar Kalyanam Date: Thu Jul 14 18:45:07 2011 -0700 msm_fb: display: Fix writeback offset with correct fbnum Fix writeback offset with correct fbnum value to avoid any memory corruption with image buffers in use CRs-Fixed: 290324 Change-Id: If2722fc012aa97f0cdb2577589d2e51b82160c24 Signed-off-by: Ravishangar Kalyanam commit 3eaa215567715925b93e5d5d60f679de6028d0c1 Author: Matt Wagantall Date: Fri Jul 15 12:26:19 2011 -0700 msm: Remove last references to NPA-related code for AXI rate management The NPA driver was removed some time ago, but wrapper code and some of its driver hooks persisted in the tree, despite not being compiled (or even compilable). Remove these now. Change-Id: I34148433f8fd946a9aa664df6ca7782cb02bba2b Signed-off-by: Matt Wagantall commit 959f5c62d3b83b65567cd8088db9d9d84774273a Author: kuogee hsieh Date: Thu Jul 14 13:30:33 2011 -0700 msm_fb: display: set flush bit at overlay_unset set flush bit at overlay_unset to notify mdp blending engine to pick up new configuration changes. Change-Id: Ib7598cb8e4ce16be39d0586c718c0753f50056c6 Signed-off-by: KUogee Hiseh commit 802cea1a8b7f850495f900b8519df1d4a064c880 Author: kuogee hsieh Date: Fri Jul 8 14:09:11 2011 -0700 msm_fb: display: add spinlock to synchronize mdp irq enable/disable To improve performance, UI push thread release mutex before blocked at waiting for vsync to allow Video thread to be updated at same vsycn. This also cause contention to enable/disable mdp irq. Add spinlock to synchronize both threads and irq context. Change-Id: I0898f3eac7ecec85b499b73ff118d846ba32bc3b Signed-off-by: Kuogee Hsieh commit 8cd1e18d1f8fe351e42a0ac5287536cdde7efcd8 Author: Jeevan Shriram Date: Fri Jul 8 17:59:18 2011 +0530 msm_fb: display: Enable H/W vsync in msm7x27a Enable tearing effect control in msm7x27a using gpio. Change-Id: I0bc92777a172a2ecf26ce34d8882a04165e859a3 CRs-Fixed: 289024 Signed-off-by: Jeevan Shriram commit 03522b71418c110c98c5982b9d28ffc97c9afdba Author: Ravishangar Kalyanam Date: Fri Jul 8 11:50:33 2011 -0700 msm_fb: display: Use spinlock instead of mutex in vsync timer handler Use spinlock instead of mutex in vsync timer handler to avoid sleeping from timer context through mutex locks Change-Id: Ib8865c8bd3390ac12a2fe1eac158b7e4fcab4bad Signed-off-by: Ravishangar Kalyanam commit 8f43f4bb7d9d56c82aa2a7630116b9f44aa99a62 Author: Jeevan Shriram Date: Thu Jul 7 21:41:10 2011 +0530 msm_fb: display: Enable lcdc for msm7x25a Enable LCDC interface on msm7x25a with dynamic detection between msm7x27a and msm7x25a Change-Id: I935ae65f8ed43b5e524da100d38feba44c3c4a16 Signed-off-by: Jeevan Shriram commit bd0ef9258776385559fd032134e0a28e9aad8f34 Author: Chandan Uddaraju Date: Tue Jul 5 18:58:27 2011 -0700 msm_fb: Display: Use pixel clock for downscale validation The clk_rate variable used in validation function represents pixel clock. For MIPI DSI video mode panels, add code to use MIPI DSI pixel clock in downscale validation function. Change-Id: Ic27d304ec6bff44c29b8d10c622363dbc5fcee75 Signed-off-by: Chandan Uddaraju commit 9ada6fcea2bbf5c92a8cf7a1dd63334e32249564 Author: Ravishangar Kalyanam Date: Wed Jul 6 15:28:46 2011 -0700 msm_fb: display: Fix MDDI multiple data write DMA abort issue Fix MDDI multiple data write DMA abort issue by passing physical address to the DMA Signed-off-by: Ravishangar Kalyanam Change-Id: Ic3060030dece7ab531d3630eebf6e4ee7267804f commit fe926e8303dc6da0adf7be76c045ac93a9f8818a Author: kuogee hsieh Date: Tue Jul 5 14:14:46 2011 -0700 msm_fb: display: remove while loop at mdp4 ISR Since mdp interrupt is enabled on demand, there is no need to have a while loop to handle interrupts at random time. There has possibility that mdp clock was turned off at first loop and ISR handler try to read mdp status register again at second loop which cause system to reset. Remove this while loop from mdp4 isr. CRs-fixed: 291602 Change-Id: I4a6d78ad939085128d261fdf8c70018fff424b26 Signed-off-by: kuogee Hsieh commit b29ea0e32018ab5e9ac6f48d0a2ad29d4591b948 Author: kuogee hsieh Date: Sat Jun 25 15:51:14 2011 -0700 msm_fb: display: increase mdp clock debouncing time Increase mdp clock on/off debuncing time from 0 to 50 ms. Change-Id: Idd3b9e6562acad96fc0f460f81e64d4483059b9d Signed-off-by: Kuogee Hsieh commit d0423ef3ca01755267a1f4e157c8ea7e468b145f Author: Chandan Uddaraju Date: Tue Jun 7 19:38:02 2011 -0700 msm: Display: Add sysfs entry to enable 3D barrier. Add code to configure the gpios lines using FPGA to enable the 3D barrier for the Novatek panel. Add sysfs entry to enable/disable the barrier.The barrier should be enabled only while playing 3D content. Change-Id: I92bb11888b004a6fbd7af900ccb490cc7f9547e3 Signed-off-by: Chandan Uddaraju commit c1abee46365a0a8b976877a6ad5f2752f410ed7b Author: kuogee hsieh Date: Fri Jul 1 09:44:58 2011 -0700 msm_fb: display: release mutex before vsync_push At pulling mode (both lcdc and dsi video mode), release mutex before waiting for vsync so that both video and UI can be updated at same vsync. CRs-fixed: 294504 Change-Id: I7a3f274dd5472fa3842a6fda586539e85c7defd9 Signed-off-by: Kuogee Hsieh commit 16636524b5635644f554435a99553c097b74a605 Author: Jeevan Shriram Date: Fri Jul 1 15:12:21 2011 +0530 msm_fb: display: reduce display initialisation command for lcdc Reduce display initialisation commands for lcdc toshiba panel to reduce the time delay to resume. Change-Id: Ib36c2546423d1b7c5c0d0c1531c480b477c2d975 CRs-fixed: 291494 Signed-off-by: Jeevan Shriram commit 4e19f50c3e21f6be4595eab4ffb1d07abfbe8025 Author: Jeevan Shriram Date: Fri Jul 1 10:52:46 2011 +0530 msm_fb: display: Configure full resolution update in dsi command mode Partial update is supported only for mddi interface,hence update whole screen for dsi command mode on msm7x2xa. Change-Id: Iecfc8d5edac2f962c3710692ed87abaa90fbe184 Signed-off-by: Jeevan Shriram commit 098325372eb8c3df9e841de9502c4bd7dcbbf5d5 Author: kuogee hsieh Date: Mon Jun 27 11:09:23 2011 -0700 msm_fb: display: add Novatek dsi panel backlight support Add MIPI led_pwm1, led_pwm2 and led_pwm3 dcs commands to control Novatek panel backlight through dcs command. CRs-fixed: 285850 Change-Id: I57ee5704dc3ec2aaa16086727470b4f6dfd9ce9f Signed-off-by: Kuogee Hsieh commit 1b3fa75696737dd7bbee380eb9dbbf81b66ba99c Author: kuogee hsieh Date: Wed Jun 29 14:23:50 2011 -0700 msm_fb: display: remove mutext from lcdc on/off Since mutext had been acquired at up stream, no mutex necessary at both mipi_toshiba_lcd_on() and mipi_toshiba_lcd_off(). Change-Id: I380a4727c0485bcdcdbfc9fad43476569f2b78ef Signed-off-by: Kuogee Hsieh commit c6e3391b53d62a42616e9d3e04e1fb2d89f2fdda Author: Chandan Uddaraju Date: Sun Jun 26 23:55:26 2011 -0700 msm_fb: Display: Enable downscale validation support for MIPI. Add code to call downscale validation function for MIPI video mode panels. This is needed for playing 720p video in portrait mode. Change-Id: I90b3582fa73040bf66239f5258592a1f08cba0f0 CRs-Fixed: 292907 Signed-off-by: Chandan Uddaraju commit da07df81fe450fb08ec68511bd4ac5004ee96f3d Author: kuogee hsieh Date: Thu Jun 23 08:59:06 2011 -0700 msm_fb: display: no overlay set and play allow after suspended Check suspend state at both overlay set and play. Return fail if system suspended. CRs-fixed: 292430 Change-Id: I2a941fafc92de61df9077cb3bb5bbb78964d1809 Signed-off-by: Kuogee Hsieh commit 9568223aa6d0fa91fd8f3a042d75e91b1895d494 Author: kuogee hsieh Date: Thu Jun 16 18:22:52 2011 -0700 msm_fb: display: wait for dma completion before dsi off Since dcs commands needed to be sent to dsi client (panel) to bring down panel during dsi off (suspend) process, check dma completion before start sending dcs comamnd to panel to avoid confliction at MIPI DSI channel. CRs-fixed: 291842 Change-Id: I380b05d8d9158c49be5bdb9a52e52a114725c22e Signed-off-by: Kuogee Hsieh commit 1fe5c7b8258ed19276d0af8b9171fd864f40619e Author: Ravishangar Kalyanam Date: Fri May 20 18:47:53 2011 -0700 msm_fb: display: Disable/enable chicken bit during video playback CRs-Fixed: 283794 Change-Id: I6d8b766fe316522451eb5e2c548799b17da431be Signed-off-by: Ravishangar Kalyanam commit f25bec14f4ab386015cd034c59ebdff9f3d266b5 Author: Chandan Uddaraju Date: Mon Mar 28 09:14:27 2011 -0700 msm: Display: Add code to provide 3D panel information to UI. Add code to provide information to the user interface about whether the panel supports 3D display or not. Change-Id: I3f8f9d8eb4014a77f9b4f4752858999009ab2407 Signed-off-by: Chandan Uddaraju commit 7eee7cfb58b63b1e710e20d994b3926b4dd126ae Author: Ravishangar Kalyanam Date: Mon May 23 20:18:38 2011 -0700 msm_fb: display: Add HDMI PHY settings for 8960 target Add HDMI 28 nm PHY settings for 8960 target and separate 8660 specific HDMI settings Change-Id: I3fe023c28fe0bf3728f7dbba8cb16fd3096985d7 Signed-off-by: Ravishangar Kalyanam commit 27f99bb784c6e390674373ae980d9fb15194f0dd Author: Ravishangar Kalyanam Date: Mon Jun 20 17:16:42 2011 -0700 msm_fb: display: Fix suspend/resume for 8960 DSI panel Change-Id: If3716f131b7b5c9d5dc176d3995622355696c5d7 Signed-off-by: Nagamalleswararao Ganji commit 24c7acd32b080d105e84994dc0cb3ee9d0d28738 Author: kuogee hsieh Date: Fri Jun 17 09:58:55 2011 -0700 msm_fb: display: check dsi_pipe for writeback mode at kickoff At MIPI DSI command mode, Writeback mode (blt) is marked at dsi_pipe. During video kickoff (overlay play) dsi_pipe->blt_addr should be check instead of pipe->blt_addr to see whether writeback mode is enabled or not. Current, pipe->blt_addr was checked which cause extra mipi_dsi_cmd_mdp_sw_trigger() was called which cause an extra mipi_dsi_enable_irq() called and flooding kernel log with "IRQ already enabled" warning messages. Change-Id: Ieae169e3ece870cac7f2c73922b60789fee11a9f Signed-off-by: Kuogee Hsieh commit afc6ae9304f27c240546f15580555913f7e27644 Author: Saurabh Shah Date: Tue Jun 21 17:58:22 2011 -0700 msm_fb: display: Use reserved[4] for storing fps Use reserved[4] field for storing fps, since reserved[3] is used by HDMI Change-Id: Ibbc77d3f369d4bf4e1a1311609039764a692d66b Signed-off-by: Saurabh Shah commit 9322f759f8437a816e44aa921a64fcb566defcfb Author: Rajesh Sastrula Date: Fri May 6 15:27:33 2011 -0700 msm_fb: display: provide panel refresh rate information user space can use refresh rate of the panel when they get variable screen info as part of calling FBIOGET_VSCREENINFO ioctl. CRs-Fixed: 283750 Change-Id: I60e4cfee8215139671248506caf0d625a1bec1ec Signed-off-by: Rajesh Sastrula commit 918ecc5201654cc8c1b5bfcaa7ef5ebc32304733 Author: Jeevan Shriram Date: Fri Jun 10 15:05:35 2011 +0530 msm_fb: display: Fill the last frame to NULL while suspend in MDP 3.03 Toshiba panel stores the last frame in its frame memory during suspend. This last frame gets displayed while resuming in quick succession which is not a valid frame to display while coming out of suspend. Hence fill the last frame to null before going to suspend. Change-Id: I605fbed97455298dcd00d884bb9f4b7256078902 CRs-Fixed: 290419 Signed-off-by: Jeevan Shriram commit fc299bb8066e0325db239bb356c546e57c7ef347 Author: kuogee hsieh Date: Mon Jun 6 10:29:28 2011 -0700 msm_fb: display: add mdp writeback mode support dsi video mode MDP writeback mode has been worked for both lcdc and dsi comamnd mode. This patch add dsi video mode writeback mode support and unify interface to enable/disable writeback mode. CRs-fixed: 287700 Change-Id: I4ced3fa8927fb94e5457957aab274e7d07acdd79 Signed-off-by: KUogee Hsieh commit 6de2b7363df7ad3bfe02b6752910675c749f910f Author: Vidyakumar Athota Date: Sat Jun 11 22:52:24 2011 -0700 Revert "msm_fb: display: provide panel refresh rate information" This reverts commit 7b401565d2ab400a3e68e1112c3d601d13a34837. Signed-off-by: Vidyakumar Athota commit 55e656e68cac78eaa367341df2e693a483a53f84 Author: Stepan Moskovchenko Date: Mon Jun 6 14:34:38 2011 -0700 drivers: barriers: Replace dsb() with mb() Replace explicit dsb() calls with mb(). Now that the generic ARM implementation defines mb() to mean (at least) dsb(), it is appropriate to switch back to the generic kernel version of the barriers. This is also needed for correctness on certain targets (such as 7x27) where dsb() is insufficient and other operations (such as outer cache sync or writing to strongly-ordered memory) are required to ensure proper I/O operations ordering. In some cases, remove explicit calls to outer_sync following a barrier since the barrier will now have an explicit outer_sync call. Change-Id: I2c53b8534af9c3cbac4d4d77b322f897a39e7758 Signed-off-by: Stepan Moskovchenko commit c105b2f0d55fa64c2c9e2715531c1bb6ff8b3de7 Author: Manoj Rao Date: Thu Jun 9 15:36:59 2011 -0700 Remove hdcp timer if the device is not hdcp-enabled. Non-HDCP enabled devices seem to have various problems when connected to various sinks. HDCP Reauth=>deauth, hdcp_auth hdcp_auth=>turn_on() which calls HDMI Core reset without informing the Audio QDSP this can do bad things to video playback on the HDTV Therefore, as surprising as it may sound do reauth only if the device is HDCP-capable Change-Id: I2593b225353ec3758f18e33ea58fd867b30ec062 Signed-off-by: Manoj Rao commit 47c54ff0e010190f0a11e7e2792642d70caa339c Author: kuogee hsieh Date: Thu Jun 9 15:53:11 2011 -0700 msm_fb: display: check suspend condition before bus scaling Overlay_unset() was called to free mdp pipe back to pool. Therefore requested bus bandwidth need to be scaled down after overlay_unset() accordingly. Bus bandwidth was scaled down to level 2 at overlay_unset(). At suspend, bus bandwidth was scaled down to level 0. It is possible that overlay_unset() will be called after suspend had been completed. Under this situation the over all bus bandwidth request stay at level 2 instead of level 0 which prevent power from being collapsed. This patch will not do bus scaling at overlay_unset() during suspend. CRs-fixed: 290583 Change-Id: I10dbb23a7f13f472c8de3014115890e689a2b6e9 Signed-off-by: Kuogee Hsieh commit 9b35d093b7b22e380ffc9f066a92dc0ef218944b Author: Gregory Bean Date: Sun Jun 5 11:34:02 2011 -0700 msm_fb: fix forbidden compiler warning. Providing forward declarations of functions and then redeclaring them to be inline later produces forbidden warnings on some versions of the codesourcery compiler, breaking builds. Change-Id: I4a65e1af002f4bc412c30b5c96601f8e650c74d1 Signed-off-by: Gregory Bean commit 60e1a17d7c3221e7f9b958ffe46e3e736dd532a1 Author: Abhishek Kharbanda Date: Thu May 26 22:30:57 2011 -0700 msm_fb: [HDMI_Compliance] FIX HDCP state machine Book-keeping HDCP State in HDMI State structure, to incorporate handling of frequent interruptions to the HDCP authentication procedure. Change-Id: I5657379eb4593eb551127a016393f231f445f423 Signed-off-by: Abhishek Kharbanda Signed-off-by: Manoj Rao commit 63a81111eb3e7143bf37e125c3abeb94fcc611ac Author: kuogee hsieh Date: Thu Jun 2 08:52:46 2011 -0700 msm_fb: display: fix hdmi reset while playing moving When mdp writeback mode is enabled, ovoerlay0_done isr handler (executed at cpu-0) will call mdp_enable_irq() to acqure lock and enable mdp interrupt before kick off dmap engine. Meanwhile dtv thread (executed at cpu-1) had called mdp_disable_irq() which had acquired same lock already and waititng for overlay0_done isr handler to complete. Hence dead lock had happen. This cause system to reset. The patch have overlay0_done isr handler to call mdp_disable_irq_nosync() at end of handler to avoid dead lock with DTV thread's mdp_disable_irq(). CRs-fixed: 289140 Change-Id: I7e98935f0bd4f29c188f46601d8df09c37cd20d7 Signed-off-by: Kuogee Hsieh commit 6a194de79ae35f9785c5a5c63cda330c7dab1a80 Author: kuogee hsieh Date: Wed May 25 08:44:37 2011 -0700 msm_fb: display: waiting for vsync for UI frame push Add waiting for vsync for UI frame push through pan display. Change-Id: I9be701c6615c139d6d07b16c32039074d5b5a431 Signed-off-by: Kuogee Hsieh commit b11c3b46619d3eaee600223859041a51fa0af218 Author: Zhang Chang Ken Date: Wed Jun 1 20:22:24 2011 -0400 msm_fb: display: YUV 444 format support Change-Id: I620d133941739eb8024cdb6d79227078c3193fac Signed-off-by: Zhang Chang Ken commit cef59b7b35b714df7b81f9bc2e96b8d49181f95a Author: Jeevan Shriram Date: Wed Jun 1 15:38:08 2011 +0530 msm_fb: display: support suspend/resume for lcdc toshiba panel Add support for suspend/resume and backlight control for lcdc toshiba panel for msm7x27a Change-Id: I49916776cc532974eed7f858cd7e2fd85b6c8fda Signed-off-by: Jeevan Shriram commit e8f469582b62d0d76faa4051227228734f226325 Author: Zhang Chang Ken Date: Mon May 30 18:04:44 2011 -0700 msm_fb: display: Tune DSI setting for Toshiba wsvga panel Change-Id: I71df1f019b1604f806af6b7ae7f379edb810a583 Signed-off-by: Zhang Chang Ken commit 6a11cb6f4d7bf536d2881512daed6e3324f65b64 Author: Carl Vanderlip Date: Mon May 23 14:17:53 2011 -0700 video:msm: Updating QSEED table2 values This patch updates the table2 QSEED filter values so that they apply visible filtering when using the QSEED smoothing/sharpening API. Change-Id: I4431a02e24f9bcae035898b758e8c462c9c044de Signed-off-by: Carl Vanderlip commit 589c897daefbcf28e8610226225bd2d8fcddee4e Author: Carl Vanderlip Date: Thu Apr 28 13:53:07 2011 -0700 video:msm: Initial QSEED sharpening/smoothing API Adds an additional parameter (.dpp.sharp_strength) and reuses flag MDP_SHARPENING to mdp_overlay, to allow for overlay_set to request for sharpening/smoothing. The overlay parameter is designed to range between -127 and 127, with negative values infering smoothing, positive infering sharpening. This range of values is then mapped onto 7 levels for both smoothing and sharpening (i.e. ~ every increase/decrease of 16 aligns with an increased sharpening level). This commit only adds the API for sharpening, a patch that updates the QSEED table2 values is needed for the desired effect to be visible. Change-Id: Ib6522e43bde4f4a54e752258553822e78a95749d Signed-off-by: Carl Vanderlip commit 4298b4f972b395b92ab0346978a9e9e9999c2e9f Author: Pradeep Jilagam Date: Tue May 24 20:10:15 2011 +0530 msm_fb: Display: Add support for DSI Single Lane for 7x25A Add changes to support QVGA resolution and Single lane configuration with DSI on 7x25A Change-Id: I3f33e3b41a860b7339abfb824aac00435606e5a2 Signed-off-by: Pradeep Jilagam commit 54aafeb90b88663a423be3459f4c05c38ccafd97 Author: Jeevan Shriram Date: Fri May 27 01:16:55 2011 +0530 msm_fb: display: Enable backlight control for mipi dsi on 7x27a Add support for Backlight control on mipi interface for msm7x27a target Change-Id: Id22cba59929eeeaecb6383b273242f12c52535f4 Signed-off-by: Jeevan Shriram commit 7b401565d2ab400a3e68e1112c3d601d13a34837 Author: Rajesh Sastrula Date: Fri May 6 15:27:33 2011 -0700 msm_fb: display: provide panel refresh rate information user space can use refresh rate of the panel when they get variable screen info as part of calling FBIOGET_VSCREENINFO ioctl. CRs-Fixed: 283750 Change-Id: I738b254bf8d2db0bd79864c0731ad0542f657bf6 Signed-off-by: Rajesh Sastrula commit c394da5a206ccb6aab93b0a3beba9d38f479d7e3 Author: Nagamalleswararao Ganji Date: Mon Apr 25 12:55:58 2011 -0700 msm_fb: display: Fix for the color swap issue for mipi simulator Color swap was wrongly added for mipi simulator panel, which makes colors to invert on simulator. It will disable the color swap at DSI controller. Change-Id: I1f00cdfaaa9e60804045d81581d3a1de059e21c6 Signed-off-by: Nagamalleswararao Ganji commit 30fda1e634d3be2d47330eb15fbbc2c4389460c1 Author: kuogee hsieh Date: Mon May 23 13:01:04 2011 -0700 msm_fb: display: add both pre and post mipi dsi kickoff action Add both pre and post mipi dsi kickoff action so that vendor can add their own call back functions to customize their mipi dsi controller. Change-Id: I382aab2bf908f0140004a6713c8e77a16f5aa925 Signed-off-by: Kuogee Hsieh commit 395c7c1d9c82d56977a611080d305aee0d974372 Author: Abhishek Kharbanda Date: Mon May 23 14:28:19 2011 -0700 msmfb:[HDMI_COMPLIANCE] Read EDID extension block. Read EDID extension block 3 and 4 as part of HDMI compliance test 7-1. Change-Id: Ief48dca2b596ac4f2c6fb23a5f20802e8b3ef4d9 Signed-off-by: Abhishek Kharbanda Signed-off-by: Raj Kushwaha commit 8ad47e5a01f5e95cc0e41c1a4a71317d4d8a9a17 Author: Abhishek Kharbanda Date: Fri May 20 07:34:52 2011 -0700 msmfb:[HDMI_COMPLIANCE] Read DDC Bus in 32bit alignment Read DDC bus in 32 bit alignment in case of failure. Change-Id: If4546501eae383755d0a5ddd059e166007f64bf7 Signed-off-by: Abhishek Kharbanda Signed-off-by: Manoj Rao commit 2604c2884489e8c76474249fff6f8d1103503f21 Author: Jeevan Shriram Date: Mon May 23 15:36:47 2011 +0530 msm_fb: display: Add histogram in MDP 3.03 Add histogram functionality in MDP 3.03 required for Content-based Adaptive backlight Change-Id: I24dd8a42c12b2311823fc25b2aca568a8c391b0e Signed-off-by: Jeevan Shriram commit 9925e41f075235b620b9d6918f9d00662a60e9d5 Author: Abhishek Kharbanda Date: Fri May 20 06:50:55 2011 -0700 msmfb:[HDMI_COMPLIANCE] Reading correct bytes of RO' Read correct number of bytes i.e. 2 for RO' and increase wait for Authentication sucess interrupt to 2 sec. Change-Id: I4247b600e31e7a5f39b44e77a49c174b8c0bd11f Signed-off-by: Abhishek Kharbanda Signed-off-by: Manoj Rao commit dcc36cc4b33d1b82b803fe1dbdb904656eef0aa8 Author: Pradeep Jilagam Date: Fri May 20 13:06:06 2011 +0530 msm-fb: DSI: Add Support for DSI CMD mode on 7x27A Add changes in MDP, DMA-P and Panel Configurations to support DSI Command Mode on 7x27A Signed-off-by: Pradeep Jilagam Change-Id: I912866f9072dda690d5e6354a05d74dcb2d2aaa0 commit d567f25ae4afa37f8f7e2fda53bade2099f7ad87 Author: Arun Kumar K.R Date: Sat May 21 16:21:26 2011 -0700 msm_fb:[HDMI_COMPLIANCE] Add HDCP node to externel common state Update the sysfs about HDCP keys. This read only attribute is used by HDMI Daemon to pass Audio, in case no HDCP keys present. Change-Id: I508d250c9193449e6663e13570c2c9fac3b8feca Signed-off-by: Abhishek Kharbanda Signed-off-by: Arun Kumar K.R commit c7163d9a33d86d1001aa4083423c68c07743861c Author: Ravishangar Kalyanam Date: Mon May 16 14:07:15 2011 -0700 msm_fb: display: Reorganize DSI clock and PHY settings code Reorganize DSI clock and PHY layer settings by moving code to different file from base driver Change-Id: I7d02a4cd0f5322b80462e3721d5c8fb4f83d002f Signed-off-by: Ravishangar Kalyanam commit ae66ded8ca3d1e7184dc04f1c165fae30ba8a203 Author: Nagamalleswararao Ganji Date: Mon May 16 19:54:16 2011 -0700 msm-fb: display: Clock changes to MDP driver Adds the mdp_axi_clk, mdp_lut_clk to the MDP driver. they are the new mdp clocks added for MDP4.2 hardware on 8960 Change-Id: Ib936a280e83a414806365836a839b5555f445724 Signed-off-by: Nagamalleswararao Ganji commit 46ad60f0cff5c2222ded7a639f337417e59b2375 Author: Abhishek Kharbanda Date: Mon May 9 13:14:53 2011 -0700 msmfb:[HDMI_COMPLIANCE] Correct sequence of events on HPD connect On HPD connect, read EDID, turn on HDMI core, send CONNECT event to UI to enable DTV clocks, then start HDCP Authentication. For HDCP reauthentication case, do HDMI core reset/programming before enabling HDCP authentication again. Change-Id: I077d497c2ac9b1dd181f4f4ea874bd2ea4dfede8 Signed-off-by: Abhishek Kharbanda commit 4217a1dacbde157ce26238904450b091778fe872 Author: kuogee hsieh Date: Thu May 19 15:50:27 2011 -0700 msm_fb: display: fix mdp shared pipe allocation bug Both VG pipes of MDP are sharable which can be used as either graphic or Video. Pipe alloction need to keep tracking of VG pipe is shared by which two virtual pipes. There has a bug to keep correct record after several pipe allocation and free operation. This patch fix this bug during pipe allocation. Change-Id: I76f7246f855d7a3e99de29da7297053c477fbbef CRs-fixed: 286350 Signed-off-by: Kuogee Hsieh commit 3700ca00ba19855081822169e144c87aa1d4953f Author: kuogee hsieh Date: Mon May 16 17:03:45 2011 -0700 msm_fb: display: disable primary and external vsync interrupt Clear PRIMARY_VSYNC and EXTERNAL_VSYCN interrupt enable bit at isr handler to disable vsync interrupt. This will mitigate un-necessary interrupt which will wake up cpu constantly and consume extra power. Change-Id: Ic635065f2bc42cdfb422f440fe65fc01a246e18f Signed-off-by: Kuogee Hsieh commit 22cff13e1115962207254980acffac8d20bd9b26 Author: kuogee hsieh Date: Mon May 16 17:01:12 2011 -0700 msm_fb: display: turn off dtv timing generator first The correct way to turn off dtv timing generator is to turn off dtv timing generator first followed by turn off dtv related clocks. So move panel_next_off() which used to turn off dtv related clocks off after dtv timing generator was turned off. Change-Id: Iee5ea7287ae8879f961a095327b71a38b8b60f57 Signed-off-by: Kuogee Hsieh commit cd0bd24a3fffff873821618009389378372fb73e Author: Abhishek Kharbanda Date: Mon May 16 14:25:28 2011 -0700 msmfb:[HDMI_COMPLIANCE] QDSP ON/OFF kobject events to userspace. Set two new kobject events i.e.QDSP ON/OFF events to userspace. QDSP ON is send only after authentication sucess. QDSP OFF is send on HDCP Failure interrupt or on HPD connect. Change-Id: I55316d9dc96fa17d275d87e75480a2209b1fa46c Signed-off-by: Abhishek Kharbanda Signed-off-by: Manoj Rao commit d89efdbbdf521f05a7b9f191e98914b40bc1962d Author: Rajesh Sastrula Date: Wed May 18 11:10:11 2011 -0700 msm_fb: display: Flush RGB pipe when solid fill mode is used Fullscreen applications can request the driver to configure the MDP back ground pipe to use solid fill mode so that the background pipe will not be fetched by MDP and it saves the bus bandwidth hence the total system power. This requires the driver to explicitly issue a register flush on the background pipe when the configuration changes from regular fetch to solid fill mode during overlay play. CRs-Fixed: 270713 Change-Id: I630f1df16212d02bd694e086d695067262b6203c Signed-off-by: Rajesh Sastrula commit 757e2ea8064b379ecfd02a6fdd36f6f2894066c8 Author: Ravishangar Kalyanam Date: Wed Apr 6 11:15:36 2011 -0700 msm_fb: Display: Enable WSVGA Toshiba MIPI DSI video mode panel. Add code to configure and enable MDT61 Toshiba MIPI DSI video mode panel. Add new command set to initialize and configure the new panel. Change-Id: I8c543677f75ade967a77100a7878b9e487dc991b Signed-off-by: Ravishangar Kalyanam commit 44a306a8c4d4e1ca66750c9ebc17ef21ab482d97 Author: Abhishek Kharbanda Date: Mon May 16 13:14:11 2011 -0700 msmfb:[HDMI_COMPLIANCE] Fill BLACK SCREEN during Authentication. Fill VG2 pipe with Solid Black color at beginning of authentication. Unfill VG2 pipe to transmit the original frame on HDCP authentication sucess. Change-Id: I83cf278310a902c263e191b714b550ee29afa5e5 Signed-off-by: Abhishek Kharbanda Signed-off-by: Manoj Rao commit 8dae3d06d1c41aa2de609056811646ff50e77791 Author: Abhishek Kharbanda Date: Thu Apr 28 18:17:49 2011 -0700 [HDCP-COMPLIANCE]:HDCP: WORK QUEUE instead of kernel work queue Not using Kernel global work queue to avoid frequent watchdog barks/bites. Instead creating a local work queue to handle all work items belonging to HDMI/HDCP driver. Change-Id: I436f1eee110562587223fd1de97821968d494034 Signed-off-by: Manoj Rao Signed-off-by: Abhishek Kharbanda commit 2c7864a358d63b3ed2681a8a0d45bea7da7f85c0 Author: Abhishek Kharbanda Date: Thu Apr 7 13:56:34 2011 -0700 msm_fb: [HDMI_COMPLIANCE]:HDMI/DVI Sink Detection. HDMI/DVI Sink detection based on reading IEEE id of Vendor Specific Data Block in EDID. Required for HDCP-1A-09 and HDMI-7-33 compliance case. Change-Id: I3df0dd292ac7d28f9eb6028ee16e5c60180e5c35 Signed-off-by: Abhishek Kharbanda commit 065b9f72784c2686aca0233e8e510229efd329c4 Author: Abhishek Kharbanda Date: Thu Apr 7 13:27:49 2011 -0700 msm_fb: [HDMI_COMPLIANCE]:Writing correct bytes on DDC bus. Writing correct bytes of An and AKSV's on DDC bus. Change-Id: I0ee5412dc5801172c00570748fbcc9a9efe04582 Signed-off-by: Abhishek Kharbanda commit dfcf3ef2212026dfb53e87f571b294627f34a4a7 Author: Ravishangar Kalyanam Date: Fri May 13 16:40:55 2011 -0700 msm_fb: display: Wait for vsync support for DSI Video interface CRs-Fixed: 287940 Signed-off-by: Ravishangar Kalyanam Change-Id: If69a6781dfc493125b5f57b937c24d17b4cbbea6 commit f0771a155634cae4052dab0c0c7ae2fc0abc4b56 Author: Jeevan Shriram Date: Mon May 16 12:19:53 2011 +0530 msm_fb: display: Enable suspend/resume for mipi dsi on 7x27a Add changes to configure Soft Reset of DSI Controller. Also, add changes to control the power of the DSI Client. Change-Id: Idb72327da1219c215c36e6b3a94d4a763e071fb5 Signed-off-by: Jeevan Shriram commit 62a5ab8164b5dd55d358b31cdd333597e2e057ff Author: Abhishek Kharbanda Date: Mon Apr 11 10:28:14 2011 -0700 msmfb:[HDMI_COMPLIANCE] HDCP Compliance 1B-06 Verified that HDMI Transmitter considers it a failure of the second part of HDCP authentication protocol that BStatus: MAX_CASCADE_EXCEEDED bit is asserted by the downstream repeater. Change-Id: I450a46cda3f18f1a54cc5e2cd0500c9d54473b7d Signed-off-by: Abhishek Kharbanda Signed-off-by: Manoj Rao commit e814b7842af3b7f15047f3f922c1f1648bb2705b Author: Abhishek Kharbanda Date: Sun Apr 17 10:48:05 2011 -0700 msm_fb: [HDMI_COMPLIANCE]: Verifying V' in Authentication Part 2 Reading value from HDCP PORT 7,8,9,10 and 11 and writing it back to HO,H1,H2,H3 and H4 portion of HDCP Hardware registers. Change-Id: I77dcf3d91046f4f6f71f4dd5c1aea90bd766e7ef Signed-off-by: Abhishek Kharbanda commit ccdb0372092c3a359754897ebec2bb8be37d6a3e Author: Abhishek Kharbanda Date: Mon Apr 11 10:21:06 2011 -0700 msmfb:[HDMI_COMPLIANCE] HDCP Compliance case 1B-05 Verified that HDMI Transmitter considers it as a failure of the second part of HDCP authentication protocol that BStatus: MAX_DEVS_EXCEEDED bit is asserted by the downstream repeater. Change-Id: I1e00a561774779703b343e08868f3da633f6dbdd Signed-off-by: Abhishek Kharbanda Signed-off-by: Manoj Rao commit a13f69fc1fdc0ccb8bcedc0001f39f2b195652bd Author: Abhishek Kharbanda Date: Mon Apr 18 14:24:59 2011 -0700 msmfb: [HDMI_COMPLIANCE] Disable HDCP H/W Disable HDCP H/W block during deauthentication Change-Id: Ibb25f7cab29c2c361020cac868b58c298ae74560 Signed-off-by: Abhishek Kharbanda commit 2c1204470d5e7376d89a7a1f69c788d79cdc53c3 Author: Abhishek Kharbanda Date: Mon May 9 12:09:45 2011 -0700 msmfb:[HDMI_COMPLIANCE] HDCP Compliance DVI mode 1A-09 HDMI core Audio setup should not be done in DVI Mode. Audio should route through Headset/Phone Speakers in DVI Mode. Change-Id: I98fb0e3b09501aa30a23eb6939102de08665f66f Signed-off-by: Abhishek Kharbanda commit ce25d616d046ee3db897fe921d300f44553d83c9 Author: Jeevan Shriram Date: Thu May 12 17:26:39 2011 +0530 msm_fb: display: increase max BL level in panel driver Increase the maximum backlight level for all panel drivers supported by msm 7x27a Change-Id: I534b8e5e3ee296e68e81d4dcdceea70319cbd0da Signed-off-by: Jeevan Shriram commit 829c88376705c6b58e62dd93e9802ffb905ad49c Author: Abhishek Kharbanda Date: Mon May 9 11:58:38 2011 -0700 msmfb:[HDMI_COMPLIANCE] HDCP Compliance case 1A-01/1B-01 ON HDCP reauthentication process, first do HDCP deauthentication and then reset/program hdmi core again , rather than just re-doing HDCP authentication only. This will reset HDCP encryption engine completely and remove "Encryption Enabled prior to reading RO'"error on Quantum Data BOX. Change-Id: I8a058147f8bd147ee2330d445f27b2ee58e5ef99 Signed-off-by: Abhishek Kharbanda Signed-off-by: Manoj Rao commit d8df7faccb2ec330eb859179ed0db07313626b7c Author: Rajesh Sastrula Date: Thu May 5 18:42:50 2011 -0700 msm_fb: display: increase backlight levels to 100 This is to improve the quality of ABL. Change-Id: I45a92c91dc5c250a91a6c069e0695f72c97a6272 Signed-off-by: Rajesh Sastrula commit e80420254616b39d0c350dcadf8f6954394e7647 Author: Rajesh Sastrula Date: Wed Apr 27 11:58:52 2011 -0700 msm_fb: display: lower the mdp clock during clock disable on halcyon MDP MSMC1 voltage stays high if the clock rate is greater than 122Mhz and causing to draw more power during mdp is idle even after disabling the mdp clock. Lowering the mdp clock after clock disable so that MSMC1 voltage goes down and restore the clock back to same value before clock enable to save power when MDP is idle. CRs-Fixed: 285714 Change-Id: I95dd4b8bc654a923730a9e4ecf16499c556201d9 Signed-off-by: Rajesh Sastrula commit 15bd60d7b277f7850bbdc814ae1e151c5cea31ba Author: Jeevan Shriram Date: Mon May 9 18:45:45 2011 +0530 msm_fb: display: turn off dsi ref clk for 7x27a during power off sequence, dsi_ref_clk is not disable and hence TCXO shutdown fails. With this change, dsi_ref_clk is disabled during off. Change-Id: I9424120370a6a6feec98ca228777ecaac9249f30 Signed-off-by: Jeevan Shriram commit 3d3439c820a1a0e79f3c3b706556a6ea11b6ee76 Author: Jeevan Shriram Date: Thu May 5 10:48:02 2011 +0530 msm_fb: display: Resolve compilation errors for dsi on 7x27a Change-Id: Id7cc3e3df2c0005f0442e03625567c40797feea3 Signed-off-by: Jeevan Shriram commit 41e0dcf972dfa5892169d9a03d6d1de9029a7556 Author: kuogee hsieh Date: Thu May 5 08:43:03 2011 -0700 msm_fb: display: waiting for dmap_done before kickoff Add waiting for dmap_done interrupt to both mdp4_dsi_cmd_overlay_restore() and mdp4_dsi_cmd_kickoff_video() before kick off overlay blending engine to avoid two consective kickoff of overlay bleanding engine and only one dmap_done interrupt after that when write back mode is enabled. This cause mdp_pipe_ctrl(ON) called two times and mdp_pipe_ctrl(OFF) only called one time which casue mdp clock and vsycn clock can not be shutoff during suspend. Change-Id: Ibe731d0c562d46a0c3888704f50b2010ec1769c0 Signed-off-by: Kuogee Hsieh commit 2152d08bd0c7d2e1ca4e49f80443b3c6336c09ab Author: kuogee hsieh Date: Tue May 3 17:26:45 2011 -0700 msm_fb: display: Revert "do not restore control screen to main panel" Reverts commit 64189b417cc545add2f496609ef11df6b491d177 since it cause mdp hang up while playing HDMI. Change-Id: Ic31ca511afe2c44bc045442c807c2b2fc554bb5a Signed-off-by: Kuogee Hsieh commit 894c60beca1296b1cc16f948f45ed140a016921f Author: Ravishangar Kalyanam Date: Mon May 2 17:38:17 2011 -0700 msm_fb: display: Configure 8960 serdes settings for DSI host Configure 8960 serdes(Serializer-Deserializer) specific PHY settings for DSI host based on target type in platform data Change-Id: I433e61f13f19a582fe3e21dc6832fcf93046a3f1 Signed-off-by: Ravishangar Kalyanam commit c7711029d933b918a97749af7e31beafef3e0d96 Author: Pradeep Jilagam Date: Tue May 3 05:59:44 2011 +0530 msm_fb : display : Correct DSI Byte Clock configuration To configure the DSI Byte clock, clock string ID is different for 7x27A and other platforms. This change handles the difference appropriately. Change-Id: Ib5bad3283287e7d36d428aa4721c87985c112d59 Signed-off-by: Pradeep Jilagam commit 64189b417cc545add2f496609ef11df6b491d177 Author: kuogee hsieh Date: Fri Apr 29 13:29:40 2011 -0700 msm_fb: display: do not restore control screen to main panel For MIPI dsi, no need to restore control screen to main panel at the end of video playback. Change-Id: Ic68a2dc646a2e2693e5eea5d9c81e629a0a84244 Signed-off-by: Kuogee Hsieh commit dee181e845c10b3b9a68fff89d965d6b99691c09 Author: kuogee hsieh Date: Fri Apr 29 11:08:50 2011 -0700 msm_fb: display: clear dmap eanble bit before shut off mdp clk At MIPI dsi write back mode, mdp clock was shut off before dmap interrupt enable bit can be cleared at dual core environment. This cause mdp interrupt line keep asserting. Fix it by moving mdp_pipe_ctrl() after clear dmap interrupt enable bit. Change-Id: Ia0f5ff8a55322546dd7d18fca4e1d7b3ad02f8ef Signed-off-by: Kuogee Hsieh commit 393e367e14977c42f62df3101535712503f1f133 Author: Kiran Kandi Date: Tue Feb 15 10:21:40 2011 -0800 msm: 8660: audio: driver for compressed audio over HDMI. This driver sends compressed audio IEC 61939 bursts in IEC 60958 Frames. Change-Id: I3d567d73d1854d62c86aed95824c39bfd1f20859 Signed-off-by: Kiran Kandi commit 0b0d5c46c0fd92350be9cd838f621aef566ce7d3 Author: Pradeep Jilagam Date: Tue Apr 26 19:01:21 2011 +0530 msm-fb: Display: Add changes to support Renesas DSI panel on 7x27A Added changes in the DSI client and panel drivers of Renesas Tremolo-M panel to support it on 7x27A Change-Id: Ibacec50454e573a065a3eabfe30e02b22896e44d Signed-off-by: Pradeep Jilagam Signed-off-by: Jeevan Shriram commit c192a65bed1be0d4d8cd80be809ca59a9fe100ee Author: Pradeep Jilagam Date: Wed Apr 20 11:17:56 2011 +0530 msm_fb: Display: Add MIPI DSI support for 7x27A Added changes in the DSI driver to extend support to 7x27A Change-Id: Idd55b0aae9aed653721357ff2c414ce081d6bbbc Signed-off-by: Pradeep Jilagam Signed-off-by: Jeevan Shriram commit 551c692934c576d7105a0d65b39aca126652ec3a Author: Pradeep Jilagam Date: Wed Apr 20 12:37:54 2011 +0530 msm_fb: mdp: Add support for DSI Interface in MDP 3.03 Add new interface support (DSI) support for MDP v3.03 Change-Id: Ifc85b8d1f84a91e97ac11c8e62480568096f1845 Signed-off-by: Pradeep Jilagam commit 5e744543c3f81650a1cea1402c58c01ae6ee421d Author: Rajesh Sastrula Date: Wed Apr 20 16:26:07 2011 -0700 msm_fb: display: use maximum performance level for interlaced content mdp is going to underflow if maximum clock is not used for interlaced videos to work around this using the maximum performance level for interlaced videos until the root cause is identified. CRs-Fixed: 283652 Change-Id: Idc788125da12f3c3aae3c2a64292e8ca8580e7c8 Signed-off-by: Rajesh Sastrula commit 2afd5ab819fe894511ed58fc1262d0452a4c70fd Author: Ravishangar Kalyanam Date: Thu Apr 21 16:11:20 2011 -0700 msm_fb: display: Disable MDP clock directly during suspend Disable MDP clock directly during suspend bypassing the pipe ctrl workqueue CRs-Fixed: 284441 Signed-off-by: Ravishangar Kalyanam Change-Id: Ic04fe003c51c2081496760531e5c7379fcfd39f7 commit 902ea8d6bcc516f383e3335cd690ef5e384c267f Author: Jeevan Shriram Date: Mon Apr 25 18:53:29 2011 +0530 msm_fb: display: add initialization of toshiba LCDC panel only on surf Only mipi dsi has support on FFA but not iLCDC. Hence the change to have LCDC panel gets initialised only for surf and not FFA. Change-Id: Ifd6526b0020c004bc413b12939701f1935c16dc3 Signed-off-by: Jeevan Shriram commit 565ecc608d46993c4afe6dd15c95942c75f1e932 Author: kuogee hsieh Date: Tue Apr 5 11:44:52 2011 -0700 msm_fb: display: wait for next vsync at overlay_unset At pulling mode (lcdc, dtv) panel, wait for next vsync during overlay unset to smooth transaction of pipes. CRs-fixed: 276786 Change-Id: Ife0af10358d3e61112f6f70349262d1bf2105c62 Signed-off-by: Kuogee Hsieh commit 801290d61d4426c1504079bbaa702f5439dc96d3 Author: Ravishangar Kalyanam Date: Tue Apr 12 19:19:17 2011 -0700 msm_fb: display: Add DSI PHY settings for 8960 RUMI Add DSI PHY settings for 8960 RUMI Renesas Command Mode panel Change-Id: I4323413414f89f60e16962887362908458bce400 Signed-off-by: Nagamalleswararao Ganji commit a6a1618edcdfa45b8a03dceb768e873ac5cec731 Author: Nagamalleswararao Ganji Date: Thu Apr 21 00:12:44 2011 -0700 msm_fb: display: Mipi driver for 8960 simulator Mipi display panel driver support is added for 8960 simulator. It will control the data flow between dsi controller and the mipi dsi panel. Right now it supports only video mode. Change-Id: I3712907a0e0c07b9ebd7e9fb2678f37a3058d5f3 Signed-off-by: Nagamalleswararao Ganji commit 708f3b8c4c8115e9a6543b6cef50288dc94aedfd Author: Pradeep Jilagam Date: Thu Feb 17 01:13:07 2011 -0800 msm_fb: display: Add support for MIPI DSI Renesas panel Adds basic support for renesas mipi dsi panel driver. It will control the data flow between msm dsi controller and the renesas mipi dsi panel. Change-Id: Ib92a342bfb3d596d99dbcf564c86a684c2d2f8c4 Signed-off-by: Nagamalleswararao Ganji commit c5ac53e3e4aeb1d73587719f639210a1b7610481 Author: Rajesh Sastrula Date: Tue Dec 28 15:19:07 2010 -0800 msm_fb: display: Add support to notify display updates new ioctls are added to notify the user space about the display updates and idle. Change-Id: I8970ca2ad9481c4b725b6431309d6153f18b9435 Signed-off-by: Rajesh Sastrula commit 8825c2547168a36b5fbb30a14add7509e33f9b41 Author: Nagamalleswararao Ganji Date: Tue Apr 19 20:41:54 2011 -0700 msm_fb: display: Adding the Interrupt in MIPI DSI Resources Right now we are accessing the Interrupt macro directly in the driver. In 8960 MIPI interrupt name got changed, so we need to move the interrupt to resources to make the driver msm platfrom agnostic Change-Id: I04ec4b3d1230dd4e5e9be0041db6efdd31045a32 Signed-off-by: Nagamalleswararao Ganji commit 994b7d8d34a81ddc9c6fd9bbf8c71791e8f36bd2 Author: Nagamalleswararao Ganji Date: Tue Apr 19 19:10:53 2011 -0700 msm_fb: display: Adding the Interrupt in MDP Resources Right now we are accessing the Interrupt macro directly in the driver. In 8960 MDP interrupt name got changed, so we need to move the interrupt to resources to make the driver msm platfrom agnostic Change-Id: I84d2825dad00fd8b6c4425b290aca070b847e9f5 Signed-off-by: Nagamalleswararao Ganji commit 75df47a6dc38b5bd08d0c8e2d7595662f9a3ddfe Author: Jeevan Shriram Date: Mon Apr 18 20:17:53 2011 +0530 msm_fb: display: Avoid EBI1 clock setting by Display in 7x27a EBI1 clock is already set to a higher rate in 7x27a and hence there is no need for display to set it explicitly. Change-Id: I316f61dd8d345d6b66a070b75c6be804ce9db0a4 Signed-off-by: Pradeep Jilagam Signed-off-by: Jeevan Shriram commit 04a6f98fb77c9749cfa50fa9e5cbfda132fdd28e Author: Pradeep Jilagam Date: Sun Apr 17 03:42:22 2011 +0530 msm_fb: display: Add support for LCDC Toshiba FWVGA panel. Add driver file to support Toshiba FWVGA panel with LCDC interface Change-Id: I15dd2abcfe474ec7737e7915884ea33ea78da689 Signed-off-by: Pradeep Jilagam commit 0df29adef313157f99c814e86f3a73e7d3c657db Author: kuogee hsieh Date: Wed Apr 13 17:49:59 2011 -0700 msm_fb: display: enable vsycn on mipi novatek panel Enable vsync on mipi dsi novatek comamnd mode panel to prevernt tearing. Change-Id: Ib71a0204e5ef4cc8a0e0b977dd3744fdb74c8af1 Signed-off-by: Kuogee Hsieh commit 605a44c18620ed364e53d1e4cc0f03fd2f815029 Author: kuogee hsieh Date: Wed Apr 13 15:05:19 2011 -0700 msm_fb: display: decrease mdp_timer_duration value To improve power efficiency, mdp clock need to be shut off as soon as possible after screen updated so that TXCO can be shut off too. Since mdp_timer_duration control the timing to shut off mdp clock, it need to be kept as shorter as possile. Decrease mdp_timer_duration from 1 second to 0 ms for MIPI DSI interface. mdp_timer_duration stays at 1 second for legacy MDDI interface. CRs-fixed: 282857 Change-Id: I930c3e9869c6bbabfd70203ddbddd15c84fbae92 Signed-off-by: Kuogee Hsieh commit cf66ffdba39e8ac83e82a19ef8ebd0f9f6f5a32b Author: kuogee hsieh Date: Wed Apr 13 14:59:21 2011 -0700 msm_fb: display: move footswitch out of mdp_pipe_ctrl() mdp_pipe_ctrl() is called frequently, move footswitch mechanism to more proper place and have it enable always. Change-Id: If54c4cd125a8504eee4cd468282f4dccabb0398f Signed-off-by: Kuogee Hsieh commit c4a80d9e8bd74410f4f9a3e636c3c617e8afa7b8 Author: Rajesh Sastrula Date: Tue Feb 22 10:59:02 2011 -0800 msm_fb: display: provide option to pass chroma pointers seperately provide option to the user space to pass seperate chroma pointers instead of deriving the chroma address based some assumptions. This gives flexibility to derive chroma address that has size alignment restictions for luma. Change-Id: I384ade86993810627655a8a446e6b9316979aca8 CRs-fixed: 274238 Signed-off-by: Rajesh Sastrula commit 8e393f6c4d77b37e5a7a8fb9e7e495cd55e2fb47 Author: Michael Bohan Date: Thu Feb 24 12:10:11 2011 -0800 Initial contribution This commit takes the MSM and driver changes from git://codeaurora.org/quic/la/kernel/msm.git:android-msm-2.6.35 and applies them on top of git://android.git.kernel.org/kernel/common.git:android-2.6.38. Change-Id: I3e80240311c76c05d4177a4958a660fba80d5d14 Signed-off-by: Michael Bohan commit 1ad6a901db3038e67a58b98ac60cf048deb7d7aa Author: Ajay Singh Parmar Date: Thu Apr 19 11:17:26 2012 +0530 msm_fb: hdmi: 3D configurations in HDMI 3D configurations using Generic0 packets need to be done after enabling HDMI Control to take these configurations into effect. CRs-fixed: 349578 Signed-off-by: Ajay Singh Parmar (cherry picked from commit 514b1c651a33b7b73fb6f654d04355eac5ecb146) Change-Id: I15ae4a26a1d1f964b41bb6174e5ea31bc4da8a59 Signed-off-by: Swetha Basineni commit 837fbaa4e02d07502c8969503ebb936c0c1716a1 Author: Swetha Basineni Date: Thu Mar 15 17:08:38 2012 +0530 msm_fb: display: clean dsi fifo during dsi_off During suspend, wait until dsi controller's fifo is cleaned before disabling dsi controller. This will prevent pixels that were left over in the fifo from being displayed during next resume. CRs-fixed: 336049 Signed-off-by: Kuogee Hsieh (cherry picked from commit 9d76704c8dac8f9e0794834cc4d62c17fd9cdf63) Conflicts: drivers/video/msm/mipi_dsi.c Change-Id: If7adff01a7fd50177761f015227986a3f93d1e49 Signed-off-by: Swetha Basineni commit 5fa503114b95e1cd0e4650a543184e36215e2522 Author: Manoj Rao Date: Thu Jan 26 17:15:09 2012 -0800 msm_fb: HDMI-CEC: Line latch patch The CEC hardware latches upon reading a corrupt bit in bit 7 of any bytes due various timing issues. If the driver detects this latch up then we call CEC reset to release the lacthed up line. CRs-Fixed: 329507 Signed-off-by: Manoj Rao (cherry picked from commit 1573599adbb42c606d8b91854c76461b3f212c3e) Change-Id: I60a2fb051add9973d98c177b58c33445260cb359 Signed-off-by: Swetha Basineni commit 08c0d505198f988d10f4f55fe30c0448b33a815e Author: kuogee hsieh Date: Mon Nov 7 14:18:51 2011 -0800 msm_fb: display: update busy flag before check blt_addr dma_busy flag is set to TRUE on every vsycn push and set it to FALSE at overlay0_done ISR. When blt disable, dma_busy need to be set to FALSE before return due to blt_addr == NULL at overlay0_done ISR. Signed-off-by: kuogee hsieh (cherry picked from commit 81be67988ef149f601064a9e8e5d91705e636ff5) Change-Id: Ia0552b3b645389efeaf2b8d3986f5ba10c4d9142 Signed-off-by: Sunil Joseph commit e4326532759c3e05741616760bb11e456ba31cff Author: Aravind Venkateswaran Date: Fri Jan 13 12:47:08 2012 -0800 msm_fb: HDMI: Correct order for BKSV read operation During HDCP authentication, the BKSV read operation should be issued after writing AKSV as per the HDCP specification. This change fixes this issue. CRs-Fixed: 327845 Signed-off-by: Aravind Venkateswaran (cherry picked from commit 228895ae217589ca71aa464f7c22bc4cedd06f77) Conflicts: drivers/video/msm/hdmi_msm.c Change-Id: I06b2cc1658e49fc5a82f156911726a41a8467bf7 Signed-off-by: Sunil Joseph commit 8b7fbe6ed5f4f38b34c69a82d711438a570304cf Author: Swetha Basineni Date: Fri Jan 20 12:43:12 2012 +0530 msm_fb: display: prefill two writeback frames for lcdc. Pre-fill two writeback frames before enable writeback mode to avoid flickering for lcdc. CRs-fixed: 325327 Signed-off-by: Mayank Chopra (cherry picked from commit 3a895fd04105cb1a1db3ae51d051ea6b6d9ef980) Conflicts: drivers/video/msm/mdp4_overlay_lcdc.c Change-Id: Ic8a2d59163c807c24ffa54a5b72d5bdd70712301 Signed-off-by: Swetha Basineni commit b77817fa07694f7fe1bd56d11e1765a66787b4e9 Author: Abhishek Kharbanda Date: Mon Sep 19 14:08:33 2011 -0700 msm_fb: HDMI: Support for clock stretching HDMI Sink may hold off the DDC transaction by stretching the SCL line during the SCL-low period following the Acknowledge bit as permitted by the I2C specification. All HDMI Sources shall delay the DDC transaction while the SCL line is being held low. HDMI_DDC_SETUP register field should be set. CRs-Fixed: 296256 Signed-off-by: Manoj Rao Signed-off-by: Ramakrishna Prasad N (cherry picked from commit dee95105fdbc21ca2cecad26403e7c6a9942f445) Change-Id: I43abe64ab53feb09a0494c9f642241e5791ce9a7 Signed-off-by: Sunil Joseph commit 721d78d25c007c5e8ac9474d95f4a952e0a1ba76 Author: Padmanabhan Komanduru Date: Mon Nov 21 10:35:35 2011 +0530 msm_fb: display: Change the timing values of MDDI toshiba panel. Adjusts the porch values and refx100 to prevent tearing effect on MDDI toshiba panel. CRs-Fixed: 309691 Signed-off-by: Padmanabhan Komanduru (cherry picked from commit a9c4e3cb9f29ced98b82ea073e7814668abf56a9) Change-Id: I395c49c3d6308c4ef2b9a7dab41167467be3519d Signed-off-by: Swetha Basineni commit 9326c60c83647488f2e33d9112b07d70296f5a6f Author: Aravind Venkateswaran Date: Wed Jan 4 16:24:19 2012 -0800 msm_fb: [HDMI_COMPLIANCE] Update audio ARCs for 480p As per HDMI specification, the correct pixel clock rate for 480p should be 27.027 MHz. In the code, we are currently using 27.03 MHz and thus the audio constants corresponding to this clock rate seem to be incorrect. This change updates these constants as per the HDMI and the CEA-861D spec. CRs-Fixed: 328553 Signed-off-by: Aravind Venkateswaran (cherry picked from commit a4f48cd3a16243671b42c6ef6437c0df77c9f1f9) Change-Id: I5069e50dea973895b67e21e60e335818c30fc142 Signed-off-by: Swetha Basineni commit 184cd5a52d1ab1864f58baaa81aeed091897667e Author: Abhishek Kharbanda Date: Thu Dec 15 11:37:57 2011 -0800 msm_fb: Removing HDCP timedout error. DEBUG mode added delay after writing RO's to RCVPORT, leading to HDCP AUthentication Sucess Interrupt coming before INIT_COMPLETION call. Re-arranging INIT_COMPLETION code before writng RO's resolved the issue. CRs-Fixed: 325564 Signed-off-by: Abhishek Kharbanda Signed-off-by: Aravind Venkateswaran (cherry picked from commit 39cf209c7f8ac4843c8b10223af15d0afdbe96ce) Change-Id: I3f97aadf0a7635bf07b206a3477afd18a23b7b44 Signed-off-by: Swetha Basineni commit df013ad8114e7e8391c90df172da0a04609fae65 Author: Abhishek Kharbanda Date: Thu Dec 15 12:21:29 2011 -0800 msm_fb: Fixing Aspect Ratio Non-standard resolution, like 531*398, is treated as 720*480 instead of 640*480 , as it has non 4:3 aspect ratio.Chanding aspect ration calculation to be in a range , rather than absolute. CRs-Fixed: 320022 Signed-off-by: Abhishek Kharbanda Signed-off-by: Aravind Venkateswaran (cherry picked from commit 402adc6142598abcb2a41a941895003f57f289a5) Change-Id: I28d6f11b20f123c52d5872f0b550c3c4531356f7 Signed-off-by: Swetha Basineni commit 9882bb2dc947df434befbae40b0d681973a4b5e4 Author: Manoj Rao Date: Wed Oct 19 11:16:08 2011 -0700 msm_fb: HDMI: EDID > 2 blocks, params not set. Currently the driver discards one byte from DDC buffer. In cases where EDID exceeds two block in length we need to discard a total of 3 bytes before reading from EDID seg. CRs-Fixed: 307706 Signed-off-by: Manoj Rao Signed-off-by: Abhishek Kharbanda (cherry picked from commit ebefc805a139e8222061b32cbf7686d76122de5f) Change-Id: I7bc723e53244983b76937deedf3524c642194e62 Signed-off-by: Swetha Basineni commit 63fcfdde892762d72a7ab15b0628167d584a2ce4 Author: Manoj Rao Date: Mon Jun 13 22:14:57 2011 -0700 msm: fb: HDMI: Sending AVI Info Frame even if HDCP is disabled AVI_INFO_FRAME was not getting sent if CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT is enabled Getting rid of the #ifdef checks around the function call/defn CRs-Fixed: 311139 Signed-off-by: Manoj Rao (cherry picked from commit 4d28b63ec5ca47e074ae87551911d6a5f8c289d0) Change-Id: I7410e176b0a2e09b87f623bdbfb08927d2525b05 Signed-off-by: Swetha Basineni commit b18226c8a815117f985eafb06439bd0d692531f4 Author: Abhishek Kharbanda Date: Fri Nov 4 14:25:48 2011 -0700 msm_fb: Check for ACP and ACFG register before reset core. Check for Bit[0] of Audio Packet Control Register and Audio Configuration Register before resetting HDMI core. Even after sending OFFLINE event, QDSP take time to switch between stereo and hdmi audio mode. HDMI reset core should not be called untill that switch happens. CRs-Fixed: 310700 Signed-off-by: Abhishek Kharbanda (cherry picked from commit a077d0063dfb8a39a869f56099dd0ffe85301180) Change-Id: Ib664232c07d00dad7a2d89875fe2903b8ab1016c Signed-off-by: Swetha Basineni commit 1e6428ce9512b074a2a586b403c331690a9813c8 Author: swetha Date: Thu Nov 17 19:08:30 2011 +0530 msm_fb: display: cleanup usage of shared pipes in overlay Remove usage of shared pipes. Shared pipes are used to allow VG pipes to play both video and rgb formats. This can now be handled by calling overlay set ioctl with new format, that means shared pipes are no longer needed and can cause instabilities if not used properly. CRs-Fixed: 312209 Signed-off-by: Adrian Salido-Moreno (cherry picked from commit cb8fbbcbe0630451ba582a0747987c48b2c603f1) Conflicts: drivers/video/msm/mdp4.h Change-Id: I0f36f65db00884b017a5bad4670794cd65e2c5e5 Signed-off-by: swetha commit 5dcef0415fe4312e4fed83c6974780fe163e6523 Author: Manoj Rao Date: Tue Nov 1 12:28:24 2011 -0700 msm: HDMI: CEC: Hardware FSM reset. Hardware requires a FSM reset toggle under frame write/read scenarios. This enables every transaction/feature to have a fresh start. CEC CTS requires this patch to pass a subset of test cases in sections 8, 9. Hardware and VI teams have confirmed this as a necessity for compliance tests to pass. CRs-Fixed: 316345 Signed-off-by: Manoj Rao (cherry picked from commit 0f0ab64f56cbc31cd2fda46ff4790ae86f89ad5f) Change-Id: Iaeb6b9b121d8c9eb4cf2413ddcaf0024b06e0d8b Signed-off-by: Swetha Basineni commit 0506478f4ef8b397b3916db47133c4d0cdc05c89 Author: swetha Date: Fri Nov 18 11:27:28 2011 +0530 msm_fb: Remove Audio Packet Control Register setup Donot set Audio Packet Control Register (0x0020) on HPD connect event. This register should be set by QDSP6 core on start of dumping Audio Data. CRs-Fixed: 316588 Signed-off-by: Abhishek Kharbanda Conflicts: drivers/video/msm/hdmi_msm.c Change-Id: Idf36ab257d4bb493c578529d4d8a7f0d68e2b1cb Signed-off-by: swetha commit 79d8f3eec036a1f0604bb296048a5c21a34a6a36 Author: Manoj Rao Date: Thu Nov 17 23:54:16 2011 -0800 msm: display: HDMI: Driver support for CEC feature Driver implementation of HDMI CEC feature. Support includes CEC frame send and frame receive. Support added for sysfs interface for CEC daemon to interact with the driver for reading and writing frames. Resolve GB HOUSE conflicts, below FR on gb house had conflicts. CRs-Fixed: 319078 Change-Id: Ie93aeb8837151ef98814a4cde463a3be58c6c1fb Signed-off-by: Manoj Rao commit 0a693110809d2a782a137f242f6438cb0e32218b Author: Manoj Rao Date: Wed Nov 16 22:00:05 2011 -0800 msm: display: HDMI: Driver support for CEC feature Driver implementation of HDMI CEC feature. Support includes CEC frame send and frame receive. Support added for sysfs interface for CEC daemon to interact with the driver for reading and writing frames. sysfs interface /sys/class/graphics/fb1/cec Read: CEC block state. Write: Enable/Disable CEC block. /sys/class/graphics/fb1/cec_logical_addr Read: Print CEC logical address Write: Set CEC logical address which is used for addressing CEC messages to and from MSM /sys/class/graphics/fb1/cec_rd_frame Read: Read rcvd CEC message from message queue. If queue is empty -EBUSY. If CEC block is disabled -EPERM. Write: N/A /sys/class/graphics/fb1/cec_wr_frame Read: N/A Write: Write to send CEC message. If CEC line arbitration fault/no ack -EINVAL. If CEC block is disabled -EPERM. Change-Id: I00ccf91c022d6b9962ec0231eb3c8f159a200e40 Signed-off-by: Manoj Rao commit c55b00c069de596e0d539314381b1139139c6932 Author: Pradeep Jilagam Date: Wed Oct 5 21:19:46 2011 +0530 msm_fb: display: Add YV12 support in the MDP Added changes to support YV12 input format in the MDP. Change-Id: I23fb10ea30117e20de654d9516f7d024b99f6c96 Signed-off-by: Pradeep Jilagam Signed-off-by: Adrian Salido-Moreno commit 6b5cabad0561eda616f892cb67306dc4231626a9 Author: Manoj Rao Date: Tue Jun 14 21:05:18 2011 -0700 msm_fb: HDMI: Support for 480p 16:9 in HDMI Driver Requirement for customer (Samsung) to have support for 720x480p 16:9 aspect ratio, prior to this we supported only 4:3 aspect ratio for 720x480p. Adding the appropriate Lookup Table changes. CRs-Fixed: 311137 Signed-off-by: Manoj Rao (cherry picked from commit 64ee60e185dd7c5b2b6d08f3c81fcdd9a7a5e178) Change-Id: I79a67ebe0a24be65c2f588d06e80e437d850dc16 Signed-off-by: swetha commit 1b0fe24150908a0474460c32347e71d1f904008e Author: kuogee hsieh Date: Tue Oct 4 08:48:18 2011 -0700 msm_fb: display: check BLT mode within overlay_done isr At dsi video mode, overlay_done isr return immediately if blt mode was not enabled. Aslo, since time between overlay_done interrupt and dmap_done interrupt is very close, both may be serviced within same ISR. In this case overlay_done is serviced first. CRs-fixed: 310918 Signed-off-by: kuogee hsieh (cherry picked from commit 40a43409804073a0442d2a1ea09293c0b95fdab1) Change-Id: I46ab957bb1f6f9289ea62f49c4c012450965cc9a Signed-off-by: swetha commit d8b5b8b42652bdf50d9d2f32c9f5df9a683bec0d Author: kuogee hsieh Date: Thu Sep 29 15:57:04 2011 -0700 msm_fb: display: prefill two writeback frames Pre-fill two writeback frames before enable writeback mode to avoid flicking. CRs-fixed: 310076 Signed-off-by: Kuogee Hsieh (cherry picked from commit 5a95ccd976434514d06384c2684c187daf3925ea) Change-Id: I645e953bcb614f18ee0d0469e7e05a81c90d6027 Signed-off-by: swetha commit 8da556479db6a5798cd64278c0a59098bab1b89f Author: Shruthi Krishna Date: Wed Oct 26 11:19:57 2011 -0700 msm-fb: display: mdp clock scaling clean up clean up of clock scaling code to organize it better Signed-off-by: Nagamalleswararao Ganji (cherry picked from commit b8c3aa8bdd5974b75a8782cab641936bfa7eb3f6) Conflicts: drivers/video/msm/mdp4.h drivers/video/msm/mdp4_dtv.c Change-Id: I5a2bb2982f49d9e3f5fa04addf60d498e8177931 Signed-off-by: Shruthi Krishna commit 0716a0cfbaa4b71cd46359b97d0595fa5eb13dd9 Author: Manoj Rao Date: Mon Oct 10 17:36:15 2011 -0700 mm: display: hdmi: QDSP_OFF evt with OFFLINE evt Every OFFLINE event should be accompanied by QDSP OFF event. This makes sure that QDSP DMA operations occur smoothly before HDMI is powered down. Signed-off-by: Manoj Rao (cherry picked from commit 09ab565589a8a1409c222ce79b6885aa9e96d33d) Change-Id: Ieb7db1ec90fb6e57b7e3cbc1929ffb74a1d96d8e Signed-off-by: Shruthi Krishna commit e2a4d84ae6cea7d8c32186e3d94d66814ad8f5cb Author: kuogee hsieh Date: Sun Sep 25 13:31:37 2011 -0700 msm_fb: display: add dcs read parser Parser byte stream responsed back from dcs client base on the dcs command type. Change-Id: Ib8c95024dc593794909893bd7daafc68ecb77769 CRs-fixed: 306936 Signed-off-by: kuogee hsieh commit 5f775050abd5416a04e2999101e98b9206fe8a25 Author: kuogee hsieh Date: Mon Sep 5 09:57:58 2011 -0700 msm_fb: display: configure dsi control as free run Configure DSI controller as free run instead of software trigger. At free run, DSI controller is triggered by MDP directly when output of blending is ready. No extra register write to trigger DSI controller is necessary. Therefore it reduce latency during MDP kickoff. Change-Id: I096939b519c0e007e69e58d0665408799e7f5e83 Signed-off-by: Kuogee Hsieh commit b5b8af371375fad123b3b26a1c8f85bc6b6c72e7 Author: kuogee hsieh Date: Wed Aug 31 17:51:34 2011 -0700 msm_fb: display: received writeback offset from board file Writeback offset need to be passed from board file to avoid hard code value used by MDP. Change-Id: I5261356f75205eb1d3ec17522779693deed09562 Signed-off-by: Kuogee Hsieh commit 6fb10dc13bdcbec93462149c90ee11a8f3101118 Author: Adrian Salido-Moreno Date: Mon Aug 8 12:13:07 2011 -0700 msm_fb: display: increase mdp max burst size increase mdp dma and pipes max burst size, to avoid mdp underruns (blue frames shown on display). Signed-off-by: Adrian Salido-Moreno (cherry picked from commit 48d2bf5e9ac5d927775c5aedbde817c192cb2aeb) Change-Id: I85bbb414a9d34981487bee63ebd7b10e76711c89 Signed-off-by: Shruthi Krishna commit 30e1b13055d905f4276d3e9fc9e0a93d9dc1f9f5 Author: Nagamalleswararao Ganji Date: Fri Jan 28 13:24:34 2011 -0800 msm_fb: display: CSC Matrix update support is added CSC Matrix update support is added for MDP4 VG pipes to convert Ycbcr -> RGB format CRs-fixed: 313601 Signed-off-by: Nagamalleswararao Ganji (cherry picked from commit 4b99172a1df8b1ad2b48343bead39685f294e680) Change-Id: Id54327394748cc4a80864967b21caf8a378f37c3 Signed-off-by: swetha commit afff1683341cc4ae64ec618a86aecbbf1a1b83ff Author: Manoj Rao Date: Mon Oct 10 17:32:28 2011 -0700 mm: display: hdmi: HPD fix multiple reconnects HDMI display remained blank after multiple reconnect of hdmi cable. Setting the trigger handler to TRUE in hdmi_hpd_on. CRs-Fixed: 291547 Signed-off-by: Manoj Rao (cherry picked from commit 53ac99d0bb8cdeb0d519b27b1159953447a7a7c7) Change-Id: Ia3ec88bb19cd2f06fd9784afb2302bce4bbe2858 Signed-off-by: Shruthi Krishna commit f00cb084795b659746359544e2d2c80acf15bd5f Author: Shruthi Krishna Date: Tue Oct 18 00:37:14 2011 -0700 msmfb: display: Fix for the 3D stride corruption issue adding the src_x offset to the address causing the stride corruption issue for tile buffer, as the it is changing the alignment Signed-off-by: Nagamalleswararao Ganji CRs-fixed: 302409 (cherry picked from commit 1c8fc4ae526f9ea79952a8dfd967ba3d11b7dc87) Conflicts: drivers/video/msm/mdp4_overlay.c Change-Id: I54afdaacc9b3b96be22ef5c0bd1ca2a2478a8f16 Signed-off-by: Shruthi Krishna commit 3c12051aa756e8ad7c9fc40bdff1171d401fea42 Author: Adrian Salido-Moreno Date: Mon Sep 26 12:54:03 2011 -0700 msm_fb: display: avoid staging up two pipes at same mixer_stage staging two pipes at same mixer stage can cause blue screen, adding additional check to avoid this. CRs-Fixed: 304278 Signed-off-by: Adrian Salido-Moreno (cherry picked from commit 39fff5a3899f8d95886ba2e50d70001602b279c0) Change-Id: I4f81ec5a61e0e12013bb866e41301b95a10c7e45 Signed-off-by: swetha commit 7a851968932a82b4b21acae0fe788fc2c48b053c Author: kuogee hsieh Date: Fri Sep 2 08:53:36 2011 -0700 msm_fb: display: vg pipe shared by both rgb and yuv format VG pipe can carry both RGB and YUV format. This patch will allow VG pipe to switch between RGB and YUV format. Signed-off-by: Kuogee Hsieh (cherry picked from commit cb472111d93fa119c52d56c102b90cc3ad2c8030) Change-Id: Ia4586f17bf7696d422c25be7c6a55c4ebfa403e1 Signed-off-by: Shruthi Krishna commit 3d3a9c230489cebc3c20eece3639e175923d604c Author: Manoj Rao Date: Fri Aug 5 17:54:25 2011 -0700 msm: display: HDMI: Remove audio packet setup for ACP, ISRC In HDMI driver we are setting audio packet with ACP, ISRC by default. Removing this setting until end-to-end feature has been supported. CRs-Fixed: 297272 Signed-off-by: Manoj Rao (cherry picked from commit 5ecbf18f5513f653847d83c8f24aae6c5a184eee) Change-Id: I9a4355eaec13aca70f9c2890e3eba96fbedf3454 Signed-off-by: Shruthi Krishna commit 0f189a55ed89593cf430e850c923369d3acb2e7b Author: Ravishangar Kalyanam Date: Tue Aug 9 17:36:23 2011 -0700 msm_fb: display: Remove histogram memcpy from MDP Interrupt handler Change-Id: If0ede3234d0ab844d2d49119873af5160e8a3e70 CRs-Fixed: 300666 Signed-off-by: Ravishangar Kalyanam commit 1df2948178c9ff509f28fdd2757119ae0923a494 Author: Nagamalleswararao Ganji Date: Mon May 16 19:54:16 2011 -0700 msm-fb: display: Add revision to MDP driver Change-Id: Id86814725955c743df4a0f85548fa64c3656feae Signed-off-by: Nagamalleswararao Ganji commit 96145b95dd0688ed0c83f33d129b4bcd8301ee54 Author: Shruthi Krishna Date: Tue Oct 4 12:25:44 2011 -0700 msm_fb: display: wait for vsync instead of dmap_done At both lcdc and dsi video mode panel, wait for vsync interrupt instead of dmap_done interrupt to make sure a single frame updated during every vsync period. CRs-fixed: 305599 Signed-off-by: Kuogee Hsieh (cherry picked from commit 2f7ff25ba93f7f6485b1a878f08a58040ee7ee57) Conflicts: drivers/video/msm/mdp4.h Change-Id: If070171b933f4b74d5ce817340ed04be0ccbf270 Signed-off-by: Shruthi Krishna commit 433b95fa866ea12a0acc768ce0378f992c1dd09d Author: Adrian Salido-Moreno Date: Mon Aug 29 11:15:47 2011 -0700 msm_fb: display: wait for vsync and change perf level only if needed since overlay_set can be called multiple times to change some parameters, there is no need to wait on vsync to change clock for each call to overlay_set unless there is a change in performance level. Signed-off-by: Adrian Salido-Moreno (cherry picked from commit 8ee9289450d530ab1fdec2379859fca5845a7808) Change-Id: I8eb4caee64a67863180dbfb45e7d8062488d493e Signed-off-by: Shruthi Krishna commit b374b85bad548b148cc232c0045351a5b4d524ad Author: kuogee hsieh Date: Mon Sep 19 09:00:07 2011 -0700 msm_fb: display: remove yield with pan display It is more proper to have USER space thread to decide when yield be called. This patch remove yield() from pan display. CRs-fixed: 307344 Signed-off-by: Kuogee Hsieh (cherry picked from commit a7cb9d450cc6aa03df1f18191c2b36c8222bbe32) Change-Id: I478dcd2a98d8825783e710aa751d89b9348f2782 Signed-off-by: Shruthi Krishna commit ad3f14bb1b57a8b3b41ed6559689f414a3d020bf Author: Ravishangar Kalyanam Date: Thu Sep 1 11:22:35 2011 -0700 msm_fb: display: Synchronize DSI CMD Mode MDP & DMA cmd triggers Synchronize DSI CMD Mode MDP & DMA cmd triggers by handling DSI IRQ enable/disable properly Signed-off-by: Ravishangar Kalyanam (cherry picked from commit 446d22d4641f699b741d16ea6086ce570c49dd7c) Change-Id: I4a7a22c5a0ac32120a7fec0a3fd22a62c8182556 Signed-off-by: Raj Kushwaha commit cbf8fea88bfcff5134c5843bb46a4ba15ea75353 Author: Carl Vanderlip Date: Fri Jul 22 12:32:33 2011 -0700 video: msm: Defining functions for MIPI CMD panel Defining do_histogram and lut_update functions for MIPI CMD panel CRs-Fixed: 294029 Signed-off-by: Carl Vanderlip (cherry picked from commit 7b31a46e449747c2ca79605450f57658c855c756) Change-Id: Ib03d80616982f4b6febbf5216b5774780e9fb726 Signed-off-by: Shruthi Krishna commit fedb6a40b997178ad2d142ae1a4209b729320c1c Author: Manoj Rao Date: Tue Aug 16 19:12:31 2011 -0700 msm:display:hdmi: Fix for EDID read/parse block[1] HDCP enabled DVI monitors with block 0 and block 1 EDID always switched to 640x480 even though they supported higher resolutions. This patch reads DTD data from the correct offset from block[1] and reads correct bits for interlaced format recognition. CRs-Fixed: 290391 Signed-off-by: Manoj Rao (cherry picked from commit 4d8813b4fd6fe7588c411e90a2603b23a772f738) Change-Id: I82c39cdfa4676293ec9a0c02b5f491ffe4b2e6aa Signed-off-by: Shruthi Krishna commit 18174612d6683ca96b4f13528af46b1f7949174e Author: kuogee hsieh Date: Fri Sep 9 10:02:58 2011 -0700 msm_fb: display: add mutex during lcdc off There has possibility that suspend operation and screen update happen simultaneously. There mutex at lcdc_off is necessary to serialize both lcdc off and pan display. CRs-fixed: 302527 Signed-off-by: Khsieh (cherry picked from commit 4e6e7ed6081dc0a6877a99f734928e9831ecfd4b) Change-Id: I8e26c37b9a54699315fda2cfcefd1f439945c67d Signed-off-by: Shruthi Krishna commit 776f9a5d02a45e7c580a494bda81cf58e6dc7242 Author: kuogee hsieh Date: Tue Sep 6 19:01:31 2011 -0700 msm_fb: display: no wait for vsync after suspend There has possibility that overlay_unset() is called after suspend had been done. In this case no wait_for_vsync is needed for pulling mode interface (lcdc and dsi video mode) since timing generator was turned off and hence no vsync interrupt will be delivered. This will cause thread to hang up. Signed-off-by: kuogee Hsieh (cherry picked from commit 743f162911247ba260445deb01b5406d0067daf3) Change-Id: Ic309e3b9311bcf0e47284fd5a13b8344a44d3315 CRs-fixed: 302527 Signed-off-by: Shruthi Krishna commit 6676fee7d309ea699e302a8d039b85754acf10e4 Author: kuogee hsieh Date: Thu Aug 18 17:12:42 2011 -0700 msm_fb: display: use blt mode to implement MDP writeback MDP frame buffer mode was used to implement writeback for pulling interface (lcdc and dsi video). However frame buffer mode is not recommanded by hardware engineer due to lacking of verification. This patch will replace frame buffer mode with BLT mode to implement MDP writeback. Signed-off-by: Kuogee Hsieh (cherry picked from commit 9c08f6850dbd998adf7956887060eec599a8f26f) Change-Id: Idc020deaee364116facc5db471f6f4e9bde4a09d Signed-off-by: Shruthi Krishna commit dd5a748949a292fe22bcf7e8e8a4f8d9f8dca7f1 Author: Raj Kushwaha Date: Wed Aug 31 10:04:28 2011 -0700 msm_fb: display: fix YCrCb planar input format support in mdp MDP hardware expects source addresses to be in YCbCr order, in order to support YCrCb, need to swap chroma planes addresses. CRs-Fixed: 302408 Signed-off-by: Adrian Salido-Moreno (cherry picked from commit 64b4b03461e39a715b33a2ea1ab97f5b27850535) Change-Id: I2ad23f7a384b4f149bd3e4529e1bf5a01de66dd8 Signed-off-by: Raj Kushwaha commit b0db685088e013e1af1378583e9798618b153f94 Author: kuogee hsieh Date: Wed Aug 24 14:34:46 2011 -0700 msm_fb: display: synchronous UI and Video thread Use mutex to synchronous between UI and Video thread. Meanwhile, add yield() when at end of frame push of UI thread to prevent UI thread from dominating cpu times. CRs-fixed: 303246 Signed-off-by: Kuogee Hsieh (cherry picked from commit 871edcfd5a801feed587b6c7f72aa4e1387d245f) Change-Id: I6c880c61b540e83072cc5ea54b120e630d5c0e04 Signed-off-by: Raj Kushwaha commit 3dc8e34c9ccf719f476019a0c2abec9ebd38034b Author: Ravishangar Kalyanam Date: Fri Aug 12 10:26:35 2011 -0700 msm_fb: display: Fix HDMI clock control during suspend/resume Fix HDMI clock control during suspend/resume to avoid incorrect reference counts CRs-Fixed: 293818 Signed-off-by: Ravishangar Kalyanam (cherry picked from commit e6613b38e178e67f441936e6820c966f553074ec) Change-Id: I5e43c80137900b9c04519e1e052cb54068d0860d Signed-off-by: Raj Kushwaha commit 69b0f5d57c7470195ee4126ceca6b52e16fc1868 Author: Raj Kushwaha Date: Mon Aug 22 11:24:32 2011 -0700 msm_fb: display: disable timing generator before enable writeback mode At pulling mode (lcdc and dsi video mode), timing generator need to be turned off before enable wriback mode and turn it back on after enabled. CRs-fixed: 298593 Signed-off-by: kuogee Hsieh (cherry picked from commit 60dc151a43093fad5f68d02323570d5efd58ee4a) Change-Id: Ica2d2026a5ea6ffdba8e53cfd3f40013435db009 Signed-off-by: Raj Kushwaha commit 7049edede74ae3ab929c0ae7261b014bb65d9ee5 Author: Abhishek Kharbanda Date: Wed Aug 10 19:45:53 2011 -0700 msm_fb: [HDMI_COMPLIANCE] Enable Audio for HDMI Compliance Enable Audio event for NON-HDCP builds required for HDMI Compliance Cases. Signed-off-by: Abhishek Kharbanda (cherry picked from commit cd1ebfb22a41e9c3c84c7c7a1e5e0b91fc1fcc8c) Change-Id: I3aa9a1ab4984ef7bf7b56e83b69d7eb41355f7e4 Signed-off-by: Shruthi Krishna commit db2b5ddcb77b564d0e569e27d7484dcb521f9498 Author: kuogee hsieh Date: Fri Aug 12 15:32:52 2011 -0700 msm_fb: display: use mutex instead of spin lock to avoid deadlock There has deadlock between mdp4_isr() and disable_irq() called by LCDC thread. Disable_irq() will wait for mdp4_isr() to complete before return. Meanwhile mdp4_isr() will try to acquire mdp_spin_lock which had been acquired by lcdc thread before call disable_irq(). This patch replace spin lock with mutex to avoid deadlock from happening. CRs-fixed: 301276 Signed-off-by: kuogee hsieh (cherry picked from commit f4e2e01971ffc096a98fb42a8a1f1db13e0b2be5) Change-Id: I72ceb2efe73ce6990b352f65cf3f36ddcd94b2b3 Signed-off-by: Shruthi Krishna commit 78e1b670c1c6d43f45ddb4d1cd290839dfe8fdb6 Author: kuogee hsieh Date: Mon Aug 1 18:26:23 2011 -0700 msm_fb: display: change mdp clock while mdp is idle at overlay_set() MDP clock is adjusted base on run time perfomance level. This patch will change MDP clock while mdp is in idle state at overlay_set() when performance level changed to avoid MDP from underrun. Signed-off-by: Kuogee Hsieh (cherry picked from commit ddc23bd81a174843ee09fe464e0afafa62bc7126) Change-Id: I7e0dd6fdb6ea50a90ed44e0dc7e9b9d8b2f71f38 Signed-off-by: Shruthi Krishna commit 575799be2dc6eae0d576e676a3c335dc9929d672 Author: Ravishangar Kalyanam Date: Mon Jul 18 18:45:06 2011 -0700 msm_fb: display: Adjust overlay VG pipe src params for non-zero x_offset Adjust overlay VG pipe src params for non-zero x_offset to avoid overfetching of pixels from the left of x_offset CRs-Fixed: 296185 Signed-off-by: Ravishangar Kalyanam (cherry picked from commit 0b3fa05890d038428d0faebcda7fc2cdc9aab4f0) Change-Id: I3c6a115fc116beb96c0ddd5324359efe992d00a2 Signed-off-by: Shruthi Krishna commit cde0d4265de0662e2f0b119477381e7f8c10aa77 Author: Zhang Chang Ken Date: Wed Jun 1 20:22:24 2011 -0400 msm_fb: display: YUV 444 format support Signed-off-by: Zhang Chang Ken (cherry picked from commit b11c3b46619d3eaee600223859041a51fa0af218) Change-Id: Ia57a4dd092811f1430367ba7285f15b4e37e6247 Signed-off-by: Shruthi Krishna commit ce2e933002ea2b6e044d8c0109e6787b3e4674b5 Author: kuogee hsieh Date: Fri Aug 5 13:30:28 2011 -0700 msm_fb: display: use spin_lock_irqsave before call disable_irq disable_irq() will wait for irq handle to complete before disable the specified irq. Therefore use spin_lock_irqsave() instead of spin_lock() before call disable_irq() to avoid deadlock on same spin lock. CRs-fixed: 299938 Signed-off-by: Kuogee Hsieh (cherry picked from commit 2920965c1443096f1707888d2fe311cb79dd68dc) Change-Id: I7599dc56b1c3a8bfe4eda7fa1b888cafd86a8df3 Signed-off-by: Shruthi Krishna commit ee9a51030967ac3c293675da9e67b438c5467c34 Author: Raj Kushwaha Date: Fri Aug 5 14:18:30 2011 -0700 msm_fb: display: disable fill screen with blank on early suspend Disable logic to fill framebuffer with black screen before early suspend, this is causing slugish wipe off from top to bottom animation on screen. This logic is still needed for MDP3 because of hardware limitation. CRs-Fixed: 298050 Signed-off-by: Adrian Salido-Moreno (cherry picked from commit 733443cb29774d7c4adb1dd0c15a897bdee47fd3) Change-Id: I71790f25e80641c821a87275b1b37088f6402cfe Signed-off-by: Raj Kushwaha commit ba5def9929507a7501e95c25cb815043d33655b9 Author: Adrian Salido-Moreno Date: Mon Aug 1 14:06:21 2011 -0700 msm_fb: display: clear interrupt flag to properly wait for vsync need to properly clear vsync interrupt flag so that subsequent waits for vsync are handled properly, otherwise wait will return before next vsync happens CRs-Fixed: 299043 Signed-off-by: Adrian Salido-Moreno (cherry picked from commit 69a5a9854608a2ee856dffb5df7780f3d9bd5ed0) Change-Id: Icacbafc93eb831ea681fd6815d6f3ff5055a5394 Signed-off-by: Shruthi Krishna commit 6e113b50c4af73ee87e90f7fc103e3f339a00719 Author: Manoj Rao Date: Wed Jun 29 09:07:55 2011 -0700 msm: display: HDMI: VG2 pipe solid fill color causes MDP to hang During 3D video playback both VG pipes are used, solid color fill into VG2 pipe for HDCP compliance purpose causes MDP to hang instead, we enable Encryption on HDMI TMDS Output By setting BIT[2] of HDMI_CTRL register to enable encryption on HDMI TMDS Output. Signed-off-by: Manoj Rao (cherry picked from commit bdf8e676b81924ee689bbf43cb7343ea3d5e77ce) Change-Id: I2fb8f17d6b94223ba9c35e429acfe571e80e0ed1 Signed-off-by: Raj Kushwaha commit 514b196c41f9e2c978b0d540f7d27a748f0264b7 Author: kuogee hsieh Date: Thu Jul 21 15:06:59 2011 -0700 msm_fb: display: add ioctl for mixer info Add new ioctl to allow user to query mdp mixer detail configuration. Signed-off-by: Kuogee Hsieh (cherry picked from commit 51159ca5df7bb860abdda9e09eba8cb39e2e5d15) Change-Id: Ie22e272d2356289e0bf286464381e23ea9ef3581 Signed-off-by: Shruthi Krishna Signed-off-by: Raj Kushwaha commit 1bdb7c7482741d74e5bf85a14f5a0dbf3e700511 Author: kuogee hsieh Date: Tue Jul 12 13:32:14 2011 -0700 msm_fb: display: change mdp clock while mdp is idle Mdp clock need to be adjusted at run time base on the performance level. However mdp clock can only be changed when mdp blending/dma engine is idle. Signed-off-by: Kuogee Hsieh (cherry picked from commit 30ea94f26e085154b974d1abeb3f1300fd5dcf83) Change-Id: I55c8d6844ff7eb676c7f8bc76e363a7769b35b23 Signed-off-by: Shruthi Krishna commit ea67ae814ceed3004bed07870545725ddd4aeb6d Author: kuogee hsieh Date: Wed Jul 6 11:05:05 2011 -0700 msm_fb: display: add 3D support at DSI video mode Currently, only DSI command mode have 3D capability. Add 3D support for DSI video mode also. CRs-fixed: 294082 Signed-off-by: Kuogee Hsieh (cherry picked from commit f711ac25a68e521ce2bbb450d34f46eb76d39a20) Change-Id: Iee4d72dc85d4042a6490dc9b4f3c593a0a325d54 Signed-off-by: Raj Kushwaha commit 8782b22d00d1211ce80d9093e658d3bba3b1b57f Author: Manoj Rao Date: Mon Jul 18 14:25:38 2011 -0700 msm: display: HDMI: ISR not triggered when HPD occurs during power_off During power off we disable 5v, power down core, by turning off the TX channels one by one. When a HPD is triggered the driver has a software debouncing timer during which interrupts are disabled to be able to read stable HPD status from the register. When HPD is detected while the core is being turned off/powered down the driver's software disables the interrupt and this was making the core to go into off state. So the fix was to keep the interrupt bit enabled through the register even during the debounce timeout (this doesn't trigger unnecessary interrupts due to appropriate clearing and masking of HPD interrupt bits). Signed-off-by: Manoj Rao (cherry picked from commit 4d4aea2e4f489fcc8a5d2eacb528d3bd8c274374) Change-Id: Ib05a6ee172acf80a77418912da3a4f8a54fb64ce Signed-off-by: Shruthi Krishna commit 296d3f254c3cd93a9296c80d9a654f86105f7343 Author: Ravishangar Kalyanam Date: Thu Jul 14 18:45:07 2011 -0700 msm_fb: display: Fix writeback offset with correct fbnum Fix writeback offset with correct fbnum value to avoid any memory corruption with image buffers in use CRs-Fixed: 290324 Signed-off-by: Ravishangar Kalyanam (cherry picked from commit 917fee282ae07cc98541a54204069bf7955e352d) Change-Id: Ie3585ca85d6714e262c3fe724d6b5b5f8c8a26bc Signed-off-by: Shruthi Krishna commit 9afa1e2e91ccb4169ea6a2365b4d98cfe237d0e8 Author: Raj Kushwaha Date: Thu Jul 14 17:41:05 2011 -0700 msm_fb: display: set flush bit at overlay_unset set flush bit at overlay_unset to notify mdp blending engine to pick up new configuration changes. Signed-off-by: KUogee Hiseh (cherry picked from commit 6caa28428d79953af20f6f65459b9217db260aa2) Change-Id: I6270dc95a85f3958c98bfffd429577dab79f408c Signed-off-by: Raj Kushwaha commit ebc6dc50dd48e2c7fe6133dfd2873aa29d5bed08 Author: Raj Kushwaha Date: Wed Jul 13 16:51:06 2011 -0700 msm_fb: display: add spin lock to synchronize mdp irq enabel/disable To improve performance, UI push thread release mutex before blocked at waitting for vsync to allow Video thread to be updated at same vsycn. This also cause contention to enable/disable mdp irq. Add spinlock to synchronize both threads and irq context. Change-Id: I165f94e77164fa5091ac4f31a7a73ed0f735c576 Signed-off-by: Kuogee Hsieh Signed-off-by: Raj Kushwaha commit 93b1ca29a4ac08326bdfdf2ec618cd275613d71c Author: kuogee hsieh Date: Fri Jul 1 09:44:58 2011 -0700 msm_fb: display: release mutex before vsync_push At pulling mode (both lcdc and dsi video mode), release mutex before waiting for vsync so that both video and UI can be updated at same vsync. CRs-fixed: 294504 Signed-off-by: Kuogee Hsieh (cherry picked from commit c1abee46365a0a8b976877a6ad5f2752f410ed7b) Change-Id: Ic9d68781d02d6bd66be107c446a706936c70ab64 Signed-off-by: Shruthi Krishna Signed-off-by: Raj Kushwaha commit e5c60572a13dd16426e7356e544e51d36c8a440e Author: Raj Kushwaha Date: Tue Jul 12 21:07:32 2011 -0700 Revert "msm_fb: display: release mutex before vsync_push" This reverts commit 78318a7a0357fc96cf4a38c90e38be0848cde0db. Change-Id: Ic2dfc460517927e853dc907fc708287bae8a98f2 Signed-off-by: Raj Kushwaha commit c0c86f1e14e98efc85f9866fff89f08d1432095e Author: Chandan Uddaraju Date: Tue Jul 5 18:58:27 2011 -0700 msm_fb: Display: Use pixel clock for downscale validation The clk_rate variable used in validation function represents pixel clock. For MIPI DSI video mode panels, add code to use MIPI DSI pixel clock in downscale validation function. Signed-off-by: Chandan Uddaraju (cherry picked from commit bd0ef9258776385559fd032134e0a28e9aad8f34) Change-Id: I6944f98caeb98bdb963d19596791469bf863e18e Signed-off-by: Raj Kushwaha commit 1ce934cf550c3f647c3eec8ddae54d1fbd891519 Author: Chandan Uddaraju Date: Sun Jun 26 23:55:26 2011 -0700 msm_fb: Display: Enable downscale validation support for MIPI. Add code to call downscale validation function for MIPI video mode panels. This is needed for playing 720p video in portrait mode. CRs-Fixed: 292907 Signed-off-by: Chandan Uddaraju (cherry picked from commit c6e3391b53d62a42616e9d3e04e1fb2d89f2fdda) Change-Id: Id12bf05976b26611e53fd9ed7d31c912bf6840c8 Signed-off-by: Raj Kushwaha commit 0ad0f07f95ff9cf373c3ea0053ea540701fd38de Author: Ravishangar Kalyanam Date: Wed Jul 6 15:28:46 2011 -0700 msm_fb: display: Fix MDDI multiple data write DMA abort issue Fix MDDI multiple data write DMA abort issue by passing physical address to the DMA Signed-off-by: Ravishangar Kalyanam (cherry picked from commit 9ada6fcea2bbf5c92a8cf7a1dd63334e32249564) Change-Id: I0b7df64ef83329b769f3200ac4cfda975118b4fc Signed-off-by: Shruthi Krishna commit 6f4be7effea2e7d42b209b83a53e29d0e599f24a Author: kuogee hsieh Date: Tue Jul 5 14:14:46 2011 -0700 msm_fb: display: remove while loop at mdp4 ISR Since mdp interrupt is enabled on demand, there is no need to have a while loop to handle interrupts at random time. There has possibility that mdp clock was turned off at first loop and ISR handler try to read mdp status register again at second loop which cause system to reset. Remove this while loop from mdp4 isr. CRs-fixed: 291602 Signed-off-by: kuogee Hsieh (cherry picked from commit fe926e8303dc6da0adf7be76c045ac93a9f8818a) Change-Id: I4c3e5f63a6d6b54bd0d12b1be609a5f0d1f73874 Signed-off-by: Sunil Joseph commit 78318a7a0357fc96cf4a38c90e38be0848cde0db Author: kuogee hsieh Date: Fri Jul 1 09:44:58 2011 -0700 msm_fb: display: release mutex before vsync_push At pulling mode (both lcdc and dsi video mode), release mutex before waiting for vsync so that both video and UI can be updated at same vsync. CRs-fixed: 294504 Signed-off-by: Kuogee Hsieh (cherry picked from commit c1abee46365a0a8b976877a6ad5f2752f410ed7b) Change-Id: I4a16e8313399c55d71a2e406e56c0c5d3f8f33e4 Signed-off-by: Shruthi Krishna commit eacd237f51c20c08c225b6b817e7a6e109ab0b52 Author: Raj Kushwaha Date: Wed Jul 6 11:21:01 2011 -0700 msm_fb: display: increase mdp clock debouncing time Increase mdp clock on/off debuncing time from 0 to 50 ms. Signed-off-by: Kuogee Hsieh (cherry picked from commit b29ea0e32018ab5e9ac6f48d0a2ad29d4591b948) Change-Id: Iad796bc1dde524b600cd5fd37ac4b85ca6f47b81 Signed-off-by: Raj Kushwaha commit 85200a4e8aabf77e3df2bbb0d50b359ee54ba402 Author: kuogee hsieh Date: Mon Jun 27 11:09:23 2011 -0700 msm_fb: display: add Novatek dsi panel backlight support Add MIPI led_pwm1, led_pwm2 and led_pwm3 dcs commands to control Novatek panel backlight through dcs command. CRs-fixed: 285850 Signed-off-by: Kuogee Hsieh (cherry picked from commit 098325372eb8c3df9e841de9502c4bd7dcbbf5d5) Change-Id: Ib5b4a9d0be4c03eb0d6525ceb1d5cdd04e970a96 Signed-off-by: Shruthi Krishna commit 784b785c7c52ce1d74b1e2ab827f485e9b9cb759 Author: kuogee hsieh Date: Wed Jun 29 14:23:50 2011 -0700 msm_fb: display: remove mutext from lcdc on/off Since mutext had been acquired at up stream, no mutex necessary at both mipi_toshiba_lcd_on() and mipi_toshiba_lcd_off(). Signed-off-by: Kuogee Hsieh (cherry picked from commit 1b3fa75696737dd7bbee380eb9dbbf81b66ba99c) Change-Id: I05abf7a3b52d015a146fdfab82a7106523d39847 Signed-off-by: Shruthi Krishna commit 90e312fd2e0f238cd374aab1c7c88905c22d22ae Author: kuogee hsieh Date: Thu Jun 23 08:59:06 2011 -0700 msm_fb: display: no overlay set and play allow after suspended Check suspend state at both overlay set and play. Return fail if system suspended. CRs-fixed: 292430 Signed-off-by: Kuogee Hsieh (cherry picked from commit da07df81fe450fb08ec68511bd4ac5004ee96f3d) Change-Id: I3f8bff425a158592cd572e0c487be41590ceff32 Signed-off-by: Shruthi Krishna commit d00fd730650f26f690df997c91243d0470b1cc3b Author: kuogee hsieh Date: Tue May 3 17:26:45 2011 -0700 msm_fb: display: Revert "do not restore control screen to main panel" Reverts commit 64189b417cc545add2f496609ef11df6b491d177 since it cause mdp hang up while playing HDMI. Signed-off-by: Kuogee Hsieh (cherry picked from commit 2152d08bd0c7d2e1ca4e49f80443b3c6336c09ab) Change-Id: Ia2f794da7f0d4717833000b7c657d7fc31987d7a Signed-off-by: Shruthi Krishna commit 53310ca7798873e4f48c426db8cd2f352cf25d33 Author: kuogee hsieh Date: Fri Jun 17 14:41:53 2011 -0700 msm_fb: display: wait for dma completion before dsi off Since dcs commands needed to be sent to dsi client (panel) to bring down panel during dsi off (suspend) process, check dma completion before start sending dcs comamnd to panel to avoid confliction at MIPI DSI channel. CRs-fixed: 291842 Change-Id: Ieaf6595baddcef945ad5606a4bbafa18bbd8033b Signed-off-by: Kuogee Hsieh commit 59863dbc83da3fd3a06a8c8be50c28b08c60b9be Author: Raj Kushwaha Date: Tue Jun 28 10:38:06 2011 -0700 msm_fb: display: Disable/enable chicken bit during video playback CRs-Fixed: 283794 Signed-off-by: Ravishangar Kalyanam (cherry picked from commit 1fe5c7b8258ed19276d0af8b9171fd864f40619e) Change-Id: I547f00f4500b40777686fc0491500c06b5b4109f Signed-off-by: Raj Kushwaha commit 6a50674d696213efebb93a5d9d109723aa69d758 Author: Chandan Uddaraju Date: Wed Jun 22 23:38:16 2011 -0700 msm: Display: Fix IOCTL ID for 3D ioctl. Add code to have unique ID for 3D Ioctl call. Move Novatek specific changes for 3D to novatek panel file and remove the usage of featurization macro "CONFIG_FB_MSM_MIPI_NOVATEK_3D_PANEL". Change-Id: I01e2ec5cd85d2778fc800fd452ee3b1e6d0602f3 Signed-off-by: Chandan Uddaraju commit 66c31a935e3d692aba41a8fcd419dab4c8acbd3c Author: kuogee hsieh Date: Fri Jun 17 09:58:55 2011 -0700 msm_fb: display: check dsi_pipe for writeback mode at kickoff At MIPI DSI command mode, Writeback mode (blt) is marked at dsi_pipe. During video kickoff (overlay play) dsi_pipe->blt_addr should be check instead of pipe->blt_addr to see whether writeback mode is enabled or not. Current, pipe->blt_addr was checked which cause extra mipi_dsi_cmd_mdp_sw_trigger() was called which cause an extra mipi_dsi_enable_irq() called and flooding kernel log with "IRQ already enabled" warning messages. Signed-off-by: Kuogee Hsieh (cherry picked from commit 24c7acd32b080d105e84994dc0cb3ee9d0d28738) Change-Id: Ib5993ad1967be2244892fe02325094b4e40c7ec9 Signed-off-by: Shruthi Krishna commit fb47e7b99107e99d4b972d2b3c9f80c7d3b62b07 Author: Saurabh Shah Date: Tue Jun 21 17:58:22 2011 -0700 msm_fb: display: Use reserved[4] for storing fps Use reserved[4] field for storing fps, since reserved[3] is used by HDMI Signed-off-by: Saurabh Shah (cherry picked from commit afc6ae9304f27c240546f15580555913f7e27644) Change-Id: Iadc2b2df0f7418fa86c4cc69d35208e8b32d095f Signed-off-by: Shruthi Krishna commit ba5be4afb461abba65cd1f588dca788c0df307b9 Author: kuogee hsieh Date: Thu Jun 9 15:53:11 2011 -0700 msm_fb: display: check suspend condition before bus scaling Overlay_unset() was called to free mdp pipe back to pool. Therefore requested bus bandwidth need to be scaled down after overlay_unset() accordingly. Bus bandwidth was scaled down to level 2 at overlay_unset(). At suspend, bus bandwidth was scaled down to level 0. It is possible that overlay_unset() will be called after suspend had been completed. Under this situation the over all bus bandwidth request stay at level 2 instead of level 0 which prevent power from being collapsed. This patch will not do bus scaling at overlay_unset() during suspend. CRs-fixed: 290583 Signed-off-by: Kuogee Hsieh (cherry picked from commit 47c54ff0e010190f0a11e7e2792642d70caa339c) Change-Id: I7061c82f24db6e70845a68d27d82dcded81b4b7f Signed-off-by: Shruthi Krishna commit 1fbbeff4b9853054cca7d585596a16ae8bfb78c2 Author: Chandan Uddaraju Date: Tue Jun 7 19:38:02 2011 -0700 msm: Display: Add sysfs entry to enable 3D barrier. Add code to configure the gpios lines using FPGA to enable the 3D barrier for the Novatek panel. Add sysfs entry to enable/disable the barrier.The barrier should be enabled only while playing 3D content. Change-Id: Ic8a96a1c2ef6473b9c95701dcebb19b43ed570e9 Signed-off-by: Chandan Uddaraju commit 6a5a125bf8fca8b9dfe3b4cb10a536c148e81c77 Author: Raj Kushwaha Date: Wed Jun 22 11:49:45 2011 -0700 msm: Display: Add code to provide 3D panel information to UI. Add code to provide information to the user interface about wheather the panel supports 3D display or not. Change-Id: I1086b8deb2980ffcacae153ba5ac80c680e04eb8 Signed-off-by: Chandan Uddaraju Signed-off-by: Raj Kushwaha commit e373013d44b00be5114ae6af212478a728eae68f Author: Rajesh Sastrula Date: Fri May 6 15:27:33 2011 -0700 msm_fb: display: provide panel refresh rate information user space can use refresh rate of the panel when they get variable screen info as part of calling FBIOGET_VSCREENINFO ioctl. CRs-Fixed: 283750 Signed-off-by: Rajesh Sastrula (cherry picked from commit 9322f759f8437a816e44aa921a64fcb566defcfb) Change-Id: I658c08b4a0d06ca2c58a06a9dfba1f80ad541c9e Signed-off-by: Shruthi Krishna commit ef8a1203fa188df6f9c905b8dbaf13d640418d9c Author: Manoj Rao Date: Thu Jun 9 15:36:59 2011 -0700 Remove hdcp timer if the device is not hdcp-enabled. Non-HDCP enabled devices seem to have various problems when connected to various sinks. HDCP Reauth=>deauth, hdcp_auth hdcp_auth=>turn_on() which calls HDMI Core reset without informing the Audio QDSP this can do bad things to video playback on the HDTV Therefore, as surprising as it may sound do reauth only if the device is HDCP-capable Signed-off-by: Manoj Rao (cherry picked from commit c105b2f0d55fa64c2c9e2715531c1bb6ff8b3de7) Change-Id: Ia7d9249dfcc6c85039304336b3f86b2e3194ec50 Signed-off-by: Shruthi Krishna commit 3b6b2347a2b87e96c566d8460c6e697622a759a5 Author: kuogee hsieh Date: Mon Jun 6 10:29:28 2011 -0700 msm_fb: display: add mdp writeback mode support dsi video mode MDP writeback mode has been worked for both lcdc and dsi comamnd mode. This patch add dsi video mode writeback mode support and unify interface to enable/disable writeback mode. Change-Id: I74898d7d80e9b4727eb417b0f1d831845d229c73 CRs-fixed: 287700 Signed-off-by: KUogee Hsieh commit bce29e40828551984b3326f13d210d338edde5b1 Author: kuogee hsieh Date: Mon May 23 13:01:04 2011 -0700 msm_fb: display: add both pre and post mipi dsi kickoff action Add both pre and post mipi dsi kickoff action so that vendor can add their own call back functions to customize their mipi dsi controller. Signed-off-by: Kuogee Hsieh (cherry picked from commit 30fda1e634d3be2d47330eb15fbbc2c4389460c1) Change-Id: I9c070246b5099664c62dc665dc27ccd8f69926d5 Signed-off-by: Shruthi Krishna commit 8f6405853a986f8e887d733b93386c705bae6c7a Author: kuogee hsieh Date: Thu Jun 2 08:52:46 2011 -0700 msm_fb: display: fix hdmi reset while playing moving When mdp writeback mode is enabled, ovoerlay0_done isr handler (executed at cpu-0) will call mdp_enable_irq() to acqure lock and enable mdp interrupt before kick off dmap engine. Meanwhile dtv thread (executed at cpu-1) had called mdp_disable_irq() which had acquired same lock already and waititng for overlay0_done isr handler to complete. Hence dead lock had happen. This cause system to reset. The patch have overlay0_done isr handler to call mdp_disable_irq_nosync() at end of handler to avoid dead lock with DTV thread's mdp_disable_irq(). CRs-fixed: 289140 Change-Id: I4b5ee7fcaf24b81a830320d1a47a9fe6b5095f7b Signed-off-by: Kuogee Hsieh commit 4efc6788d96403be44453d9d83ad0598fdf17795 Author: Abhishek Kharbanda Date: Thu May 26 22:30:57 2011 -0700 msm_fb: [HDMI_Compliance] FIX HDCP state machine Book-keeping HDCP State in HDMI State structure, to incorporate handling of frequent interruptions to the HDCP authentication procedure. Signed-off-by: Abhishek Kharbanda Signed-off-by: Manoj Rao (cherry picked from commit 60e1a17d7c3221e7f9b958ffe46e3e736dd532a1) Change-Id: Ia30bbdabec6abdcfc2e17912d9d3506ab56283cd Signed-off-by: Sunil Joseph commit 884a69dc1ab07f18d5bec5a6868a7dc8ed0648c4 Author: Raj Kushwaha Date: Fri Jun 3 14:12:43 2011 -0700 msm_fb: display: do not restore control screen to main panel For MIPI dsi, no need to restore control screen to main panel at the end of video playback. (cherry picked from commit 64189b417cc545add2f496609ef11df6b491d177) Conflicts: drivers/video/msm/mdp4_overlay.c drivers/video/msm/mdp4_overlay_dsi_cmd.c Change-Id: Ie04cc7322fe7b53058f371941af5ba16c93174d2 Signed-off-by: Raj Kushwaha commit a150e2043331160e9b996d1fead53d095ec1578b Author: kuogee hsieh Date: Mon May 16 17:03:45 2011 -0700 msm_fb: display: disable primary and external vsync interrupt Clear PRIMARY_VSYNC and EXTERNAL_VSYCN interrupt enable bit at isr handler to disable vsync interrupt. This will mitigate un-necessary interrupt which will wake up cpu constantly and consume extra power. Signed-off-by: Kuogee Hsieh (cherry picked from commit 3700ca00ba19855081822169e144c87aa1d4953f) Change-Id: Iba7ef824baf4f95aa0fbb6bfa09446ca589f7648 Signed-off-by: Shruthi Krishna commit 297c5cba4110a4595f5e84082f5970c9a7f225d2 Author: kuogee hsieh Date: Mon May 16 17:01:12 2011 -0700 msm_fb: display: turn off dtv timing generator first The correct way to turn off dtv timing generator is to turn off dtv timing generator first followed by turn off dtv related clocks. So move panel_next_off() which used to turn off dtv related clocks off after dtv timing generator was turned off. Signed-off-by: Kuogee Hsieh (cherry picked from commit 22cff13e1115962207254980acffac8d20bd9b26) Change-Id: I3c1c3518db28d80e5a5a31bfd5b5740dbba65ada Signed-off-by: Shruthi Krishna commit 0ec06ef1a1ecf52b5408e4c0509bcbe0a70ead3c Author: kuogee hsieh Date: Fri Mar 18 14:46:20 2011 -0700 msm_fb: display: add memory barrier to mdp Add wmb() to enforce mdp registers are updated before kickoff. Also add dsb() to mdp_pipe_ctrl() to make sure mdp register updates had been finished before shut donw mdp clock. CRs-Fixed: 288084 Change-Id: I056143511cfa7e397983b7465fcebff06ada8a3e Signed-off-by: KUogee Hsieh Signed-off-by: Raj Kushwaha commit 52c880d22b6e58f259f02f956357e4b8650102f4 Author: Ravishangar Kalyanam Date: Fri May 13 16:40:55 2011 -0700 msm_fb: display: Wait for vsync support for DSI Video interface CRs-Fixed: 287940 (cherry picked from commit dfcf3ef2212026dfb53e87f571b294627f34a4a7) Change-Id: I0083bab592975576d511ef8f6070d38acc40d117 Signed-off-by: Raj Kushwaha commit 0f990641485d3340fb8bacd741eb6ccfcac51186 Author: kuogee hsieh Date: Thu May 19 15:50:27 2011 -0700 msm_fb: display: fix mdp shared pipe allocation bug Both VG pipes of MDP are sharable which can be used as either graphic or Video. Pipe alloction need to keep tracking of VG pipe is shared by which two virtual pipes. There has a bug to keep correct record after several pipe allocation and free operation. This patch fix this bug during pipe allocation. CRs-fixed: 286350 Signed-off-by: Kuogee Hsieh (cherry picked from commit 4217a1dacbde157ce26238904450b091778fe872) Change-Id: Ife220d4f0f756aba62e3c30dc7ea52a1e4814ebc Signed-off-by: Shruthi Krishna commit 978d4d142600a38bff5082b0ff2ea23fab5d2f91 Author: Abhishek Kharbanda Date: Mon May 23 14:28:19 2011 -0700 msmfb:[HDMI_COMPLIANCE] Read EDID extension block. Read EDID extension block 3 and 4 as part of HDMI compliance test 7-1. Change-Id: Ia4578cc5c35f44c5708d9c4756600490df35ff67 Signed-off-by: Raj Kushwaha commit d0244c6c479ee348493568556afe49ff9f80f2f0 Author: kuogee hsieh Date: Mon May 23 14:52:03 2011 -0700 msm_fb: display: remove un-balanced mdp_pipe_ctrl() remove un-balanced mdp_pipe_ctrl() called from both mdp4_overlay0_done_dsi_cmd() and mdp4_dma_p_done_dsi(). Change-Id: Ie47dbe02c7fa5938eef8414a6041b431e55cc986 Signed-off-by: Kuogee Hsieh commit 89f874aa1fce2e9d4f488a5e37d226e3ecbe7cf2 Author: Arun Kumar K.R Date: Sat May 21 16:21:26 2011 -0700 msm_fb:[HDMI_COMPLIANCE] Add HDCP node to externel common state Update the sysfs about HDCP keys. This read only attribute is used by HDMI Daemon to pass Audio, in case no HDCP keys present. Change-Id: If8db70e22f7b5163fa7a0cfbbdd27d8560f64df1 Signed-off-by: Raj Kushwaha commit 9e8929676679717bee2f16bad6611bb0b94a7780 Author: Abhishek Kharbanda Date: Fri May 20 07:34:52 2011 -0700 msmfb:[HDMI_COMPLIANCE] Read DDC Bus in 32bit alignment Read DDC bus in 32 bit alignment in case of failure Change-Id: Ib323dc9ca806b1bab22baa2612e2f470f5c2ecaf Signed-off-by: Raj Kushwaha commit fc3c8c0bb9e685052b7edc8040167d643c63b3c7 Author: Abhishek Kharbanda Date: Fri May 20 06:50:55 2011 -0700 msmfb:[HDMI_COMPLIANCE] Reading correct bytes of RO' Read correct number of bytes i.e. 2 for RO' and increase wait for Authentication sucess interrupt to 2 sec. Change-Id: Id08a8d74a0b681dfce6d7635d280e5c31b7acbc3 Signed-off-by: Raj Kushwaha commit 13de0ca3217e379d2c2574b0f6f81ebe3400a13f Author: Abhishek Kharbanda Date: Mon May 9 13:14:53 2011 -0700 msmfb:[HDMI_COMPLIANCE] Correct sequence of events on HPD connect On HPD connect, read EDID, turn on HDMI core, send CONNECT event to UI to enable DTV clocks, then start HDCP Authentication. For HDCP reauthentication case, do HDMI core reset/programming before enabling HDCP authentication again. (cherry picked from commit 46ad60f0cff5c2222ded7a639f337417e59b2375) Change-Id: Ie6e8378aeca07644c69bbfede61d457446c88f5a Signed-off-by: Raj Kushwaha commit 3c809bfc5abd0c13a50ad773268efc1bbe442d8e Author: Abhishek Kharbanda Date: Mon May 16 14:25:28 2011 -0700 msmfb:[HDMI_COMPLIANCE] QDSP ON/OFF kobject events to userspace. Set two new kobject events i.e.QDSP ON/OFF events to userspace. QDSP ON is send only after authentication sucess. QDSP OFF is send on HDCP Failure interrupt or on HPD connect. (cherry picked from commit cd0bd24a3fffff873821618009389378372fb73e) Change-Id: I700599b4926770dc7602f970a4bd5c30dc457969 Signed-off-by: Raj Kushwaha commit e60b4d1c7ba520319c5ddc60b68b8fbe1a6c72a2 Author: Abhishek Kharbanda Date: Mon May 16 13:14:11 2011 -0700 msmfb:[HDMI_COMPLIANCE] Fill BLACK SCREEN during Authentication. Fill VG2 pipe with Solid Black color at beginning of authentication. Unfill VG2 pipe to transmit the original frame on HDCP authentication sucess. (cherry picked from commit 44a306a8c4d4e1ca66750c9ebc17ef21ab482d97) Change-Id: Ie3fbcb42e8b313a1f0861df324c10e370fdfbb2f Signed-off-by: Raj Kushwaha commit c2a00f21c60eb88ed17e348ae947fdffcf7aedaf Author: Abhishek Kharbanda Date: Thu Apr 28 18:17:49 2011 -0700 [HDCP-COMPLIANCE]:HDCP: WORK QUEUE instead of kernel work queue Not using Kernel global work queue to avoid frequent watchdog barks/bites. Instead creating a local work queue to handle all work items belonging to HDMI/HDCP driver. (cherry picked from commit 8dae3d06d1c41aa2de609056811646ff50e77791) Change-Id: I793b3aee06cac0bd62158c55ee9233dadf51c873 Signed-off-by: Raj Kushwaha commit fa6ee4594caaa7cf28fd33bcfb8a62165602224e Author: Abhishek Kharbanda Date: Thu Apr 7 13:56:34 2011 -0700 msm_fb: [HDMI_COMPLIANCE]:HDMI/DVI Sink Detection. HDMI/DVI Sink detection based on reading IEEE id of Vendor Specific Data Block in EDID. Required for HDCP-1A-09 and HDMI-7-33 compliance case. (cherry picked from commit 2c7864a358d63b3ed2681a8a0d45bea7da7f85c0) Change-Id: I0b054dcfb6e98b635cb4d8b6a14f6541d97f3287 Signed-off-by: Raj Kushwaha commit 199f5f94edd7c6c127dd4b402cf7866e641a3396 Author: Abhishek Kharbanda Date: Mon Apr 11 10:28:14 2011 -0700 msmfb:[HDMI_COMPLIANCE] HDCP Compliance 1B-06 Verified that HDMI Transmitter considers it a failure of the second part of HDCP authentication protocol that BStatus: MAX_CASCADE_EXCEEDED bit is asserted by the downstream repeater. (cherry picked from commit 62a5ab8164b5dd55d358b31cdd333597e2e057ff) Change-Id: I96b1d3c3ae55dd427c7270d419bbece05917c590 Signed-off-by: Raj Kushwaha commit 33381e73bfa8c51bf91e04d3e5f6fe0930addb9e Author: Abhishek Kharbanda Date: Thu Apr 7 13:27:49 2011 -0700 msm_fb: [HDMI_COMPLIANCE]:Writing correct bytes on DDC bus. Writing correct bytes of An and AKSV's on DDC bus. (cherry picked from commit 065b9f72784c2686aca0233e8e510229efd329c4) Change-Id: Icf3c87bce4102fc1d24931f8dde15478bf71fd19 Signed-off-by: Raj Kushwaha commit 57c3657ebbd5273c1f84f28f460482a68b50c968 Author: Abhishek Kharbanda Date: Sun Apr 17 10:48:05 2011 -0700 msm_fb: [HDMI_COMPLIANCE]: Verifying V' in Authentication Part 2 Reading value from HDCP PORT 7,8,9,10 and 11 and writing it back to HO,H1,H2,H3 and H4 portion of HDCP Hardware registers. (cherry picked from commit e814b7842af3b7f15047f3f922c1f1648bb2705b) Change-Id: I524b700973062f51b123f100dc115b5c873d7346 Signed-off-by: Raj Kushwaha commit 1fdcac8e3387d1f8435090fae2bffeec3eae6970 Author: Abhishek Kharbanda Date: Mon Apr 11 10:21:06 2011 -0700 msmfb:[HDMI_COMPLIANCE] HDCP Compliance case 1B-05 Verified that HDMI Transmitter considers it as a failure of the second part of HDCP authentication protocol that BStatus: MAX_DEVS_EXCEEDED bit is asserted by the downstream repeater. (cherry picked from commit ccdb0372092c3a359754897ebec2bb8be37d6a3e) Change-Id: I02ee8d0ce604cda993f90158282544afb7490cb1 Signed-off-by: Raj Kushwaha commit ffe43137a4024e0941417d19fb2e51946c1f4e0d Author: Abhishek Kharbanda Date: Mon Apr 18 14:24:59 2011 -0700 msmfb: [HDMI_COMPLIANCE] Disable HDCP H/W Disable HDCP H/W block during deauthentication (cherry picked from commit a13f69fc1fdc0ccb8bcedc0001f39f2b195652bd) Change-Id: I82fa0248329d56f0662785b1ff7b35ad94e657d2 Signed-off-by: Raj Kushwaha commit 73d05af290793eb0da55a556c4bbaa28c9706dd8 Author: Abhishek Kharbanda Date: Mon May 9 12:09:45 2011 -0700 msmfb:[HDMI_COMPLIANCE] HDCP Compliance DVI mode 1A-09 HDMI core Audio setup should not be done in DVI Mode. Audio should route through Headset/Phone Speakers in DVI Mode. (cherry picked from commit 2c1204470d5e7376d89a7a1f69c788d79cdc53c3) Change-Id: I4ce8dc81a137a3646c9d508d682f3ef05b3bc435 Signed-off-by: Raj Kushwaha commit 645ebc3ec6214d0d9fe32a32fa7e10558c74af6b Author: Abhishek Kharbanda Date: Mon May 9 11:58:38 2011 -0700 msmfb:[HDMI_COMPLIANCE] HDCP Compliance case 1A-01/1B-01 ON HDCP reauthentication process, first do HDCP deauthentication and then reset/program hdmi core again , rather than just re-doing HDCP authentication only. This will reset HDCP encryption engine completely and remove "Encryption Enabled prior to reading RO'"error on Quantum Data BOX. (cherry picked from commit 829c88376705c6b58e62dd93e9802ffb905ad49c) Change-Id: I55d1ee5918b05279abcfe63ab74d172e5e8671b5 Signed-off-by: Raj Kushwaha commit 5208a4caa32f8775a10c1567d2749599a2fb839c Author: Kiran Kandi Date: Tue Feb 15 10:21:40 2011 -0800 msm: 8660: audio: driver for compressed audio over HDMI. This driver sends compressed audio IEC 61939 bursts in IEC 60958 Frames. Change-Id: I6cdd36efe643b0bdaec0436e57a6364076d47239 Signed-off-by: Kiran Kandi commit b8b834d4da42df635254a5b656e5579bf9237f73 Author: Rajesh Sastrula Date: Tue Dec 28 15:19:07 2010 -0800 msm_fb: display: Add support to notify display updates new ioctls are added to notify the user space about the display updates and idle. Signed-off-by: Rajesh Sastrula (cherry picked from commit 7ff0f5166ed9f2ff4f1a37b8bce2501a2029905e) Change-Id: Ibca9d3a2427f484227a6083b6ef11fbb7555cecc Signed-off-by: Sunil Joseph commit 3ad826161f59f6531afa19412f3c8b2f2d0362da Author: Rajesh Sastrula Date: Wed May 18 11:10:11 2011 -0700 msm_fb: display: Flush RGB pipe when solid fill mode is used Fullscreen applications can request the driver to configure the MDP back ground pipe to use solid fill mode so that the background pipe will not be fetched by MDP and it saves the bus bandwidth hence the total system power. This requires the driver to explicitly issue a register flush on the background pipe when the configuration changes from regular fetch to solid fill mode during overlay play. CRs-Fixed: 270713 Signed-off-by: Rajesh Sastrula (cherry picked from commit d89efdbbdf521f05a7b9f191e98914b40bc1962d) Change-Id: Ie5cbe004768986dfd5f53d4cbdec9c28506fac03 Signed-off-by: Sunil Joseph commit 0cb3d75a60e141d786e68fdb713382620d39e18c Author: kuogee hsieh Date: Thu May 5 08:43:03 2011 -0700 msm_fb: display: waiting for dmap_done before kickoff Add waiting for dmap_done interrupt to both mdp4_dsi_cmd_overlay_restore() and mdp4_dsi_cmd_kickoff_video() before kick off overlay blending engine to avoid two consective kickoff of overlay bleanding engine and only one dmap_done interrupt after that when write back mode is enabled. This cause mdp_pipe_ctrl(ON) called two times and mdp_pipe_ctrl(OFF) only called one time which casue mdp clock and vsycn clock can not be shutoff during suspend. Signed-off-by: Kuogee Hsieh (cherry picked from commit 41e0dcf972dfa5892169d9a03d6d1de9029a7556) Change-Id: I0c3fc7d4ebcaada2732eced5ea84b94f1a2d9a0b Signed-off-by: Sunil Joseph commit 66f2c07c8a78044fb26cc853702adfc106c99209 Author: Rajesh Sastrula Date: Thu May 5 18:42:50 2011 -0700 msm_fb: display: increase backlight levels to 100 This is to improve the quality of ABL. Signed-off-by: Rajesh Sastrula (cherry picked from commit d8df7faccb2ec330eb859179ed0db07313626b7c) Change-Id: I8c566c3dfa8c638e370aba384b80936a03bee88d Signed-off-by: Sunil Joseph commit 231a253c7248971c0a3881ec2fefea45ab20b775 Author: kuogee hsieh Date: Wed May 11 09:46:07 2011 -0700 msm_fb: display: mdp_pipe_ctrl called symmetrically mdp_pipe_ctrl() only need to be called when write back mode is not enabled at mdp4_overlay0_done_dsi_cmd(). Unsymmetrically mdp_pipe_ctrl() called will cause mdp clocks can not be shut off during suspend. Change-Id: I1783a736c86e5a36a2edfb6b266832e3d691be7b Signed-off-by: kuogee Hsieh commit 64eaf4972c8dea0368d3a4113d6b19a058fc3b3d Author: Rajesh Sastrula Date: Wed Apr 27 11:58:52 2011 -0700 msm_fb: display: lower the mdp clock during clock disable on halcyon MDP MSMC1 voltage stays high if the clock rate is greater than 122Mhz and causing to draw more power during mdp is idle even after disabling the mdp clock. Lowering the mdp clock after clock disable so that MSMC1 voltage goes down and restore the clock back to same value before clock enable to save power when MDP is idle. CRs-Fixed: 285714 Signed-off-by: Rajesh Sastrula (cherry picked from commit e80420254616b39d0c350dcadf8f6954394e7647) Change-Id: I84df4bc1ca3b0df34d2fab559cace1ca740f2702 Signed-off-by: Sunil Joseph commit 1323385de767733a659d397ca487e578315d887a Author: kuogee hsieh Date: Tue Apr 5 11:44:52 2011 -0700 msm_fb: display: wait for next vsync at overlay_unset At pulling mode (lcdc, dtv) panel, wait for next vsync during overlay unset to smooth transaction of pipes. CRs-fixed: 276786 (cherry picked from commit 565ecc608d46993c4afe6dd15c95942c75f1e932) Change-Id: I908ffa60cd820a47c49d25b1732f7f0f0f1748b0 Signed-off-by: Raj Kushwaha commit 9d7f8859560ac2f3c6f84f35e28f24b33809ccb0 Author: kuogee hsieh Date: Wed Apr 13 15:05:19 2011 -0700 msm_fb: display: decrease mdp_timer_duration value To improve power efficiency, mdp clock need to be shut off as soon as possible after screen updated so that TXCO can be shut off too. Since mdp_timer_duration control the timing to shut off mdp clock, it need to be kept as shorter as possile. Decrease mdp_timer_duration from 1 second to 0 ms for MIPI DSI interface. mdp_timer_duration stays at 1 second for legacy MDDI interface. CRs-fixed: 282857 (cherry picked from commit 605a44c18620ed364e53d1e4cc0f03fd2f815029) Change-Id: Ia1c487a95cc7fba7aee2b8d9dc522296446a7fb1 Signed-off-by: Raj Kushwaha commit ad6004f89f6972f513b0a71cff515f670db661c7 Author: Raj Kushwaha Date: Wed May 11 12:11:41 2011 -0700 msm_fb: display: move footswitch out of mdp_pipe_ctrl() mdp_pipe_ctrl() is called frequently, move footswitch mechanism to more proper place and have it enable always. (cherry picked from commit cf66ffdba39e8ac83e82a19ef8ebd0f9f6f5a32b) Conflicts: drivers/video/msm/mdp.c Change-Id: I88901c3b3640dd1030246de0dbeee3109787bc23 Signed-off-by: Raj Kushwaha commit aa53b629ae7c52ffaa50934a87a48e2887357d85 Author: Rajesh Sastrula Date: Wed Apr 20 16:26:07 2011 -0700 msm_fb: display: use maximum performance level for interlaced content mdp is going to underflow if maximum clock is not used for interlaced videos to work around this using the maximum performance level for interlaced videos until the root cause is identified. CRs-Fixed: 283652 Signed-off-by: Rajesh Sastrula (cherry picked from commit 5e744543c3f81650a1cea1402c58c01ae6ee421d) Change-Id: I0d16f22a98e25b8366b6c3eaf60cd6277f5a76f1 Signed-off-by: Shruthi Krishna commit 754ac15b2a298b38873fadc47ec4b89602aa71df Author: kuogee hsieh Date: Fri Apr 29 11:08:50 2011 -0700 msm_fb: display: clear dmap eanble bit before shut off mdp clk At MIPI dsi write back mode, mdp clock was shut off before dmap interrupt enable bit can be cleared at dual core environment. This cause mdp interrupt line keep asserting. Fix it by moving mdp_pipe_ctrl() after clear dmap interrupt enable bit. This patch also move footswitch out of mdp_pipe_ctrl() and have footswitch always enabled. Change-Id: I8beb66da6afb606da9460f5c8027f298227bf0aa Signed-off-by: Kuogee Hsieh commit 2c5fc636989ba248384240b8f31ff82791790a23 Author: kuogee hsieh Date: Wed Apr 6 09:20:08 2011 -0700 msm_fb: display: mipi dsi read function Re-write MIPI DSI read function to allow it to read more than 4 bytes of data from client. Change-Id: I016bb0accfd71526a32f96878e64c439f2e53537 Signed-off-by: Kuogee Hsieh commit 58979b79f5ca8211aac7faad413934ee8f09bf8e Author: Abhishek Kharbanda Date: Fri Feb 25 12:23:06 2011 -0800 msm_fb: Disabling DTV timing Generator after hdmi off. DTV timing Generator should be enable for updating Audio Packet Control(0x0020) and Audio Configuration(0x01D0) register in HDMI core. Need to checks Bit[0] of both registers before doing the HDMI Audio Shutdown. CRs-fixed: 274278,274284 Change-Id: Id15e4bcbddea4a7c0c9926f5420c0b639ab599bb Signed-off-by: Abhishek Kharbanda commit 9e0698f6708ed4da35b2da7281fb7a5044ba0801 Author: Chandan Uddaraju Date: Wed Mar 23 11:38:42 2011 -0700 msm_fb: display: Configure MDP clock depending on dsi_pclk rate. In MDP 4.1, the MDP core clock should be greater than 1.5 times the dsi_pclk frequency. Add code to set the minimum frequency for MDP core clock depending the MIPI dsi pixel clock frequency. For LCDC panel, add code to set the minimum frequency for MDP core clock to be atleast 1.15 times the pixel clock. CRs-Fixed: 279386 Change-Id: I065bb0eb13c68ee191c8693fe5ca73b3587c1edd Signed-off-by: Chandan Uddaraju commit 70b65dca8d88287a259f88591255f3725a50026d Author: Chandan Uddaraju Date: Thu Mar 31 18:21:47 2011 -0700 msm_fb: Display: Fix MIPI DSI video mode configuration settings Modify the video mode settings according to suggestions from hardware team. Enable High Speed mode during horizontal blanking period. Configure Novatek panel to run at 60 fps in video mode. Change-Id: I9e68f1175caece135ac4074fcc35a907f8006158 CRs-Fixed: 279535 Signed-off-by: Chandan Uddaraju commit 68848ff4fc21b2dbd068e29ddb391a088eba2137 Author: Abhishek Kharbanda Date: Tue Dec 21 13:48:40 2010 -0800 msmfb: msm_hdmi: extract 3D information from EDID Header Extract 3D presnt information from Vendor Specific Data Block from EDID header extension. Change-Id: If5d94382a9c610f7a241a91ef5c61801366d5e9c Signed-off-by: Abhishek Kharbanda Signed-off-by: Urs Muff commit 07099e1ef27c0dd6bc6bea859211bb36239d53db Author: Omprakash Dhyade Date: Fri Mar 11 13:33:23 2011 -0800 msm_fb: display: Remove RGB performance level vector With RGB performance level vector requesting for performance level 1 for all RGB type surfaces, power consumption increases. Performance level 4 is sufficient for single WSVGA size RGB buffer scanning. Remove RGB performance level vector and add check to request performance level 4 for signle WSVGA RGB buffer scanning. Change-Id: Icfb6f00799fc510d23a6f048fc4729471576d00e Signed-off-by: Omprakash Dhyade commit c85505b79eb8b10c0bba8ed6891ded008588a55c Author: Arun Kumar K.R Date: Thu Mar 31 12:18:02 2011 -0700 msm_fb: add DTV vsycn push Add DTV vsync push to block on vsync so that overlay play calls can synchronius with UI push. Change-Id: I382c16fda3846f983b00f175619d18d7ddc5e762 Signed-off-by: Kuogee Hsieh commit 4f6b6e3fdee8ed083e609204bbd05d99923104ac Author: Rajesh Sastrula Date: Wed Mar 30 17:12:36 2011 -0700 msm_fb: display: add a flag to know the rotated source content expose a bit in the flags field so that driver knows whether the source content is rotated, this is used by mdp to deinterlace the content in horizontal direction for landscape video if the video is rotated portrait. CRs-fixed: 281389 Change-Id: I303f6c5f03763b9f68d1f7388839764a69bb428f Signed-off-by: Rajesh Sastrula commit 7c0c2fe5ac873e185dfbad153bbc5d489b0a8906 Author: kuogee hsieh Date: Wed Mar 30 13:39:01 2011 -0700 msm_fb: display: turn dsi clocks off when no display update Turn dsi related clocks off after have no any display updates for a second. This is feature for screen static update. Change-Id: Ifa25a6af18c78ec6ee619347f124e5600831e173 Signed-off-by: Kuogee Hsieh commit 8ac5d4ab983a05ec976a391234a74bb9ceae4807 Author: David Ng Date: Fri Apr 1 14:37:50 2011 -0700 video: msm: mdp: Optimize mdp_pipe_ctrl handler Optimize pipe control handler by aborting mdp block power control check within loop earlier. Also, reorder MDP_BLOCK_TYPE enum to move high likelihood enums near the start to optimize value check in a loop. Change-Id: Id656f005863bebf7fc9d4e8543f5161b25a9b5e8 Signed-off-by: David Ng commit 4f5de8242637db49dfd7e96499dc6866dfad084e Author: kuogee hsieh Date: Tue Mar 29 10:36:18 2011 -0700 msm_fb: display: send dcs commands at video mode during booting up Add capability to send dcs command at video mode to initialize display panel during booting up. Change-Id: I826a2045b9b883c207e450c95d76dbf341de026f Signed-off-by: Kuogee Hsieh commit 5b3193d6655a955ec0dfc6af7583b15dee5053ca Author: Nagamalleswararao Ganji Date: Fri Mar 18 19:45:13 2011 -0700 video: msm: display: Bandwidth requirement for 3D display Increase Bandwidth requirement for 3D display to avoid the blank display CRs-fixed: 277304 Change-Id: Iaf3ac31b17521320cd2b7b6a5e82a7fa9fe07819 Signed-off-by: Nagamalleswararao Ganji commit 869aac9b3eca7661e13147063e15c9996056c5ea Author: kuogee hsieh Date: Thu Mar 3 08:59:33 2011 -0800 msm_fb: display: enable/disable DSI irq dynamically Enable/disable DSI irq dynamically so that the power grill can be shutdown. Change-Id: I6f4a4a3f740743804ee720712b4c0f2caa6e20a3 Signed-off-by: Kuogee Hsieh commit 86bacb945b5317d6600abc7206c9b5ad3a1c2b8d Author: kuogee hsieh Date: Tue Mar 29 16:43:02 2011 -0700 msm_fb: display: check x offset before enable mdp write back mode When destination x offset is not equal to 0 will trigger dsi command mode interface hardware bug. SInce write back mode will introduce bus accessing overhead, only enable mdp write back mode when destination x offset is not equal to 0. This patch also add writeback statistic. Change-Id: Ia97d2c4d8080e8b0ca9f61d3d24fc3f13d106f16 Signed-off-by: Kuogee Hsieh commit ad9506b0811e31107fcbefe437ac2c5390ddf3f9 Author: Ravishangar Kalyanam Date: Tue Mar 29 18:09:17 2011 -0700 msm_fb: display: Fix MIPI DSI Video suspend/resume issue Fix MIPI DSI Video suspend/resume issue by enabling MDP footswitch during device probing. Change-Id: I3461e4c69f24d09a84bcf9d626a4212e0434be87 CRs-Fixed: 278357 Signed-off-by: Ravishangar Kalyanam commit cd4d51d521d351649ad91695069fac6842052a61 Author: Jilai Wang Date: Tue Mar 15 15:52:52 2011 -0400 adv7520: add hdcp hw support check Add hdcp hw support check since fluid 7x30 p5 devices have hdcp disabled in hardware. This will disable hdcp in software. Change-Id: Icb8afd23f06a97ba549522d8af98c7968c172e1c CRs-Fixed: 272573 Signed-off-by: Jilai Wang commit a9e0558e9f28c19733b3f40d404c26d64d87fe78 Author: kuogee hsieh Date: Mon Mar 28 09:13:17 2011 -0700 msm_fb: display: add panel type check before disable tear check Check DSI panel type and only disable tear check logic and free vsync gpio if it was a command mode panel. Change-Id: I7b075d75cbf75d3b20bba3e6a52d1435133c7aa2 Signed-off-by: Kuogee Hsieh commit 8e7a0f2d0a1a9cf51bf509cdb3642dd5c20c39da Author: kuogee hsieh Date: Fri Mar 25 15:48:51 2011 -0700 msm_fb: display: do not check dma busy while in video mode DMA busy flag is used for DSI command mode (push mode) to indicate DAM engine is active to prevent double kickoffs.It is not necessary for DSI video mode to check this flag since it is pull mode which has internal timing generator trigger DMA engine on every vsync. Change-Id: I2420b525cffcfda110e25d0295e66fa28bb2e423 Signed-off-by: Kuogee Hsieh commit a0a73f93763280b7129314d95c130ea42c8d87a4 Author: Rajesh Sastrula Date: Tue Mar 22 11:35:59 2011 -0700 msm_fb: display: use 720p tile dimensions to decide performance level decide the performance level based on the samsung tiled format aligned dimensions for 720p resolution otherwise it will end up using 1080p clocks with overlay when the input video is rotated. Change-Id: I68f71dc2e6a0c74b5324af945d58cf1dd3f1f33b Signed-off-by: Rajesh Sastrula commit 4b73ec6089ff89a43e31c48ca696c264d26294d6 Author: kuogee hsieh Date: Wed Mar 23 18:08:35 2011 -0700 msm_fb: display: add dynamic enable/disable mdp write back mode Add dynamic mdp4 write back mode enable/disable capability on top of existing mdp4 write back mode implementation to provide software work around for MDP4 hardware bug between DMA_P engine and DSI command egnine. Change-Id: I2de277e2a5b31335907088862279f4a5c7fc60e6 Signed-off-by: Kuogee Hiseh commit e924f3c470540de586acdf4cf03bc91c0ea3f653 Author: Chandan Uddaraju Date: Mon Mar 21 16:55:35 2011 -0700 msm_fb: display: Configure MIPI DSI clocks using panel settings Remove hardcoded clock dividers and other clock related settings. Remove support for mxo clock. Add code to generate the clock divider settings using the panel frame rate, format and porch settings. Change-Id: Idfe301d389d5f71d09b36e6957e473bd53be009b Signed-off-by: Chandan Uddaraju commit 9ffa68409df9960b4cb9303bba0fa673dd1c9215 Author: kuogee hsieh Date: Thu Mar 24 08:33:41 2011 -0700 msm_fb: display: fix mddi overlay interrupt handler MDP4 write back mode provides work around for MIPI DSI command engine hardware bug. But it breaks MDDI overlay interrupt handler accidently. This patch fixs MDDI overlay interrupt handler. Change-Id: I759a26e64202b2bcdf359e76d09f1cbff8343769 Signed-off-by: Kuogee Hsieh commit f4a2361bbaad07a9e7eade0e42a1a0d20bd81914 Author: Zhang Chang Ken Date: Fri Mar 11 15:41:04 2011 -0500 msm_fb: display: AUO WVGA LCDC Panel Adding driver for AUO wvga(480x800) 3.61" lcdc panel. Activated for msm8660 Fluid platform revision 3 and up Change-Id: I528894540ed1990b7d0e8ea763fd9c54c70cf276 Signed-off-by: Zhang Chang Ken commit a10db6ff521dd54b213533f4093565bfa1275761 Author: kuogee hsieh Date: Wed Mar 9 09:48:12 2011 -0800 msm_fb: display: shut off dsi pll with correct register setting To prevent power from leaking, dsi pll need to be shut off with correct register setting sequence. This patch also fix the timer configuration used for turn dsi related clocks off when no screen update for one second. Change-Id: I33452bc02fb33ef3c780b9f9aa0e840f90f8598d Signed-off-by: Kuogee Hsieh commit c3a958f6c0573ba0bce94df40e50c2b5550645fd Author: Wentao Xu Date: Fri Mar 18 15:28:37 2011 -0400 msm_fb: display: not to register platform device from AMOLED panel driver The platform device is already registered from board file Change-Id: I469b70af30dffc5a8e5f08516d942f441ff21f89 Signed-off-by: Wentao Xu commit 79e20ca76f1db3c2861c28681f0e16cb97d3ccc8 Author: kuogee hsieh Date: Thu Mar 3 13:45:31 2011 -0800 msm_fb: display: add MDP writeback mode to DSI panel Implement MDP4 writeback mode by using double buffers for dsi comamnd mode panel. Write mode for MDDI has no changed (single buffer). Writeback mode is enabled at boot up. This patch does not provide siwtch between enable and disable of writeback mode. This patch provides software workaround for the hardware bug at the interface between MDP4 and MIPI DSI Command engine. CRs-fixed: 277310 Change-Id: I28d4dab3b05bda02e2def474644ed045776d0241 Signed-off-by: Kuogee Hsieh commit a7c0fe5e2f435e45d2ba1ac1be8b310681a3ad18 Author: Ravishangar Kalyanam Date: Tue Feb 8 17:32:12 2011 -0800 msm_fb: display: Fix LCDC underflow by downscale parameter validation Fix LCDC underflow by downscale parameter validation against mdp clk and panel clk frequency during overlay_set. CRs-Fixed: 271494 CRs-Fixed: 279382 Signed-off-by: Ravishangar Kalyanam Change-Id: I363a87777311b66e5acc2c29afe8da6b2287694a commit a225d0e971254d2c49fc8d08537d22875b83f46a Author: Rajesh Sastrula Date: Wed Mar 16 15:30:01 2011 -0700 msm_fb: display: handle histogram during suspend/resume disable the histogram irq and clear the histogram registers during suspend and re enable them when resume. CRs-fixed: 280419 Change-Id: I54154a89c7a2f92dba8ee9e99943e61279b29c44 Signed-off-by: Rajesh Sastrula commit 54afe26ae0f0800584d19aa9495bcbd48c52440d Author: Manoj Rao Date: Wed Mar 16 10:08:43 2011 -0700 msm_fb: tvout: Removing mutex_lock in ISR CRs-Fixed: 278755 Change-Id: I6e5e13edc9048757c87f57f8579776d7ce878bb5 Signed-off-by: Manoj Rao commit b35b92b71ded97db1d1e2b8fe34c45bfbf5ab6fe Author: kuogee hsieh Date: Sun Mar 20 12:19:32 2011 -0700 msm_fb: display: synch mdp irq enable/disable Add spin_lock() and spin_unlock() inside mdp_disble_irq_nosync() to synchronize with mdp_enable_irq() to prevent race condition from happenning. Change-Id: Ieb76a5a920d7d92b627108d033e34874c7acdd82 Signed-off-by: Kuogee Hsieh commit 3b74ce77d0cebd282fb6b17c959146db9620383f Author: Rajesh Sastrula Date: Tue Mar 15 16:46:52 2011 -0700 msm_fb: display: remove redundant call to disable irq in off function CRs-fixed: 278326 Change-Id: Ib0ffca8862aa34438ae8575ea3b9ed21cf7418f6 Signed-off-by: Rajesh Sastrula commit df448ca39305b85fc318c16d067e1cb6ba386a0f Author: Chandan Uddaraju Date: Sun Mar 13 19:41:51 2011 -0700 msm_fb: display: Fix MIPI DSI driver initialization sequence. Change-Id: Ifcb67a166b68db45d6d3b14ba9cc5caa48316ee8 Signed-off-by: Chandan Uddaraju commit de64d12d9e0806e630e148d3da7f9d390a92db1a Author: kuogee hsieh Date: Fri Mar 4 17:18:18 2011 -0800 msm_fb: display: Remove secure_io to MIPI DSI register access. Only clocks belong to MMSS_CC need to be accessed by using secure_io. Secure IO access for MIPI DSI register region is not required. Use normal io access using readl/writel to MIPI DSI registers. Change-Id: Ifc49b1812efa0fbe82d48bef7f5054064f55043a Signed-off-by: Kuogee Hsieh commit 00c6dbec219e11a71bc0c077e53779d97365e5c7 Author: Abhishek Kharbanda Date: Mon Mar 7 13:34:56 2011 -0800 msm_fb: Reading Ro' from correct HDCP port offset Reading RO's from correct port address and offset and start HDCP reauthentication again,in case of authentication failure. CRs-fixed: 275796,276921,277082 Change-Id: I984054384cedbcc96fb8cd68b4d3f533ff33a969 Signed-off-by: Abhishek Kharbanda commit 715b3fe8316555da278042f6371c3bc9a0dcea05 Author: Chandan Uddaraju Date: Tue Mar 8 18:31:10 2011 -0800 msm_fb: display: Enable secure IO access and fix DSI clock settings. Read back register value is not updated properly for MIPI DSI clocks. Revert back to the older method of configuring the dsi core and dsi pclk settings. Modify clock control block access to enable read/writes using secure IO. CRs-Fixed: 278206 Change-Id: I5d5503d39ddd5d2ae0fa0dbdaa592686ae5e5ffe Signed-off-by: Chandan Uddaraju commit e3cc2ce88868ee28f9ba4268b75e5a7bd671953a Author: Ravishangar Kalyanam Date: Tue Mar 8 15:00:36 2011 -0800 msm_fb: display: Log cleanup for LCDC Samsung WSVGA driver Change-Id: Ia0372db34b3c9a74202ef692d9c30c5fd43f6a6b CRs-Fixed: 275930 Signed-off-by: Ravishangar Kalyanam commit d4b31a95cc9477c47fe9b1c5b5c96ddfb075da24 Author: Rajesh Sastrula Date: Fri Feb 25 12:09:06 2011 -0800 msm_fb: display: Call pm runtime apis with the correct fb device use the same frame buffer device for all runtime pm apis calls. Change-Id: I2dccf69f6f9ed115fbeceef0636e39bbdfd5c67a Signed-off-by: Rajesh Sastrula commit 8ae66ceb26dd7baecc85d2b334029903cb7a1bb8 Author: Urs Muff Date: Wed Sep 8 12:42:21 2010 -0600 msm_fb: display: Samsung AMOLED PenTile panel Adding driver for the Samsung AMS367PE02 3.7" PenTile 480 x 800 16.7M AMOLED panel. Enable LCDC auto detect when MIPI detect is enabled Clear regulator handles after they are released to avoid crashing Change-Id: I6abf705fd19d5baa429fb2a7c47e4299f73c6b67 Signed-off-by: Urs Muff Signed-off-by: Wentao Xu commit d91951d2c7feec7b81b814434848cc28e8a167c0 Author: kuogee hsieh Date: Wed Mar 2 17:55:09 2011 -0800 msm_fb: display: Fix dsi command mode compiler error Remove un-necessary dma_busy_comp and vsync_start_y_adjust to fix compiler error. Change-Id: Id56568bb3d4cdbe091dd09584bf6d26183812e1d Signed-off-by: Kuogee Hsieh commit 73b51ce75cba3caa4ac511503f46705a356896af Author: kuogee hsieh Date: Wed Mar 2 15:51:27 2011 -0800 msm_fb: display: add support of sending DCS command at video mode At MIPI video mode, set CMD_MODE_EN bit to enable command mode engine before sending DCS comamnd to client (display panel). Change-Id: I6462eef5c3c378176e8df61d3a5108148cda3047 Signed-off-by: Kuogee Hsieh commit 5ed1dca7d697327a9ff9dbbae45fb20e73a2c010 Author: kuogee hsieh Date: Tue Mar 1 14:47:36 2011 -0800 msm_fb: display: initialize comp struct at pipe_alloc Initialize per pipe comp struct during pipe allocation. Change-Id: I48c919b3b520cfaf12f5b6fa713fde9f5fb866d0 Signed-off-by: Kuogee Hsieh commit 03dac3988c186dfd125b5f07501e2e3fe3d7b6e4 Author: kuogee hsieh Date: Wed Feb 23 08:54:33 2011 -0800 msm_fb: display: add dsi clocks control Add runtime dsi clock control to turn dsi related clocks off after screen update and turn clocks on before screen update. This patch also provide clcok off debounce mechanism by using kernel timer. CRs-fixed: 276211 Change-Id: I68f4cc48ba4887d2240d96936674eb460618de1e Signed-off-by: Kuogee Hsieh commit 74ce95472814e2561ff258668ba6c9febdf54556 Author: kuogee hsieh Date: Fri Feb 18 14:46:37 2011 -0800 msm_fb: display: add support of DCS backlight command Add backlight control by using inband DCS set backlight command. Transmit DCS backlight command to client while DMA is not busy. CRs-fixed: 275660 Change-Id: I6954bb6e86d15a8f4076d9bb576667669459725c Signed-off-by: Kuogee Hsieh commit 2245b9e330cd54ac4e4580a5208da1f61209c340 Author: kuogee hsieh Date: Sun Feb 20 16:04:47 2011 -0800 msm_fb: display: remove extra bracket to fix compiler error Remove extra bracket to fix secure_writel compiler error. Change-Id: I11ebda03004dd0a7fea648cb32675c8dc456bc47 Signed-off-by: Kuogee Hsieh commit 252d99d19002242dfb78b4b1c1ac604787c3d83c Author: kuogee hsieh Date: Sun Feb 20 16:01:28 2011 -0800 msm_fb: display: check mipi panel mode before enable vsync Checnk mipi dsi panle mode first. Only enable hardware vsync mechanism if it was command mode panel. This patch also remove the unio declaration of lcd_panel_info and lcdc_panel_info of msm_panel_info struct to fix vsync configuration over written panel's porch configuration. Change-Id: I1d0806df04b884e1fb5a596baedd4b5f3630d01a Signed-off-by: Kuogee Hsieh commit ab42fa9b082706916123315e5647789b7f01a3d1 Author: Ravishangar Kalyanam Date: Mon Feb 14 14:55:24 2011 -0800 msm_fb: display: Fix MDDI CRC Error handling condition Fix MDDI CRC Error handling condition to avoid looping of MDDI reads infinitely Change-Id: I4e65b635fc4041213e544f64919a9a6f074b366e CRs-Fixed: 275229 Signed-off-by: Ravishangar Kalyanam commit 38c908beabb5f40225314642d88d09e299806b6e Author: Rajesh Sastrula Date: Tue Feb 22 10:53:15 2011 -0800 msm_fb: display: fix a typo in using the correct packing format Change-Id: I0f522ea04ece89c6f387d22634d4d33139f2a631 Signed-off-by: Rajesh Sastrula commit 4a3fed28675ebf7bacd209a8baea84265dd664c2 Author: Matt Wagantall Date: Wed Jan 19 15:56:14 2011 -0800 msm: 8x60: Use secure_readl() and secure_writel() for clock registers The application processor is unable to access MSM_MMSS_CLK_CTL_BASE register directly. Secure APIs must be used to read and write all registers in this region. Change-Id: I2906d3b8e28b45ff896a41103fecce9491b5a991 Signed-off-by: Matt Wagantall commit 57ea567a20d102404287eb09ee2dabeae04093c1 Author: kuogee hsieh Date: Fri Feb 18 15:06:30 2011 -0800 msm_fb: display: mitigate lcdc interrupts Primary vsync interrupt are always enabled which causes interrupts are generated at every 16 ms. This patch will only enable ingterrupt when has frame push. Change-Id: I062bf19a9b56ef6fea4c4374d8751625bbb86a42 CRs-fixed: 275999 Signed-off-by: Kuogee Hsieh commit c315489fbe1a75c52b968c4a237d9f7f4334336f Author: kuogee hsieh Date: Mon Feb 7 16:58:43 2011 -0800 msm_fb: display: add chimei panel driver Add Chimei LCDC panel driver. This patch also incorporate backlight control through PWM of gpio-24 (channel 0) of pm8058. Change-Id: I2e00d6ce0f6a9858a56d929c660776fcbfc54732 Signed-off-by: Kuogee Hsieh commit 030612a798461326d82d5fab950ca2a071d057a1 Author: Ravishangar Kalyanam Date: Thu Feb 17 18:21:25 2011 -0800 msm_fb: display: Enable S/W Vsync handler only if MDDI clock is enabled Signed-off-by: Ravishangar Kalyanam Change-Id: I3800f7b27f7730cd9e60e37b0f060ede9f79c83e commit ac9fd472e5832a56d20e06654e5a8fd04d3583e9 Author: Ravishangar Kalyanam Date: Mon Feb 14 14:16:51 2011 -0800 msm_fb: display: Fix vsync timer deactivation by shutdown flag Fix vsync timer deactivation issue resulting in timer handler run continuously during suspend/resume by using a shutdown flag Change-Id: I71806b491d15b454b1e56f01e78223e26df7062b CRs-Fixed: 274480 Signed-off-by: Ravishangar Kalyanam commit 52f6889f672d53e9c80cfde8335fde65e1022fff Author: kuogee hsieh Date: Fri Feb 4 16:30:31 2011 -0800 msm_fb: display: add support of mddi MDP_OV_PLAY_NOWAIT Add support of mddi MDP_OV_PLAY_NOWAIT mechansim so that overlay requester can issue multiple frame updates followed by a single DMA kickoff. This patch also remove 10 ms timer from UI kickoff which try to consolidate multiple frame updates into a single kickoff. This is not necessary at NOWAIT implemention since both frame update and kickoff are controlled by requester totally. Change-Id: I901054eba78d946549b05e667dd580a95ee18a87 Signed-off-by: Kuogee Hsieh commit e9bfe26bd022597402b9070c41fe89c2040a7227 Author: kuogee hsieh Date: Mon Jan 31 10:01:13 2011 -0800 msm_fb: display: add 3D side-by-side to interleave support Add 3D side-by-side to line interleave conversion by introducing MSMFB_OVERLAY_3D ioctl to allow user to change frame buffer's width and height at run time. Change-Id: I5801425a1f03ceedf69522c28780bb200ab63c57 Signed-off-by: Kuogee Hsieh commit e908e0c469fb2fa7dc7ecb659158d91d082b5d08 Author: Rajesh Sastrula Date: Tue Feb 8 18:05:10 2011 -0800 msm_fb: display: Fix incorrect fail in tvenc_probe feature pm_qos usage correctly with CONFIG_MSM_BUS_SCALING to avoid incorrect fail in probe call. Change-Id: I5677e0d10fef30ef1f41a87e6415782777612d87 Signed-off-by: Rajesh Sastrula commit ec2908a70273dec14893222233530f7cf5664a1f Author: Ravishangar Kalyanam Date: Fri Feb 11 16:30:28 2011 -0800 msm_fb: display: Cleanup of Log messages Signed-off-by: Ravishangar Kalyanam Change-Id: Icc911682233d48e3dcae0b78e8aa0138fd3af027 commit d034fc1101365fd5593b8dc1da66da63d8a5f61f Author: Harshad Bhutada Date: Fri Jan 21 19:42:49 2011 +0530 msm_fb: display: add 3 frame buffers support Add triple framebuffer to improve display performance Change-Id: I132c74f11f5ddcee62d12599c85dd615e14235d4 Signed-off-by: Harshad Bhutada commit f5593a5556724456bb71754554e06ce91690108f Author: Rajesh Sastrula Date: Thu Feb 10 09:56:05 2011 -0800 Revert "msm_fb: display: soft reset mixer1 when external under flow occurs" soft reset mixer1 has side affect of blank display on primary intermittently hence revert this commit until the corret software work around is found for mdp pixel shift hardware issue. This reverts commit 1a789b5b8a8b4e8a992b7d7d7a184f271e05bd23. Change-Id: I75e319461e474394cdc35d3f5dbbd2f7502107cf Signed-off-by: Rajesh Sastrula commit 9ad8eed3ad1e5fcee31bafb36f89fc27c8587335 Author: Arun Kumar K.R Date: Wed Feb 9 14:54:06 2011 -0800 msm_fb: msm_hdmi: turn off hpd on boot-up Ensure hpd is off on boot up, so that the power on hdmi rail will be zero. Change-Id: I80212511d30d58e4f65ee938621ee959e5623a79 CRs-fixed: 274396 Signed-off-by: Arun Kumar K.R commit 65ec3d97b4df9de23c46f82cf62f1ec32c4d8c51 Author: Philip Elcan Date: Tue Feb 8 10:03:49 2011 -0500 msm_fb: Calculate smem size with correct bpp value Always the bytes per pixel for the framebuffer format to calculate the shared memory length, not the panel. Change-Id: Ief3adced9c8f0265babfde44b9ca5c40af2423e4 Signed-off-by: Philip Elcan commit 52a629f3ccc8caf40b2a4796b7287f1bef9b3096 Author: Omprakash Dhyade Date: Wed Jan 26 18:57:20 2011 -0800 msm_fb: display: Use solid fill attribute for no fetch in is_fg mode. In is_fg mode, when alpha is 0xff, use solid fill attribute to set no fetch, also set constant color to black for blending. With this FB is not fetched and we could save bus bandwidth. Change-Id: Iff88269c9e00bb7b6277cb4368c3d0efbbfe5257 Signed-off-by: Omprakash Dhyade commit df9278b93dbba60b8cdb8f043d851f21508a8764 Author: Omprakash Dhyade Date: Wed Jan 26 18:31:55 2011 -0800 msm_fb: display: Add performance level for RGB buffers To request highest bandwidth on SMI/EBI for RGB/VG pipe, this change adds performance level for RGB buffers. Also, add one more clock level for corresponding perforamnce level. Change-Id: Ifde6d7ee295d8335e2c2dac6de8580a9f6ee5dd5 Signed-off-by: Omprakash Dhyade commit 17f4ba96318300509d022d1ef56678aa6e1a9787 Author: Ravishangar Kalyanam Date: Fri Feb 4 11:59:57 2011 -0800 msm_fb: display: Fix MDDI blackscreen issue by vsync pending flag reset Fix MDDI mode blackscreen issues by resetting vsync pending flag when vsync clock is not enabled. msm_fb suspend routine requires the pending flag to be FALSE to exit. Cleanup vsync timer usage during vsync clk enable/disable. Change-Id: Idb5fcb5f281cbc7cc41db47a63cde35b18c5a1de CRs-Fixed: 271317, 271775 Signed-off-by: Ravishangar Kalyanam commit d11c910649c0d88d432abe0253d9bfd45e924f6a Author: Ravishangar Kalyanam Date: Wed Jan 26 15:54:57 2011 -0800 msm_fb: display: Add cursor support for MDDI primary interface Change-Id: I490d362c2389f1ececb850340fc97cbd64e2b296 Signed-off-by: Ravishangar Kalyanam commit ec31d4b82b67e43cebf9467c1531288b7b36f6ce Author: Ravishangar Kalyanam Date: Fri Jan 21 15:55:11 2011 -0800 msm_fb: display: Fix crashes in MDDI mode during fbtest/boot/suspend Fix register access crashes in MDDI mode during fbtest/boot/suspend operations. This change has been reverted once since MDDI clock was disabled during the execution of mddi_on from a previous pipe_ctrl OFF request. This patch includes enabling MDDI clock in mddi_on directly. Change-Id: Icc302ea312b5dc96b65bdfe5cb65b9f12341f7ef Signed-off-by: Ravishangar Kalyanam commit a8b2d85d754bd338a05a574006a1a81366898b8a Author: Ravishangar Kalyanam Date: Sun Jan 30 15:13:39 2011 -0800 msm_fb: display: Fix underrun during suspend/resume There is MDP underrun issue while doing the suspend/resume when the video playback is in the pause state. Fix is added to set the right MDP clock in this case. Change-Id: I8b488cc629766aa2671537bfe3a3b3804966a7aa Signed-off-by: Ravishangar Kalyanam commit fb7f5cf847e4fe37e2af6c5c1a642f9875320b9e Author: kuogee hsieh Date: Wed Jan 26 09:24:17 2011 -0800 msm_fb: display: Add dma busy checking at overlay unset Add busy-wait mechanism to ensure mdp dma engine is not busy (not active) before un-staged a mdp pipe. Change-Id: I66982d75b75e114cd9129a341af147a0e6dfdef0 Signed-off-by: Kuogee Hsieh commit 5db13dea0a21124d3e33fdbdc832dd433521a215 Author: kuogee hsieh Date: Mon Jan 24 13:46:41 2011 -0800 msm_fb: display: add MIPI Tearing Effect support Add MIPI tearing effect support by connect mdp_vsync gpio (28) to mipi dsi display panel and send set_tear_on command to panel to enable it. CRs-fixed: 267852 Change-Id: I364202c5b4c824ca5be1716619a4bee836618da0 Signed-off-by: Kuogee Hsieh commit 9768b27ab8963102d56f2de38c626c91edef26de Author: Rajesh Sastrula Date: Thu Jan 27 18:30:24 2011 -0800 msm_fb: display : Implement mdp clock scaling support scale mdp clock based on various performance levels to save power Change-Id: Ia682325f4227c083a783cd2fb33e6d54003b944b Signed-off-by: Rajesh Sastrula commit 4b7f5eba092f72a42edeb7fa72502502317c22ba Author: Rajesh Sastrula Date: Mon Jan 24 16:23:47 2011 -0800 msm_fb: display: do not reinitialize qseed during resume reinitializing qseed tables during resume is causing artifacts on hdmi since they are getting updated while dtv timing generator is active. reinitialization part is already taken care by checking whether mdp hw is reset just before resume hence remove this code. Change-Id: Ic448cafd69e8a4c66b5097d55d8e59acd0985d71 CRs-Fixed: 272138 Signed-off-by: Rajesh Sastrula commit 0dff7e9161fdcb5fdde2ec387f1686b9324ab422 Author: Vasantha Kumar Date: Thu Jan 27 14:59:09 2011 -0800 Revert "msm_fb: display: Fix clock crashes during boot/suspend/resume operations" This reverts commit 73f531d9d58b9d1036b0b8e1dfdd237dbc6cf85d. Change-Id: I7a9b89c8a116445aae47ca6b7f128bdf24822ad2 Signed-off-by: Vasantha Kumar commit ef072d28af4812966be54a33f5b51d785ac1e2bc Author: kuogee hsieh Date: Mon Jan 24 10:57:36 2011 -0800 msm_fb: display: Add MIPI DSI read function Add MIPI DSI manufacture ID read during MIPI DSI initialization. MIPI DSI host issue DCS read and issue BTA to allow client to send DCS long read data back to host. This patch also add MIPI DSI ACK-ERR-STATUS handler at reverse link. Change-Id: I2106df419cd809cc862fcdb37112cfaf3ad811f2 Signed-off-by: Kuogee Hsieh commit a269fdf061c0946d704eeb4a487b7aaa86aa5dc3 Author: Rajesh Sastrula Date: Wed Jan 26 09:53:01 2011 -0800 msm_fb: display: Fix mdp underflow on hdmi underflow during suspend/resume on hdmi is caused due to incorrect bw requests on primary during overlay_set and requesting bw after enabling lcdc timing generator. Change-Id: I1e6aadee03b7c4c0f678bdd387515dbd07587fb5 CRs-Fixed: 271912 Signed-off-by: Rajesh Sastrula commit 5b3a94e9512771acecec016cb1a6d39c2bc71017 Author: Stephen Boyd Date: Mon Dec 20 17:18:49 2010 -0800 msm_fb: Migrate to clock rate voting Use the clock api, instead of pm_qos, to vote on the EBI1 rate. The transformation is as follows: pm_qos_add_request() -> clk_get() pm_qos_update_request(*, 0) -> clk_disable() pm_qos_update_request(*, ) -> clk_enable() pm_qos_remove_request() -> clk_put() The rate a driver requests is almost always the same and can be set with clk_set_rate() after the clk_get() call. Change-Id: Id7f4d1fef62d9ce1e49f88daae1ca56608d3cd7d Signed-off-by: Stephen Boyd commit 73f531d9d58b9d1036b0b8e1dfdd237dbc6cf85d Author: Ravishangar Kalyanam Date: Fri Jan 21 15:55:11 2011 -0800 msm_fb: display: Fix clock crashes during boot/suspend/resume operations Change-Id: I80aebe2ad76892f16c27f6d68aaff0a3a4d13a86 Signed-off-by: Ravishangar Kalyanam commit 15ad3e6e356b0cd963e91db6a2eb1d3f7f65726c Author: Ravishangar Kalyanam Date: Thu Jan 20 18:45:00 2011 -0800 msm_fb: display: Set MDDI clock rate before enabling first time Change-Id: I1beeca0d57ae294d18cb337d5b93285f87215f05 CRs-Fixed: 271561 Signed-off-by: Ravishangar Kalyanam commit da220e2b85a730c980a30500792b815035bd6dfe Author: Abhishek Kharbanda Date: Fri Jan 21 08:10:56 2011 -0800 msm_fb: Add suspend/resume support for ADV7520 Added suspend/resume functions for ADV7520 chip. Change-Id: I2aaeed91615e9be66f9abe79b0502ba53b851a04 Signed-off-by: Urs Muff Signed-off-by: Abhishek Kharbanda commit 0e38a1c08495abb77a088fe5310d66c885201396 Author: Urs Muff Date: Mon Sep 13 15:21:53 2010 -0600 msm_fb: enable HPD even when HDMI panel is off - Turn on LDO8 & LDO10 during I2C communication - Turn on LDO8 while HPD and while cable connected - Turn on HDMI_5V_EN during EDID and HDCP - Always listen for HPD IRQ Change-Id: If24d05b3dea81cb73004900ea23ab51e483f1b38 Signed-off-by: Urs Muff Signed-off-by: Abhishek Kharbanda commit 98b8a1a579cef545b9700d7838f117ab43518c0e Author: kuogee hsieh Date: Sun Oct 24 11:03:26 2010 -0700 msm_fb: display: synchronous with vsync at lcdc frame push When frame push over 60 FPS at LCDC may cause display tearing due to previous frame was over stepped by next frame. This patch allow mdp to hold push thread until next vsync to guarantee the previous had been consumed by overlay engine to avoid tearing. Change-Id: Ic9bc96377649805211baba8e1e2570b18fb26954 CRs-fixed: 270946 Signed-off-by: Kuogee Hsieh commit edca916e571cadbc7f7262b5a537ac3884972320 Author: Chandan Uddaraju Date: Thu Jan 20 12:20:38 2011 -0800 msm_fb:display: Fix section mismatch The mipi_novatek_lcd_probe was being referenced outside of a non __init section. Fix this by placing mipi_novatek_lcd_probe in the section which exists for device intialization code. Change-Id: I4c9dbbbb7ca1368beda8aee59c8bedb60efa8dc6 Signed-off-by: Chandan Uddaraju commit a11f5f7eea649696e4c12bc057815a615ee201d0 Author: Urs Muff Date: Mon Jan 17 14:31:16 2011 -0700 msm_fb: msm_hdmi: reset HDMI PHY on resolution change HDMI PHY needs to be reinitialized when panel resolution changes. Change-Id: Ib01be9f51668cb290b61360b3775993d232169bd Signed-off-by: Urs Muff CRs-fixed: 263676 commit c1ee3af7b4b1580eaf83bfe875df7ff0c44bd6e8 Author: Alan Gerber Date: Tue Jan 11 18:26:37 2011 -0800 msm_fb: hdmi: Hold idle wakelock when HDMI is enabled In our current implementation, allowing idle power collapse during HDMI output causes underruns/flickering in the HDMI content on some devices. This patch takes an idle wakelock during HDMI output to prevent idle power collapse as a preliminary solution to this issue. CRs-Fixed: 266067 Change-Id: Id91011067b7c808548e6ee3df00e53c4e2aa8013 Signed-off-by: Alan Gerber commit 7ca0f321d7c0815c1dd13387fcad55266a87c0da Author: Ravishangar Kalyanam Date: Mon Jan 17 13:42:06 2011 -0800 msm_fb: display: Disable Optimal Fetch bit in FETCH_CFG of MDP pipes Change-Id: I58af7a86c7a9b27dcff5573b44534c968cf4fde0 CRs-Fixed: 270136 Signed-off-by: Ravishangar Kalyanam commit ed91ea3ea225adfc3bc7091eac5d22413af0d20f Author: Urs Muff Date: Fri Jan 14 08:35:59 2011 -0700 msm: board: allow to hide hdmi log entries Reduce kernel log spam. Change-Id: I05a650041e47f5abadccf5cecac303ebf0c1c830 Signed-off-by: Urs Muff commit 519c18879d14b3bda62765c66f222afe2ac97cda Author: Wentao Xu Date: Mon Jan 17 15:50:33 2011 -0500 msm_fb: display: change sharp panel backlight Kernel pwm_config() parameter has been changed to expect both period and duty_level with unit of micro second. Change sharp panel backlight period and duty_level to have unit of micro second accordingly. Change-Id: I00f3b7f3b45161ba2152f935147e0d5fd22d2a8f Signed-off-by: Wentao Xu commit d42938452d1c005046b00b50d61ccd65a15ae3a6 Author: Ravishangar Kalyanam Date: Mon Jan 17 17:02:05 2011 -0800 msm_fb: display: Fix backlight issues during boot Initialize backlight level to 0 in msm_fb probe to allow the userspace/framework set the required backlight level. Allow backlight settings always in msm_fb_set_backlight call. Change-Id: Ic42b76e6b8886957856683ee0343afd383ef42c8 CRs-Fixed: 270638 Signed-off-by: Ravishangar Kalyanam commit 1a789b5b8a8b4e8a992b7d7d7a184f271e05bd23 Author: Rajesh Sastrula Date: Wed Jan 12 14:38:11 2011 -0800 msm_fb: display: soft reset mixer1 when external under flow occurs This is to avoid the pixel shift on hdmi during under flow. CRs-Fixed: 264718 Change-Id: I4b178dadc3f0f4266da427f584ce10cf0f339d2c Signed-off-by: Rajesh Sastrula commit f5c41e7535e347fb0aefcc533d8c3f015baf484d Author: Urs Muff Date: Thu Jan 13 11:38:57 2011 -0700 msm_fb: msm_hdmi: correct hpd power-on logic error codes are non-zero, logic introduced with hpd feature change e7164df63e7b87b19ee69ddc7f3db74c65b863b6. Change-Id: I178f5bb5a6ce006599322418bb1b6ddf6849bf62 Signed-off-by: Urs Muff commit b3cd5d6a4ca3c12425c48fd9586500f088653042 Author: Arun Kumar K.R Date: Tue Jan 11 17:30:40 2011 -0800 msm_fb: fill framebuffer with black pixels On MDP with Overlay, on suspend write black pixels to framebuffer to show black screen on HDMI. CRs-fixed: 266993 Change-Id: Ibcd5802059154d6431888a61d6ad4f4c5c11b9bc Signed-off-by: Arun Kumar K.R commit a739b3bead1308a7c40f0820e72f2031f532832d Author: Ravishangar Kalyanam Date: Wed Dec 15 12:20:15 2010 -0800 msm_fb: display: Disable/enable MDP/MDDI/Vsync clocks based on frame update Disable MDP/MDDI/Vsync clocks if there are no frame updates and enable them on any new updates Signed-off-by: Ravishangar Kalyanam Change-Id: Ic5cbac3efdcd87ab3b44a5c2866fefcab09ab07a commit 002d6e11806ada7ac8cde6d05f15b69138cbfa4d Author: Abhishek Kharbanda Date: Wed Dec 15 14:30:36 2010 -0800 msmfb: msm_hdmi: Turning off HDMI PHY on power off Change-Id: I9f2d39076df35963dff3d4608c182f0ee6d9abb6 Signed-off-by: Abhishek Kharbanda commit 655c7961d9bce8ccceab635343c4157584e409d9 Author: Nagamalleswararao Ganji Date: Fri Dec 3 12:31:27 2010 -0800 msm_fb: display: Fix for the pixel shift issue with VG pipe MDDI kick off is added to make sure the VG pipe is disconnected from the mixer while switching it across the mixers Change-Id: I708b37b1d9e60e19acc25d5ca2b3589bc7ae04ed Signed-off-by: Nagamalleswararao Ganji CRs-Fixed: 256671 commit 7f4053846ddb619a4a23b7bebbf814eef0773ca2 Author: Chandan Uddaraju Date: Wed Dec 15 12:53:59 2010 -0800 msm_fb: Display: Enable two lane video mode for Novatek MIPI panel Add configuration changes for Novatek panel to operate in two lane video mode. Tune the panel settings to improve fps. Change-Id: I151018b39429af747ecdc991748bdb17aa7c2051 CRs-Fixed: 266737 Signed-off-by: Chandan Uddaraju commit c7677581e46b2fb42de29ad2c709e814a232f34f Author: kuogee hsieh Date: Tue Dec 14 15:55:12 2010 -0800 msm_fb: display: add sync between UI and video for MIPI panel Change-Id: I5b505c07c42d80ce5e42a0b27a70076ccfb71233 Signed-off-by: Kuogee Hsieh commit fb3b75f1c2eb222113b531c482ee9fe936b4eae4 Author: kuogee hsieh Date: Mon Dec 13 09:43:09 2010 -0800 msm_fb: display: fix bpp of MDDI BLT mode At MDDI BLT mode, the output format of overlay engine is RGB565. Therefore set bpp to 2 instead of 3 accordingly. Change-Id: Ibc321a6c9817b972652797966571b35ddd941c5c Signed-off-by: Kuogee Hsieh commit 227aa0adacf9f947af8d16c633e1d3afa33f650b Author: Rajesh Sastrula Date: Tue Dec 14 17:04:50 2010 -0800 msm_fb: display: Fix registering multiple bus scale clients Do not register bus scale client if it is already register in the earlier probe call. Change-Id: Icc14898ce28e9507540ce2419c3f41accf3af651 Signed-off-by: Rajesh Sastrula commit f58ceb6b3442958cbb2866fe115a33926b1b5bfc Author: kuogee hsieh Date: Wed Dec 8 08:30:38 2010 -0800 msm_fb: display: add support of DE_INTERLACE_ODD The de-interlace is default as even line reference. Add support of odd line reference. CRs-fixed: 260959 Change-Id: I637c79c2f5236fc38116693b50c69415e41ebdda Signed-off-by: Kuogee Hsieh commit dbc4b8738bdca502c2cccbcfe1ee0c1755488ca5 Author: kuogee hsieh Date: Tue Dec 14 15:25:33 2010 -0800 msm_fb: display: fix MDDI compiler error Add CONFIG_FB_MSM_MDDI compiler option to not to compile MDDI code under 8660 platform. Change-Id: Ia905636bbe6800996fcf9eb24f1487e28cfc9c97 Signed-off-by: Kuogee Hsieh commit 4334af8abf1ec212df6778a7405de0d3070abd6d Author: Chandan Uddaraju Date: Fri Nov 19 13:53:14 2010 -0800 msm_fb: Display: Add two lane command mode support for Novatek panel. Add code to change the clock configurations for MIPI DSI to support two lane command mode for novatek panel. Add code to turn off of the novatek display when the device goes into suspend mode. By default, command mode for novatek panel is configured for two lane. CRs-fixed: 264213 Change-Id: I98df05199a1680375ab4c0274418d1730b052f6a Signed-off-by: Chandan Uddaraju commit a809819d9d5d0b59f2c2eee0534bc68048b09016 Author: kuogee hsieh Date: Tue Nov 30 15:40:46 2010 -0800 msm_fb: display: Add delay kickoff to MDDI Add delay kickoff mechanism to consolidate multiple kickoffs into one to avoid unnecessary delay at MDDI interface. Also the MDP4_NONBLOCKING was removed due to every MDDI kickoff is blocked until overlay blending completion interrupt is delivered. This patch also remove unnecessary semaphore at the topmost layer (fbmem) ioctl to allow multiple msm_fb ioctl calls. Mutex is provided by individual function to synch between multiple ioctl calls. CRs-fixed: 264934 Change-Id: I3aecdd9cb4d7c79f67b641f90e78a6764095a6b2 Signed-off-by: Kuogee Hsieh commit 6ac2d1a19bcfce5c9c60eb4d063bce4eac924515 Author: Ravishangar Kalyanam Date: Tue Dec 7 15:19:42 2010 -0800 msm_fb: display: Remove backlight control from blank/unblank Change-Id: I3f1b1958423c2970f72bfa71f2ac5615055687f5 CRs-fixed: 265531 Signed-off-by: Ravishangar Kalyanam commit 5c75292d6e2a31323236482442148bacc57ae1d2 Author: Ravishangar Kalyanam Date: Tue Dec 7 12:36:36 2010 -0800 msm_fb: display: Fix MDDI video leak during suspend/resume Fix MDDI video leak during suspend/resume by waiting on overlay_restore to complete before switching off MDDI and panel driver CRs-fixed: 265531 Change-Id: I8c3f15800aade087145e50fbd053e817a51a903a Signed-off-by: Ravishangar Kalyanam commit 25953d224b91e2cf230ae845d5db0f374818bcfa Author: Chandan Uddaraju Date: Fri Nov 19 17:07:54 2010 -0800 msm_fb: display: Fix suspend mode for MIPI panel Add code to turn off of the MIPI DSI module when the device goes into suspend state. Change-Id: I243e77c37d4332f5c67794a3922f24355cb8273b Signed-off-by: Chandan Uddaraju commit c98ad9e172386b9a53ed7f01658837b596e86e05 Author: Rajesh Sastrula Date: Tue Dec 7 18:42:38 2010 -0800 msm_fb: Fix detection of MDP4.1 core reset The MDP status register cannot be used to reliably detect a reset of the MDP core since some of its bits come from peripheral interfaces external to the MDP core. These bits may not be reset along with the core. Instead, use the MDP_SW_SCRATCHPAD_REG register to store a flag indicating that hardware initialization has been completed. This register will be reset to 0x0 whenever the MDP core is reset. MDP_SW_SCRATCHPAD_REG is only available on MDP4.1, not MDP4.0. CRs-fixed: 266140 Change-Id: I7ceccc1cfb22a8cd9355aa6cc39b82cf3729936e Signed-off-by: Rajesh Sastrula commit 8abbc4bc0ccfcfda27895a889091f6a21af3674b Author: Philip Elcan Date: Fri Dec 3 12:07:28 2010 -0500 msm_fb: Make smem size a multiple of page size drm_gem throws a BUG if smem isn't a multiple of the page size Change-Id: Iaa1a96bb259238f6e5850a7012aa5408c4a44e41 Signed-off-by: Philip Elcan commit 0d841d87f7ec8b59ff009af94c379e5a7b674bd1 Author: kuogee hsieh Date: Tue Dec 7 08:36:18 2010 -0800 msm_fb: display: set MASTER4 bits to icrease MDDI throughput There has DMA_P buffer hardware bug which cause MDDI throughput is much lower than noraml. This bug had been fix at revision 2.1. However MASTER4 of MDP_AXI_RDMASTER_CONFIG need to be set to correct value to increase throughput. Change-Id: Idee0c388f6ca4c0953bba86d6ef6c2132c298802 Signed-off-by: Kuogee Hsieh commit 071243a12712d740c33fc632431b43381dcb848f Author: Philip Elcan Date: Wed Dec 1 13:39:16 2010 -0500 msm_fb: hdmi_msm: Fix compile with HDCP disabled Can't compile without HDCP enabled. Need some ifdefs around some unused code when HDCP is disabled. Change-Id: I9682febae5ec4d766fdb62c51180d8295f111646 Signed-off-by: Philip Elcan commit e7164df63e7b87b19ee69ddc7f3db74c65b863b6 Author: Abhishek Kharbanda Date: Tue Nov 9 19:48:12 2010 -0800 msm_fb: msm_hdmi: enable HPD on request only Enable HPD sense only when panel power is on or when sysfs/hpd is turned on. Change-Id: Ibbd45d2c673aeea08660a0087cbec8b82e497584 Signed-off-by: Abhishek Kharbanda commit ecdbbed83e693269918ca9d0e7f94b0fb15d9d30 Author: kuogee hsieh Date: Thu Nov 11 13:29:58 2010 -0800 msm_fb: display: add planar support Add support of Planar (Y-CB-CR/Y-CR-CB) source format. Change-Id: I0bed22156fc6c327c48d94764d8283ec9491b85b Signed-off-by: Kuogee Hsieh commit 1dbf239b10fa4255770704e5957340cd118582eb Author: Ashish Bijlani Date: Thu Nov 18 19:37:07 2010 -0500 msm: mdp: Fix MDP underruns on 8660 To avoid MDP underruns, hardware cursor updates should be made in sync with the dma completion interrupt. Change-Id: If6b4922e2087c8a3f4c8354d173019f76cdaa519 Signed-off-by: Ashish Bijlani commit 2d55c0bd07cafc12c7ed23a38433e2944de04b6f Author: Rajesh Sastrula Date: Wed Dec 1 15:07:26 2010 -0800 msm_fb: display: do not do mdp clk scaling turning on/off dtv or lcdc during clock scaling has side affect of showing blank on hdmi. Change-Id: I4ab5dabef12ecbcee014bee21ffe695b2d74646a Signed-off-by: Rajesh Sastrula commit c7701ba49d17276c20dd4c7e4375844fc568f5cb Author: Ravishangar Kalyanam Date: Mon Nov 22 18:27:53 2010 -0800 msm_fb: display: Support to reduce power for non QuickLogic clients Change-Id: Ica37e9748c280bfe12f2c220f5dc585eac608e4f CRs-fixed: 264628 Signed-off-by: Ravishangar Kalyanam commit 59bd6d8480c4cb529f80069a2a575ac0b5e4f7a9 Author: Ravishangar Kalyanam Date: Wed Nov 17 10:49:46 2010 -0800 msm_fb: display: Fix invalid image errors in PPP stress test Fix invalid image errors in PPP stress test by fixing the internal blit regions that are split from the original blit region Change-Id: I73a9f424459fb0c4f0ceebc4fddf89d20c4bc744 CRs-fixed: 263764 Signed-off-by: Ravishangar Kalyanam commit 94d57fd66777b0387e50d4c39a241f097a3558b4 Author: Ravishangar Kalyanam Date: Fri Nov 19 18:28:10 2010 -0800 msm_fb: display: Fix USB OTG None mode flicker for 8x50a_st1x Change-Id: Ib8f2ca21cb29e7de3a2f12e4de434eef4549de93 CRs-fixed: 259149 Signed-off-by: Ravishangar Kalyanam commit 5ac62b6a6fbfcd5506bf83e83d0b52337649e602 Author: kuogee hsieh Date: Thu Nov 25 09:42:08 2010 -0800 msm_fb: display: do not re-fresh primary display for external interface Do not re-fresh primary display when external display interface, such as HDMI and ATV, issue unset operation. Change-Id: I0d8865361c5377dfae7bec5cdc10e80eb7caf968 Signed-off-by: Kuogee Hsieh commit 434f989b4b52133c7a204b9c72e06321e53bf48e Author: Urs Muff Date: Wed Nov 24 08:57:25 2010 -0700 msm-fb: msm-hdmi: reinitialize HDMI core on HPD Ensure HDMI core is properly initialized after each HPD event. CRs-fixed: 262669 Change-Id: If96a9e0c0fb7c785c640254247adaac4b5fb8a77 Signed-off-by: Urs Muff commit d0e8d669e6e1a9aa3924621b57b6bc314a75f895 Author: Rajesh Sastrula Date: Tue Nov 23 18:43:01 2010 -0800 msm_fb: display: reinitialize the mdp hardware during resume turning off the mdp footswitch during suspend doesn't retain any mdp hardware registers that are initialized one time in mdp_probe since it turns off the mdp power rail. Hence reinitialize the mdp hardware during resume only when the mdp status is not active. Change-Id: I95c6b04be26ddbb6fd6f8346b9f44eacab698f59 Signed-off-by: Rajesh Sastrula commit 2d5b134c38b47c5f5d5aae81a60a59555ca2a9f0 Author: Rajesh Sastrula Date: Tue Nov 23 18:39:22 2010 -0800 msm_fb: display: remove redundant turn off mdp footswitch. mdp footswitch is already turn off during mdp clk_disable in mdp_pipe_ctrl function hence removing the redundant call. Change-Id: Id0e6178210b836703618137e4c877f1e7036277a Signed-off-by: Rajesh Sastrula commit e4eb02a22a66ae82af4638a03ffde2b87878269a Author: kuogee hsieh Date: Sat Oct 9 11:33:32 2010 -0700 msm_fb: display: Add new pipe alloction to support 3D Modifiy pipe allocation algorithm to to support many applications including 3D. Change-Id: I3688ab44bd86b6eedf94bd7cb904e7b6fac4f89b Signed-off-by: Kuogee Hsieh commit f773d073fa24a571b299034aeeb01a4c464a0390 Author: Ravishangar Kalyanam Date: Fri Nov 19 16:41:04 2010 -0800 msm_fb: display: Set QuickLogic panel to MDDI Type 1 mode Change-Id: I32dcb588c4a583474f9c57fcda06e902ab94247c Signed-off-by: Ravishangar Kalyanam commit aba3918a084d9a914ce7cddfd2acbd1e4dad8c1e Author: Ravishangar Kalyanam Date: Mon Nov 8 18:11:20 2010 -0800 msm_fb: display: Fix SPI read API for Quicklogic panel Fix SPI read API for Quicklogic panel with configuration of TLEN and TX0 registers Change-Id: I6728322e562f525c9a5cee1afa73bb47f173418e Signed-off-by: Ravishangar Kalyanam commit e69f641acbe060badb10a354bfbf46076f8ad7e7 Author: Philip Elcan Date: Thu Oct 14 15:20:01 2010 -0400 msm_fb: Add VGA resolution to 8660 FFA panel On 8660, the LCDC panel and VGA display are on the same bus, so specify the maximum VGA mode as the secondary mode in the panel definition and the Samsung WSGA panel settings for the primary. This will allow userspace to change the resolution when using VGA mode. Change-Id: Ia805ce6477cf9b300a1f969679f2012980d14a61 Signed-off-by: Philip Elcan commit be482dd056b5ff02c8a3f98d60875e7f80fe0aec Author: Chandan Uddaraju Date: Tue Nov 9 16:57:21 2010 -0800 defconfig: Add configuration macros for MIPI DSI display Interface. Add configuration macros for Toshiba and Novatek MIPI panels. Add macros for both command and video mode. Disable MIPI panels and enable SAMSUNG display by default. Change-Id: Id2a9dca3a2467e588ffdad1ec9d149ca6a4d4d76 Signed-off-by: Chandan Uddaraju commit 85e5df5ed487db598f06bd37436629ea2b637b49 Author: kuogee hsieh Date: Wed Nov 10 08:37:11 2010 -0800 msm_fb: display: add control of dsi_s_pclk There has problem at dynamic clock gating hardware which may cause glitch of dsi_s_plck. Move dsi_s_pclk control to dsi driver. Change-Id: I466eebb0309b82ad83c54bed0840cd42d1f1b4ff Signed-off-by: Kuogee Hsieh commit 3661713ece532d5b50fd0fa1ab415058736fd0ce Author: kuogee hsieh Date: Wed Nov 3 09:19:57 2010 -0700 msm_fb: display Add Novatek video/cmd panel support Incorporated both video/command mode panel configuation to mipi_host_init to support both video/command. Change-Id: I51555e9065038607765de54e98c36128aa611d8f Signed-off-by: Kuogee Hsieh commit c2c8a3a62f8f9bdb45a606764edfb0efd25a7c24 Author: Rajesh Sastrula Date: Mon Nov 15 10:49:41 2010 -0800 msm_fb: display: Fix command block power on/off sequence. Command block is not power off in all return paths that prevents mdp clocks to turn off when display is off. Change-Id: I4aecc8be8e25780a5e45d304dc2982df40433a4f CRs-fixed: 262107 Signed-off-by: Rajesh Sastrula commit 667560bf45d30464fb82ccec0bce9a09653eec4c Author: kuogee hsieh Date: Mon Nov 1 15:49:47 2010 -0700 msm_fb: display: add mipi panel and cmd mode support Add mipi dsi per panel control configuration along with mipi dsi command mode configuration. This patch also including supports of video mode suspend/resume. CRs-fixed: 259499 Change-Id: I6be8f8edb342874c1d90ce06df094157f320ffa1 Signed-off-by: Kuogee Hsieh commit 547f7aca18653ef13bf05da91c23c4a1b607fcfe Author: kuogee hsieh Date: Fri Nov 12 10:59:39 2010 -0800 msm_fb: display: add auto detection for dmas dmap switching Add auto-detection mechanism base on the mdp_hw_revision to enable/disable MDP switching between dmas and dmap. Change-Id: If9dbae23886c94ef52350614c1f27c568ff79ca4 Signed-off-by: Kuogee Hsieh commit a5e8f857b0ececc25dbc5dbbc9967d2d80e40f90 Author: Abhishek Kharbanda Date: Wed Nov 10 10:22:56 2010 -0800 msm_fb: Add support for AHB master and slave clocks. Enabling AHB bus master and slave clocks in driver to avoid glitching by dynamic clock gating hardware. Change-Id: I66facbc85374f30c28c4b93890fd29bb88559d88 Signed-off-by: Abhishek Kharbanda commit c7ab3f03de38180c7081b48fd29fce8caaef735c Author: Laura Abbott Date: Wed Nov 17 09:05:08 2010 -0800 msm_fb: Fix section mismatch of prism_probe prism_probe was being reference outside of an __init section. Fix this by placing prism_probe in the section which is the place for device initialization code. Change-Id: I4272e2bf283a8f2a59ecabf6287683b32f6601c1 Signed-off-by: Laura Abbott commit 249a736ee2ee7fd206cad6cf5a99a643ef78246f Author: Laura Abbott Date: Tue Nov 16 16:32:22 2010 -0800 msm_fb: Fix section mismatch of lcdc_panel_probe The lcdc_panel_probe function was being reference outside of an __init section. This fixes the problem by placing the function in the section. Change-Id: Iec1f60d98249802f9c9aff795b085bc0518c26ee Signed-off-by: Laura Abbott commit abf906b0506d2c38faf0deaafd3e1c26e9b52a99 Author: Abhishek Kharbanda Date: Tue Nov 9 18:31:52 2010 -0800 msm_fb: make HDCP enabled on all panels. Try to read DDC with different alignments for different panel for HDCP protocol communication. Change-Id: Icfb51764f42497375df4c58d0977105c8f6b757f CRs-Fixed: 261508 Signed-off-by: Abhishek Kharbanda commit 7b0d8cbfa4f86a197bd88d99063df8fca1a23b32 Author: Abhishek Kharbanda Date: Mon Nov 15 14:02:39 2010 -0800 msm_fb: Fix section mismatch of hdmi_msm_probe The function hdmi_msm_probe was being reference outside of an __init section. Fixes the problem by placing hdmi_msm_probe in the section. Change-Id: I4dcfcbeaefde7e71ef9f18140dd64648b46891bd Signed-off-by: Abhishek Kharbanda commit 96c1a7422faeff26cbd70629ba1fbd838b988f50 Author: Abhishek Kharbanda Date: Mon Nov 15 14:53:23 2010 -0800 msm_fb: Fix section mismatch of samsung_probe The function samsung_probe was being reference outside of an __init section. Fixes the problem by placing samsung_probe in the section. Change-Id: I39de06c0692ddf963d2d11f069ff5dd0d8714d43 Signed-off-by: Abhishek Kharbanda commit 3f466d9a313a64af18e036d002d1738fc23c29fe Author: Abhishek Kharbanda Date: Mon Nov 15 14:47:19 2010 -0800 msm_fb: Fix section mismatch of mipi_toshiba_lcd_probe The function mipi_toshiba_lcd_probe was being reference outside of an __init section. Fixes the problem by placing mipi_toshiba_lcd_probe in the section. Change-Id: I9f0f2b1e0ed65edf9adbcf1dfb9a424aa379b7ab Signed-off-by: Abhishek Kharbanda commit 596c4c2dafbb59ade4616387fe1531efaf738a4b Author: Laura Abbott Date: Wed Oct 13 17:51:22 2010 -0700 msm_fb: Fix section mismatch of toshiba_probe The function toshiba_probe was being reference outside of an __init section. This fixes the problem by placing toshiba_probe in the section. Change-Id: I2d992ff67abf4f34ccb3c91f1b438df9fe7f0295 Signed-off-by: Laura Abbott commit 03b098b26bcb79921b55399dcf82a38e9770b560 Author: Laura Abbott Date: Wed Oct 13 17:53:50 2010 -0700 msm_fb: Fix section mismatch of sharp_probe The function sharp_probe was being reference outside of an __init section. This problem is fixed by placing sharp_probe in the section. Change-Id: I3d45fa65f34a91f9d28aaa812832a9e6d778a55f Signed-off-by: Laura Abbott commit f1fd48f9199f7695d7475a02e0ddfe489f49274e Author: Laura Abbott Date: Wed Oct 13 17:32:23 2010 -0700 msm_fb: Fix section mismatch of mddi_orise_probe The mddi_orise_probe function was being reference in a section outside of __init. This fixes the problem by calling platform_driver_probe instead of platform_driver_register since the driver is not hotplugable. Change-Id: Ic79081dea2775354dc9695747e91a6f96cbb6b23 Signed-off-by: Laura Abbott commit 23ad01dfe9d9bad23138e41c65ae7744235d2b90 Author: Laura Abbott Date: Wed Oct 13 17:38:24 2010 -0700 msm_fb: Fix mddi_quickvx_lcd_probe mismatch The mddi_quickvx_lcd_probe function was being reference outside of an __init section. This fixes the problem by marking the function as existing in the section, which is for device initialization code. Change-Id: I31dc111643915860a0ce9644c888240e611758db Signed-off-by: Laura Abbott commit 5b1d692a8deae3fc06d1855bd84dfe18958d9e21 Author: Laura Abbott Date: Wed Oct 13 17:48:58 2010 -0700 msm_fb: Fix section mismatch of gordon_probe The function gordon_probe was being reference outside of an __init section. This is fixed by placing gordon_probe in the section. Change-Id: I11f58d7157a4bdf00fe0cc631fac9b24f6a12e49 Signed-off-by: Laura Abbott commit 8e8a8451d6b82a28b1606be1d54d60cd8df40500 Author: Abhishek Kharbanda Date: Mon Nov 8 19:13:27 2010 -0800 msm_fb: Bound checking variable "count" Put upper limit bound check on "count" variable to avoid acknowledging corrupted values from user space. CRs-Fixed: 262787 Change-Id: I31517a486803871be2e304747aabfc3d4f230c86 Signed-off-by: Abhishek Kharbanda commit de90534498bde43541e7a8bf59ac640124b3e72c Author: kuogee hsieh Date: Wed Nov 10 10:37:44 2010 -0800 msm_fb: display: add synchronous between DMA_P and DMA_S. Change the execution order from update --> wait for completion --> kickoff to wait for completion --> update --> kickoff to prevent un-necessary flicking. Also remove piggy-back kickoff mechanism to prevent frames from being dropped. Change-Id: I25cd4ced51d2f5cc72d9b83e938a93d92d6f5ed2 Signed-off-by: Kuogee Hsieh commit 8d2d3ec7c1cf9b0969d0b8f13955688063d1335c Author: Rajesh Sastrula Date: Thu Nov 11 10:19:05 2010 -0800 msm_fb: display: Kick off histogram when primary underflows When underflow occurs MDP clears all the histogram registers and driver need to kick off the histogram if it start before. Change-Id: Ib15e4084da5d9d170484e9e1b6d260d17035a864 Signed-off-by: Rajesh Sastrula commit 82f8fe684610a3cfb65f3195912d3c0e870fcecb Author: Abhishek Kharbanda Date: Mon Nov 8 18:41:43 2010 -0800 msm_fb: properly handles return value of sys_lseek handle error condition of negative return value of sys_lseek, to avoid allocting large chunk of memory through kmalloc. CRs-Fixed: 262768 Change-Id: Ide303f955de30c05fe56e9f528508b8bb6e027ab Signed-off-by: Abhishek Kharbanda commit 7ef97f597ece29145a252c95f3707961377d9d30 Author: Ravishangar Kalyanam Date: Wed Nov 10 19:19:42 2010 -0800 msm_fb: display: Fix data size in MDDI host register reverse read Fix data size in memcpy in MDDI host register reverse read path Change-Id: Ia75bac5576898a510937cb0f6bc10304b7015314 Signed-off-by: Ravishangar Kalyanam commit 3e44b7399750352bd375a2d41a919fe4d737f437 Author: Philip Elcan Date: Thu Oct 14 15:18:24 2010 -0400 msm_fb: Allow panels to specify a second mode This allows for panels that support more than one mode to specify the maximum configuration. The framebuffer size is now based on the larger of the primary and alternate modes. The alternate mode is also used to check parameters when userspace is requesting a change to the framebuffer configuration. Change-Id: Icf644b0fb5e54fc95f45ea8c5ed97f6243cb886c Signed-off-by: Philip Elcan commit 9a2a724813bada5684f6bf9eeef4ba1b13db315d Author: Ravishangar Kalyanam Date: Sun Nov 7 15:23:49 2010 -0800 msm_fb: display: Implement bus scaling for TV encoder Add usage of bus scale apis to scale bus bandwidth for TVOUT. Change-Id: Id0d9a147c3d24c94b1351656b6c8938c3db10706 Signed-off-by: Ravishangar Kalyanam commit e9736b53a5642d93abb3631ea572d11f25c40b6f Author: Ravishangar Kalyanam Date: Sat Nov 6 23:29:55 2010 -0700 msm_fb: display: Implement bus scaling for dtv Request bus bandwidth for both SMI and EBI while using DTV/HDMI. This needs to be optimized once the bus scale api is integrated. Change-Id: I71162923ae8a11e7737c702b5f7b2078b995426e Signed-off-by: Ravishangar Kalyanam commit 12b28ba64a3fce1b9c97432b0f54027c4436d3f4 Author: Ravishangar Kalyanam Date: Tue Oct 19 16:34:23 2010 -0700 msm_fb: display: Implement mdp bus scaling Add the usage of bus scale apis to scale bus bandwidth based on the performance level to save power. Code assumes that FB is EBI and overlay is from SMI this need to be changed to find the correct buffer source whether EBI or SMI at runtime. Change-Id: I9936fef798379ce4698840f951dbf301430055dd Signed-off-by: Ravishangar Kalyanam commit 2f6cc1402dc448174721be73c2d48a8f12a8e347 Author: Ravishangar Kalyanam Date: Fri Oct 22 19:04:46 2010 -0700 msm_fb: display: Add MDDI Type 1 Forward Link Skew calibration support Change-Id: I344403d67a9361b626eb67bd3c9e8ad5f21660e5 CRs-Fixed: 246784 Signed-off-by: Ravishangar Kalyanam commit a179efda6e7588b3e3f56b8819c21b16647741f7 Author: Abhishek Kharbanda Date: Mon Nov 1 10:18:10 2010 -0700 msm_fb: Fix hdmi driver for enabling/disabling HDCP Fix for enabling/disabling HDCP feature from kernel config. Change-Id: Icd7f76f263780212064833084d967ab10f001b70 Signed-off-by: Abhishek Kharbanda commit c1f05d2d08eec5e95b47088a6de5c6f560d6a7a1 Author: Abhishek Kharbanda Date: Wed Oct 20 16:01:50 2010 -0700 msm_fb: Added support for premultiplied alpha. CRs-fixed: 258209 Change-Id: I891a81d76030b66e0133a689b695bb39af923b98 Signed-off-by: Abhishek Kharbanda commit 997d3c514075eb1246552aa313dd6964de36e6fa Author: Urs Muff Date: Tue Oct 26 15:43:27 2010 -0600 msm-fb: msm-hdmi: adding additional DDC request options Some panels succeed with 128bytes/page read for EDID, and some panels will fail. This will try 128/64/32/16 bytes per page in succession. Change-Id: Ibef7af8f6da57d2ecc12ed26ba5f2acb13fe4f1f Signed-off-by: Urs Muff commit 8e230203d3a85e610bc4ec23993dcff8660474d2 Author: Urs Muff Date: Tue Oct 26 16:45:47 2010 -0600 msm-fb: msm-hdmi: fix 3d info packet Use GENERIC0_LINE=1 for GEN_PKT_CTRL according to spec (bit 16). Add Top-and-Bottom mode as new 3D-mode. Use no Generic0-Line for none-3D mode, which fixes the VT issue. Change-Id: Ib1a6621bc4364fe3c56d3e26869894f52010c855 CRs-fixed: 261085 Signed-off-by: Urs Muff commit 3d480fcff95309472e8256829b5bde8f962565d1 Author: Ravishangar Kalyanam Date: Mon Oct 25 17:56:55 2010 -0700 msm_fb: display: Handle Zero MDDI Reverse packet count error Change-Id: Ib4699b17524abff43cadda36856fa7995060b3b8 CRs-fixed: 260745 Signed-off-by: Ravishangar Kalyanam commit 70b380c25316d37edc1da15cc3765b07dee175c5 Author: kuogee hsieh Date: Tue Oct 26 15:50:22 2010 -0700 msm_fb: display: synchronize dma_s kick off with dma_p During switch back from dma_p to dma_s, check dma->busy flag and wait for dma_p's completion before kick off dma_s if dma->busy was set. CRs-fixed: 260626 Change-Id: Id22b65b410ddb3e5f9faca0b8423f0e74ee6ccbe Signed-off-by: Kuogee Hsieh commit aea07835e1659c9be68ff074b8f37654eb921799 Author: Urs Muff Date: Tue Oct 26 15:45:46 2010 -0600 msm-fb: msm-hdmi: remove HDMI audio teardown from HPD event Leave HDMI audio running, so that audio-flinger can switch away from HDMI before tearing down the HDMI audio setup. Change-Id: I4090c8771143e50f9202e9e8c5902f5ce893c74a Signed-off-by: Urs Muff commit 957bbadab433ec4a4f24830dcdd38bd30394eaf4 Author: Ravishangar Kalyanam Date: Mon Oct 11 12:09:21 2010 -0700 msm_fb: display: Add MDDI multiple data read/write support Change-Id: If34dcfb0ffca650f00d5cc897fc79ff42ad939bc Signed-off-by: Ravishangar Kalyanam CRs-fixed: 258225 commit 27c0c5d6471e1af1adaae6394717701f5f0949db Author: Rajesh Sastrula Date: Mon Oct 18 10:19:50 2010 -0700 msm_fb: display: Add new ioctls for histogram. Add MSMFB_HISTOGRAM_START and MSMFB_HISTOGRAM_STOP ioctls to reduce the blocking time for histogram generation from two frames update time to one frame update time.These two ioctls help to start the MDP histogram generation process for the next frame in the isr itself just after reading the histogram bins for the previous frame. Change-Id: I8adfe2314284703ea1f51a8bb76c586f553d065c Signed-off-by: Rajesh Sastrula commit c6536fd7aa0b92270175f4bfc03a57428a75412f Author: Urs Muff Date: Wed Oct 20 10:49:19 2010 -0600 msm_fb: msm_hdmi: HDCP support for 1.4 panel Ensure to retry HDCP when failing during phase I, II, or III. Change-Id: I60a1523a5ccca70cc660d5211f23f53e75827e0f Signed-off-by: Urs Muff commit 164a5b01b3708c4c0e688ef93d628ef884a85aad Author: Urs Muff Date: Fri Oct 15 10:43:18 2010 -0600 msm_fb: msm_hdmi: handle EDID on different panel This HDMI sink does not allow to read the second EDID page in one shot, and does fail to read just 5 bytes. Changing to 32 bytes reads solves this issue. Change-Id: I36e65da1e5e67bf9b5a0bc00c0c8c1e8d67bae8f Signed-off-by: Urs Muff commit da8794fcb39dd8fb3a7daf994f693e1b06474047 Author: Abhishek Kharbanda Date: Thu Oct 21 14:44:23 2010 -0700 msm_fb: Change Packet Memory map I2C default address Changed default I2C address for Packet Memory map to avoid address conflict with BMA150 accelerometer. CRs-fixed: 215783 Change-Id: I22f76f0b888cdb377bd91e00b54bd4ad8c46d4f2 Signed-off-by: Abhishek Kharbanda commit c438f987bde833284286fb2e5434036c8def7c9f Author: Urs Muff Date: Wed Sep 22 12:07:21 2010 -0600 msm_fb: msm_hdmi: add debugfs entries Adding debugfs API to debug HDMI registers. Change-Id: If0fd415c53cf49fcaa0d38387eeef33dc14fcbc7 Signed-off-by: Urs Muff commit fffb24688cfd3560ecca5b8d162427c21467ecd1 Author: Ravishangar Kalyanam Date: Tue Oct 19 15:49:07 2010 -0700 msm_fb: display: Correct Initlogo filename Correct Initlogo filename accessed from display driver CRs-fixed: 257109 Signed-off-by: Ravishangar Kalyanam Change-Id: I95e5ff1f473e3c0a73a7a693c1965ad6e7653ee5 commit 05ca25d7023b90920ca241058e5b3266846b833b Author: Urs Muff Date: Wed Oct 13 14:46:50 2010 -0600 msm_fb: msm_hdmi: add HDCP status to AUTH_FAIL error log Add log entry detail for diagnostic of HDCP failures. Change-Id: I0f5520346952f85562e872795dde114247d5aae4 Signed-off-by: Urs Muff commit 2c3fcdb2978ef1902717ab48c74214fa857346e8 Author: Rajesh Sastrula Date: Mon Oct 18 10:13:34 2010 -0700 msm_fb: display: enable runtime clock scaling for mdp_clk scale the mdp_clk based on various performance levels. increase mdp core clk to 192Mhz for lcdc/dtv when playing 720p video since 122Mhz is not sufficient. CRs-Fixed: 254222 Change-Id: I9454cfc324c74e99a2fe6d44dd58ae5d575b60cf Signed-off-by: Rajesh Sastrula commit 166854ea7e67749badf61ab7df82e833f7fbfc50 Author: Laura Abbott Date: Thu Oct 14 15:25:15 2010 -0700 msm: video: Fix section mismatch The function tvout_probe is referenced outside of the __init section. This fixes the problem by placing tvout_probe in the section. Change-Id: I14ae9a028f32d1b0de65c99d8eea740a929721e9 Signed-off-by: Laura Abbott commit d4a6fbcb997b2800587eb5263c9dfc44d3843e66 Author: Ravishangar Kalyanam Date: Thu Oct 14 19:10:13 2010 -0700 msm_fb: display: Fix screen split issue in suspend/resume Change-Id: Ic5ccffaa12e0e546750d65e604326a4a39281f51 Signed-off-by: Ravishangar Kalyanam CRs-fixed: 253026 commit d5d9778a48d988002f87359973193749a924f3dc Author: Rajesh Sastrula Date: Fri Oct 1 11:08:54 2010 -0700 msm_fb: display: change the pixel clk to 30720000 Changing the pixel clk back to 30720000 because the maximum pixel clk supported by panel is 30Mhz.Since making it higher clk is causing display corruption issue while playing some 720p video clips where mdp clk is not sufficient to push data even though mdp is running at maximum clk it supports. Change-Id: I7d68d8728fdc7c30c6ba9549eaffef748d1147df CRs-Fixed: 254222 Signed-off-by: Rajesh Sastrula commit 414f630f8f60ede6a0d5982d7e41dd4fa9948a08 Author: Urs Muff Date: Mon Oct 18 14:42:09 2010 -0600 msm_fb: adv7520 hdmi: sysfs hdcp integration Use the external_common API to signal HDCP availability to the user-space. Change-Id: Ia5e8f51620ae29c84cf5dd8e16c81d3746b82228 Signed-off-by: Urs Muff commit 1ab44dda69fe0e7ee3995260ff06b0cdcc430746 Author: Laura Abbott Date: Wed Oct 13 17:27:47 2010 -0700 msm_fb: Fix section mismatch The mddi_sharp_probe function was being reference outside of an __init section. This fixes the mismatch by marking mddi_sharp_probe as __devinit, which is the section for device initialization code. Change-Id: I3c1103a956279e75db3bc9025186b260f901325d Signed-off-by: Laura Abbott commit 74213166390c1d70147bdf601892881ad8103c06 Author: kuogee hsieh Date: Fri Oct 15 22:47:09 2010 -0700 msm_fb: display: reset client_status_cnt to fix MDDI RTD Failure Reset client_status_cnt to 0 during system resume to make sure host does not send RTD cmd to mddi client before mddi client be powered up. CRs-fixed: 260405 Change-Id: I90194791521dd192ba1d7260ffcd2241c07b8221 Signed-off-by: Kuogee Hsieh commit 6b57dd4b598f6e8a3f42d56927dc4ffc371bbc9e Author: Laura Abbott Date: Wed Oct 13 17:23:44 2010 -0700 msm_fb: Fix section mismatch The mddi_toshiba_lcd_probe was being referenced outside of a non __init section. Fix this by placing mddi_toshiba_lcd_probe in the section which exists for device intialization code. Change-Id: I1a43bc7fa61541b9be5e7aeed701071e2c756007 Signed-off-by: Laura Abbott commit 4611e9a0b0b7ce7f7f884ff28029500c5da281ec Author: Philip Elcan Date: Wed Sep 22 09:58:36 2010 -0400 msm_fb: Make lcdc use resolution from fb driver The lcdc overlay uses the fixed panel resolution. However, it should use the variable resolution passed to the fb driver in fb_var_screeninfo. Change-Id: I77818af8722be715b5281c00b5e6e752389e3dba Signed-off-by: Philip Elcan commit 302e36a9907723d9b48d37297072b64ac078cd76 Author: Ravishangar Kalyanam Date: Tue Oct 12 19:59:42 2010 -0700 msm_fb: display: Add dynamic MIPI panel detection support Change-Id: Ie1281a353c15c7d7575eb1b591d325382d61c303 Signed-off-by: Ravishangar Kalyanam commit 75f34ead5e0489b5cae23339e0fe57dd7bb51ee4 Author: Urs Muff Date: Wed Oct 13 14:43:51 2010 -0600 msm_fb: common_hdmi: add support for audio EDID packets Add parsing for Audio related EDID packets to the HDMI common package. Change-Id: I55ff5adba4382a30fb4a686cca63bdeabd21e77d Signed-off-by: Urs Muff commit c5c8c4cb8c7e9c7f0a48634f8b2965ccce2c4570 Author: kuogee hsieh Date: Wed Oct 13 15:40:54 2010 -0700 msm_fb: display: fix MDDI compiler error on 8660 Since msm8660 does not have MDDI, MDDI ISR handler need to be excluded for 8660 platform. Change-Id: I0bcc5e413e299cfdbf91fc5275388ba4e42ff1de Signed-off-by: Kuogee Hsieh commit e8aa64ba20b7939c4fa86aecec4101af9c248a04 Author: kuogee hsieh Date: Thu Sep 23 10:02:42 2010 -0700 msm_fb: display: add panel info to mdp4_isr Since new panels such as dtv, atv, mipi video are added into system, They need to be handled diffferently at mdp4 isr. Change-Id: I25d720df12a0aaf0b3984683e283aebe7cd843b7 Signed-off-by: Kuogee Hsieh commit 5c1074bff79decc6b1a52aa8db2cff198b288eaf Author: Matt Wagantall Date: Tue Aug 17 18:59:52 2010 -0700 msm_fb: Enable/disable MDP core power rail as needed On newer SoC like 8x60, power to the MDP hardware must be turned off and on explicity. Introduce use of 'regulator' APIs to turn on and off power with the clocks. Calls are introduced to both the MDP and LCD drivers so that MDP is now powered off unless both MDP and LCDC are idle. Previous SoC that automatically turned power on and off as part of clk_enable() and clk_disable() calls are still supported. The MDP and LCDC drivers now assume that if the calls to regulator_get() are unsuccessful, then the rail will be controlled automatically. Change-Id: Ica87d8ca439130cdd6d2df04801de76a888fbdc9 Signed-off-by: Matt Wagantall commit 63c1090c30f76a955d4a894f619a30c309101d61 Author: Michael Burr Date: Mon Oct 11 10:14:50 2010 -0700 msm_fb: display: Fix framebuffer format used for MIPI devices Select the MSMFB_DEFAULT_TYPE framebuffer format instead of the 16bpp MDP_RGB_565 format. CRs-Fixed: 259512 Change-Id: I13ad0f3920baf286d9be994378c4e0538dbdbe9d Signed-off-by: Michael Burr commit 179e0ae68264329d3887d4d076623afd84e73171 Author: kuogee hsieh Date: Thu Oct 7 16:09:07 2010 -0700 msm_fb: display: re-program qseed table At msm8660 FFA, the qseed table corrupted during suspend. Therefore display garbled at both camera/camcorder preview and video playback after resumed. Re-program qseed table to fix this problem. This is temporary work around solution. Change-Id: I8d716f706f4926855ed008f5012bc2f5853161f3 Signed-off-by: Kuogee Hsieh commit 1b3424827245f23f9423ac7671ecb40d9b6c5ce0 Author: kuogee hsieh Date: Wed Sep 29 13:35:29 2010 -0700 msm_fb: display: base on is_fg flag to apply alpha effects Change-Id: Ifdf7d9f247a3619c2d710367e63ca368c1762ba8 Signed-off-by: Kuogee Hsieh commit 82506520a0631fbc25bee646f410f8ca920d89ab Author: David Brown Date: Thu Oct 7 22:21:17 2010 -0700 msm: video: Fix warning in switch_3d The entry for switch_3d does not return a value, and no result is expected when called. Change the type and function to void to avoid a compiler warning. Change-Id: Ice08a08735a6d058e09a079cbe63fdc9681d66f5 Signed-off-by: David Brown commit 80726b692d586d1d7d10d75db1966128f468f27a Author: David Brown Date: Thu Oct 7 14:56:56 2010 -0700 msm_fb: Warning fixes Eliminite some unused variables. Change-Id: Ia8d6d1edb99eb67bf60cc183a87482d5871a129a Signed-off-by: David Brown commit a0f19d22dd7698cfd851c1ce75259c277d7b03bb Author: Ajay Krishnaprasad Date: Thu Oct 7 11:23:19 2010 -0600 msm: video: fix for sending tv-out cable detect event Fix to send cable detect event only when connection state changes. Change-Id: If14f32b72f22f30dcb6ad869c5be69817ebc0996 Signed-off-by: Ajay Krishnaprasad commit e91fcab88f81f3e8304f2040a684658816436018 Author: kuogee hsieh Date: Wed Sep 29 15:32:27 2010 -0700 msm_fb: display: cursor update align with dma completion To avoid under run during cursor update, it is necessary to synchronous cursor update with dma completion. Change-Id: Ib2e6e18c88adacfe1b5235d42affa69ead5a3a11 Signed-off-by: Kuogee Hsieh commit 07240c18f405c0a9a7c071635b5507072a2d2566 Author: Urs Muff Date: Tue Oct 5 10:22:45 2010 -0600 msm_fb: msm_hdmi: change EXT_INTERFACE prefix to HDMI allow DEV_DBG to use a more specific prefix. Change-Id: I00b484f8f7f218ff6cfa1c6b17d4f6454da32519 Signed-off-by: Urs Muff commit fe019f3c4070a1945b8ba4d44943576ced22cc33 Author: kuogee hsieh Date: Tue Oct 5 08:22:49 2010 -0700 msm_fb: display: fix MDDI_LD_PARAM_SEL for DMA_P During DAM_P and DMA_S dynamic switch, the DMA_P's MDDI_LD_PARAM_SEL was over written by DMA_S. CRs-fixed: 256428 Change-Id: I79f96e8c3e5e61e0fc328fd7f83c2c6e60b50869 Signed-off-by: Kuogee Hsieh commit aeb5596d9be836ab19e75d4db4ada457b26ec64c Author: kuogee hsieh Date: Mon Oct 4 14:33:03 2010 -0700 msm_fb: display fix compiler warning message Change-Id: Ibf3609b882a99b9cbac33f6557bc633a6931a59a Signed-off-by: Kuogee Hsieh commit e662af7106510eddc6f6144df0afd54704fff1c2 Author: Ravishangar Kalyanam Date: Wed Sep 1 17:32:16 2010 -0700 msm_fb: display: Add QuickLogic MDDI panel driver Change-Id: I2829ea3c91cbb658544a46fc1de5343a9883637b Signed-off-by: Ravishangar Kalyanam commit 9f1dcfb0004a4ebfbe6a4241895b40650a03a5b0 Author: Ajay Krishnaprasad Date: Fri Oct 1 10:00:17 2010 -0600 msm: video: support for tv-out on 8660 Added support for tv-out on 8660. Cable detect is interrupt driven on 8660 & polling driven on 7630. Change-Id: Icdc6e8ae512ddcb91b766fdff2583e8157bc868c Signed-off-by: Ajay Krishnaprasad commit 07cefc8f36b8d8f1827358e6000e8691697586f4 Author: Rajesh Sastrula Date: Tue Sep 21 18:56:33 2010 -0700 msm_fb: display: turn on/off mdp clock Turn on mdp clock before read/write mdp register and turn off mdp clock after read/write mdp register. Change-Id: I0603f3a351a92b576a78370d3f974926e0441920 Signed-off-by: Rajesh Sastrula commit 2af9f6215c3ff34eb01d1c1032cbb026c2ae6dfa Author: Rajesh Sastrula Date: Thu Sep 30 11:19:14 2010 -0700 msm_fb: display: Add error check for source and dest rectangles return error if source and destination rectangle parameters set by the client are invalid. Change-Id: I8c93e84005655a62b8f4f441cc6055d3d1af46d0 CRs-Fixed: 254320 Signed-off-by: Rajesh Sastrula commit 870cbe2b5127a8cf5615249cc2c9aeff95283ded Author: Ravishangar Kalyanam Date: Thu Sep 30 16:21:36 2010 -0700 msm_fb: display: Enable H/W Vsync in DMA_P for MDDI type 2 panel Enable H/W Vsync in DMA_P for MDDI type 2 panel to avoid tearing issue Change-Id: Ifd0ad38f9c98b430c2c3c3fd01df8343684f5394 Signed-off-by: Ravishangar Kalyanam CRs-Fixed: 255990 commit a38e51d5349c52705dd3baab850c1ba65988bee7 Author: kuogee hsieh Date: Tue Sep 28 13:15:16 2010 -0700 msm_fb: display: check power status before restore screen Always check current power status before restore last screen. CRs-fixed: 256126 Change-Id: If5b46683b7c112b32955bd0475a4cbe898f3ea9c Signed-off-by: Kuogee Hsieh commit de437f1260ebca32dadcf01fd15e8a8ea7b6085c Author: Urs Muff Date: Fri Oct 1 10:52:08 2010 -0600 msm_fb: hdmi_msm: fix CONFIG_SUSPEND undefined case Since 'pm_suspended' is not defined when CONFIG_SUSPEND is not defined, the guards have to be conditional as well. Change-Id: I6c8fe29999e8c18ee2d247ca87b0162e8dd8c18b Signed-off-by: Urs Muff commit 4ae1f467dc6576fa4dfe0f60b14f047b78c0a275 Author: Michael Burr Date: Fri Oct 1 19:43:04 2010 -0700 msm_fb: display: Fix MIPI DCS Short Write, 1 Param packets The parameter byte of DTYPE_DCS_WRITE1 packets was being written into the wrong byte of the packet header. Change-Id: I6bf00d6cc287f8b6f88a9c332bf94db5f119bc89 Signed-off-by: Michael Burr commit aabef1e74db50ce5342171daf0119c2cee77ddb8 Author: Urs Muff Date: Tue Sep 28 16:01:42 2010 -0600 msm_fb: msm_hdmi: support 3D Side-by-side mode Adding support to send 3D mode over HDMI. To turn 3D on write 1 into /sys/class/graphics/fbx/format_3d. This can be done during actual playback, switching in real-time. Change-Id: If933332b84ecbbe6b75fd896b3acf804216a6abf Signed-off-by: Urs Muff commit fe5ce8d4bbcd99721b6e914a863b85cbe1f888c1 Author: Rajesh Sastrula Date: Wed Sep 29 19:37:14 2010 -0700 msm_fb:display: kickoff DMA when there is no update for video When video overlay is used DMA is kicked off only when there is a video update. This prevents the UI bar update if the video is smaller than audio. CRs-Fixed: 255766 Change-Id: I19c54ee051ddeca3e89a183f878b5c2bb2f60461 Signed-off-by: Rajesh Sastrula commit 61802d15a50c90f7ba01d308503f4d67c520914b Author: Urs Muff Date: Wed Sep 29 14:22:32 2010 -0600 msm_fb: msm_hdmi: protect worker/isr from NULL pointer When probe fails HDMI_BASE can be NULL. Change-Id: I90d185e338df4fee9f37a62c1005c3b83f2619d5 Signed-off-by: Urs Muff commit 9391f66a1674cb0de65a91275bb355772c68c8fc Author: Ajay Krishnaprasad Date: Wed Sep 29 15:53:04 2010 -0600 msm: video: support for switching TV encoder mode using ioctl Use reserved[3] field of struct fb_var_screeninfo to switch mode. Change-Id: I5f027612410f26e1e9d440235c4d1924b490fd9c Signed-off-by: Ajay Krishnaprasad commit d7801961dc00f7c57f948296307610c35f541a75 Author: Urs Muff Date: Mon Sep 27 15:38:01 2010 -0600 msm_fb: adv7520: fix audio mute after HDCP error Use Av-mute during HDCP negotiations, but turn off Av-mute after HDCP success or error. Change-Id: I82ef4e67e45c38f38f1fdd28b19028ab63a0d092 CRs-Fixed: 257430, 257702 Signed-off-by: Urs Muff commit 770f7448a6ae89d0e20aa1f5724dc7283c3cc69c Author: kuogee hsieh Date: Sat Sep 18 16:42:20 2010 -0700 msm_fb: display: remove early suspend/resume from mipi This patch contains: 1) remove early suspend/resume from mipi 2) add pm_qos to mipi 3) register MDP4_PANEL_DSI_VIDEO Change-Id: I563fbae57dca0042355637e3f0da2fd3fbbd3b6d Signed-off-by: Kuogee Hsieh commit 39e957faae7f1d0d0fbd3dec411f751a72fad64d Author: Urs Muff Date: Fri Sep 24 14:46:24 2010 -0600 msm_fb: msm_hdmi: guard against double suspend calls Suspend / Resume can only be handled once, and independent entry points are now guarded against failing while in suspend. Change-Id: Ie964db014354f4b649e153ac2d6077d17f18db85 Signed-off-by: Urs Muff commit 0a70e5f17ca65e8449a53585c89959e375e5bc69 Author: kuogee hsieh Date: Tue Sep 21 11:25:30 2010 -0700 msm_fb: display: upscaling ratio to include 8 MDP4 support scaling range from 1/4 to 8 included. CRs_fixed: 255497 Change-Id: Ib3f846a71f126c7c36a72059e463027898bad7f5 Signed-off-by: Kuogee Hsieh commit aa117d04153ab8eda2a53bc60f1ed80a8caaa777 Author: kuogee hsieh Date: Fri Sep 17 09:59:24 2010 -0700 msm_fb: display: add MDDI compiler option Add MDDI compiler option to prevent compiler error for 8660 platform since 8660 does not have MDDI interface. Change-Id: I6ecd990906667dd38fc6d50b94c1c0a00b9ba726 Signed-off-by: Kuogee Hsieh commit a23179efe8a5b7f99c67eb046cec4f99601ab5a0 Author: Ashish Bijlani Date: Fri Sep 24 01:40:40 2010 -0400 msm: mdp: enable framebuffer caching on 8660v1 for chromeos Enables FB caching on 8660v1 for chromeos. Xserver decides the caching policy. Change-Id: Id97a47c511270312614264b353b60c98f9cf96ac Signed-off-by: Ashish Bijlani commit 45ec8d7a220095ef6e0ca6bf3240288a979a1d33 Author: Urs Muff Date: Wed Sep 22 23:54:35 2010 -0600 msm_fb: msm_hdmi: completely reinitialize core after HPD Turn HDMI Engine off, init PHY, init video, init audio, turn HDMI Engine on, init HDCP (if available) after each HPD online event, and after a panel-on event while connected. Change-Id: I4f12d91885a6195c6fee1d09458183d615ac10ad Signed-off-by: Urs Muff commit 3a154cdb742e479b0939107297465ec45c92318f Author: Urs Muff Date: Tue Sep 21 10:10:56 2010 -0600 msm_fb: msm_hdmi: move audio init to panel on Since the panel resolution may change, the audio needs to be initialized once the panel resolution is set. Also handle the case when panel is on but cable is disconnected. Change-Id: I857de36c4d42f9e2df14205cf498f02a049c3357 Signed-off-by: Urs Muff commit 92df7eef80e028adfeb30445c6cbf66b1fbe830e Author: Neil Leeder Date: Tue Sep 21 17:54:34 2010 -0400 msm_fb: add qrdc lcd panel support Change-Id: Id8f57b99300075d4b4a0f7a53b222c8f9614b2ef Signed-off-by: Neil Leeder commit 33b773e2dbf0a973c0bfa187123271388b44be9a Author: kuogee hsieh Date: Wed Sep 15 16:37:50 2010 -0700 msm_fb: display: perform down scaling check base on mdp revision MDP4 of Halcyon V1 has down scaling limition. The limition had been fixed at V2 and V2.1. Change-Id: I62ca1e62178fc1b69ce80aaa38d1e65cf242ba7f Signed-off-by: Kuogee Hsieh commit 65dd5e92304aa362582c72def459c04141a171c9 Author: Ravishangar Kalyanam Date: Mon Sep 13 18:36:21 2010 -0700 msm_fb: display: Add common Debugfs support for all MDP versions Change-Id: Ifd57e1d9072444678d5d325ebaee1aecbb788a43 Signed-off-by: Ravishangar Kalyanam commit 569245db188004bf6f76fc2fc25de7fc9b833840 Author: Philip Elcan Date: Tue Sep 14 17:29:57 2010 -0400 msm_fb: Add toggle for VGA on 8x60 FFA Add sysfs entry to allow for toggling the external VGA out on/off on 8x60 FFA. Change-Id: Idb42de126daf0c4a8def9f85e80d55a586130591 Signed-off-by: Philip Elcan commit 34a939d02afa388b911070b3b872f6f12cfabbc2 Author: Ajay Krishnaprasad Date: Tue Sep 14 13:08:24 2010 -0600 msm: video: cable detect feature for tv-out Cable detect feature for tv-out. Interrupt-driven when external display is on. Polling-driven when external display is off. Change-Id: I41e9005c61d65657b9db54531306bd664d839cde Signed-off-by: Ajay Krishnaprasad commit 3f5bd44db5ebf8d27fefb386e81dc00bc0b2c20d Author: Omprakash Dhyade Date: Wed Sep 15 17:30:12 2010 -0700 msm: Use VG pipe for all the userspace requests RGB pipe might be allocated when userspace requests comes. Use RGB pipe only for kernel requests. Change-Id: Ibb5dbd8f57f1d5bd656b719ddaac9b5d973df8eb Signed-off-by: Omprakash Dhyade commit 46e08cd2287d3f56715d6e6ca8f7e3d166fd0eaa Author: Urs Muff Date: Mon Sep 20 10:27:45 2010 -0600 msm_fb: msm_hdmi: Use mutex for synchronization The ISR and worker function (queued by the timer) both access the state variable. Rather than disabling the irq from the worker function which may not guarantee exclusive access to the state, use a mutex. Change-Id: If6aded298f6f40bbe374b4436fb43117c2501b8a Signed-off-by: Urs Muff commit 0181e48defeac5f43304f78e32f3e08e4fb42e9b Author: Urs Muff Date: Sun Sep 19 00:38:34 2010 -0600 msm_fb: msm_hdmi: turn on HPD on probe HPD needs to be armed outside of panel-power so that proper HPD events can be sent to the user-side Change-Id: I50c4c23617c9ae8905678250276169d0b688a90a Signed-off-by: Urs Muff commit 515a37dfae03a50b16cc72c0a58952075e9e6f4a Author: Urs Muff Date: Mon Sep 20 12:52:02 2010 -0600 msm_fb: msm_hdmi: use regulators on demand Turn off regulators during suspend, and use board API to turn 5V HDMI and HDMI Core VDD on/off. Change-Id: I9c8736f81d212d80ad76440b5fd7bebf781f8bc5 Signed-off-by: Urs Muff commit 15556a05cdf0bee96e55df4e09415c02c364beb6 Author: Stephen Boyd Date: Fri Sep 3 16:28:59 2010 -0700 msm_fb: Round lcdc rate all the time We need to round the rate before calling clk_set_rate() on 7x30 since local clock control clocks expect an exact rate when called with clk_set_rate(). Round the rate all the time to make sure we never fail to set the rate appropriately. Change-Id: I4aeaa70df728a614fe54ec7fb06bdf974ffafdc6 Signed-off-by: Stephen Boyd commit e3530ce520cb0622d58a0f9f8958199f16f80cd5 Author: Abhishek Kharbanda Date: Mon Sep 13 11:36:58 2010 -0700 msm_fb: HDCP feature support on 7x30 Read EDID,set HDCP start bit,set internal keys bit, wait for BKSV interrupts,read BKSV keys against revocation list,shut down A/V transmission on HDMI interface on getting HDCP controller error interrupt. Change-Id: I5cf518598f2ccde8327757e5da39f5b8de46b765 CRs-Fixed: 254800 Signed-off-by: Abhishek Kharbanda commit 8ed64a02c290b0cfa5071a31a4073fd2e5516309 Author: Urs Muff Date: Fri Sep 17 12:12:49 2010 -0600 msm_fb: hdmi: fix sysfs entry creation sysfs entries are attached to the fbx returned Change-Id: Iada960f1688564185b9de42ec7b9213018b8ec0a Signed-off-by: Urs Muff commit 207a747004c6ead4c7fe7b9d3dca789744eabf19 Author: Ajay Krishnaprasad Date: Thu Sep 16 13:01:33 2010 -0600 msm: video: featurize external interface code for hdmi and tv-out Featurized HDMI specific code to use appropriate methods and sysfs attributes. Change-Id: I9b67ec23a6c3debfc6e65e9776d05e059c3e3cd2 Signed-off-by: Ajay Krishnaprasad commit 36b51586aa3958f1f70687f0dc4315e86ee00e86 Author: Ravishangar Kalyanam Date: Thu Sep 16 11:10:19 2010 -0700 msm_fb: display: Disable MDP DMA dithering Disable MDP DMA dithering to avoid double dither effect after PPP dither Change-Id: Ib218e6670deb2b9c0cc9cc18371495f75e66dbeb Signed-off-by: Ravishangar Kalyanam commit cb25ff4fb1b15a0b2cc036fab46588213936acde Author: kuogee hsieh Date: Thu Sep 16 10:56:53 2010 -0700 msm_fb: display: turn mdp clock on/off during histogram Change-Id: I83b602ec4a01fde0b5531df7fa4b1f66295d69b8 Signed-off-by: Kuogee Hsieh commit 9b8ff10a55a733c83f9f9ab4eb4f308bd75c16be Author: Michael Burr Date: Wed Sep 15 11:17:59 2010 -0700 msm_fb: display: Don't flush img buffers unless it is cached There is now a bit in mdp_blit_req.flags to indicate if the input image buffer is not cached, in which case there's no reason to flush it for DMA. The upper framework (eg. SurfaceFlinger) should set this flag accordingly to avoid unnecessary cache flushes. Also removed the destination cache flush since the composition engine doesn't read back the framebuffer directly. Change-Id: I1916c6a51c335eb0bdc0c765319b603deca82f92 Signed-off-by: Michael Burr commit 80225245ec846957a19d3c5cf97ef8e67ed0b0b8 Author: Michael Burr Date: Thu Sep 2 16:55:27 2010 -0700 msm_fb: display: Add early_suspend element for mipi dsi Add a struct early_suspend element for MIPI DSI's use in the msm_fb_data_type struct for when HAS_EARLYSUSPEND is configured. Change-Id: I39357a9ef992881201a8a9f735b91dc6674de4aa Signed-off-by: Michael Burr commit e0d8a781a00c43726baa32864925fa04f373e534 Author: Ajay Krishnaprasad Date: Tue Sep 14 21:57:35 2010 -0600 msm: video: rename hdmi common code for reuse with tv-out Rename hdmi common as external common so that it could be reused with TV out Change-Id: I110fb77df6db097f9f60d1845b692fda5b9a1b42 Signed-off-by: Ajay Krishnaprasad commit b7c94c54bd67f784d5f109de6a6700fae40d2810 Author: Ravishangar Kalyanam Date: Mon Aug 16 17:38:32 2010 -0700 msm_fb: display: Correct pixel clock frequency for LCDC Prism Pixel clock is set to correct value to achieve 60 FPS Change-Id: Ibcdbc6780a4fed6a81020edcc43cf6a6a605a43c Signed-off-by: Ravishangar Kalyanam CRs-Fixed: 251463 commit 4c5175576868064d48651819d0bbdc473b7ab49b Author: kuogee hsieh Date: Sat Jul 31 11:40:02 2010 -0700 msm_fb: display: Add MDP4 BLT mode support Add BLT mode support to have overlay output to an intermedium buffer before dma to display panel. Change-Id: I14c6fd383d8d498e56620389c6a5a69768b5bffd Signed-off-by: Kuogee Hsieh commit c55ad5731465eb43c781b6d880e9bfe791ec4041 Author: kuogee hsieh Date: Wed Aug 25 09:06:29 2010 -0700 msm_fb: display: fix op_mode over written bug Fix op_mode of overlay over written bug which cause some settings never executed. Add deinterlace enable bit of op_mode. Also correct DMA_E fetch configure address. CRs-fixed: 252617, 252845 Change-Id: I65ea5a2e718e7d34b7400394a20dbcd7d4891533 Signed-off-by: Kuogee Hsieh commit f8cbfe60ddfb5306f13267f1fecb866c04f0c6df Author: Michael Burr Date: Wed Sep 8 11:25:32 2010 -0700 msm_fb: display: Implement Forward Link Skew Calibration Packet Change-Id: I59d6e2f9cdc44cc702fd244356959931c30e616d CRs-Fixed: 246784 Signed-off-by: Michael Burr commit f5eeb754e03385d1b3e89b055626effca2bb1eee Author: Ajay Krishnaprasad Date: Tue Sep 14 11:42:51 2010 -0600 msm: video: Set clock rate in TV encoder driver Set clock rate of tv_src_clk to 27MHz and correct clock dependencies. Change-Id: Id7ffdc2de039f1ccc68f464e184409774e1dbb15 Signed-off-by: Ajay Krishnaprasad commit a0cede5868c6da21bdbb15ffc29e8bd734fbe18e Author: Urs Muff Date: Tue Aug 31 01:20:25 2010 -0600 msm_fb: hdmi: power control entry points create required entry points to control the different use cases for the HDMI driver, so that the power footprint can be optimized. Change-Id: Ied0551077a33c63f1f6e250a12259fbcd30aff38 Signed-off-by: Urs Muff commit 38dbe553fc35d1d3c0d1c2c2b5749101ea139768 Author: Urs Muff Date: Tue Aug 31 01:20:25 2010 -0600 msm_fb: adding sysfs entries in probe moving up sysfs entry creation from panel power-on to probe, so that user-space daemon can read the cable state before panel power is first turned on, and so that the driver can send uevents during initial panel power off phase. Change-Id: I43388c37dfbf048bd0c14130b807446cb6eaacdf Signed-off-by: Urs Muff commit 4d8d83fb198a309f1c99494d5863d68c673e1b1a Author: Ravishangar Kalyanam Date: Mon Sep 13 16:47:48 2010 -0700 msm_fb: display: Enable EMDH PCLK Change-Id: I2a674dfec9c140e49250cb644126812d069fbb4c Signed-off-by: Ravishangar Kalyanam CRs-Fixed: 255313 commit 74a75835cef8cde911a560fb5aff13756e30d7d9 Author: Ravishangar Kalyanam Date: Mon Aug 16 17:15:10 2010 -0700 msm_fb: display: Enable BG Tile fetching HW workaround only for MDP2.2 Change-Id: I483fe5182302293d0f967b99ce49de2109247858 Signed-off-by: Ravishangar Kalyanam CRs-Fixed: 249932 commit 4661621e735ac029293c6872bd7d342a351247cc Author: Abhishek Kharbanda Date: Mon Sep 13 11:29:59 2010 -0700 msm_fb : Set proper FPGA setting for 8x55 platform Enable proper FPGA Settings for HDMI interface on 8x55 SURF platform too. Change-Id: I5da9539c008f05c32a9f7cea6b6af56d2305570c CRs-Fixed: 254427,250608 Signed-off-by: Abhishek Kharbanda commit 95079ae135cecb86a88e620f92de766c89ec0006 Author: kuogee hsieh Date: Mon Sep 13 09:08:48 2010 -0700 msm_fb: display: add pm_qos to MDDI Use PM_QOS to request basic axi bus bandwidth for MDDI. Change-Id: I858706d224c7037d036e8c2e96649da4c9540bc4 Signed-off-by: Kuogee Hsieh commit 160d42d529f7a5563bbd7cd117c83b7f434f0c22 Author: Bryan Huntsman Date: Wed Sep 8 18:01:18 2010 -0700 Initial contribution. This commit takes the MSM and driver changes from git://codeaurora.org/quic/la/kernel/msm.git:android-msm-2.6.32 and applies them on top of git://android.git.kernel.org/kernel/common.git:android-2.6.35. Signed-off-by: Bryan Huntsman commit cd238df6940e8f3515c43e34e00ff825a4a8f9c7 Author: kuogee hsieh Date: Thu Sep 16 10:17:24 2010 -0700 msm_fb: display: turn on/off mdp clock Turn on mdp clock before read/write mdp register and turn off mdp clock after read/write mdp register. Change-Id: Ia11784f64216e58564b65da4935fca8f26ff5d2b Signed-off-by: Kuogee Hsieh commit 0bb93216c642f90e9be8904150943342b16f5b43 Author: Amar Singhal Date: Wed Aug 4 13:57:03 2010 -0700 driver: runtime pm annotation for drivers/video/msm/mdp4_dtv.c Change-Id: I1bacecbdec9e62dca1be99ab4fb8a593562d2cba Signed-off-by: Amar Singhal commit 6c2231402b3d7a671939e8910589bc2b895e1a25 Author: Urs Muff Date: Tue Aug 31 21:49:22 2010 -0600 msm_fb: fix dynamic resolution switching for 7x30 27.03MHz is not yet supported on 7x30, so we need to force using 27MHz instead, if clk_set_rate for 27.03MHz fails. Change-Id: I874d242b42e3e3b85d3370e1e277dea8db9e1d4d Signed-off-by: Urs Muff commit 1266c58750bd52a48be70514dd150975e1684180 Author: Michael Burr Date: Fri Aug 27 16:07:57 2010 -0700 msm_fb: display: select MXO or PXO for DSI PLL clk-ref dynamically A future hardware design will not have a 27MHz MXO crystal, but will have a 27MHz PXO crystal. Detect when PXO should be used instead of MXO and set the DSI PLL clk-ref appropriately. Change-Id: I4ae91435aad99ac34fdfb7540b49b901cea96fc4 Signed-off-by: Michael Burr commit 625cb21cd30bafc1e7ac7dd0e45c5cfd244060d6 Author: Aparna Mallavarapu Date: Tue Aug 31 11:34:54 2010 +0530 Revert "mdp: Add support for MDP composition for QSD8650A target." This reverts commit 88a2b88655c6fced3a0e342ebcb9bbf807a526e2. Change-Id: Ia9e7d03d405cd9ec62dffa620081e52d4607c3b2 Signed-off-by: Aparna Mallavarapu commit 6aea65b1cabafdf0c37b4c3d1cb3e8f309117d3a Author: Philip Elcan Date: Mon Aug 30 15:00:09 2010 -0400 msm_fb: Add sysfs entry for panel type Add an entry in /sys/class/graphics/fbX so a userspace app can know what type of panel is behind the framebuffer device. For example, X will know if it is an HDMI panel and do any extra steps required for setup. Change-Id: I951041a0613502be1fbfaca3d7ed8b5a10fec3d8 Signed-off-by: Philip Elcan commit 444aa5a8324427cc42f7d757ad8eef42b22838c2 Author: Ajay Krishnaprasad Date: Thu Aug 26 11:37:40 2010 -0600 msm: video: sysfs support for TV out driver and replace old files TV out driver with sysfs support for switching video modes. Merged files for better management of sysfs attributes for TV out Change-Id: I3f71e8f92a3e420762190824265ad4209bd3f42d Signed-off-by: Ajay Krishnaprasad commit f91289987a77d8d86199feb34c802dd86c7ce922 Author: Abhishek Kharbanda Date: Thu Aug 26 07:47:17 2010 -0700 msm_fb: Add feature support for HDCP protocol. HDCP is designed to protect the transmission of Audiovisual Content between an HDCP Transmitter and an HDCP Receiver.Enable support for HDCP encryption in ADV7520 HDMI chip. Change-Id: I9704f64b9b0df169a0370ff8c5a6e96d8b4ac4b4 Signed-off-by: Abhishek Kharbanda commit 0ef61e3116045dfd3af2d44598b90aa527551a58 Author: Urs Muff Date: Tue Aug 10 22:55:16 2010 -0600 msm_fb: add kernel logs for ioctl failures fbtest was causing unidentified ioctl failures; this is helping identifying the cause for those failures Change-Id: Ic3980b2ee27b423f2936a468ef66f725a89fe8df Signed-off-by: Urs Muff commit dec207bf6bd3c32c1965b07bd53ab7143c058741 Author: Mansi Patel Date: Thu Jul 22 13:22:44 2010 -0600 msm: video: 8660 HDMI TX / PHY kernel driver: HDCP Adding HDCP support Change-Id: I6f6f9a6cd3f3b0ed62973095a5abb91c9fb69583 Signed-off-by: Mansi Patel commit 815a8e7bf3d8a1064ca2168a29bf98defb604ec2 Author: Urs Muff Date: Wed Aug 25 02:31:22 2010 -0600 msm_fb: use hdmi common for sysfs entry creation Use the common HDMI functionality for the sysfs API. Change-Id: If42a4408469d262b72884b29fc69da42b8799c8a Signed-off-by: Urs Muff commit d7762c1f8c9dce3f410b0db65e78d459549b15cf Author: Urs Muff Date: Tue Aug 24 22:16:02 2010 -0600 msm_fb: using hdmi_common to parse EDID make use of common HDMI code to parse the EDID data Change-Id: I312942975067ae1bbfb10958d84e0f1ac2234142 Signed-off-by: Urs Muff commit e28154c9723ee7d232e7a9aab42a4d24b3390c3d Author: Urs Muff Date: Tue Aug 10 10:01:42 2010 -0600 msm: video: HDMI common code Move common HDMI code into hdmi_common.c so that it can be reused by 7x30 and other HDMI drivers. Change-Id: I41ecc78f9e68e8f80b3ce8da41eb27244e5b101d Signed-off-by: Urs Muff commit 4796e2b9f8c47659dca75d3eecd9e4068c5c5403 Author: kuogee hsieh Date: Thu Aug 26 10:49:03 2010 -0700 Revert "msm_fb: display: fix mixer stage range out of bound bug" This reverts commit 517e3355ab974cbf9d529d1ec660d06c29a4d51c. Change-Id: Ifc0a3be36b6b1e5c6db4e9c3b7c20671dbe95f71 Signed-off-by: Kuogee Hsieh commit 2f876295641716521afe4b95d35465cde68ddeed Author: kuogee hsieh Date: Wed Aug 25 09:40:00 2010 -0700 msm_fb: display: Do not power on DTV at probe which will result in having no power on I2C for 7x30 until panel power on is call. Change-Id: Ifd50d9065432ad3a58764798405d04bdd9128700 Signed-off-by: Kuogee Hsieh Signed-off-by: Urs Muff Signed-off-by: Abhishek Kharbanda commit 88a2b88655c6fced3a0e342ebcb9bbf807a526e2 Author: Aparna Mallavarapu Date: Thu Aug 26 20:08:37 2010 +0530 mdp: Add support for MDP composition for QSD8650A target. CRs-Fixed: 251979 Change-Id: Iba8281ea47b37a024bdd6239835909a90cb2a203 Signed-off-by: Aparna Mallavarapu commit 01ab957732bb79793d2ec4e7d0da02638a6dc6f9 Author: Ajay Krishnaprasad Date: Thu Aug 26 15:07:39 2010 -0600 msm: video: TV encoder kernel driver: Clock fixes Proper error checks while enabling/disabling TV encoder clocks Change-Id: I13d9bec38968bf619f9b6258e4037faa3bb2df1a Signed-off-by: Ajay Krishnaprasad commit 0d41b4f23142deca25cb6d56a75944ab27ada063 Author: Ajay Krishnaprasad Date: Thu Aug 26 14:34:05 2010 -0600 msm: video: ATV support for dynamic mode switching Turn tv encoder on before configuring overlay pipe to get correct resolution for the mode. Change-Id: I77f96633ce91df4658500e2cb7e7679ad0dbdeda Signed-off-by: Ajay Krishnaprasad commit e519e09063f60200d1397263c02845c639267972 Author: Rajesh Sastrula Date: Fri Aug 6 09:39:22 2010 -0700 msm_fb: display: reduce the delay during power off Do not have to wait for 100ms during power off 16ms is sufficient on 60Hz display. Change-Id: I06fe266de7f3848d2ad43f5837f95dd99c660329 CRs-fixed: 231755 Signed-off-by: Rajesh Sastrula commit 6a2e3fc2cc64ae4e1b8ad30614271bd0f4e840bf Author: kuogee hsieh Date: Wed Jul 7 15:09:53 2010 -0700 msm_fb: display: Add mipi dsi display panel support Add mipi dsi both video and command mode display support by adding mipi dsi host, mipi dsi client and display panel drivers. Change-Id: I67d6d6881993c021706f07d96b02902c9393f7d9 Signed-off-by: Kuogee Hsieh commit 730c676384f227032873f5066d78929d3baffdf5 Author: Urs Muff Date: Sat Jul 24 01:45:52 2010 -0600 msm: video: 8660 HDMI TX / PHY kernel driver: HPD Adding HPD and EDID support Supporting dynamic mode switching Change-Id: I95b7488ceffab919f76300f358ca6cdd15820b4a Signed-off-by: Urs Muff commit 519f339af23717cf871a12bf2458dba8c07647c9 Author: Abhishek Kharbanda Date: Wed Aug 18 13:49:08 2010 -0700 msm_fb: HDMI should be powered ON by user space on HDP detection HDMI/DTV clocks should be enable only when HDMI cable event is detected, to save power. Also resolves the bootup issue with HDMI cable connected. CRs-fixed: 248533,249902 Change-Id: I13d8b2bcb1f17f2d6982636f749fef1e6b26e800 Signed-off-by: Abhishek Kharbanda commit 150e5e7964e7fe4b8e77fe79c6770f6bcf28f239 Author: kuogee hsieh Date: Sat Aug 14 14:36:13 2010 -0700 msm_fb: display: reset vsync_handler_pending flag during suspend At both mddi_toshiba_lcd_off/mddi_sharp_lcd_off function call mddi_toshiba_vsync_handler/mddi_sharp_vsync_handler to set vsync_handler_pendign flag to false to avoid suspend process stuck at busy loop and never get out of it at msm_fb_suspend_sub(). This problem prevent resume process from happenning so display stay blank. This also contributes to "MDDI RTD failuer" problem since MDDI was power off and MDDI link is shut donw between MDDI host and client. CRs-fixed: 248624, 244906 Change-Id: I7ab0dc6420d80cda19ad43a4dd2ddbe7318bd698 Signed-off-by: Kuogee Hsieh commit a469172a1c5884996d7d4cb66ebf6a8d0dda8d18 Author: Abhishek Kharbanda Date: Wed Aug 18 16:56:10 2010 -0700 msm_fb: Put last frame as black on suspend Put black frame as last frame on suspend on both HDMI panel and primary panel. Change-Id: I1620292c0abe0c81df1acfeffec54a5824175446 Signed-off-by: Abhishek Kharbanda commit 5455b12c4d410da95dd8a90f9934d494c122bd2c Author: Gopikrishnaiah Anandan Date: Mon Aug 9 18:52:09 2010 -0700 msm: vidc: Move 720p video driver into msm folder. Moved the 720p driver files from drivers/misc/vidc to drivers/video/msm/vidc Change-Id: I27cfd2e9258a95e9190ce0fec37fad2265fba8eb Signed-off-by: Gopikrishnaiah Anandan commit 9a72e92e095d14fffc8a31c3b9b1a7747057e253 Author: Amar Singhal Date: Wed Aug 4 17:10:14 2010 -0700 video: runtime pm annotation for drivers/video/msm/tvenc.c Change-Id: Ic9f6d859fdfc24d08ac27bc2d99898aba4e4bbcd Signed-off-by: Amar Singhal commit 003b979f5e1e519a35b5697d1bf4bd423c4f6582 Author: Amar Singhal Date: Wed Aug 4 16:33:55 2010 -0700 video: runtime_pm annotation for drivers/video/msm/mdp.c Change-Id: Ic1531c6d31739a7d81de205692506f272888602d Signed-off-by: Amar Singhal commit 93aba6dccc134cc2b14a0c3c8f18f0f0bc800902 Author: Amar Singhal Date: Wed Aug 4 16:20:12 2010 -0700 video: pm_runtime annotation for drivers/video/msm/ebi2_lcd.c Change-Id: I730e13dae48e04a5cc9b11586bd4526378b41e84 Signed-off-by: Amar Singhal commit 517e3355ab974cbf9d529d1ec660d06c29a4d51c Author: kuogee hsieh Date: Tue Aug 17 09:55:18 2010 -0700 msm_fb: display: fix mixer stage range out of bound bug CRs-fixed: 251191 Change-Id: Ied2d51729e78dad6519d00e66e0cbf0d46920599 Signed-off-by: Kuogee Hsieh commit 14d3db274a3eacea5878dd31e7e10927020d230f Author: Jeffrey Chuang Date: Tue Aug 3 17:40:00 2010 -0700 msm_fb: annotating msm_fb for runtime PM Change-Id: Id1b7ed4f8373b4431e33c8854d71658ebaab68fe Signed-off-by: Jeffrey Chuang commit 5fc970fd24f1d90a2fa371bf7eaf5780c3e310e9 Author: Gregory Bean Date: Wed Aug 11 15:35:35 2010 -0700 msm: change GPIO_CFG enums to reflect .35 naming. Change the GPIO_CFG enumeration prefix from GPIO_ to GPIO_CFG_ in anticipation of the backport of the msmgpio driver from Google's 2.6.35-wip branch, where the symbols have had their names changed. Change-Id: Ie818d28f86f4c6c92aa052ddb9f594b81f067df0 Signed-off-by: Gregory Bean commit d2ebe7626ebab06648f9697515179e11e2c404c5 Author: kuogee hsieh Date: Tue Aug 3 15:20:34 2010 -0700 msm_fb: display: remove DMA_PACK_TIGHT from mdp3.0 and above Change-Id: I853620cca00408b7e8da268e5066bc1393063b3d CRs-fixed: 245392 Signed-off-by: Kuogee Hsieh commit 2053340fb119a09a105ea110b37d9ae4b5fb08a6 Author: Rajesh Sastrula Date: Thu Jul 15 13:03:12 2010 -0700 msm_fb: display: create barrier when writing qseed tables workaround the 1K Boundary AXI Interleave operations from Scorpion that can potentially corrupt the QSEED table. Change-Id: Ia61076cbdb99b95aeb12a9ce4af7fcc12bc9d761 Signed-off-by: Rajesh Sastrula commit 51edd49793e8567604efcc7d26376634af27288d Author: Abhishek Kharbanda Date: Wed Jul 14 10:08:04 2010 -0700 msm_fb: No Suspend/Resume function for DTV interface DTV interface connected device should not go into suspend/resume state for power savings to acheive continous audio playback functionality. CR's fixed: 244994 Change-Id: I69b46e5dc6c96a7138ff57ddaa545d5ba73e00c2 Signed-off-by: Abhishek Kharbanda commit 9d6106c7fa05809d972b95dc1834159aec0afeb4 Author: Jeffrey Chuang Date: Wed Aug 4 13:54:33 2010 -0700 mddi: annotating mddi for runtime PM Change-Id: I154695f4f9718464830e67e051b9e30f40dc0206 Signed-off-by: Jeffrey Chuang commit 42e1283c5f7d5928097e1d1b349ee8876d322c3d Author: Jeffrey Chuang Date: Wed Aug 4 14:06:08 2010 -0700 mddi_ext: annotating mddi_ext for runtime PM Change-Id: I5d53a2bb76e6ad535b55f60320593c7316c23dea Signed-off-by: Jeffrey Chuang commit 2768c4933148c64f318b7411ca3fd95bfc97ae9c Author: Rajesh Sastrula Date: Tue Aug 3 17:06:44 2010 -0700 msm_fb: display: correct pixel clock frequency pixel clk is set to correct value to get 60 fps Change-Id: I77fa24d148be1e1cb8f6b4874ebdd822a766b588 CRs-fixed: 248848 Signed-off-by: Rajesh Sastrula commit c5cdaaa58e7b1bd6da45f4ab14caf749a9dc21cf Author: kuogee hsieh Date: Fri Jul 30 16:04:45 2010 -0700 msm_fb: display: make TV_OUT is not set by default Make TV_OUT configure is not set at default configure setting to avoid confliction with DTV. Change-Id: I95b51f38ea9fcb3178639a161822880fe370059f Signed-off-by: Kuogee Hsieh commit e29c212a71773a732f019b3d73b3c7a8d39dd4ce Author: Michael Burr Date: Wed Jul 28 11:18:53 2010 -0700 msm_fb: display: cleaned up mdp_blit() to be MDP3.02 clean For MDP30 the tile processing is different and thus we do a different check. Also, 7x27 does NOT have MN scaling and overhang issues in the height so no height splits are required. ONLY split in the width for MDP30. CRs-fixed: 247272 Change-Id: I7bdc7832914eaa80d668fd00851272f162a0e0e9 Signed-off-by: Michael Burr commit 1a9a814f18cdee2ff2b07b18222d5b6f6a0438ef Author: Urs Muff Date: Wed Jun 9 11:32:37 2010 -0600 msm: video: 8660 HDMI TX / PHY kernel driver. Setup PHY and TX Core, and adding FB_MSM device. Handle Power on/off events by the controlling panel. HDMI Audio support (2 channel, 48kHz) HDMI SWI debug support (enabled by default until feature complete) MDP-DTV debug support (needs to be enabled) Change-Id: I74cdfe1489f8a981efa7b415f6f7ee0507643fe1 Signed-off-by: Urs Muff commit 86b810f046b0d76146d46ae720dbbdc18fee4d5c Author: Ravi Bandi Date: Mon Jul 12 15:16:38 2010 -0700 msm_fb: MDP4 Analog TV support Add an RGB pipe as base layer to blend with a VG pipe to carry Analog TV YUV format and put it to tv encoder through dma_e dma engine. CRs-fixed: 241816 Change-Id: I847a7eeafe6f4b1b9977e144374eb3c1a6a2498a Signed-off-by: Kuogee Hsieh commit e67ca29a62cac202adbf092efc28e76357d65a69 Author: Abhishek Kharbanda Date: Mon Jul 26 19:03:27 2010 -0700 msm_fb: Write proper FPGA value to avoid conflict with UART Write proper FPGA value into SIGNAL_EXPANDER registers in HDMI driver to avoid conflict with UART GPIO's selection. CR's fixed: 241467 Change-Id: I5880b287454870e2c1fae82691b9584a3ae27027 Signed-off-by: Abhishek Kharbanda commit f6d4b96e080e6e3eebcc1f1b2a43e7535f62d377 Author: Jordan Crouse Date: Tue Jul 6 15:33:45 2010 -0600 msmfb: Allow MDP4 overlays to use GEM objects Expand the MDP4 overlay structures to allow the user to pass in a GEM handle as a source for the overlay display memory. The GEM handle and flags will trigger the driver to query buffer information from KGSL rather then from PMEM. Signed-off-by: Jordan Crouse commit 0f3a4677bdbb48e2df64de250b789a02167717a9 Author: Jordan Crouse Date: Tue Jul 6 15:29:58 2010 -0600 msmfb: Allow MDP operations to use GEM handles Expand the MDP structures to allow a GEM handle to be passed in as an option for MDP blit operations. Rather then pulling the buffer information from PMEM, the GEM flags prompt the driver to query the information from KGSL. Signed-off-by: Jordan Crouse commit 624e9899b6a4362218d5cdd073642fe367552bae Author: Abhishek Kharbanda Date: Tue Jul 20 16:41:23 2010 -0700 msm_fb: Added HPD and EDID feature support in HDMI driver a. Set Interrupt Mask register for catching HPD interrupt. b. Add ISR for HPD Interrupt on HDMI cable detection/removal event. c. Add kobject api's to send uevent to user sapce on HPD interrupt. d. Add timer control to take care of debouncing interrupts. e. Support for configuring framebuffer structure on reading EDID information from sink. Change-Id: Ic96ba3fc785d54bb2a882bff509655335d57165c Signed-off-by: Abhishek Kharbanda commit 2a228e7612135c700d75917a69668942d8910d43 Author: Nagamalleswararao Ganji Date: Wed Jun 16 09:59:15 2010 -0700 msm: vidc: 1080p video driver support for 8660 1080p video driver support is added for 8660 Change-Id: I0e2a491dd32d2a8eeee5d65cd70a7fe4fa719678 Signed-off-by: Nagamalleswararao Ganji commit dea68ae99815fcdeecd98cb2cc60d0505957ebce Author: kuogee hsieh Date: Tue Jul 20 10:35:42 2010 -0700 msm_fb: display: reduce pixel clock of display panel Reduce the pixel clock rate from 539900000 to 43192000 to decrease bus access bandwidth and power consumption at LCDC mode. Change-Id: If0cc46b70ebb86aad1efe1cbadeed3cdb67cb38d Signed-off-by: Kuogee Hsieh commit cb514d96a5d4d66370e74d3ae98e7cbbf339515e Author: Rajesh Sastrula Date: Mon Jul 19 14:06:10 2010 -0700 msm_fb: replace BUG_ON with error message replace BUG_ON call with error message to avoid the crash when incorrect color format is passed. CR's fixed: 246713 Change-Id: Ia5b84330bfc71e27cf09921f8def56da5784c0bf Signed-off-by: Rajesh Sastrula commit 345475e974a6281be1b95ac5a060b5177291754a Author: kuogee hsieh Date: Tue Jul 6 10:53:22 2010 -0700 msm_fb: display: initialize intv to 0 at first MDDI kickoff Initialize intv variable to 0 at first MDDI kcikoff to prevent mddi_kick_interval become huge number which prevent pan_display from working at first mddi kcikoff. CRs-fixed: 245197 Change-Id: I14d90129cf63988a1d63856527107fcffd4092e7 Signed-off-by: Kuogee Hsieh commit 51c4ae4090b8a20b243056f1b272a5dde307fe42 Author: Ravi Bandi Date: Mon Jul 12 12:17:38 2010 -0700 msm_fb: Deinterlaing in MDP3.1 is enabled Deinterlaing in the MDP3.1 was not enabled earlier causing this functionality not being observed on this platform. CRs-fixed: 246029 Change-Id: I00a9495314f34f610791c55b6492d6caf96f6548 Signed-off-by: Ravi Bandi commit 4b9e5b18bf2f97f153546a697d5ec7df5ee92d5e Author: Rajesh Sastrula Date: Fri Jun 25 12:35:24 2010 -0700 msm_fb: display: enable irq before kick off histogram enable the irq before kick off the histgram process and disable it once histogram is done. when overlay is used on lcdc mode it is disabling irq after overlay is done so we are missing histogram interrupt handling. Change-Id: I111394c705a43e4cc5e4861f02667a5491ae69fe Signed-off-by: Rajesh Sastrula commit 8b9675df4eb7d98a1709e069846a174edee3b9ae Author: Urs Muff Date: Wed Jun 9 11:32:37 2010 -0600 msm: video: setup DTV overlay polarity for low resolutions. clk_set_rate has to be called before clk_enable. H-Sync and V-Sync polarity are active low for low resolutions. Add mdp_tv_clk for HDMI drivers that need this clock (8x60). Change-Id: If76300ac4d0b6c8a66492f8e0f77b61e133ef709 Signed-off-by: Urs Muff commit 781c6b0fbe05c56bda8d15359907d9e583231ee7 Author: Rajesh Sastrula Date: Thu Jul 8 10:22:03 2010 -0700 msm_fb: display: remove spi bit-banging in lcdc lcdc panel drivers are using spi bit-banging and causing a GPIO conflit with MSM SPI controller driver.Hence remove the bit-banging and using the MSM SPI controller for SPI transfer. Change-Id: I37abe848ed5f486ba0a8709512a076421fc58299 CRs-fixed: 220233 Signed-off-by: Rajesh Sastrula commit b8edd675c91c8f6f92a6067356cacf01dff95393 Author: Jordan Crouse Date: Mon Jun 28 11:08:34 2010 -0600 msm_fb: Set the default color depth from the kernel config Make the default color depth for the framebuffer configurable via the kernel config. Default is RGB565, but ARGB8888 and RGBA8888 are available. Signed-off-by: Jordan Crouse commit 78f720650b1c5400baf067c6e766ef753dfa5b4d Author: Jordan Crouse Date: Mon Jun 28 10:55:09 2010 -0600 msm_fb: Use varinfo information to choose the proper color config Use the position of the transparent portion of the color information in varinfo to determine if we should use RGBA8888 or ARGB8888 when 32bpp is selected. Signed-off-by: Jordan Crouse commit 410efd5af5b0a8f230e5c98c64eddac9061d493a Author: Naomi Luis Date: Thu Jul 1 22:19:23 2010 -0700 msm: Return the correct size for tiled formats The tiled format buffers are 8K aligned. Return the 8K aligned buffer size for the tiled color format. Change-Id: I81d04ec1d7f55ee68c361aaa1c515cc4318e906d Signed-off-by: Naomi Luis commit 450e38300a07cdb77b3ef36a4e61a3f0f835aba0 Author: Ravi Bandi Date: Sat Jun 26 20:37:14 2010 -0700 msm-fb: s/w workaround for MDP3.0 ppp h/w lockup Pulling in the changes of s/w workaround added for MDP3.1 to MDP3.0 CRs-fixed: 242307, 244250 Change-Id: I7c5ecdd8c0e02ea6c1fb2ec3261f81d6c1171f3d Signed-off-by: Ravi Bandi commit f55b99553dc3ae09afb816e25cf657cff8e2356e Author: Ravi Bandi Date: Wed Jun 23 19:08:28 2010 -0700 msm_fb: Set correct video format for different bpp values Video format is not set properly across 16, 18 and 24bpp formats, due to which colors are not displayed properly. Rectified the issue by using appropriate video format descriptors for these panel types. Change-Id: Id79703b51aa3aceb02d080372a5696d41658f67d Signed-off-by: Ravi Bandi commit 4325aa8038ed6631aa49a272c8951ddd042288d7 Author: Abhishek Kharbanda Date: Wed Jun 23 13:16:47 2010 -0700 msm_fb: Shutdown HDMI clock on dtv off. Disabling HDMI clock while dtv interface is off. Change-Id: Ib060580a79572d646b98687f4577f665ca5fdc0e Signed-off-by: Abhishek Kharbanda commit ee61d7178de4c8f986ae33ec5813ed34bac0a3e3 Author: Abhishek Kharbanda Date: Mon Jun 14 18:32:01 2010 -0700 msm_fb: Enable Audio settings for ADV7520 HDMI chip Configure ADV7520 HDMI chip for dual channel audio through I2S inerface. Change-Id: I916acfc38fe497b54ce5147a07a700f57b305a4b Signed-off-by: Abhishek Kharbanda commit f29603084ab9ae536eccdf741533e39fe6cae746 Author: Omprakash Dhyade Date: Tue Jun 15 11:56:03 2010 -0700 msm: Add framebuffer read and write support in rotator driver Rotator driver can only read or write to PMEM. To read or write to framebuffer, we change MDP driver to provide framebuffer physical address information. This change is required so that we avoid copy of framebuffer in PMEM for rotation. The rotated buffer is then used to push on overlay engine. Change-Id: I17322fa77bb05f36f70ac0c225299614dd607fe9 Signed-off-by: Omprakash Dhyade commit 4e2da5926dc4b904dcfa930219c4bc1a1e2f6233 Author: kuogee hsieh Date: Mon May 17 15:57:43 2010 -0700 msm_fb: display: add HDMI mirror support Allow VG pipe can be shared by both RGB and YUV format (video). YUV format (video) have higher priority than RGB format during overlay play so that RGB format can be preemepted by YUV format during VG pipe sharing. Change-Id: Ie9bf1beb28095e157f5be4a573fc541780a54e09 Signed-off-by: Kuogee Hsieh commit 5eef0fe4e1eb1150166233425f42b05d307962b4 Author: Kuogee Hsieh khsieh Date: Fri Apr 9 16:05:28 2010 -0700 msm_fb: display: enable software vsync to prevent display from tearing Enable software vsync and adjust frequence of MDDI display panel to prevent tearing from happening. Also add vsync can be enabled/disabled from mdp4 debugfs. CRs-fixed: 221821, 227518, 241791 Change-Id: I482980ce1d12b083745e74aad1248a66b33d4cb8 Signed-off-by: kuogee hsieh commit b1703457d0b166d30fbea0ee1147cc8bbcf478e6 Author: Derek Kulinski Date: Wed Jun 2 15:34:26 2010 -0700 msm_fb: proper order of IRQ operations for ST1.5 Ensure interrupt is requested before it's enabled during panel-on processing. Disable the interrupt before adding fb device to avoid panel-on enabling it a second time. Change-Id: I38c16c4d2fd3a2aa1e8ab4589980dd8e753f9ed5 Signed-off-by: Derek Kulinski commit 4c018c787d601ad9beadaf8ada3b2dba8c5f8e82 Author: kuogee hsieh Date: Fri Jun 11 11:26:06 2010 -0700 msm_fb: display: fix MDDI NULL function pointer bug Check function pointer before call it during parser received reverse MDDI packets. CRs-fixed: 239194 Change-Id: Ia4d371f4f4d1500b227ee6361dc5b81087e9735c Signed-off-by: Kuogee Hsieh commit 14abca9a4a199a325690aed620aa0adc659f6d86 Author: kuogee hsieh Date: Wed Jun 9 17:27:31 2010 -0700 msm_fb: display: change fb state to FBINFO_STATE_RUNNING In msm_fb_resume, changed the fb state to FBINFO_STATE_RUNNING instead of a magic number 1 (SUSPEND) after resume. In addition, change all the magic numbers to macros in suspend as well. Change-Id: I5a854293a3577522c559fd90a2dbc84a06072097 Signed-off-by: Kuogee Hsieh commit 91277807c75b4ed9844441da31d9a49c990c1334 Author: kuogee hsieh Date: Fri Jun 4 08:19:58 2010 -0700 msm_fb: display: Add FB_MSM_OVERLAY dependency Add FB_MSM_OVERLAY dependency to FB_MSM_HDMI_ADV7520_PANEL to fix compiler error when FB_MSM_OVERLAY is not defined. CRs-fixed: 240734 Change-Id: I948b2b198f69ada3dfb2eb4903363230a48935aa Signed-off-by: Kuogee Hsieh commit a54aac47e202993920fae8e9297e6bf59221b765 Author: Ajay Dudani Date: Wed Jun 2 18:40:14 2010 -0700 msm_fb: Add ST1.5 LCDC driver Change-Id: Ia592bed81e316118f4c301ad59931fb9502ce49e Signed-off-by: Ajay Dudani commit 2c970e38fe13d77a00323897ac62a15423996329 Author: Abhijeet Dharmapurikar Date: Tue Jun 1 13:28:42 2010 -0700 msm_fb: make 8660 backlight work with new pwm api The pwm api changed to use a callback function in the board file and to specify the pwm duty cycle and period in terms of usecs instead on nsecs. Update the 8660 display to work with it. Change-Id: Idfc67a88261ac099c50214d61ac55dbc0311d405 Signed-off-by: Abhijeet Dharmapurikar commit 8bbb084294c576722b05e5d941528f5cf129bffd Author: Abhijeet Dharmapurikar Date: Wed Apr 14 12:42:37 2010 -0700 msm: display: backlight intensity Update the panel driver to handle backlight intensity calls using pmic's pwm channels. Change-Id: I3c63588e5244748da5461e43f7f0831ddf635c5c Signed-off-by: Abhijeet Dharmapurikar commit d4ac1bbc8a7a10d457f5809728a481656a64da3b Author: Steve Muckle Date: Wed May 12 22:43:25 2010 -0700 video: msm: remove suspend_late, resume_early initializations The platform_driver struct does not have suspend_late or resume_early data members. Change-Id: Ice92977de598fd4bad6f607a8b1e1fc97e03b826 Signed-off-by: Steve Muckle commit f95c6bd8c07d38466c51d2c245aeaac3aac189d8 Author: Abhijeet Dharmapurikar Date: Fri Apr 2 13:11:55 2010 -0700 msm_fb: display: Add panel driver for wsvga display Add code for the Samsung's wsvga panel (part number LTS480WS-C01). It has a resolution of 1024 x 600 pixels, runs over an LVDS interface and accepts RGB666 pixel data. Change-Id: I399a0c08257a645fe205d5f3cb766e7dfbf20121 Signed-off-by: Abhijeet Dharmapurikar commit 404c2879aa60104da586011fc5504163cc5143b4 Author: Abhijeet Dharmapurikar Date: Fri Apr 2 13:48:49 2010 -0700 msm_fb: display: set mdp core clock rate from the board file Rather than hard-coding core clock's rate, set it to a value passed from the board file. If it isn't set then the mdp core clock was not meant to be set with a rate on that board. Change-Id: Ic7ca1b830a8b1bf4bedb9449e58b7f4b58424019 Signed-off-by: Abhijeet Dharmapurikar commit a3224f712002dbf029fab77d9c848de3a01bde9d Author: kuogee hsieh Date: Tue May 25 09:17:49 2010 -0700 Revert "msm_fb: display: add zorder check during overlay_set" This reverts commit a048cadbbfbf89e28802d3ce2da5c7b997c49b42. Change-Id: I1ce7311f326a99b738d32055f98879754e5b25b6 Signed-off-by: Kuogee Hsieh commit 4fa05a83d4bcc394d536cd2490c3c95e74f5fb11 Author: kuogee hsieh Date: Mon May 24 09:04:24 2010 -0700 msm_fb: display: retransmit set_backlight pmapp rpc request Re-transmit set_backlight pmapp rpc request in case of rpc failed. Change-Id: I2ed01bd7ec40da313a75d441a438491a13a875a7 CRs-fixed: 236277 Signed-off-by: Kuogee Hsieh commit a048cadbbfbf89e28802d3ce2da5c7b997c49b42 Author: kuogee hsieh Date: Thu May 13 14:25:57 2010 -0700 msm_fb: display: add zorder check during overlay_set Add zorder check to avoid same zorder using by multiple overlay pipes. CRs-fixed: 232438 Change-Id: Ia6e66aba70f01a9b77ac6f2e1c565cc16496e613 Signed-off-by: Kuogee Hsieh commit 795d1b324ee9052b0d4ee96771bc87bf61088fce Author: Abhijeet Dharmapurikar Date: Fri Apr 2 17:03:53 2010 -0700 msm_fb: lcdc: Add support for clocks on 8660 8660 has different clocks than older platforms. Update lcdc to handle 8660 clocks as well as the older clocks. Change-Id: I0b57a525205af448207a1500e23910e5c13c3738 Signed-off-by: Abhijeet Dharmapurikar commit a3ca6eef9dff1c435fc48d51bbd71edc71f7b0c0 Author: Rajesh Sastrula Date: Fri May 14 15:05:42 2010 -0700 msm_fb: display: Fix calculating brightness duty level Calculate the brightness duty level based on the maximum brightness level supported by the panel rather than from a constant value. Change-Id: I4c8d371a59e38c084bddeaa827c3982b47bbc7ee Signed-off-by: Rajesh Sastrula commit 347a643f440b0ba370830d54cb85966df18d7023 Author: Stephen Boyd Date: Thu May 13 18:23:59 2010 -0700 msm_fb: Fallback to correct clock The tv_src clock should fallback to the TV_ENC clock and not the TV_DAC clock. This was already fixed in the devices.c table but wasn't fixed in the driver. Change-Id: I9dbf17d9123d25142e8123b54b1c5856482b087b Signed-off-by: Stephen Boyd commit dc34a27a27d726d98b34046c9fa5175322d794ba Author: kuogee hsieh Date: Thu May 13 10:21:54 2010 -0700 msm_fb: display: initialize op_mode at every overlay play Re-initilize op_mode to have it update with new value according to new overlay play's configuration Change-Id: I7ee2489a93efa72e691746037bdf853d862a023b CRs-fixed: 230612 Signed-off-by: Kuogee Hsieh --- drivers/video/msm/Kconfig | 921 ++++ drivers/video/msm/Makefile | 192 + drivers/video/msm/adv7520.c | 1035 ++++ drivers/video/msm/ebi2_epson_s1d_qvga.c | 374 ++ drivers/video/msm/ebi2_host.c | 307 ++ drivers/video/msm/ebi2_l2f.c | 566 ++ drivers/video/msm/ebi2_lcd.c | 308 ++ drivers/video/msm/ebi2_tmd20.c | 1120 ++++ drivers/video/msm/external_common.c | 2103 +++++++ drivers/video/msm/external_common.h | 272 + drivers/video/msm/hdmi_msm.c | 4817 +++++++++++++++++ drivers/video/msm/hdmi_msm.h | 138 + drivers/video/msm/hdmi_sii9022.c | 245 + drivers/video/msm/lcdc.c | 289 + drivers/video/msm/lcdc_auo_wvga.c | 411 ++ drivers/video/msm/lcdc_chimei_wxga.c | 231 + drivers/video/msm/lcdc_external.c | 51 + drivers/video/msm/lcdc_gordon.c | 457 ++ drivers/video/msm/lcdc_nt35582_wvga.c | 472 ++ drivers/video/msm/lcdc_panel.c | 84 + drivers/video/msm/lcdc_prism.c | 61 + drivers/video/msm/lcdc_samsung_oled_pt.c | 588 ++ drivers/video/msm/lcdc_samsung_wsvga.c | 270 + drivers/video/msm/lcdc_sharp_wvga_pt.c | 414 ++ drivers/video/msm/lcdc_st15.c | 413 ++ drivers/video/msm/lcdc_toshiba_fwvga_pt.c | 471 ++ drivers/video/msm/lcdc_toshiba_wvga_pt.c | 519 ++ drivers/video/msm/lcdc_truly_ips3p2335.c | 305 ++ drivers/video/msm/lcdc_wxga.c | 53 + drivers/video/msm/logo.c | 103 + drivers/video/msm/lvds.c | 373 ++ drivers/video/msm/lvds_chimei_wxga.c | 167 + drivers/video/msm/mddi.c | 590 ++ drivers/video/msm/mddi_client_dummy.c | 97 + drivers/video/msm/mddi_client_nt35399.c | 251 + drivers/video/msm/mddi_client_toshiba.c | 256 + drivers/video/msm/mddi_ext.c | 354 ++ drivers/video/msm/mddi_ext_lcd.c | 90 + drivers/video/msm/mddi_hw.h | 314 ++ drivers/video/msm/mddi_orise.c | 128 + drivers/video/msm/mddi_prism.c | 112 + drivers/video/msm/mddi_quickvx.c | 719 +++ drivers/video/msm/mddi_sharp.c | 901 +++ drivers/video/msm/mddi_toshiba.c | 1753 ++++++ drivers/video/msm/mddi_toshiba.h | 37 + drivers/video/msm/mddi_toshiba_vga.c | 134 + drivers/video/msm/mddi_toshiba_wvga.c | 61 + drivers/video/msm/mddi_toshiba_wvga_pt.c | 69 + drivers/video/msm/mddihost.c | 626 +++ drivers/video/msm/mddihost.h | 231 + drivers/video/msm/mddihost_e.c | 59 + drivers/video/msm/mddihosti.c | 2268 ++++++++ drivers/video/msm/mddihosti.h | 552 ++ drivers/video/msm/mdp.c | 2701 +++++++++ drivers/video/msm/mdp.h | 840 +++ drivers/video/msm/mdp4.h | 819 +++ drivers/video/msm/mdp4_dtv.c | 326 ++ drivers/video/msm/mdp4_hsic.c | 534 ++ drivers/video/msm/mdp4_overlay.c | 3356 ++++++++++++ drivers/video/msm/mdp4_overlay_atv.c | 210 + drivers/video/msm/mdp4_overlay_dsi_cmd.c | 718 +++ drivers/video/msm/mdp4_overlay_dsi_video.c | 729 +++ drivers/video/msm/mdp4_overlay_dtv.c | 728 +++ drivers/video/msm/mdp4_overlay_lcdc.c | 621 +++ drivers/video/msm/mdp4_overlay_mddi.c | 726 +++ drivers/video/msm/mdp4_overlay_writeback.c | 596 ++ drivers/video/msm/mdp4_util.c | 3306 +++++++++++ drivers/video/msm/mdp4_wfd_writeback.c | 102 + drivers/video/msm/mdp4_wfd_writeback_panel.c | 83 + drivers/video/msm/mdp4_wfd_writeback_util.h | 28 + drivers/video/msm/mdp_csc_table.h | 641 +++ drivers/video/msm/mdp_cursor.c | 264 + drivers/video/msm/mdp_debugfs.c | 1392 +++++ drivers/video/msm/mdp_dma.c | 612 +++ drivers/video/msm/mdp_dma_dsi_video.c | 275 + drivers/video/msm/mdp_dma_lcdc.c | 377 ++ drivers/video/msm/mdp_dma_s.c | 166 + drivers/video/msm/mdp_dma_tv.c | 140 + drivers/video/msm/mdp_hw.h | 769 +++ drivers/video/msm/mdp_hw40.c | 94 + drivers/video/msm/mdp_hw_init.c | 714 +++ drivers/video/msm/mdp_lcdc.c | 432 ++ drivers/video/msm/mdp_ppp.c | 1686 ++++++ drivers/video/msm/mdp_ppp.h | 82 + drivers/video/msm/mdp_ppp22.c | 1091 ++++ drivers/video/msm/mdp_ppp31.c | 332 ++ drivers/video/msm/mdp_ppp_v20.c | 2541 +++++++++ drivers/video/msm/mdp_ppp_v31.c | 844 +++ drivers/video/msm/mdp_vsync.c | 491 ++ drivers/video/msm/mhl/mhl_8334.c | 849 +++ drivers/video/msm/mhl/mhl_8334.h | 74 + drivers/video/msm/mhl/mhl_defs.h | 222 + drivers/video/msm/mhl/mhl_devcap.h | 45 + drivers/video/msm/mhl/mhl_i2c_utils.c | 107 + drivers/video/msm/mhl/mhl_i2c_utils.h | 39 + drivers/video/msm/mhl_api.h | 26 + drivers/video/msm/mipi_NT35510.c | 609 +++ drivers/video/msm/mipi_NT35510.h | 20 + drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c | 98 + .../video/msm/mipi_NT35510_video_wvga_pt.c | 108 + drivers/video/msm/mipi_chimei_wuxga.c | 197 + drivers/video/msm/mipi_chimei_wxga_pt.c | 192 + drivers/video/msm/mipi_dsi.c | 639 +++ drivers/video/msm/mipi_dsi.h | 318 ++ drivers/video/msm/mipi_dsi_host.c | 1493 +++++ drivers/video/msm/mipi_novatek.c | 658 +++ drivers/video/msm/mipi_novatek.h | 22 + drivers/video/msm/mipi_novatek_cmd_qhd_pt.c | 100 + drivers/video/msm/mipi_novatek_video_qhd_pt.c | 97 + drivers/video/msm/mipi_orise.c | 194 + drivers/video/msm/mipi_orise.h | 21 + drivers/video/msm/mipi_orise_cmd_720p_pt.c | 96 + drivers/video/msm/mipi_orise_video_720p_pt.c | 98 + drivers/video/msm/mipi_renesas.c | 1262 +++++ drivers/video/msm/mipi_renesas.h | 21 + drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c | 157 + .../video/msm/mipi_renesas_video_fwvga_pt.c | 163 + drivers/video/msm/mipi_simulator.c | 167 + drivers/video/msm/mipi_simulator.h | 19 + drivers/video/msm/mipi_simulator_video.c | 86 + drivers/video/msm/mipi_tc358764_dsi2lvds.c | 997 ++++ drivers/video/msm/mipi_tc358764_dsi2lvds.h | 21 + drivers/video/msm/mipi_toshiba.c | 355 ++ drivers/video/msm/mipi_toshiba.h | 30 + .../video/msm/mipi_toshiba_video_wsvga_pt.c | 105 + drivers/video/msm/mipi_toshiba_video_wuxga.c | 98 + .../video/msm/mipi_toshiba_video_wvga_pt.c | 106 + drivers/video/msm/mipi_truly.c | 259 + drivers/video/msm/mipi_truly.h | 21 + drivers/video/msm/mipi_truly_tft540960_1_e.c | 817 +++ drivers/video/msm/mipi_truly_tft540960_1_e.h | 20 + .../msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c | 98 + .../mipi_truly_tft540960_1_e_video_qhd_pt.c | 107 + drivers/video/msm/mipi_truly_video_wvga_pt.c | 108 + drivers/video/msm/msm_dss_io_7x27a.c | 470 ++ drivers/video/msm/msm_dss_io_8960.c | 830 +++ drivers/video/msm/msm_dss_io_8x60.c | 690 +++ drivers/video/msm/msm_fb.c | 3771 +++++++++++++ drivers/video/msm/msm_fb.h | 223 + drivers/video/msm/msm_fb_bl.c | 75 + drivers/video/msm/msm_fb_def.h | 204 + drivers/video/msm/msm_fb_panel.c | 148 + drivers/video/msm/msm_fb_panel.h | 213 + drivers/video/msm/tvenc.c | 522 ++ drivers/video/msm/tvenc.h | 129 + drivers/video/msm/tvout_msm.c | 652 +++ 146 files changed, 76364 insertions(+) create mode 100644 drivers/video/msm/Kconfig create mode 100644 drivers/video/msm/Makefile create mode 100644 drivers/video/msm/adv7520.c create mode 100644 drivers/video/msm/ebi2_epson_s1d_qvga.c create mode 100644 drivers/video/msm/ebi2_host.c create mode 100644 drivers/video/msm/ebi2_l2f.c create mode 100644 drivers/video/msm/ebi2_lcd.c create mode 100644 drivers/video/msm/ebi2_tmd20.c create mode 100644 drivers/video/msm/external_common.c create mode 100644 drivers/video/msm/external_common.h create mode 100644 drivers/video/msm/hdmi_msm.c create mode 100644 drivers/video/msm/hdmi_msm.h create mode 100644 drivers/video/msm/hdmi_sii9022.c create mode 100644 drivers/video/msm/lcdc.c create mode 100644 drivers/video/msm/lcdc_auo_wvga.c create mode 100644 drivers/video/msm/lcdc_chimei_wxga.c create mode 100644 drivers/video/msm/lcdc_external.c create mode 100644 drivers/video/msm/lcdc_gordon.c create mode 100644 drivers/video/msm/lcdc_nt35582_wvga.c create mode 100644 drivers/video/msm/lcdc_panel.c create mode 100644 drivers/video/msm/lcdc_prism.c create mode 100644 drivers/video/msm/lcdc_samsung_oled_pt.c create mode 100644 drivers/video/msm/lcdc_samsung_wsvga.c create mode 100644 drivers/video/msm/lcdc_sharp_wvga_pt.c create mode 100644 drivers/video/msm/lcdc_st15.c create mode 100644 drivers/video/msm/lcdc_toshiba_fwvga_pt.c create mode 100644 drivers/video/msm/lcdc_toshiba_wvga_pt.c create mode 100644 drivers/video/msm/lcdc_truly_ips3p2335.c create mode 100644 drivers/video/msm/lcdc_wxga.c create mode 100644 drivers/video/msm/logo.c create mode 100644 drivers/video/msm/lvds.c create mode 100644 drivers/video/msm/lvds_chimei_wxga.c create mode 100644 drivers/video/msm/mddi.c create mode 100644 drivers/video/msm/mddi_client_dummy.c create mode 100644 drivers/video/msm/mddi_client_nt35399.c create mode 100644 drivers/video/msm/mddi_client_toshiba.c create mode 100644 drivers/video/msm/mddi_ext.c create mode 100644 drivers/video/msm/mddi_ext_lcd.c create mode 100644 drivers/video/msm/mddi_hw.h create mode 100644 drivers/video/msm/mddi_orise.c create mode 100644 drivers/video/msm/mddi_prism.c create mode 100644 drivers/video/msm/mddi_quickvx.c create mode 100644 drivers/video/msm/mddi_sharp.c create mode 100644 drivers/video/msm/mddi_toshiba.c create mode 100644 drivers/video/msm/mddi_toshiba.h create mode 100644 drivers/video/msm/mddi_toshiba_vga.c create mode 100644 drivers/video/msm/mddi_toshiba_wvga.c create mode 100644 drivers/video/msm/mddi_toshiba_wvga_pt.c create mode 100644 drivers/video/msm/mddihost.c create mode 100644 drivers/video/msm/mddihost.h create mode 100644 drivers/video/msm/mddihost_e.c create mode 100644 drivers/video/msm/mddihosti.c create mode 100644 drivers/video/msm/mddihosti.h create mode 100644 drivers/video/msm/mdp.c create mode 100644 drivers/video/msm/mdp.h create mode 100644 drivers/video/msm/mdp4.h create mode 100644 drivers/video/msm/mdp4_dtv.c create mode 100644 drivers/video/msm/mdp4_hsic.c create mode 100644 drivers/video/msm/mdp4_overlay.c create mode 100644 drivers/video/msm/mdp4_overlay_atv.c create mode 100644 drivers/video/msm/mdp4_overlay_dsi_cmd.c create mode 100644 drivers/video/msm/mdp4_overlay_dsi_video.c create mode 100644 drivers/video/msm/mdp4_overlay_dtv.c create mode 100644 drivers/video/msm/mdp4_overlay_lcdc.c create mode 100644 drivers/video/msm/mdp4_overlay_mddi.c create mode 100644 drivers/video/msm/mdp4_overlay_writeback.c create mode 100644 drivers/video/msm/mdp4_util.c create mode 100644 drivers/video/msm/mdp4_wfd_writeback.c create mode 100644 drivers/video/msm/mdp4_wfd_writeback_panel.c create mode 100644 drivers/video/msm/mdp4_wfd_writeback_util.h create mode 100644 drivers/video/msm/mdp_csc_table.h create mode 100644 drivers/video/msm/mdp_cursor.c create mode 100644 drivers/video/msm/mdp_debugfs.c create mode 100644 drivers/video/msm/mdp_dma.c create mode 100644 drivers/video/msm/mdp_dma_dsi_video.c create mode 100644 drivers/video/msm/mdp_dma_lcdc.c create mode 100644 drivers/video/msm/mdp_dma_s.c create mode 100644 drivers/video/msm/mdp_dma_tv.c create mode 100644 drivers/video/msm/mdp_hw.h create mode 100644 drivers/video/msm/mdp_hw40.c create mode 100644 drivers/video/msm/mdp_hw_init.c create mode 100644 drivers/video/msm/mdp_lcdc.c create mode 100644 drivers/video/msm/mdp_ppp.c create mode 100644 drivers/video/msm/mdp_ppp.h create mode 100644 drivers/video/msm/mdp_ppp22.c create mode 100644 drivers/video/msm/mdp_ppp31.c create mode 100644 drivers/video/msm/mdp_ppp_v20.c create mode 100644 drivers/video/msm/mdp_ppp_v31.c create mode 100644 drivers/video/msm/mdp_vsync.c create mode 100644 drivers/video/msm/mhl/mhl_8334.c create mode 100644 drivers/video/msm/mhl/mhl_8334.h create mode 100644 drivers/video/msm/mhl/mhl_defs.h create mode 100644 drivers/video/msm/mhl/mhl_devcap.h create mode 100644 drivers/video/msm/mhl/mhl_i2c_utils.c create mode 100644 drivers/video/msm/mhl/mhl_i2c_utils.h create mode 100644 drivers/video/msm/mhl_api.h create mode 100644 drivers/video/msm/mipi_NT35510.c create mode 100644 drivers/video/msm/mipi_NT35510.h create mode 100644 drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c create mode 100644 drivers/video/msm/mipi_NT35510_video_wvga_pt.c create mode 100644 drivers/video/msm/mipi_chimei_wuxga.c create mode 100644 drivers/video/msm/mipi_chimei_wxga_pt.c create mode 100644 drivers/video/msm/mipi_dsi.c create mode 100644 drivers/video/msm/mipi_dsi.h create mode 100644 drivers/video/msm/mipi_dsi_host.c create mode 100644 drivers/video/msm/mipi_novatek.c create mode 100644 drivers/video/msm/mipi_novatek.h create mode 100644 drivers/video/msm/mipi_novatek_cmd_qhd_pt.c create mode 100644 drivers/video/msm/mipi_novatek_video_qhd_pt.c create mode 100644 drivers/video/msm/mipi_orise.c create mode 100644 drivers/video/msm/mipi_orise.h create mode 100644 drivers/video/msm/mipi_orise_cmd_720p_pt.c create mode 100644 drivers/video/msm/mipi_orise_video_720p_pt.c create mode 100644 drivers/video/msm/mipi_renesas.c create mode 100644 drivers/video/msm/mipi_renesas.h create mode 100644 drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c create mode 100644 drivers/video/msm/mipi_renesas_video_fwvga_pt.c create mode 100644 drivers/video/msm/mipi_simulator.c create mode 100644 drivers/video/msm/mipi_simulator.h create mode 100644 drivers/video/msm/mipi_simulator_video.c create mode 100644 drivers/video/msm/mipi_tc358764_dsi2lvds.c create mode 100644 drivers/video/msm/mipi_tc358764_dsi2lvds.h create mode 100644 drivers/video/msm/mipi_toshiba.c create mode 100644 drivers/video/msm/mipi_toshiba.h create mode 100644 drivers/video/msm/mipi_toshiba_video_wsvga_pt.c create mode 100644 drivers/video/msm/mipi_toshiba_video_wuxga.c create mode 100644 drivers/video/msm/mipi_toshiba_video_wvga_pt.c create mode 100644 drivers/video/msm/mipi_truly.c create mode 100644 drivers/video/msm/mipi_truly.h create mode 100644 drivers/video/msm/mipi_truly_tft540960_1_e.c create mode 100644 drivers/video/msm/mipi_truly_tft540960_1_e.h create mode 100644 drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c create mode 100644 drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c create mode 100644 drivers/video/msm/mipi_truly_video_wvga_pt.c create mode 100644 drivers/video/msm/msm_dss_io_7x27a.c create mode 100644 drivers/video/msm/msm_dss_io_8960.c create mode 100644 drivers/video/msm/msm_dss_io_8x60.c create mode 100644 drivers/video/msm/msm_fb.c create mode 100644 drivers/video/msm/msm_fb.h create mode 100644 drivers/video/msm/msm_fb_bl.c create mode 100644 drivers/video/msm/msm_fb_def.h create mode 100644 drivers/video/msm/msm_fb_panel.c create mode 100644 drivers/video/msm/msm_fb_panel.h create mode 100644 drivers/video/msm/tvenc.c create mode 100644 drivers/video/msm/tvenc.h create mode 100644 drivers/video/msm/tvout_msm.c diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig new file mode 100644 index 000000000000..f5e3093ffeb1 --- /dev/null +++ b/drivers/video/msm/Kconfig @@ -0,0 +1,921 @@ +config FB_MSM + tristate "MSM Framebuffer support" + depends on FB && ARCH_MSM + select FB_BACKLIGHT if FB_MSM_BACKLIGHT + select NEW_LEDS + select LEDS_CLASS + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + Support for MSM Framebuffer. + +if FB_MSM + +config FB_MSM_BACKLIGHT + bool "Support for backlight control" + default y + ---help--- + Say Y here if you want to control the backlight of your display. + +config FB_MSM_LOGO + bool "MSM Frame Buffer Logo" + default n + ---help--- + Show /initlogo.rle during boot. + +config FB_MSM_LCDC_HW + bool + default n + +config FB_MSM_TRIPLE_BUFFER + bool "Support for triple frame buffer" + default n + +config FB_MSM_MDP_HW + bool + default n + +choice + prompt "MDP HW version" + default FB_MSM_MDP22 + +config FB_MSM_MDP22 + select FB_MSM_MDP_HW + bool "MDP HW ver2.2" + ---help--- + Support for MSM MDP HW revision 2.2 + Say Y here if this is msm7201 variant platform. + +config FB_MSM_MDP30 + select FB_MSM_LCDC_HW + bool "MDP HW ver3.0" + ---help--- + Support for MSM MDP HW revision 3.0 + Say Y here if this is msm7x25 variant platform. + +config FB_MSM_MDP303 + depends on FB_MSM_MDP30 + select FB_MSM_MDP_HW + bool "MDP HW ver3.03" + default n + ---help--- + Support for MSM MDP HW revision 3.03. This is a new version of + MDP3.0 which has the required functionality to support the features + required for msm7x2xA platform. + Say Y here if this is msm7x2xA variant platform. + +config FB_MSM_MDP31 + select FB_MSM_LCDC_HW + select FB_MSM_MDP_HW + bool "MDP HW ver3.1" + ---help--- + Support for MSM MDP HW revision 3.1 + Say Y here if this is msm8x50 variant platform. + +config FB_MSM_MDP40 + select FB_MSM_LCDC_HW + select FB_MSM_MDP_HW + bool "MDP HW ver4.0" + ---help--- + Support for MSM MDP HW revision 4.0 + Say Y here if this is msm7x30 variant platform. + +config FB_MSM_MDP_NONE + bool "MDP HW None" + ---help--- + Say Y here if this is mdm platform. + +endchoice + +config FB_MSM_EBI2 + bool + default n + +config FB_MSM_MDDI + bool + default n + +config FB_MSM_MIPI_DSI + bool + default n + +config FB_MSM_LCDC + bool + default n + +config FB_MSM_LVDS + bool + default n + +config FB_MSM_OVERLAY + depends on FB_MSM_MDP40 && ANDROID_PMEM + bool "MDP4 overlay support" + default n + +config FB_MSM_DTV + depends on FB_MSM_OVERLAY + bool + default n + +config FB_MSM_EXTMDDI + bool + default n + +config FB_MSM_TVOUT + bool + default n + +config FB_MSM_MDDI_TOSHIBA_COMMON + bool + select FB_MSM_MDDI + default n + +config FB_MSM_MDDI_TOSHIBA_COMMON_VGA + bool + select FB_MSM_MDDI_TOSHIBA_COMMON + default n + +config FB_MSM_MDDI_ORISE + bool + select FB_MSM_MDDI + default n + +config FB_MSM_MDDI_QUICKVX + bool + select FB_MSM_MDDI + default n + +config FB_MSM_MDDI_AUTO_DETECT + bool + select FB_MSM_MDDI + default n + +config FB_MSM_LCDC_AUTO_DETECT + bool + select FB_MSM_LCDC + default n + +config FB_MSM_LCDC_PANEL + bool + select FB_MSM_LCDC + default n + +config FB_MSM_MIPI_DSI_TOSHIBA + bool + select FB_MSM_MIPI_DSI + default n + +config FB_MSM_MIPI_DSI_RENESAS + bool + select FB_MSM_MIPI_DSI + default n + +config FB_MSM_MIPI_DSI_TRULY + bool + select FB_MSM_MIPI_DSI + +config FB_MSM_MIPI_DSI_SIMULATOR + bool + select FB_MSM_MIPI_DSI + default n + +config FB_MSM_MIPI_DSI_NOVATEK + bool + select FB_MSM_MIPI_DSI + default n + +config FB_MSM_MIPI_DSI_NT35510 + bool + select FB_MSM_MIPI_DSI + +config FB_MSM_MIPI_DSI_ORISE + bool + select FB_MSM_MIPI_DSI + default n + +config FB_MSM_MIPI_DSI_NT35516 + bool + select FB_MSM_MIPI_DSI + +config FB_MSM_MIPI_DSI_TC358764_DSI2LVDS + bool + select FB_MSM_MIPI_DSI + ---help--- + Support for Toshiba MIPI DSI-to-LVDS bridge. + The chip supports 1366x768 24-bit + using a single LVDS link + and up to WUXGA 1920x1200 18-bit + using a dual LVDS link. + +config FB_MSM_LCDC_ST15_WXGA + bool + select FB_MSM_LCDC_PANEL + default n + +config FB_MSM_LCDC_ST15_PANEL + depends on FB_MSM_LCDC_HW + bool "LCDC ST1.5 Panel" + select FB_MSM_LCDC_ST15_WXGA + ---help--- + Support for ST1.5 WXGA (1366x768) panel + +config FB_MSM_LCDC_PRISM_WVGA + bool + select FB_MSM_LCDC_PANEL + default n + +config FB_MSM_LCDC_SAMSUNG_WSVGA + bool + select FB_MSM_LCDC_PANEL + default n + +config FB_MSM_LCDC_CHIMEI_WXGA + bool + select FB_MSM_LCDC_PANEL + default n + +config FB_MSM_LCDC_GORDON_VGA + bool + select FB_MSM_LCDC_PANEL + default n + +config FB_MSM_LCDC_TOSHIBA_WVGA_PT + bool + select FB_MSM_LCDC_PANEL + default n + +config FB_MSM_LCDC_TOSHIBA_FWVGA_PT + bool + select FB_MSM_LCDC_PANEL + default n + +config FB_MSM_LCDC_SHARP_WVGA_PT + bool + select FB_MSM_LCDC_PANEL + default n + +config FB_MSM_LCDC_AUO_WVGA + bool + select FB_MSM_LCDC_PANEL + default n + +config FB_MSM_LCDC_TRULY_HVGA_IPS3P2335 + bool + select FB_MSM_LCDC_PANEL + default n + +config FB_MSM_LCDC_TRULY_HVGA_IPS3P2335_PT_PANEL + depends on FB_MSM_LCDC_HW + bool "LCDC Truly HVGA PT Panel" + select FB_MSM_LCDC_TRULY_HVGA_IPS3P2335 + default n + ---help--- + Support for LCDC Truly HVGA PT panel + + +config FB_MSM_LCDC_SAMSUNG_OLED_PT + bool + select FB_MSM_LCDC_PANEL + default n + +config FB_MSM_LCDC_NT35582_WVGA + bool + select FB_MSM_LCDC_PANEL + default n + +config FB_MSM_LCDC_WXGA + bool + select FB_MSM_LCDC_PANEL + default n + +config FB_MSM_LVDS_CHIMEI_WXGA + bool + select FB_MSM_LVDS + default n + +config FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT + bool + select FB_MSM_MIPI_DSI_TOSHIBA + default n + +config FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT + bool + select FB_MSM_MIPI_DSI_TOSHIBA + default n + +config FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA + bool + select FB_MSM_MIPI_DSI_TOSHIBA + default n + +config FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT + bool + select FB_MSM_MIPI_DSI_NOVATEK + default n + +config FB_MSM_MIPI_NOVATEK_CMD_QHD_PT + bool + select FB_MSM_MIPI_DSI_NOVATEK + default n + +config FB_MSM_MIPI_ORISE_VIDEO_720P_PT + bool + select FB_MSM_MIPI_DSI_ORISE + default n + +config FB_MSM_MIPI_ORISE_CMD_720P_PT + bool + select FB_MSM_MIPI_DSI_ORISE + default n + +config FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT + bool + select FB_MSM_MIPI_DSI_RENESAS + default n + +config FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT + bool + select FB_MSM_MIPI_DSI_RENESAS + default n + +config FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT + bool + select FB_MSM_MIPI_DSI_NT35510 + default n + +config FB_MSM_MIPI_NT35510_CMD_WVGA_PT + bool + select FB_MSM_MIPI_DSI_NT35510 + default n + +config FB_MSM_MIPI_NT35516_VIDEO_QHD_PT + bool + select FB_MSM_MIPI_DSI_NT35516 + default n + +config FB_MSM_MIPI_NT35516_CMD_QHD_PT + bool + select FB_MSM_MIPI_DSI_NT35516 + default n + + +config FB_MSM_MIPI_CHIMEI_WXGA + bool "LVDS Chimei WXGA Panel using Toshiba MIPI DSI-to-LVDS bridge." + select FB_MSM_MIPI_DSI_TC358764_DSI2LVDS + ---help--- + Support for Chimei WXGA (1366x768) panel. + The panel is using a serial LVDS input. + The panel is connected to the host + via Toshiba DSI-to-LVDS bridge. + +config FB_MSM_MIPI_CHIMEI_WUXGA + bool "LVDS Chimei WUXGA Panel using Toshiba MIPI DSI-to-LVDS bridge." + select FB_MSM_MIPI_DSI_TC358764_DSI2LVDS + ---help--- + Support for Chimei WUXGA (1920x1200) panel. + The panel is using a serial LVDS input. + The panel is connected to the host + via Toshiba DSI-to-LVDS bridge. + +config FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT + bool + select FB_MSM_MIPI_DSI_TRULY + +config FB_MSM_MIPI_SIMULATOR_VIDEO + bool + select FB_MSM_MIPI_DSI_SIMULATOR + default n + +config FB_MSM_OVERLAY0_WRITEBACK + depends on FB_MSM_OVERLAY + bool "MDP overlay0 write back mode enable" + ---help--- + Support for MDP4 OVERLAY0 write back mode + + +config FB_MSM_OVERLAY1_WRITEBACK + depends on FB_MSM_OVERLAY + bool "MDP overlay1 write back mode enable" + ---help--- + Support for MDP4 OVERLAY1 write back mode + +config FB_MSM_WRITEBACK_MSM_PANEL + depends on FB_MSM_OVERLAY + bool "MDP overlay write back panel enable" + ---help--- + Support for MDP4 OVERLAY write back mode +choice + prompt "LCD Panel" + default FB_MSM_MDDI_AUTO_DETECT + +config FB_MSM_LCDC_PRISM_WVGA_PANEL + depends on FB_MSM_LCDC_HW + bool "LCDC Prism WVGA Panel" + select FB_MSM_LCDC_PRISM_WVGA + ---help--- + Support for LCDC Prism WVGA (800x480) panel + +config FB_MSM_LCDC_SAMSUNG_WSVGA_PANEL + depends on FB_MSM_LCDC_HW + bool "LCDC Samsung WSVGA Panel" + select FB_MSM_LCDC_SAMSUNG_WSVGA + ---help--- + Support for LCDC Samsung WSVGA (1024x600) panel + +config FB_MSM_LCDC_CHIMEI_WXGA_PANEL + depends on FB_MSM_LCDC_HW + bool "LCDC Chimei WXGA Panel" + select FB_MSM_LCDC_CHIMEI_WXGA + ---help--- + Support for LCDC Chimei WXGA (1366x768) panel + +config FB_MSM_LCDC_GORDON_VGA_PANEL + depends on FB_MSM_LCDC_HW + bool "LCDC Gordon VGA Panel" + select FB_MSM_LCDC_GORDON_VGA + ---help--- + Support for LCDC Gordon VGA (480x640) panel + +config FB_MSM_LCDC_TOSHIBA_WVGA_PT_PANEL + depends on FB_MSM_LCDC_HW + bool "LCDC Toshiba WVGA PT Panel" + select FB_MSM_LCDC_TOSHIBA_WVGA_PT + ---help--- + Support for LCDC Toshiba WVGA PT (480x800) panel + +config FB_MSM_LCDC_TOSHIBA_FWVGA_PT_PANEL + depends on FB_MSM_LCDC_HW + bool "LCDC Toshiba FWVGA PT Panel" + select FB_MSM_LCDC_TOSHIBA_FWVGA_PT + ---help--- + Support for LCDC Toshiba FWVGA PT (480x864) panel. This + configuration has to be selected to support the Toshiba + FWVGA (480x864) portrait panel. + +config FB_MSM_LCDC_SHARP_WVGA_PT_PANEL + depends on FB_MSM_LCDC_HW + bool "LCDC Sharp WVGA PT Panel" + select FB_MSM_LCDC_SHARP_WVGA_PT + ---help--- + Support for LCDC Sharp WVGA PT (480x800) panel + +config FB_MSM_LCDC_AUO_WVGA_PANEL + depends on FB_MSM_LCDC_HW + bool "LCDC AUO WVGA Panel" + select FB_MSM_LCDC_AUO_WVGA + ---help--- + Support for LCDC AUO WVGA(480x800) panel + +config FB_MSM_LCDC_NT35582_PANEL + depends on FB_MSM_LCDC_HW + bool "LCDC NT35582 WVGA Panel" + select FB_MSM_LCDC_NT35582_WVGA + ---help--- + Support for LCDC NT35582 WVGA(480x800) panel + +config FB_MSM_LCDC_SAMSUNG_OLED_PT_PANEL + depends on FB_MSM_LCDC_HW + bool "LCDC Samsung OLED PT Panel" + select FB_MSM_LCDC_SAMSUNG_OLED_PT + ---help--- + Support for LCDC Samsung OLED PT (480x800) panel + +config FB_MSM_LVDS_CHIMEI_WXGA_PANEL + bool "LVDS Chimei WXGA Panel" + select FB_MSM_LVDS_CHIMEI_WXGA + ---help--- + Support for LVDS Chimei WXGA(1366x768) panel + +config FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM + depends on FB_MSM_LCDC_HW + bool "MDDI Panel Auto Detect + LCDC Prism WVGA" + select FB_MSM_MDDI_AUTO_DETECT + select FB_MSM_LCDC_PRISM_WVGA + select FB_MSM_LCDC_GORDON_VGA + select FB_MSM_LCDC_WXGA + select FB_MSM_LCDC_TOSHIBA_WVGA_PT + select FB_MSM_LCDC_TOSHIBA_FWVGA_PT + select FB_MSM_LCDC_SHARP_WVGA_PT + select FB_MSM_LCDC_ST15_WXGA + ---help--- + Support for MDDI panel auto detect. + If it can't find any MDDI panel, it will load an LCDC panel. + +config FB_MSM_MIPI_PANEL_DETECT + bool "MIPI Panel Detect" + select FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT + select FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT + select FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA + select FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT + select FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT + select FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT + select FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT + select FB_MSM_MIPI_NOVATEK_CMD_QHD_PT + select FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT + select FB_MSM_MIPI_NT35510_CMD_WVGA_PT + select FB_MSM_MIPI_ORISE_VIDEO_720P_PT + select FB_MSM_MIPI_ORISE_CMD_720P_PT + select FB_MSM_MIPI_NT35516_VIDEO_QHD_PT + select FB_MSM_MIPI_NT35516_CMD_QHD_PT + select FB_MSM_MIPI_SIMULATOR_VIDEO + select FB_MSM_MIPI_CHIMEI_WXGA + select FB_MSM_MIPI_CHIMEI_WUXGA + ---help--- + Support for MIPI panel auto detect + +config FB_MSM_MDDI_PANEL_AUTO_DETECT + bool "MDDI Panel Auto Detect" + select FB_MSM_MDDI_AUTO_DETECT + ---help--- + Support for MDDI panel auto detect + +config FB_MSM_LCDC_PANEL_AUTO_DETECT + bool "LCDC Panel Auto Detect" + select FB_MSM_LCDC_AUTO_DETECT + select FB_MSM_LCDC_SAMSUNG_WSVGA + select FB_MSM_LCDC_AUO_WVGA + select FB_MSM_LCDC_NT35582_WVGA + select FB_MSM_LCDC_SAMSUNG_OLED_PT + ---help--- + Support for LCDC panel auto detect + +config FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT + bool "LCDC + MIPI Panel Auto Detect" + select FB_MSM_LCDC_AUTO_DETECT + select FB_MSM_LCDC_SAMSUNG_WSVGA + select FB_MSM_LCDC_AUO_WVGA + select FB_MSM_LCDC_SAMSUNG_OLED_PT + select FB_MSM_LCDC_NT35582_WVGA + select FB_MSM_LCDC_TOSHIBA_FWVGA_PT + select FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT + select FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT + select FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT + select FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT + select FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT + select FB_MSM_MIPI_NOVATEK_CMD_QHD_PT + select FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT + select FB_MSM_MIPI_NT35510_CMD_WVGA_PT + select FB_MSM_MIPI_NT35516_VIDEO_QHD_PT + select FM_MSM_MIPI_NT35516_CMD_QHD_PT + select FB_MSM_MIPI_SIMULATOR_VIDEO + ---help--- + Support for LCDC + MIPI panel auto detect + +config FB_MSM_LVDS_MIPI_PANEL_DETECT + bool "LVDS + MIPI Panel Auto Detect" + select FB_MSM_LVDS_CHIMEI_WXGA + select FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT + select FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT + select FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA + select FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT + select FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT + select FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT + select FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT + select FB_MSM_MIPI_NOVATEK_CMD_QHD_PT + select FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT + select FB_MSM_MIPI_NT35510_CMD_WVGA_PT + select FB_MSM_MIPI_ORISE_VIDEO_720P_PT + select FB_MSM_MIPI_ORISE_CMD_720P_PT + select FB_MSM_MIPI_SIMULATOR_VIDEO + select FB_MSM_MIPI_CHIMEI_WXGA + select FB_MSM_MIPI_CHIMEI_WUXGA + ---help--- + Support for LVDS + MIPI panel auto detect + +config FB_MSM_MDDI_PRISM_WVGA + bool "MDDI Prism WVGA Panel" + select FB_MSM_MDDI + ---help--- + Support for MDDI Prism WVGA (800x480) panel + +config FB_MSM_MDDI_TOSHIBA_WVGA_PORTRAIT + bool "MDDI Toshiba WVGA Portrait Panel" + select FB_MSM_MDDI_TOSHIBA_COMMON + ---help--- + Support for MDDI Toshiba WVGA (480x800) panel + +config FB_MSM_MDDI_TOSHIBA_VGA + bool "MDDI Toshiba VGA Panel" + select FB_MSM_MDDI_TOSHIBA_COMMON_VGA + ---help--- + Support for MDDI Toshiba VGA (480x640) and QCIF (176x220) panel + +config FB_MSM_MDDI_TOSHIBA_WVGA + bool "MDDI Toshiba WVGA panel" + select FB_MSM_MDDI_TOSHIBA_COMMON + ---help--- + Support for MDDI Toshiba (800x480) WVGA panel + +config FB_MSM_MDDI_SHARP_QVGA_128x128 + bool "MDDI Sharp QVGA Dual Panel" + select FB_MSM_MDDI + ---help--- + Support for MDDI Sharp QVGA (240x320) and 128x128 dual panel + +config FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT_PANEL + bool "MIPI Toshiba WVGA PT Panel" + select FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT + +config FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT_PANEL + bool "MIPI Toshiba WSVGA PT Panel" + select FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT + +config FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA_PANEL + bool "MIPI Toshiba WUXGA (1920x1200) Panel" + select FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA + +config FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT_PANEL + bool "MIPI NOVATEK VIDEO QHD PT Panel" + select FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT + +config FB_MSM_MIPI_NOVATEK_CMD_QHD_PT_PANEL + bool "MIPI NOVATEK CMD QHD PT Panel" + select FB_MSM_MIPI_NOVATEK_CMD_QHD_PT + +config FB_MSM_MIPI_ORISE_VIDEO_720P_PT_PANEL + bool "MIPI ORISE VIDEO 720P PT Panel" + select FB_MSM_MIPI_ORISE_VIDEO_720P_PT + +config FB_MSM_MIPI_ORISE_CMD_720P_PT_PANEL + bool "MIPI ORISE CMD 720P PT Panel" + select FB_MSM_MIPI_ORISE_CMD_720P_PT + +config FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT_PANEL + bool "MIPI Renesas Video FWVGA PT Panel" + select FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT + +config FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT_PANEL + bool "MIPI Renesas Command FWVGA PT Panel" + select FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT + +config FB_MSM_MIPI_CHIMEI_WXGA_PANEL + bool "MIPI Chimei WXGA PT Panel" + select FB_MSM_MIPI_CHIMEI_WXGA + +config FB_MSM_MIPI_CHIMEI_WUXGA_PANEL + bool "MIPI Chimei WUXGA Panel" + select FB_MSM_MIPI_CHIMEI_WUXGA + +config FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT_PANEL + bool "MIPI Truly Video WVGA PT Panel" + select FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT + +config FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT_PANEL + bool "MIPI NT35510 Video WVGA PT Panel" + select FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT + +config FB_MSM_MIPI_NT35510_CMD_WVGA_PT_PANEL + bool "MIPI NT35510 Command WVGA PT Panel" + select FB_MSM_MIPI_NT35510_CMD_WVGA_PT + +config FB_MSM_MIPI_NT35516_VIDEO_QHD_PT_PANEL + bool "MIPI NT35516 Video qHD PT Panel" + select FB_MSM_MIPI_NT35516_VIDEO_QHD_PT + +config FB_MSM_MIPI_NT35516_CMD_QHD_PT_PANEL + bool "MIPI NT35516 Command qHD PT Panel" + select FB_MSM_MIPI_NT35516_CMD_QHD_PT + +config FB_MSM_MIPI_SIMULATOR_VIDEO_PANEL + bool "MIPI Simulator Video Panel" + select FB_MSM_MIPI_SIMULATOR_VIDEO + +config FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF + bool "EBI2 TMD QVGA Epson QCIF Dual Panel" + select FB_MSM_EBI2 + ---help--- + Support for EBI2 TMD QVGA (240x320) and Epson QCIF (176x220) panel + +config FB_MSM_HDMI_AS_PRIMARY + depends on FB_MSM_HDMI_COMMON + bool "Use HDMI as primary panel" + ---help--- + Support for using HDMI as primary + +config FB_MSM_PANEL_NONE + bool "NONE" + ---help--- + This will disable LCD panel +endchoice + +choice + prompt "Secondary LCD Panel" + depends on FB_MSM_MDP31 + default FB_MSM_SECONDARY_PANEL_NONE + +config FB_MSM_LCDC_EXTERNAL_WXGA + depends on FB_MSM_MDP31 + bool "External WXGA on LCDC" + select FB_MSM_LCDC_PANEL + ---help--- + Support for external WXGA display (1280x720) + +config FB_MSM_HDMI_SII_EXTERNAL_720P + depends on FB_MSM_MDP31 + bool "External SiI9022 HDMI 720P" + select FB_MSM_LCDC_PANEL + ---help--- + Support for external HDMI 720p display (1280x720p) + Using SiI9022 chipset + +config FB_MSM_SECONDARY_PANEL_NONE + bool "NONE" + ---help--- + No secondary panel +endchoice + +config FB_MSM_LCDC_DSUB + depends on FB_MSM_LCDC_SAMSUNG_WSVGA && FB_MSM_MDP40 && FB_MSM_LCDC_HW + bool "External DSUB support" + default n + ---help--- + Support for external DSUB (VGA) display up to 1440x900. The DSUB + display shares the same video bus as the primary LCDC attached display. + Typically only one of the two displays can be used at one time. + +config FB_MSM_EXT_INTERFACE_COMMON + bool + default n + +config FB_MSM_HDMI_COMMON + bool + default n + +config FB_MSM_HDMI_3D + bool + default n + +config FB_MSM_HDMI_ADV7520_PANEL + depends on FB_MSM_MDP40 && FB_MSM_OVERLAY + bool "LCDC HDMI ADV7520 720p Panel" + select FB_MSM_DTV + select FB_MSM_EXT_INTERFACE_COMMON + select FB_MSM_HDMI_COMMON + default n + ---help--- + Support for LCDC 720p HDMI panel attached to ADV7520 + +config FB_MSM_HDMI_ADV7520_PANEL_HDCP_SUPPORT + depends on FB_MSM_HDMI_ADV7520_PANEL + bool "Use HDCP mode" + default y + ---help--- + Support for HDCP mode for ADV7520 HDMI 720p Panel + Choose to enable HDCP + + +config FB_MSM_HDMI_MSM_PANEL + depends on FB_MSM_MDP40 + bool "MSM HDMI 1080p Panel" + select FB_MSM_DTV + select FB_MSM_EXT_INTERFACE_COMMON + select FB_MSM_HDMI_COMMON + select FB_MSM_HDMI_3D + default n + ---help--- + Support for 480p/720p/1080i/1080p output through MSM HDMI + +config FB_MSM_HDMI_MSM_PANEL_DVI_SUPPORT + depends on FB_MSM_HDMI_MSM_PANEL + bool "Use DVI mode" + default n + ---help--- + Support for DVI mode for MSM HDMI 1080p Panel + +config FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + depends on FB_MSM_HDMI_MSM_PANEL + bool "Use HDCP mode" + default y + ---help--- + Support for HDCP mode for MSM HDMI 1080p Panel + Choose to enable HDCP + +config FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT + depends on FB_MSM_HDMI_MSM_PANEL + bool "Enable CEC" + default n + ---help--- + Support for HDMI CEC Feature + Choose to enable CEC + +config FB_MSM_HDMI_MHL_9244 + depends on FB_MSM_HDMI_MSM_PANEL + bool 'SI_MHL 9244 support' + default n + ---help--- + Support the HDMI to MHL conversion. + MHL (Mobile High-Definition Link) technology + uses USB connector to output HDMI content + +config FB_MSM_HDMI_MHL_8334 + depends on FB_MSM_HDMI_MSM_PANEL + bool 'SI_MHL 8334 support ' + default n + ---help--- + Support the HDMI to MHL conversion. + MHL (Mobile High-Definition Link) technology + uses USB connector to output HDMI content + +choice + depends on (FB_MSM_MDP22 || FB_MSM_MDP31 || FB_MSM_MDP40) + prompt "TVOut Region" + default FB_MSM_TVOUT_NONE + +config FB_MSM_TVOUT_NTSC_M + bool "NTSC M" + select FB_MSM_TVOUT + select FB_MSM_EXT_INTERFACE_COMMON + ---help--- + Support for NTSC M region (North American and Korea) + +config FB_MSM_TVOUT_NTSC_J + bool "NTSC J" + select FB_MSM_TVOUT + select FB_MSM_EXT_INTERFACE_COMMON + ---help--- + Support for NTSC J region (Japan) + +config FB_MSM_TVOUT_PAL_BDGHIN + bool "PAL BDGHIN" + select FB_MSM_TVOUT + select FB_MSM_EXT_INTERFACE_COMMON + ---help--- + Support for PAL BDGHIN region (Non-argentina PAL-N) + +config FB_MSM_TVOUT_PAL_M + bool "PAL M" + select FB_MSM_TVOUT + select FB_MSM_EXT_INTERFACE_COMMON + ---help--- + Support for PAL M region + +config FB_MSM_TVOUT_PAL_N + bool "PAL N" + select FB_MSM_TVOUT + select FB_MSM_EXT_INTERFACE_COMMON + ---help--- + Support for PAL N region (Argentina PAL-N) + +config FB_MSM_TVOUT_NONE + bool "NONE" + ---help--- + This will disable TV Out functionality. +endchoice + +config FB_MSM_TVOUT_SVIDEO + bool "TVOut on S-video" + depends on FB_MSM_TVOUT + default n + ---help--- + Selects whether the TVOut signal uses S-video. + Choose n for composite output. + +choice + depends on FB_MSM_MDP22 + prompt "External MDDI" + default FB_MSM_EXTMDDI_SVGA + +config FB_MSM_EXTMDDI_SVGA + bool "External MDDI SVGA" + select FB_MSM_MDDI + select FB_MSM_EXTMDDI + ---help--- + Support for MSM SVGA (800x600) external MDDI panel + +config FB_MSM_EXTMDDI_NONE + bool "NONE" + ---help--- + This will disable External MDDI functionality. +endchoice + +choice + prompt "Default framebuffer color depth" + depends on FB_MSM_MDP40 || FB_MSM_MDP31 || FB_MSM_MDP303 + default FB_MSM_DEFAULT_DEPTH_RGBA8888 + +config FB_MSM_DEFAULT_DEPTH_RGB565 + bool "16 bits per pixel (RGB565)" + +config FB_MSM_DEFAULT_DEPTH_ARGB8888 + bool "32 bits per pixel (ARGB8888)" + +config FB_MSM_DEFAULT_DEPTH_RGBA8888 + bool "32 bits per pixel (RGBA8888)" + +endchoice + +config FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL + bool "EBI2 Epson QVGA Panel" + select FB_MSM_EBI2 + default n + ---help--- + Support for EBI2 Epson QVGA (240x320) panel + +config FB_MSM_EBI2_PANEL_DETECT + bool "EBI2 Panel Detect" + select FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL + default n + ---help--- + Support for EBI2 panel auto detect +endif diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile new file mode 100644 index 000000000000..0a37cf3a78ae --- /dev/null +++ b/drivers/video/msm/Makefile @@ -0,0 +1,192 @@ +obj-y := msm_fb.o + +obj-$(CONFIG_FB_MSM_LOGO) += logo.o +obj-$(CONFIG_FB_BACKLIGHT) += msm_fb_bl.o + +ifeq ($(CONFIG_FB_MSM_MDP_HW),y) + +# MDP +obj-y += mdp.o + +obj-$(CONFIG_DEBUG_FS) += mdp_debugfs.o + +ifeq ($(CONFIG_FB_MSM_MDP40),y) +obj-y += mdp4_util.o +obj-y += mdp4_hsic.o +else +obj-y += mdp_hw_init.o +obj-y += mdp_ppp.o +ifeq ($(CONFIG_FB_MSM_MDP31),y) +obj-y += mdp_ppp_v31.o +else +obj-y += mdp_ppp_v20.o +endif +endif + +ifeq ($(CONFIG_FB_MSM_OVERLAY),y) +obj-y += mdp4_overlay.o +obj-y += mdp4_overlay_lcdc.o +ifeq ($(CONFIG_FB_MSM_MIPI_DSI),y) +obj-y += mdp4_overlay_dsi_video.o +obj-y += mdp4_overlay_dsi_cmd.o +else +obj-y += mdp4_overlay_mddi.o +endif +else +obj-y += mdp_dma_lcdc.o +endif + +obj-$(CONFIG_FB_MSM_MDP303) += mdp_dma_dsi_video.o + +ifeq ($(CONFIG_FB_MSM_DTV),y) +obj-y += mdp4_dtv.o +obj-y += mdp4_overlay_dtv.o +endif + +obj-y += mdp_dma.o +obj-y += mdp_dma_s.o +obj-y += mdp_vsync.o +obj-y += mdp_cursor.o +obj-y += mdp_dma_tv.o +obj-$(CONFIG_ARCH_MSM7X27A) += msm_dss_io_7x27a.o +obj-$(CONFIG_ARCH_MSM8X60) += msm_dss_io_8x60.o +obj-$(CONFIG_ARCH_MSM8960) += msm_dss_io_8960.o + +# EBI2 +obj-$(CONFIG_FB_MSM_EBI2) += ebi2_lcd.o + +# LCDC +obj-$(CONFIG_FB_MSM_LCDC) += lcdc.o + +# LVDS +obj-$(CONFIG_FB_MSM_LVDS) += lvds.o + +# MDDI +msm_mddi-objs := mddi.o mddihost.o mddihosti.o +obj-$(CONFIG_FB_MSM_MDDI) += msm_mddi.o + +# External MDDI +msm_mddi_ext-objs := mddihost_e.o mddi_ext.o +obj-$(CONFIG_FB_MSM_EXTMDDI) += msm_mddi_ext.o + +# MIPI gereric +msm_mipi-objs := mipi_dsi.o mipi_dsi_host.o +obj-$(CONFIG_FB_MSM_MIPI_DSI) += msm_mipi.o + +# MIPI manufacture +obj-$(CONFIG_FB_MSM_MIPI_DSI_TOSHIBA) += mipi_toshiba.o +obj-$(CONFIG_FB_MSM_MIPI_DSI_NOVATEK) += mipi_novatek.o +obj-$(CONFIG_FB_MSM_MIPI_DSI_ORISE) += mipi_orise.o +obj-$(CONFIG_FB_MSM_MIPI_DSI_RENESAS) += mipi_renesas.o +obj-$(CONFIG_FB_MSM_MIPI_DSI_TRULY) += mipi_truly.o +obj-$(CONFIG_FB_MSM_MIPI_DSI_NT35510) += mipi_NT35510.o +obj-$(CONFIG_FB_MSM_MIPI_DSI_NT35516) += mipi_truly_tft540960_1_e.o +obj-$(CONFIG_FB_MSM_MIPI_DSI_SIMULATOR) += mipi_simulator.o + +# MIPI Bridge +obj-$(CONFIG_FB_MSM_MIPI_DSI_TC358764_DSI2LVDS) += mipi_tc358764_dsi2lvds.o + +# TVEnc +obj-$(CONFIG_FB_MSM_TVOUT) += tvenc.o +ifeq ($(CONFIG_FB_MSM_OVERLAY),y) +obj-$(CONFIG_FB_MSM_TVOUT) += mdp4_overlay_atv.o +endif + +# MSM FB Panel +obj-y += msm_fb_panel.o +obj-$(CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF) += ebi2_tmd20.o +obj-$(CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF) += ebi2_l2f.o + +ifeq ($(CONFIG_FB_MSM_MDDI_AUTO_DETECT),y) +obj-y += mddi_prism.o +obj-y += mddi_toshiba.o +obj-y += mddi_toshiba_vga.o +obj-y += mddi_toshiba_wvga_pt.o +obj-y += mddi_toshiba_wvga.o +obj-y += mddi_sharp.o +obj-y += mddi_orise.o +obj-y += mddi_quickvx.o +else +obj-$(CONFIG_FB_MSM_MDDI_PRISM_WVGA) += mddi_prism.o +obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON) += mddi_toshiba.o +obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON_VGA) += mddi_toshiba_vga.o +obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA_PORTRAIT) += mddi_toshiba_wvga_pt.o +obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA) += mddi_toshiba_wvga.o +obj-$(CONFIG_FB_MSM_MDDI_SHARP_QVGA_128x128) += mddi_sharp.o +obj-$(CONFIG_FB_MSM_MDDI_ORISE) += mddi_orise.o +obj-$(CONFIG_FB_MSM_MDDI_QUICKVX) += mddi_quickvx.o +endif + +ifeq ($(CONFIG_FB_MSM_MIPI_PANEL_DETECT),y) +obj-y += mipi_toshiba_video_wvga_pt.o mipi_toshiba_video_wsvga_pt.o mipi_toshiba_video_wuxga.o +obj-y += mipi_novatek_video_qhd_pt.o mipi_novatek_cmd_qhd_pt.o +obj-y += mipi_orise_video_720p_pt.o mipi_orise_cmd_720p_pt.o +obj-y += mipi_renesas_video_fwvga_pt.o mipi_renesas_cmd_fwvga_pt.o +obj-y += mipi_NT35510_video_wvga_pt.o mipi_NT35510_cmd_wvga_pt.o +obj-y += mipi_truly_tft540960_1_e_video_qhd_pt.o mipi_truly_tft540960_1_e_cmd_qhd_pt.o +obj-y += mipi_chimei_wxga_pt.o +obj-y += mipi_chimei_wuxga.o +obj-y += mipi_truly_video_wvga_pt.o +else +obj-$(CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT) += mipi_toshiba_video_wvga_pt.o +obj-$(CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT) += mipi_toshiba_video_wsvga_pt.o +obj-$(CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA) += mipi_toshiba_video_wuxga.o +obj-$(CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT) += mipi_novatek_video_qhd_pt.o +obj-$(CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT) += mipi_orise_video_720p_pt.o +obj-$(CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT) += mipi_orise_cmd_720p_pt.o +obj-$(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT) += mipi_novatek_cmd_qhd_pt.o +obj-$(CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT) += mipi_renesas_video_fwvga_pt.o +obj-$(CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT) += mipi_renesas_cmd_fwvga_pt.o +obj-$(CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT) += mipi_renesas_video_fwvga_pt.o +obj-$(CONFIG_FB_MSM_MIPI_TRULY_VIDEO_WVGA_PT) += mipi_truly_video_wvga_pt.o +obj-$(CONFIG_FB_MSM_MIPI_NT35510_CMD_WVGA_PT) += mipi_NT35510_cmd_wvga_pt.o +obj-$(CONFIG_FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT) += mipi_NT35510_video_wvga_pt.o +obj-$(CONFIG_FB_MSM_MIPI_NT35516_CMD_QHD_PT) += mipi_truly_tft540960_1_e_cmd_qhd_pt.o +obj-$(CONFIG_FB_MSM_MIPI_NT35516_VIDEO_QHD_PT) += mipi_truly_tft540960_1_e_video_qhd_pt.o +obj-$(CONFIG_FB_MSM_MIPI_SIMULATOR_VIDEO) += mipi_simulator_video.o +obj-$(CONFIG_FB_MSM_MIPI_CHIMEI_WXGA) += mipi_chimei_wxga_pt.o +obj-$(CONFIG_FB_MSM_MIPI_CHIMEI_WUXGA) += mipi_chimei_wuxga.o +endif + +obj-$(CONFIG_FB_MSM_LCDC_PANEL) += lcdc_panel.o +obj-$(CONFIG_FB_MSM_LCDC_PRISM_WVGA) += lcdc_prism.o +obj-$(CONFIG_FB_MSM_LCDC_SAMSUNG_WSVGA) += lcdc_samsung_wsvga.o +obj-$(CONFIG_FB_MSM_LCDC_CHIMEI_WXGA) += lcdc_chimei_wxga.o +obj-$(CONFIG_FB_MSM_LCDC_NT35582_WVGA) += lcdc_nt35582_wvga.o +obj-$(CONFIG_FB_MSM_LCDC_EXTERNAL_WXGA) += lcdc_external.o +obj-$(CONFIG_FB_MSM_HDMI_SII_EXTERNAL_720P) += hdmi_sii9022.o +obj-$(CONFIG_FB_MSM_LCDC_GORDON_VGA) += lcdc_gordon.o +obj-$(CONFIG_FB_MSM_LCDC_WXGA) += lcdc_wxga.o +obj-$(CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT) += lcdc_toshiba_wvga_pt.o +obj-$(CONFIG_FB_MSM_LCDC_TOSHIBA_FWVGA_PT) += lcdc_toshiba_fwvga_pt.o +obj-$(CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT) += lcdc_sharp_wvga_pt.o +obj-$(CONFIG_FB_MSM_LCDC_AUO_WVGA) += lcdc_auo_wvga.o +obj-$(CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT) += lcdc_samsung_oled_pt.o +obj-$(CONFIG_FB_MSM_HDMI_ADV7520_PANEL) += adv7520.o +obj-$(CONFIG_FB_MSM_LCDC_ST15_WXGA) += lcdc_st15.o +obj-$(CONFIG_FB_MSM_LVDS_CHIMEI_WXGA) += lvds_chimei_wxga.o +obj-$(CONFIG_FB_MSM_HDMI_MSM_PANEL) += hdmi_msm.o +obj-$(CONFIG_FB_MSM_EXT_INTERFACE_COMMON) += external_common.o +obj-$(CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335) += lcdc_truly_ips3p2335.o + +obj-$(CONFIG_FB_MSM_TVOUT) += tvout_msm.o + +ccflags-y := -I$(src)/mhl +obj-$(CONFIG_FB_MSM_HDMI_MHL_8334) += mhl-8334.o +mhl-8334-objs += mhl/mhl_8334.o +mhl-8334-objs += mhl/mhl_i2c_utils.o + +obj-$(CONFIG_FB_MSM_EXTMDDI_SVGA) += mddi_ext_lcd.o + +obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += mdp4_wfd_writeback_panel.o +obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += mdp4_wfd_writeback.o +obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += mdp4_overlay_writeback.o +else +obj-$(CONFIG_FB_MSM_EBI2) += ebi2_host.o +obj-$(CONFIG_FB_MSM_EBI2) += ebi2_lcd.o +obj-y += msm_fb_panel.o +obj-$(CONFIG_FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL) += ebi2_epson_s1d_qvga.o +endif + +clean: + rm *.o .*cmd diff --git a/drivers/video/msm/adv7520.c b/drivers/video/msm/adv7520.c new file mode 100644 index 000000000000..2ac22de838a5 --- /dev/null +++ b/drivers/video/msm/adv7520.c @@ -0,0 +1,1035 @@ +/* Copyright (c) 2010,2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "msm_fb.h" + +#define DEBUG +#define DEV_DBG_PREFIX "HDMI: " + +#include "external_common.h" + +/* #define PORT_DEBUG */ +/* #define TESTING_FORCE_480p */ + +#define HPD_DUTY_CYCLE 4 /*secs*/ + +static struct external_common_state_type hdmi_common; + +static struct i2c_client *hclient; +static struct clk *tv_enc_clk; + +static bool chip_power_on = FALSE; /* For chip power on/off */ +static bool enable_5v_on = FALSE; +static bool hpd_power_on = FALSE; +static atomic_t comm_power_on; /* For dtv power on/off (I2C) */ +static int suspend_count; + +static u8 reg[256]; /* HDMI panel registers */ + +struct hdmi_data { + struct msm_hdmi_platform_data *pd; + struct work_struct isr_work; +}; +static struct hdmi_data *dd; +static struct work_struct hpd_timer_work; + +#ifdef CONFIG_FB_MSM_HDMI_ADV7520_PANEL_HDCP_SUPPORT +static struct work_struct hdcp_handle_work; +static int hdcp_activating; +static DEFINE_MUTEX(hdcp_state_mutex); +static int has_hdcp_hw_support = true; +#endif + +static struct timer_list hpd_timer; +static struct timer_list hpd_duty_timer; +static struct work_struct hpd_duty_work; +static unsigned int monitor_sense; +static boolean hpd_cable_chg_detected; + +static struct pm_qos_request pm_qos_req; + +/* Change HDMI state */ +static void change_hdmi_state(int online) +{ + if (!external_common_state) + return; + + mutex_lock(&external_common_state_hpd_mutex); + external_common_state->hpd_state = online; + mutex_unlock(&external_common_state_hpd_mutex); + + if (!external_common_state->uevent_kobj) + return; + + if (online) { + kobject_uevent(external_common_state->uevent_kobj, + KOBJ_ONLINE); + switch_set_state(&external_common_state->sdev, 1); + } else { + kobject_uevent(external_common_state->uevent_kobj, + KOBJ_OFFLINE); + switch_set_state(&external_common_state->sdev, 0); + } + DEV_INFO("adv7520_uevent: %d [suspend# %d]\n", online, suspend_count); +} + + +/* + * Read a value from a register on ADV7520 device + * If sucessfull returns value read , otherwise error. + */ +static u8 adv7520_read_reg(struct i2c_client *client, u8 reg) +{ + int err; + struct i2c_msg msg[2]; + u8 reg_buf[] = { reg }; + u8 data_buf[] = { 0 }; + + if (!client->adapter) + return -ENODEV; + if (!atomic_read(&comm_power_on)) { + DEV_WARN("%s: WARN: missing GPIO power\n", __func__); + return -ENODEV; + } + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = reg_buf; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 1; + msg[1].buf = data_buf; + + err = i2c_transfer(client->adapter, msg, 2); + + if (err < 0) { + DEV_INFO("%s: I2C err: %d\n", __func__, err); + return err; + } + +#ifdef PORT_DEBUG + DEV_INFO("HDMI[%02x] [R] %02x\n", reg, data); +#endif + return *data_buf; +} + +/* + * Write a value to a register on adv7520 device. + * Returns zero if successful, or non-zero otherwise. + */ +static int adv7520_write_reg(struct i2c_client *client, u8 reg, u8 val) +{ + int err; + struct i2c_msg msg[1]; + unsigned char data[2]; + + if (!client->adapter) + return -ENODEV; + if (!atomic_read(&comm_power_on)) { + DEV_WARN("%s: WARN: missing GPIO power\n", __func__); + return -ENODEV; + } + + msg->addr = client->addr; + msg->flags = 0; + msg->len = 2; + msg->buf = data; + data[0] = reg; + data[1] = val; + + err = i2c_transfer(client->adapter, msg, 1); + if (err >= 0) + return 0; +#ifdef PORT_DEBUG + DEV_INFO("HDMI[%02x] [W] %02x [%d]\n", reg, val, err); +#endif + return err; +} + +#ifdef CONFIG_FB_MSM_HDMI_ADV7520_PANEL_HDCP_SUPPORT +static void adv7520_close_hdcp_link(void) +{ + if (!external_common_state->hdcp_active && !hdcp_activating) + return; + + DEV_INFO("HDCP: Close link\n"); + + reg[0xD5] = adv7520_read_reg(hclient, 0xD5); + reg[0xD5] &= 0xFE; + adv7520_write_reg(hclient, 0xD5, (u8)reg[0xD5]); + + reg[0x16] = adv7520_read_reg(hclient, 0x16); + reg[0x16] &= 0xFE; + adv7520_write_reg(hclient, 0x16, (u8)reg[0x16]); + + /* UnMute Audio */ + adv7520_write_reg(hclient, 0x0C, (u8)0x84); + + external_common_state->hdcp_active = FALSE; + mutex_lock(&hdcp_state_mutex); + hdcp_activating = FALSE; + mutex_unlock(&hdcp_state_mutex); +} + +static void adv7520_comm_power(int on, int show); +static void adv7520_hdcp_enable(struct work_struct *work) +{ + DEV_INFO("HDCP: Start reg[0xaf]=%02x (mute audio)\n", reg[0xaf]); + + adv7520_comm_power(1, 1); + + /* Mute Audio */ + adv7520_write_reg(hclient, 0x0C, (u8)0xC3); + + msleep(200); + /* Wait for BKSV ready interrupt */ + /* Read BKSV's keys from HDTV */ + reg[0xBF] = adv7520_read_reg(hclient, 0xBF); + reg[0xC0] = adv7520_read_reg(hclient, 0xC0); + reg[0xC1] = adv7520_read_reg(hclient, 0xC1); + reg[0xC2] = adv7520_read_reg(hclient, 0xC2); + reg[0xc3] = adv7520_read_reg(hclient, 0xC3); + + DEV_DBG("HDCP: BKSV={%02x,%02x,%02x,%02x,%02x}\n", reg[0xbf], reg[0xc0], + reg[0xc1], reg[0xc2], reg[0xc3]); + + /* Is SINK repeater */ + reg[0xBE] = adv7520_read_reg(hclient, 0xBE); + if (~(reg[0xBE] & 0x40)) { + ; /* compare with revocation list */ + /* Check 20 1's and 20 zero's */ + } else { + /* Don't implement HDCP if sink as a repeater */ + adv7520_write_reg(hclient, 0x0C, (u8)0x84); + mutex_lock(&hdcp_state_mutex); + hdcp_activating = FALSE; + mutex_unlock(&hdcp_state_mutex); + DEV_WARN("HDCP: Sink Repeater (%02x), (unmute audio)\n", + reg[0xbe]); + + adv7520_comm_power(0, 1); + return; + } + + msleep(200); + reg[0xB8] = adv7520_read_reg(hclient, 0xB8); + DEV_INFO("HDCP: Status reg[0xB8] is %02x\n", reg[0xb8]); + if (reg[0xb8] & 0x40) { + /* UnMute Audio */ + adv7520_write_reg(hclient, 0x0C, (u8)0x84); + DEV_INFO("HDCP: A/V content Encrypted (unmute audio)\n"); + external_common_state->hdcp_active = TRUE; + } + adv7520_comm_power(0, 1); + + mutex_lock(&hdcp_state_mutex); + hdcp_activating = FALSE; + mutex_unlock(&hdcp_state_mutex); +} +#endif + +static int adv7520_read_edid_block(int block, uint8 *edid_buf) +{ + u8 r = 0; + int ret; + struct i2c_msg msg[] = { + { .addr = reg[0x43] >> 1, + .flags = 0, + .len = 1, + .buf = &r }, + { .addr = reg[0x43] >> 1, + .flags = I2C_M_RD, + .len = 0x100, + .buf = edid_buf } }; + + if (block > 0) + return 0; + ret = i2c_transfer(hclient->adapter, msg, 2); + DEV_DBG("EDID block: addr=%02x, ret=%d\n", reg[0x43] >> 1, ret); + return (ret < 2) ? -ENODEV : 0; +} + +static void adv7520_read_edid(void) +{ + external_common_state->read_edid_block = adv7520_read_edid_block; + if (hdmi_common_read_edid()) { + u8 timeout; + DEV_INFO("%s: retry\n", __func__); + adv7520_write_reg(hclient, 0xc9, 0x13); + msleep(500); + timeout = (adv7520_read_reg(hclient, 0x96) & (1 << 2)); + if (timeout) { + hdmi_common_read_edid(); + } + } +} + +static void adv7520_chip_on(void) +{ + if (!chip_power_on) { + /* Get the current register holding the power bit. */ + unsigned long reg0xaf = adv7520_read_reg(hclient, 0xaf); + + dd->pd->core_power(1, 1); + + /* Set the HDMI select bit. */ + set_bit(1, ®0xaf); + DEV_INFO("%s: turn on chip power\n", __func__); + adv7520_write_reg(hclient, 0x41, 0x10); + adv7520_write_reg(hclient, 0xaf, (u8)reg0xaf); + chip_power_on = TRUE; + } else + DEV_INFO("%s: chip already has power\n", __func__); +} + +static void adv7520_chip_off(void) +{ + if (chip_power_on) { +#ifdef CONFIG_FB_MSM_HDMI_ADV7520_PANEL_HDCP_SUPPORT + if (has_hdcp_hw_support) + adv7520_close_hdcp_link(); +#endif + + DEV_INFO("%s: turn off chip power\n", __func__); + adv7520_write_reg(hclient, 0x41, 0x50); + dd->pd->core_power(0, 1); + chip_power_on = FALSE; + } else + DEV_INFO("%s: chip is already off\n", __func__); + + monitor_sense = 0; + hpd_cable_chg_detected = FALSE; + + if (enable_5v_on) { + dd->pd->enable_5v(0); + enable_5v_on = FALSE; + } +} + +/* Power ON/OFF ADV7520 chip */ +static void adv7520_isr_w(struct work_struct *work); +static void adv7520_comm_power(int on, int show) +{ + if (!on) + atomic_dec(&comm_power_on); + dd->pd->comm_power(on, 0/*show*/); + if (on) + atomic_inc(&comm_power_on); +} + +#ifdef CONFIG_FB_MSM_HDMI_ADV7520_PANEL_HDCP_SUPPORT +static void adv7520_start_hdcp(void); +#endif +static int adv7520_power_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); + + clk_prepare_enable(tv_enc_clk); + external_common_state->dev = &pdev->dev; + if (mfd != NULL) { + DEV_INFO("adv7520_power: ON (%dx%d %d)\n", + mfd->var_xres, mfd->var_yres, mfd->var_pixclock); + hdmi_common_get_video_format_from_drv_data(mfd); + } + + adv7520_comm_power(1, 1); + /* Check if HPD is signaled */ + if (adv7520_read_reg(hclient, 0x42) & (1 << 6)) { + DEV_INFO("power_on: cable detected\n"); + monitor_sense = adv7520_read_reg(hclient, 0xC6); +#ifdef CONFIG_FB_MSM_HDMI_ADV7520_PANEL_HDCP_SUPPORT + if (has_hdcp_hw_support) { + if (!hdcp_activating) + adv7520_start_hdcp(); + } +#endif + } else + DEV_INFO("power_on: cable NOT detected\n"); + adv7520_comm_power(0, 1); + pm_qos_update_request(&pm_qos_req, msm_cpuidle_get_deep_idle_latency()); + + return 0; +} + +static int adv7520_power_off(struct platform_device *pdev) +{ + DEV_INFO("power_off\n"); + adv7520_comm_power(1, 1); + adv7520_chip_off(); + pm_qos_update_request(&pm_qos_req, PM_QOS_DEFAULT_VALUE); + adv7520_comm_power(0, 1); + clk_disable_unprepare(tv_enc_clk); + return 0; +} + + +/* AV7520 chip specific initialization */ +static void adv7520_chip_init(void) +{ + /* Initialize the variables used to read/write the ADV7520 chip. */ + memset(®, 0xff, sizeof(reg)); + + /* Get the values from the "Fixed Registers That Must Be Set". */ + reg[0x98] = adv7520_read_reg(hclient, 0x98); + reg[0x9c] = adv7520_read_reg(hclient, 0x9c); + reg[0x9d] = adv7520_read_reg(hclient, 0x9d); + reg[0xa2] = adv7520_read_reg(hclient, 0xa2); + reg[0xa3] = adv7520_read_reg(hclient, 0xa3); + reg[0xde] = adv7520_read_reg(hclient, 0xde); + + /* Get the "HDMI/DVI Selection" register. */ + reg[0xaf] = adv7520_read_reg(hclient, 0xaf); + + /* Read Packet Memory I2C Address */ + reg[0x45] = adv7520_read_reg(hclient, 0x45); + + /* Hard coded values provided by ADV7520 data sheet. */ + reg[0x98] = 0x03; + reg[0x9c] = 0x38; + reg[0x9d] = 0x61; + reg[0xa2] = 0x94; + reg[0xa3] = 0x94; + reg[0xde] = 0x88; + + /* Set the HDMI select bit. */ + reg[0xaf] |= 0x16; + + /* Set the audio related registers. */ + reg[0x01] = 0x00; + reg[0x02] = 0x2d; + reg[0x03] = 0x80; + reg[0x0a] = 0x4d; + reg[0x0b] = 0x0e; + reg[0x0c] = 0x84; + reg[0x0d] = 0x10; + reg[0x12] = 0x00; + reg[0x14] = 0x00; + reg[0x15] = 0x20; + reg[0x44] = 0x79; + reg[0x73] = 0x01; + reg[0x76] = 0x00; + + /* Set 720p display related registers */ + reg[0x16] = 0x00; + + reg[0x18] = 0x46; + reg[0x55] = 0x00; + reg[0x3c] = 0x04; + + /* Set Interrupt Mask register for HPD/HDCP */ + reg[0x94] = 0xC0; +#ifdef CONFIG_FB_MSM_HDMI_ADV7520_PANEL_HDCP_SUPPORT + if (has_hdcp_hw_support) + reg[0x95] = 0xC0; + else + reg[0x95] = 0x00; +#else + reg[0x95] = 0x00; +#endif + adv7520_write_reg(hclient, 0x94, reg[0x94]); + adv7520_write_reg(hclient, 0x95, reg[0x95]); + + /* Set Packet Memory I2C Address */ + reg[0x45] = 0x74; + + /* Set the values from the "Fixed Registers That Must Be Set". */ + adv7520_write_reg(hclient, 0x98, reg[0x98]); + adv7520_write_reg(hclient, 0x9c, reg[0x9c]); + adv7520_write_reg(hclient, 0x9d, reg[0x9d]); + adv7520_write_reg(hclient, 0xa2, reg[0xa2]); + adv7520_write_reg(hclient, 0xa3, reg[0xa3]); + adv7520_write_reg(hclient, 0xde, reg[0xde]); + + /* Set the "HDMI/DVI Selection" register. */ + adv7520_write_reg(hclient, 0xaf, reg[0xaf]); + + /* Set EDID Monitor address */ + reg[0x43] = 0x7E; + adv7520_write_reg(hclient, 0x43, reg[0x43]); + + /* Enable the i2s audio input. */ + adv7520_write_reg(hclient, 0x01, reg[0x01]); + adv7520_write_reg(hclient, 0x02, reg[0x02]); + adv7520_write_reg(hclient, 0x03, reg[0x03]); + adv7520_write_reg(hclient, 0x0a, reg[0x0a]); + adv7520_write_reg(hclient, 0x0b, reg[0x0b]); + adv7520_write_reg(hclient, 0x0c, reg[0x0c]); + adv7520_write_reg(hclient, 0x0d, reg[0x0d]); + adv7520_write_reg(hclient, 0x12, reg[0x12]); + adv7520_write_reg(hclient, 0x14, reg[0x14]); + adv7520_write_reg(hclient, 0x15, reg[0x15]); + adv7520_write_reg(hclient, 0x44, reg[0x44]); + adv7520_write_reg(hclient, 0x73, reg[0x73]); + adv7520_write_reg(hclient, 0x76, reg[0x76]); + + /* Enable 720p display */ + adv7520_write_reg(hclient, 0x16, reg[0x16]); + adv7520_write_reg(hclient, 0x18, reg[0x18]); + adv7520_write_reg(hclient, 0x55, reg[0x55]); + adv7520_write_reg(hclient, 0x3c, reg[0x3c]); + + /* Set Packet Memory address to avoid conflict + with Bosch Accelerometer */ + adv7520_write_reg(hclient, 0x45, reg[0x45]); + + /* Ensure chip is in low-power state */ + adv7520_write_reg(hclient, 0x41, 0x50); +} + +#ifdef CONFIG_FB_MSM_HDMI_ADV7520_PANEL_HDCP_SUPPORT +static void adv7520_start_hdcp(void) +{ + mutex_lock(&hdcp_state_mutex); + if (hdcp_activating) { + DEV_WARN("adv7520_timer: HDCP already" + " activating, skipping\n"); + mutex_unlock(&hdcp_state_mutex); + return; + } + hdcp_activating = TRUE; + mutex_unlock(&hdcp_state_mutex); + + del_timer(&hpd_duty_timer); + + adv7520_comm_power(1, 1); + + if (!enable_5v_on) { + dd->pd->enable_5v(1); + enable_5v_on = TRUE; + adv7520_chip_on(); + } + + /* request for HDCP */ + reg[0xaf] = adv7520_read_reg(hclient, 0xaf); + reg[0xaf] |= 0x90; + adv7520_write_reg(hclient, 0xaf, reg[0xaf]); + reg[0xaf] = adv7520_read_reg(hclient, 0xaf); + + reg[0xba] = adv7520_read_reg(hclient, 0xba); + reg[0xba] |= 0x10; + adv7520_write_reg(hclient, 0xba, reg[0xba]); + reg[0xba] = adv7520_read_reg(hclient, 0xba); + adv7520_comm_power(0, 1); + + DEV_INFO("HDCP: reg[0xaf]=0x%02x, reg[0xba]=0x%02x, waiting for BKSV\n", + reg[0xaf], reg[0xba]); + + /* will check for HDCP Error or BKSV ready */ + mod_timer(&hpd_duty_timer, jiffies + HZ/2); +} +#endif + +static void adv7520_hpd_timer_w(struct work_struct *work) +{ + if (!external_common_state->hpd_feature_on) { + DEV_INFO("adv7520_timer: skipping, feature off\n"); + return; + } + + if ((monitor_sense & 0x4) && !external_common_state->hpd_state) { + int timeout; + DEV_DBG("adv7520_timer: Cable Detected\n"); + adv7520_comm_power(1, 1); + adv7520_chip_on(); + + if (hpd_cable_chg_detected) { + hpd_cable_chg_detected = FALSE; + /* Ensure 5V to read EDID */ + if (!enable_5v_on) { + dd->pd->enable_5v(1); + enable_5v_on = TRUE; + } + msleep(500); + timeout = (adv7520_read_reg(hclient, 0x96) & (1 << 2)); + if (timeout) { + DEV_DBG("adv7520_timer: EDID-Ready..\n"); + adv7520_read_edid(); + } else + DEV_DBG("adv7520_timer: EDID TIMEOUT (C9=%02x)" + "\n", adv7520_read_reg(hclient, 0xC9)); + } +#ifdef TESTING_FORCE_480p + external_common_state->disp_mode_list.num_of_elements = 1; + external_common_state->disp_mode_list.disp_mode_list[0] = + HDMI_VFRMT_720x480p60_16_9; +#endif + adv7520_comm_power(0, 1); +#ifndef CONFIG_FB_MSM_HDMI_ADV7520_PANEL_HDCP_SUPPORT + /* HDMI_5V_EN not needed anymore */ + if (enable_5v_on) { + DEV_DBG("adv7520_timer: EDID done, no HDCP, 5V not " + "needed anymore\n"); + dd->pd->enable_5v(0); + enable_5v_on = FALSE; + } +#endif + change_hdmi_state(1); + } else if (external_common_state->hpd_state) { + adv7520_comm_power(1, 1); + adv7520_chip_off(); + adv7520_comm_power(0, 1); + DEV_DBG("adv7520_timer: Cable Removed\n"); + change_hdmi_state(0); + } +} + +static void adv7520_hpd_timer_f(unsigned long data) +{ + schedule_work(&hpd_timer_work); +} + +static void adv7520_isr_w(struct work_struct *work) +{ + static int state_count; + static u8 last_reg0x96; + u8 reg0xc8; + u8 reg0x96; +#ifdef CONFIG_FB_MSM_HDMI_ADV7520_PANEL_HDCP_SUPPORT + static u8 last_reg0x97; + u8 reg0x97 = 0; +#endif + if (!external_common_state->hpd_feature_on) { + DEV_DBG("adv7520_irq: skipping, hpd off\n"); + return; + } + + adv7520_comm_power(1, 1); + reg0x96 = adv7520_read_reg(hclient, 0x96); +#ifdef CONFIG_FB_MSM_HDMI_ADV7520_PANEL_HDCP_SUPPORT + if (has_hdcp_hw_support) { + reg0x97 = adv7520_read_reg(hclient, 0x97); + /* Clearing the Interrupts */ + adv7520_write_reg(hclient, 0x97, reg0x97); + } +#endif + /* Clearing the Interrupts */ + adv7520_write_reg(hclient, 0x96, reg0x96); + + if ((reg0x96 == 0xC0) || (reg0x96 & 0x40)) { +#ifdef DEBUG + unsigned int hpd_state = adv7520_read_reg(hclient, 0x42); +#endif + monitor_sense = adv7520_read_reg(hclient, 0xC6); + DEV_DBG("adv7520_irq: reg[0x42]=%02x && reg[0xC6]=%02x\n", + hpd_state, monitor_sense); + + if (!enable_5v_on) { + dd->pd->enable_5v(1); + enable_5v_on = TRUE; + } + if (!hpd_power_on) { + dd->pd->core_power(1, 1); + hpd_power_on = TRUE; + } + + /* Timer for catching interrupt debouning */ + DEV_DBG("adv7520_irq: Timer in .5sec\n"); + hpd_cable_chg_detected = TRUE; + mod_timer(&hpd_timer, jiffies + HZ/2); + } +#ifdef CONFIG_FB_MSM_HDMI_ADV7520_PANEL_HDCP_SUPPORT + if (has_hdcp_hw_support) { + if (hdcp_activating) { + /* HDCP controller error Interrupt */ + if (reg0x97 & 0x80) { + DEV_ERR("adv7520_irq: HDCP_ERROR\n"); + state_count = 0; + adv7520_close_hdcp_link(); + /* BKSV Ready interrupts */ + } else if (reg0x97 & 0x40) { + DEV_INFO("adv7520_irq: BKSV keys ready, Begin" + " HDCP encryption\n"); + state_count = 0; + schedule_work(&hdcp_handle_work); + } else if (++state_count > 2 && (monitor_sense & 0x4)) { + DEV_INFO("adv7520_irq: Still waiting for BKSV," + "restart HDCP\n"); + hdcp_activating = FALSE; + state_count = 0; + adv7520_chip_off(); + adv7520_start_hdcp(); + } + reg0xc8 = adv7520_read_reg(hclient, 0xc8); + DEV_INFO("adv7520_irq: DDC controller reg[0xC8]=0x%02x," + "state_count=%d, monitor_sense=%x\n", + reg0xc8, state_count, monitor_sense); + } else if (!external_common_state->hdcp_active + && (monitor_sense & 0x4)) { + DEV_INFO("adv7520_irq: start HDCP with" + " monitor sense\n"); + state_count = 0; + adv7520_start_hdcp(); + } else + state_count = 0; + if (last_reg0x97 != reg0x97 || last_reg0x96 != reg0x96) + DEV_DBG("adv7520_irq: reg[0x96]=%02x " + "reg[0x97]=%02x: HDCP: %d\n", reg0x96, reg0x97, + external_common_state->hdcp_active); + last_reg0x97 = reg0x97; + } else { + if (last_reg0x96 != reg0x96) + DEV_DBG("adv7520_irq: reg[0x96]=%02x\n", reg0x96); + } +#else + if (last_reg0x96 != reg0x96) + DEV_DBG("adv7520_irq: reg[0x96]=%02x\n", reg0x96); +#endif + last_reg0x96 = reg0x96; + adv7520_comm_power(0, 1); +} + +static void adv7520_hpd_duty_work(struct work_struct *work) +{ + if (!external_common_state->hpd_feature_on) { + DEV_WARN("%s: hpd feature is off, skipping\n", __func__); + return; + } + + dd->pd->core_power(1, 0); + msleep(10); + adv7520_isr_w(NULL); + dd->pd->core_power(0, 0); +} + +static void adv7520_hpd_duty_timer_f(unsigned long data) +{ + if (!external_common_state->hpd_feature_on) { + DEV_WARN("%s: hpd feature is off, skipping\n", __func__); + return; + } + + mod_timer(&hpd_duty_timer, jiffies + HPD_DUTY_CYCLE*HZ); + schedule_work(&hpd_duty_work); +} + +static const struct i2c_device_id adv7520_id[] = { + { ADV7520_DRV_NAME , 0}, + {} +}; + +static struct msm_fb_panel_data hdmi_panel_data = { + .on = adv7520_power_on, + .off = adv7520_power_off, +}; + +static struct platform_device hdmi_device = { + .name = ADV7520_DRV_NAME , + .id = 2, + .dev = { + .platform_data = &hdmi_panel_data, + } +}; + +static void adv7520_ensure_init(void) +{ + static boolean init_done; + if (!init_done) { + int rc = dd->pd->init_irq(); + if (rc) { + DEV_ERR("adv7520_init: init_irq: %d\n", rc); + return; + } + + init_done = TRUE; + } + DEV_INFO("adv7520_init: chip init\n"); + adv7520_comm_power(1, 1); + adv7520_chip_init(); + adv7520_comm_power(0, 1); +} + +static int adv7520_hpd_feature(int on) +{ + int rc = 0; + + if (!on) { + if (enable_5v_on) { + dd->pd->enable_5v(0); + enable_5v_on = FALSE; + } + if (hpd_power_on) { + dd->pd->core_power(0, 1); + hpd_power_on = FALSE; + } + + DEV_DBG("adv7520_hpd: %d: stop duty timer\n", on); + del_timer(&hpd_timer); + del_timer(&hpd_duty_timer); + external_common_state->hpd_state = 0; + } + + if (on) { + dd->pd->core_power(1, 0); + adv7520_ensure_init(); + + adv7520_comm_power(1, 1); + monitor_sense = adv7520_read_reg(hclient, 0xC6); + DEV_DBG("adv7520_irq: reg[0xC6]=%02x\n", monitor_sense); + adv7520_comm_power(0, 1); + dd->pd->core_power(0, 0); + + if (monitor_sense & 0x4) { + if (!enable_5v_on) { + dd->pd->enable_5v(1); + enable_5v_on = TRUE; + } + if (!hpd_power_on) { + dd->pd->core_power(1, 1); + hpd_power_on = TRUE; + } + + hpd_cable_chg_detected = TRUE; + mod_timer(&hpd_timer, jiffies + HZ/2); + } + + DEV_DBG("adv7520_hpd: %d start duty timer\n", on); + mod_timer(&hpd_duty_timer, jiffies + HZ/100); + } + + DEV_INFO("adv7520_hpd: %d\n", on); + return rc; +} + +static int + adv7520_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int rc; + struct platform_device *fb_dev; + + dd = kzalloc(sizeof *dd, GFP_KERNEL); + if (!dd) { + rc = -ENOMEM; + goto probe_exit; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + + external_common_state->dev = &client->dev; + + /* Init real i2c_client */ + hclient = client; + + i2c_set_clientdata(client, dd); + dd->pd = client->dev.platform_data; + if (!dd->pd) { + rc = -ENODEV; + goto probe_free; + } + + INIT_WORK(&dd->isr_work, adv7520_isr_w); + INIT_WORK(&hpd_timer_work, adv7520_hpd_timer_w); +#ifdef CONFIG_FB_MSM_HDMI_ADV7520_PANEL_HDCP_SUPPORT + if (dd->pd->check_hdcp_hw_support) + has_hdcp_hw_support = dd->pd->check_hdcp_hw_support(); + + if (has_hdcp_hw_support) + INIT_WORK(&hdcp_handle_work, adv7520_hdcp_enable); + else + DEV_INFO("%s: no hdcp hw support.\n", __func__); +#endif + + init_timer(&hpd_timer); + hpd_timer.function = adv7520_hpd_timer_f; + hpd_timer.data = (unsigned long)NULL; + hpd_timer.expires = 0xffffffff; + add_timer(&hpd_timer); + + external_common_state->hpd_feature = adv7520_hpd_feature; + DEV_INFO("adv7520_probe: HPD detection on request\n"); + init_timer(&hpd_duty_timer); + hpd_duty_timer.function = adv7520_hpd_duty_timer_f; + hpd_duty_timer.data = (unsigned long)NULL; + hpd_duty_timer.expires = 0xffffffff; + add_timer(&hpd_duty_timer); + INIT_WORK(&hpd_duty_work, adv7520_hpd_duty_work); + DEV_INFO("adv7520_probe: HPD detection ON (duty)\n"); + + fb_dev = msm_fb_add_device(&hdmi_device); + + if (fb_dev) { + rc = external_common_state_create(fb_dev); + if (rc) + goto probe_free; + } else + DEV_ERR("adv7520_probe: failed to add fb device\n"); + + if (hdmi_prim_display) + external_common_state->sdev.name = "hdmi_as_primary"; + else + external_common_state->sdev.name = "hdmi"; + + if (switch_dev_register(&external_common_state->sdev) < 0) + DEV_ERR("Hdmi switch registration failed\n"); + + return 0; + +probe_free: + kfree(dd); + dd = NULL; +probe_exit: + return rc; + +} + +static int adv7520_remove(struct i2c_client *client) +{ + if (!client->adapter) { + DEV_ERR("%s: No HDMI Device\n", __func__); + return -ENODEV; + } + switch_dev_unregister(&external_common_state->sdev); + pm_qos_remove_request(&pm_qos_req); + kfree(dd); + dd = NULL; + return 0; +} + +#ifdef CONFIG_SUSPEND +static int adv7520_i2c_suspend(struct device *dev) +{ + DEV_INFO("%s\n", __func__); + + ++suspend_count; + + if (external_common_state->hpd_feature_on) { + DEV_DBG("%s: stop duty timer\n", __func__); + del_timer(&hpd_duty_timer); + del_timer(&hpd_timer); + } + + /* Turn off LDO8 and go into low-power state */ + if (chip_power_on) { + DEV_DBG("%s: turn off power\n", __func__); + adv7520_comm_power(1, 1); + adv7520_write_reg(hclient, 0x41, 0x50); + adv7520_comm_power(0, 1); + dd->pd->core_power(0, 1); + } + + return 0; +} + +static int adv7520_i2c_resume(struct device *dev) +{ + DEV_INFO("%s\n", __func__); + + /* Turn on LDO8 and go into normal-power state */ + if (chip_power_on) { + DEV_DBG("%s: turn on power\n", __func__); + dd->pd->core_power(1, 1); + adv7520_comm_power(1, 1); + adv7520_write_reg(hclient, 0x41, 0x10); + adv7520_comm_power(0, 1); + } + + if (external_common_state->hpd_feature_on) { + DEV_DBG("%s: start duty timer\n", __func__); + mod_timer(&hpd_duty_timer, jiffies + HPD_DUTY_CYCLE*HZ); + } + + return 0; +} +#else +#define adv7520_i2c_suspend NULL +#define adv7520_i2c_resume NULL +#endif + +static const struct dev_pm_ops adv7520_device_pm_ops = { + .suspend = adv7520_i2c_suspend, + .resume = adv7520_i2c_resume, +}; + +static struct i2c_driver hdmi_i2c_driver = { + .driver = { + .name = ADV7520_DRV_NAME, + .owner = THIS_MODULE, + .pm = &adv7520_device_pm_ops, + }, + .probe = adv7520_probe, + .id_table = adv7520_id, + .remove = adv7520_remove, +}; + +static int __init adv7520_init(void) +{ + int rc; + + pr_info("%s\n", __func__); + external_common_state = &hdmi_common; + external_common_state->video_resolution = HDMI_VFRMT_1280x720p60_16_9; + + tv_enc_clk = clk_get(NULL, "tv_enc_clk"); + if (IS_ERR(tv_enc_clk)) { + printk(KERN_ERR "error: can't get tv_enc_clk!\n"); + return IS_ERR(tv_enc_clk); + } + + HDMI_SETUP_LUT(640x480p60_4_3); /* 25.20MHz */ + HDMI_SETUP_LUT(720x480p60_16_9); /* 27.03MHz */ + HDMI_SETUP_LUT(1280x720p60_16_9); /* 74.25MHz */ + + HDMI_SETUP_LUT(720x576p50_16_9); /* 27.00MHz */ + HDMI_SETUP_LUT(1280x720p50_16_9); /* 74.25MHz */ + + hdmi_common_init_panel_info(&hdmi_panel_data.panel_info); + + rc = i2c_add_driver(&hdmi_i2c_driver); + if (rc) { + pr_err("hdmi_init FAILED: i2c_add_driver rc=%d\n", rc); + goto init_exit; + } + + if (machine_is_msm7x30_surf() || machine_is_msm8x55_surf()) { + short *hdtv_mux = (short *)ioremap(0x8e000170 , 0x100); + *hdtv_mux++ = 0x020b; + *hdtv_mux = 0x8000; + iounmap(hdtv_mux); + } + pm_qos_add_request(&pm_qos_req, PM_QOS_CPU_DMA_LATENCY, + PM_QOS_DEFAULT_VALUE); + + return 0; + +init_exit: + if (tv_enc_clk) + clk_put(tv_enc_clk); + return rc; +} + +static void __exit adv7520_exit(void) +{ + i2c_del_driver(&hdmi_i2c_driver); +} + +module_init(adv7520_init); +module_exit(adv7520_exit); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("0.1"); +MODULE_AUTHOR("Qualcomm Innovation Center, Inc."); +MODULE_DESCRIPTION("ADV7520 HDMI driver"); diff --git a/drivers/video/msm/ebi2_epson_s1d_qvga.c b/drivers/video/msm/ebi2_epson_s1d_qvga.c new file mode 100644 index 000000000000..8db3cf9bf3be --- /dev/null +++ b/drivers/video/msm/ebi2_epson_s1d_qvga.c @@ -0,0 +1,374 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" + +#include +#include +#include +#include +#include +#include +#include "linux/proc_fs.h" + +#include + +#include +#include + +#include +#include + +#define CMD_NOP_C 0x00 +#define CMD_SOFT_RESET_C 0x99 +#define CMD_DISPLAY_ON_C 0xAF +#define CMD_DISPLAY_OFF_C 0xAE +#define CMD_SET_DISPLAY_C 0xCA +#define CMD_SET_DISPLAY_TIMING_C 0xA1 +#define CMD_SET_DATA_C 0xBC +#define CMD_SET_START_ADDRESS_C 0x15 +#define CMD_SET_END_ADDRESS_C 0x75 +#define CMD_RAM_WRITE_C 0x5C +#define CMD_RAM_READ_C 0x5D +#define CMD_SET_AREA_SCROLLING_C 0xAA +#define CMD_SET_DISPLAY_START_LINE_C 0xAB +#define CMD_PARTIAL_DISPLAY_IN_C 0xA8 +#define CMD_PARTIAL_DISPLAY_OUT_C 0xA9 +#define CMD_SET_DISPLAY_DATA_INTERFACE_C 0x31 +#define CMD_SET_DISPLAY_COLOR_MODE_C 0x8B +#define CMD_SELECT_MTP_ROM_MODE_C 0x65 +#define CMD_MTP_ROM_MODE_IN_C 0x67 +#define CMD_MTP_ROM_MODE_OUT_C 0x68 +#define CMD_MTP_ROM_OPERATION_IN_C 0x69 +#define CMD_MTP_ROM_OPERATION_OUT_C 0x70 +#define CMD_GATE_LINE_SCAN_MODE_C 0x6F +#define CMD_SET_AC_OPERATION_DRIVE_C 0x8C +#define CMD_SET_ELECTRONIC_CONTROL_C 0x20 +#define CMD_SET_POSITIVE_CORRECTION_CHARS_C 0x22 +#define CMD_SET_NEGATIVE_CORRECTION_CHARS_C 0x25 +#define CMD_SET_POWER_CONTROL_C 0x21 +#define CMD_SET_PARTIAL_POWER_CONTROL_C 0x23 +#define CMD_SET_8_COLOR_CONTROL_C 0x24 +#define CMD_SLEEP_IN_C 0x95 +#define CMD_SLEEP_OUT_C 0x94 +#define CMD_VDD_OFF_C 0x97 +#define CMD_VDD_ON_C 0x96 +#define CMD_STOP_OSCILLATION_C 0x93 +#define CMD_START_OSCILLATION_C 0x92 +#define CMD_TEST_SOURCE_C 0xFD +#define CMD_TEST_FUSE_C 0xFE +#define CMD_TEST_C 0xFF +#define CMD_STATUS_READ_C 0xE8 +#define CMD_REVISION_READ_C 0xE9 + +#define PANEL_WIDTH 240 +#define PANEL_HEIGHT 320 +#define ACTIVE_WIN_WIDTH PANEL_WIDTH +#define ACTIVE_WIN_HEIGHT PANEL_HEIGHT + +#define ACTIVE_WIN_H_START 0 +#define ACTIVE_WIN_V_START 0 + +#define DISP_CMD_OUT(cmd) outpw(DISP_CMD_PORT, (cmd << 1)); +#define DISP_DATA_OUT(data) outpw(DISP_DATA_PORT, (data << 1)); +#define DISP_DATA_IN() inpw(DISP_DATA_PORT); + +static void *DISP_CMD_PORT; +static void *DISP_DATA_PORT; +static boolean disp_initialized; +static boolean display_on; +static struct msm_panel_common_pdata *ebi2_epson_pdata; + +static void epson_s1d_disp_init(struct platform_device *pdev); +static int epson_s1d_disp_off(struct platform_device *pdev); +static int epson_s1d_disp_on(struct platform_device *pdev); +static void epson_s1d_disp_set_rect(int x, int y, int xres, int yres); + +static void epson_s1d_disp_set_rect(int x, int y, int xres, int yres) +{ + int right, bottom; + + if (!disp_initialized) + return; + + right = x + xres - 1; + bottom = y + yres - 1; + + x += ACTIVE_WIN_H_START; + y += ACTIVE_WIN_V_START; + right += ACTIVE_WIN_H_START; + bottom += ACTIVE_WIN_V_START; + + if ((PANEL_WIDTH > x) && + (PANEL_HEIGHT > y) && + (PANEL_WIDTH > right) && + (PANEL_HEIGHT > bottom)) { + DISP_CMD_OUT(CMD_SET_START_ADDRESS_C); + DISP_DATA_OUT((uint8)x); + DISP_DATA_OUT((uint8)(y>>8)); + DISP_DATA_OUT((uint8)y); + + DISP_CMD_OUT(CMD_SET_END_ADDRESS_C); + DISP_DATA_OUT((uint8)right); + DISP_DATA_OUT((uint8)(bottom>>8)); + DISP_DATA_OUT((uint8)bottom); + DISP_CMD_OUT(CMD_RAM_WRITE_C); + } +} + +static void epson_s1d_disp_init(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + if (disp_initialized) + return; + + mfd = platform_get_drvdata(pdev); + + DISP_CMD_PORT = mfd->cmd_port; + DISP_DATA_PORT = mfd->data_port; + + disp_initialized = TRUE; +} + +static int epson_s1d_disp_off(struct platform_device *pdev) +{ + if (!disp_initialized) + epson_s1d_disp_init(pdev); + + if (display_on) { + DISP_CMD_OUT(CMD_SOFT_RESET_C); + DISP_CMD_OUT(CMD_VDD_OFF_C); + display_on = FALSE; + } + + return 0; +} + +static int epson_s1d_disp_on(struct platform_device *pdev) +{ + int i; + if (!disp_initialized) + epson_s1d_disp_init(pdev); + + if (!display_on) { + /* Enable Vdd regulator */ + DISP_CMD_OUT(CMD_VDD_ON_C); + msleep(20); + + /* Soft Reset before configuring display */ + DISP_CMD_OUT(CMD_SOFT_RESET_C); + msleep(20); + + /* Set display attributes */ + + /* GATESCAN */ + DISP_CMD_OUT(CMD_GATE_LINE_SCAN_MODE_C); + DISP_DATA_OUT(0x0); + + /* DISSET */ + DISP_CMD_OUT(CMD_SET_DISPLAY_C); + DISP_DATA_OUT(0x31); + DISP_DATA_OUT(0x00); + DISP_DATA_OUT((uint8)((PANEL_HEIGHT - 1)>>8)); + DISP_DATA_OUT((uint8)(PANEL_HEIGHT - 1)); + DISP_DATA_OUT(0x03); + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x08); + + /* VOLSET */ + DISP_CMD_OUT( + CMD_SET_ELECTRONIC_CONTROL_C); + DISP_DATA_OUT(0x10); + DISP_DATA_OUT(0x80); + DISP_DATA_OUT(0x11); + DISP_DATA_OUT(0x1B); + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x0D); + DISP_DATA_OUT(0x00); + + /* PWRCTL */ + DISP_CMD_OUT(CMD_SET_POWER_CONTROL_C); + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x24); + DISP_DATA_OUT(0x0F); + DISP_DATA_OUT(0xFE); + DISP_DATA_OUT(0x33); + DISP_DATA_OUT(0x31); + DISP_DATA_OUT(0xFF); + DISP_DATA_OUT(0x03); + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x77); + DISP_DATA_OUT(0x33); + DISP_DATA_OUT(0x11); + DISP_DATA_OUT(0x44); + DISP_DATA_OUT(0x00); + + /* PPWRCTL */ + DISP_CMD_OUT(CMD_SET_PARTIAL_POWER_CONTROL_C); + DISP_DATA_OUT(0x33); + DISP_DATA_OUT(0xFF); + DISP_DATA_OUT(0x03); + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x44); + DISP_DATA_OUT(0x00); + + /* SPLOUT */ + DISP_CMD_OUT(CMD_SLEEP_OUT_C); + msleep(100); + + /* DATSET */ + DISP_CMD_OUT(CMD_SET_DATA_C); + DISP_DATA_OUT(0x00); + + /* DISTMEMSET */ + DISP_CMD_OUT(CMD_SET_DISPLAY_TIMING_C); + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x2E); + DISP_DATA_OUT(0x0A); + DISP_DATA_OUT(0x2C); + DISP_DATA_OUT(0x23); + DISP_DATA_OUT(0x2F); + DISP_DATA_OUT(0x00); + + /* GAMSETP */ + DISP_CMD_OUT(CMD_SET_POSITIVE_CORRECTION_CHARS_C); + DISP_DATA_OUT(0x37); + DISP_DATA_OUT(0xFF); + DISP_DATA_OUT(0x7F); + DISP_DATA_OUT(0x15); + DISP_DATA_OUT(0x37); + DISP_DATA_OUT(0x05); + + /* GAMSETN */ + DISP_CMD_OUT(CMD_SET_NEGATIVE_CORRECTION_CHARS_C); + DISP_DATA_OUT(0x37); + DISP_DATA_OUT(0xFF); + DISP_DATA_OUT(0x7F); + DISP_DATA_OUT(0x15); + DISP_DATA_OUT(0x37); + DISP_DATA_OUT(0x05); + + /* ACDRIVE */ + DISP_CMD_OUT(CMD_SET_AC_OPERATION_DRIVE_C); + DISP_DATA_OUT(0x00); + + /* TEST */ + DISP_CMD_OUT(CMD_TEST_C); + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x01); + + /* COLMOD */ + DISP_CMD_OUT(CMD_SET_DISPLAY_COLOR_MODE_C); + DISP_DATA_OUT(0x00); + + /* STADDSET */ + DISP_CMD_OUT(CMD_SET_START_ADDRESS_C); + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x00); + + /* EDADDSET */ + DISP_CMD_OUT(CMD_SET_END_ADDRESS_C); + DISP_DATA_OUT(0xEF); + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x3F); + + /* Set Display Start Line */ + DISP_CMD_OUT(CMD_SET_DISPLAY_START_LINE_C); + DISP_DATA_OUT(0x00); + + /* Set Display Data Interface */ + DISP_CMD_OUT(CMD_SET_DISPLAY_DATA_INTERFACE_C); + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x04); + + epson_s1d_disp_set_rect(0, + 0, + ACTIVE_WIN_WIDTH, + ACTIVE_WIN_HEIGHT); + + for (i = 0; i < (ACTIVE_WIN_WIDTH * ACTIVE_WIN_HEIGHT); i++) + outpdw(DISP_DATA_PORT, 0); + + /* DISON */ + DISP_CMD_OUT(CMD_DISPLAY_ON_C); + msleep(60); + + display_on = TRUE; + } + + return 0; +} + +static int epson_s1d_probe(struct platform_device *pdev) +{ + if (pdev->id == 0) { + ebi2_epson_pdata = pdev->dev.platform_data; + return 0; + } + + msm_fb_add_device(pdev); + return 0; +} + +static struct platform_driver this_driver = { + .probe = epson_s1d_probe, + .driver = { + .name = "ebi2_epson_s1d_qvga", + }, +}; + +static struct msm_fb_panel_data epson_s1d_panel_data = { + .on = epson_s1d_disp_on, + .off = epson_s1d_disp_off, + .set_rect = epson_s1d_disp_set_rect, +}; + +static struct platform_device this_device = { + .name = "ebi2_epson_s1d_qvga", + .id = 1, + .dev = { + .platform_data = &epson_s1d_panel_data, + } +}; + +static int __init epson_s1d_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + + ret = platform_driver_register(&this_driver); + if (!ret) { + pinfo = &epson_s1d_panel_data.panel_info; + pinfo->xres = PANEL_WIDTH; + pinfo->yres = PANEL_HEIGHT; + MSM_FB_SINGLE_MODE_PANEL(pinfo); + pinfo->type = EBI2_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->wait_cycle = 0x048423E8; + pinfo->bpp = 18; + pinfo->fb_num = 2; + pinfo->lcd.vsync_enable = FALSE; + + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + } + + return ret; +} + +module_init(epson_s1d_init); diff --git a/drivers/video/msm/ebi2_host.c b/drivers/video/msm/ebi2_host.c new file mode 100644 index 000000000000..bebc36ecbd43 --- /dev/null +++ b/drivers/video/msm/ebi2_host.c @@ -0,0 +1,307 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm_fb.h" + +struct mdp_ccs mdp_ccs_rgb2yuv; +struct mdp_ccs mdp_ccs_yuv2rgb; + +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; +static int ebi2_host_resource_initialized; +static struct msm_panel_common_pdata *ebi2_host_pdata; + +static int ebi2_host_probe(struct platform_device *pdev); +static int ebi2_host_remove(struct platform_device *pdev); + +static int ebi2_host_runtime_suspend(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: suspending...\n"); + return 0; +} + +static int ebi2_host_runtime_resume(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: resuming...\n"); + return 0; +} + +static const struct dev_pm_ops ebi2_host_dev_pm_ops = { + .runtime_suspend = ebi2_host_runtime_suspend, + .runtime_resume = ebi2_host_runtime_resume, +}; + + +static struct platform_driver ebi2_host_driver = { + .probe = ebi2_host_probe, + .remove = ebi2_host_remove, + .shutdown = NULL, + .driver = { + /* + * Simulate mdp hw + */ + .name = "mdp", + .pm = &ebi2_host_dev_pm_ops, + }, +}; + +void mdp_pipe_ctrl(MDP_BLOCK_TYPE block, MDP_BLOCK_POWER_STATE state, + boolean isr) +{ + return; +} +int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req) +{ + return 0; +} +int mdp_start_histogram(struct fb_info *info) +{ + return 0; +} +int mdp_stop_histogram(struct fb_info *info) +{ + return 0; +} +void mdp_refresh_screen(unsigned long data) +{ + return; +} + +static int ebi2_host_off(struct platform_device *pdev) +{ + int ret; + ret = panel_next_off(pdev); + return ret; +} + +static int ebi2_host_on(struct platform_device *pdev) +{ + int ret; + ret = panel_next_on(pdev); + return ret; +} + + +static int ebi2_host_probe(struct platform_device *pdev) +{ + struct platform_device *msm_fb_dev = NULL; + struct msm_fb_data_type *mfd; + struct msm_fb_panel_data *pdata = NULL; + int rc; + + if ((pdev->id == 0) && (pdev->num_resources > 0)) { + + ebi2_host_pdata = pdev->dev.platform_data; + + ebi2_host_resource_initialized = 1; + return 0; + } + + ebi2_host_resource_initialized = 1; + if (!ebi2_host_resource_initialized) + return -EPERM; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) + return -ENOMEM; + + msm_fb_dev = platform_device_alloc("msm_fb", pdev->id); + if (!msm_fb_dev) + return -ENOMEM; + + /* link to the latest pdev */ + mfd->pdev = msm_fb_dev; + + if (ebi2_host_pdata) { + mfd->mdp_rev = ebi2_host_pdata->mdp_rev; + mfd->mem_hid = ebi2_host_pdata->mem_hid; + } + + /* add panel data */ + if (platform_device_add_data + (msm_fb_dev, pdev->dev.platform_data, + sizeof(struct msm_fb_panel_data))) { + pr_err("ebi2_host_probe: platform_device_add_data failed!\n"); + rc = -ENOMEM; + goto ebi2_host_probe_err; + } + /* data chain */ + pdata = msm_fb_dev->dev.platform_data; + pdata->on = ebi2_host_on; + pdata->off = ebi2_host_off; + pdata->next = pdev; + + /* set driver data */ + platform_set_drvdata(msm_fb_dev, mfd); + + rc = platform_device_add(msm_fb_dev); + if (rc) + goto ebi2_host_probe_err; + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + pdev_list[pdev_list_cnt++] = pdev; + return 0; + +ebi2_host_probe_err: + platform_device_put(msm_fb_dev); + return rc; +} + +void mdp_set_dma_pan_info(struct fb_info *info, struct mdp_dirty_region *dirty, + boolean sync) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct fb_info *fbi = mfd->fbi; + struct msm_panel_info *panel_info = &mfd->panel_info; + MDPIBUF *iBuf; + int bpp = info->var.bits_per_pixel / 8; + int yres, remainder; + + if (panel_info->mode2_yres != 0) { + yres = panel_info->mode2_yres; + remainder = (fbi->fix.line_length*yres)%PAGE_SIZE; + } else { + yres = panel_info->yres; + remainder = (fbi->fix.line_length*yres)%PAGE_SIZE; + } + + if (!remainder) + remainder = PAGE_SIZE; + + down(&mfd->sem); + + iBuf = &mfd->ibuf; + /* use virtual address */ + iBuf->buf = (uint8 *) fbi->screen_base; + + if (fbi->var.yoffset < yres) { + iBuf->buf += fbi->var.xoffset * bpp; + } else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) { + iBuf->buf += fbi->var.xoffset * bpp + yres * + fbi->fix.line_length + PAGE_SIZE - remainder; + } else { + iBuf->buf += fbi->var.xoffset * bpp + 2 * yres * + fbi->fix.line_length + 2 * (PAGE_SIZE - remainder); + } + + iBuf->ibuf_width = info->var.xres_virtual; + iBuf->bpp = bpp; + + iBuf->vsync_enable = sync; + + if (dirty) { + /* + * ToDo: dirty region check inside var.xoffset+xres + * <-> var.yoffset+yres + */ + iBuf->dma_x = dirty->xoffset % info->var.xres; + iBuf->dma_y = dirty->yoffset % info->var.yres; + iBuf->dma_w = dirty->width; + iBuf->dma_h = dirty->height; + } else { + iBuf->dma_x = 0; + iBuf->dma_y = 0; + iBuf->dma_w = info->var.xres; + iBuf->dma_h = info->var.yres; + } + mfd->ibuf_flushed = FALSE; + up(&mfd->sem); +} + +void mdp_dma_pan_update(struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + MDPIBUF *iBuf; + int i, j; + uint32 data; + uint8 *src; + struct msm_fb_panel_data *pdata = + (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + struct fb_info *fbi = mfd->fbi; + + iBuf = &mfd->ibuf; + + invalidate_caches((unsigned long)fbi->screen_base, + (unsigned long)info->fix.smem_len, + (unsigned long)info->fix.smem_start); + + pdata->set_rect(iBuf->dma_x, iBuf->dma_y, iBuf->dma_w, + iBuf->dma_h); + for (i = 0; i < iBuf->dma_h; i++) { + src = iBuf->buf + (fbi->fix.line_length * (iBuf->dma_y + i)) + + (iBuf->dma_x * iBuf->bpp); + for (j = 0; j < iBuf->dma_w; j++) { + data = (uint32)(*src++ >> 2) << 12; + data |= (uint32)(*src++ >> 2) << 6; + data |= (uint32)(*src++ >> 2); + data = ((data&0x1FF)<<16) | ((data&0x3FE00)>>9); + outpdw(mfd->data_port, data); + } + } +} + +static int ebi2_host_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static int ebi2_host_register_driver(void) +{ + return platform_driver_register(&ebi2_host_driver); +} + +static int __init ebi2_host_driver_init(void) +{ + int ret; + + ret = ebi2_host_register_driver(); + if (ret) { + pr_err("ebi2_host_register_driver() failed!\n"); + return ret; + } + + return 0; +} + +module_init(ebi2_host_driver_init); diff --git a/drivers/video/msm/ebi2_l2f.c b/drivers/video/msm/ebi2_l2f.c new file mode 100644 index 000000000000..2e944bea7975 --- /dev/null +++ b/drivers/video/msm/ebi2_l2f.c @@ -0,0 +1,566 @@ +/* Copyright (c) 2008-2010, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" + +#include +#include +#include +#include +#include +#include +#include "linux/proc_fs.h" + +#include + +#include +#include + +#include +#include + +/* The following are for MSM5100 on Gator +*/ +#ifdef FEATURE_PM1000 +#include "pm1000.h" +#endif /* FEATURE_PM1000 */ +/* The following are for MSM6050 on Bambi +*/ +#ifdef FEATURE_PMIC_LCDKBD_LED_DRIVER +#include "pm.h" +#endif /* FEATURE_PMIC_LCDKBD_LED_DRIVER */ + +#ifdef DISP_DEVICE_18BPP +#undef DISP_DEVICE_18BPP +#define DISP_DEVICE_16BPP +#endif + +#define QCIF_WIDTH 176 +#define QCIF_HEIGHT 220 + +static void *DISP_CMD_PORT; +static void *DISP_DATA_PORT; + +#define DISP_CMD_DISON 0xaf +#define DISP_CMD_DISOFF 0xae +#define DISP_CMD_DISNOR 0xa6 +#define DISP_CMD_DISINV 0xa7 +#define DISP_CMD_DISCTL 0xca +#define DISP_CMD_GCP64 0xcb +#define DISP_CMD_GCP16 0xcc +#define DISP_CMD_GSSET 0xcd +#define DISP_GS_2 0x02 +#define DISP_GS_16 0x01 +#define DISP_GS_64 0x00 +#define DISP_CMD_SLPIN 0x95 +#define DISP_CMD_SLPOUT 0x94 +#define DISP_CMD_SD_PSET 0x75 +#define DISP_CMD_MD_PSET 0x76 +#define DISP_CMD_SD_CSET 0x15 +#define DISP_CMD_MD_CSET 0x16 +#define DISP_CMD_DATCTL 0xbc +#define DISP_DATCTL_666 0x08 +#define DISP_DATCTL_565 0x28 +#define DISP_DATCTL_444 0x38 +#define DISP_CMD_RAMWR 0x5c +#define DISP_CMD_RAMRD 0x5d +#define DISP_CMD_PTLIN 0xa8 +#define DISP_CMD_PTLOUT 0xa9 +#define DISP_CMD_ASCSET 0xaa +#define DISP_CMD_SCSTART 0xab +#define DISP_CMD_VOLCTL 0xc6 +#define DISP_VOLCTL_TONE 0x80 +#define DISP_CMD_NOp 0x25 +#define DISP_CMD_OSSEL 0xd0 +#define DISP_CMD_3500KSET 0xd1 +#define DISP_CMD_3500KEND 0xd2 +#define DISP_CMD_14MSET 0xd3 +#define DISP_CMD_14MEND 0xd4 + +#define DISP_CMD_OUT(cmd) outpw(DISP_CMD_PORT, cmd); + +#define DISP_DATA_OUT(data) outpw(DISP_DATA_PORT, data); + +#define DISP_DATA_IN() inpw(DISP_DATA_PORT); + +/* Epson device column number starts at 2 +*/ +#define DISP_SET_RECT(ulhc_row, lrhc_row, ulhc_col, lrhc_col) \ + DISP_CMD_OUT(DISP_CMD_SD_PSET) \ + DISP_DATA_OUT((ulhc_row) & 0xFF) \ + DISP_DATA_OUT((ulhc_row) >> 8) \ + DISP_DATA_OUT((lrhc_row) & 0xFF) \ + DISP_DATA_OUT((lrhc_row) >> 8) \ + DISP_CMD_OUT(DISP_CMD_SD_CSET) \ + DISP_DATA_OUT(((ulhc_col)+2) & 0xFF) \ + DISP_DATA_OUT(((ulhc_col)+2) >> 8) \ + DISP_DATA_OUT(((lrhc_col)+2) & 0xFF) \ + DISP_DATA_OUT(((lrhc_col)+2) >> 8) + +#define DISP_MIN_CONTRAST 0 +#define DISP_MAX_CONTRAST 127 +#define DISP_DEFAULT_CONTRAST 80 + +#define DISP_MIN_BACKLIGHT 0 +#define DISP_MAX_BACKLIGHT 15 +#define DISP_DEFAULT_BACKLIGHT 2 + +#define WAIT_SEC(sec) mdelay((sec)/1000) + +static word disp_area_start_row; +static word disp_area_end_row; +static byte disp_contrast = DISP_DEFAULT_CONTRAST; +static boolean disp_powered_up; +static boolean disp_initialized = FALSE; +/* For some reason the contrast set at init time is not good. Need to do + * it again + */ +static boolean display_on = FALSE; +static void epsonQcif_disp_init(struct platform_device *pdev); +static void epsonQcif_disp_set_contrast(word contrast); +static void epsonQcif_disp_set_display_area(word start_row, word end_row); +static int epsonQcif_disp_off(struct platform_device *pdev); +static int epsonQcif_disp_on(struct platform_device *pdev); +static void epsonQcif_disp_set_rect(int x, int y, int xres, int yres); + +volatile word databack; +static void epsonQcif_disp_init(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + int i; + + if (disp_initialized) + return; + + mfd = platform_get_drvdata(pdev); + + DISP_CMD_PORT = mfd->cmd_port; + DISP_DATA_PORT = mfd->data_port; + + /* Sleep in */ + DISP_CMD_OUT(DISP_CMD_SLPIN); + + /* Display off */ + DISP_CMD_OUT(DISP_CMD_DISOFF); + + /* Display normal */ + DISP_CMD_OUT(DISP_CMD_DISNOR); + + /* Set data mode */ + DISP_CMD_OUT(DISP_CMD_DATCTL); + DISP_DATA_OUT(DISP_DATCTL_565); + + /* Set display timing */ + DISP_CMD_OUT(DISP_CMD_DISCTL); + DISP_DATA_OUT(0x1c); /* p1 */ + DISP_DATA_OUT(0x02); /* p1 */ + DISP_DATA_OUT(0x82); /* p2 */ + DISP_DATA_OUT(0x00); /* p3 */ + DISP_DATA_OUT(0x00); /* p4 */ + DISP_DATA_OUT(0xe0); /* p5 */ + DISP_DATA_OUT(0x00); /* p5 */ + DISP_DATA_OUT(0xdc); /* p6 */ + DISP_DATA_OUT(0x00); /* p6 */ + DISP_DATA_OUT(0x02); /* p7 */ + DISP_DATA_OUT(0x00); /* p8 */ + + /* Set 64 gray scale level */ + DISP_CMD_OUT(DISP_CMD_GCP64); + DISP_DATA_OUT(0x08); /* p01 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x2a); /* p02 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x4e); /* p03 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x6b); /* p04 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x88); /* p05 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0xa3); /* p06 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0xba); /* p07 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0xd1); /* p08 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0xe5); /* p09 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0xf3); /* p10 */ + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x03); /* p11 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x13); /* p12 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x22); /* p13 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x2f); /* p14 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x3b); /* p15 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x46); /* p16 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x51); /* p17 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x5b); /* p18 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x64); /* p19 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x6c); /* p20 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x74); /* p21 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x7c); /* p22 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x83); /* p23 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x8a); /* p24 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x91); /* p25 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x98); /* p26 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x9f); /* p27 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xa6); /* p28 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xac); /* p29 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xb2); /* p30 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xb7); /* p31 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xbc); /* p32 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xc1); /* p33 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xc6); /* p34 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xcb); /* p35 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xd0); /* p36 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xd4); /* p37 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xd8); /* p38 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xdc); /* p39 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xe0); /* p40 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xe4); /* p41 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xe8); /* p42 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xec); /* p43 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xf0); /* p44 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xf4); /* p45 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xf8); /* p46 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xfb); /* p47 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xfe); /* p48 */ + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0x01); /* p49 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x03); /* p50 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x05); /* p51 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x07); /* p52 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x09); /* p53 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x0b); /* p54 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x0d); /* p55 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x0f); /* p56 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x11); /* p57 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x13); /* p58 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x15); /* p59 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x17); /* p60 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x19); /* p61 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x1b); /* p62 */ + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x1c); /* p63 */ + DISP_DATA_OUT(0x02); + + /* Set 16 gray scale level */ + DISP_CMD_OUT(DISP_CMD_GCP16); + DISP_DATA_OUT(0x1a); /* p01 */ + DISP_DATA_OUT(0x32); /* p02 */ + DISP_DATA_OUT(0x42); /* p03 */ + DISP_DATA_OUT(0x4c); /* p04 */ + DISP_DATA_OUT(0x58); /* p05 */ + DISP_DATA_OUT(0x5f); /* p06 */ + DISP_DATA_OUT(0x66); /* p07 */ + DISP_DATA_OUT(0x6b); /* p08 */ + DISP_DATA_OUT(0x70); /* p09 */ + DISP_DATA_OUT(0x74); /* p10 */ + DISP_DATA_OUT(0x78); /* p11 */ + DISP_DATA_OUT(0x7b); /* p12 */ + DISP_DATA_OUT(0x7e); /* p13 */ + DISP_DATA_OUT(0x80); /* p14 */ + DISP_DATA_OUT(0x82); /* p15 */ + + /* Set DSP column */ + DISP_CMD_OUT(DISP_CMD_MD_CSET); + DISP_DATA_OUT(0xff); + DISP_DATA_OUT(0x03); + DISP_DATA_OUT(0xff); + DISP_DATA_OUT(0x03); + + /* Set DSP page */ + DISP_CMD_OUT(DISP_CMD_MD_PSET); + DISP_DATA_OUT(0xff); + DISP_DATA_OUT(0x01); + DISP_DATA_OUT(0xff); + DISP_DATA_OUT(0x01); + + /* Set ARM column */ + DISP_CMD_OUT(DISP_CMD_SD_CSET); + DISP_DATA_OUT(0x02); + DISP_DATA_OUT(0x00); + DISP_DATA_OUT((QCIF_WIDTH + 1) & 0xFF); + DISP_DATA_OUT((QCIF_WIDTH + 1) >> 8); + + /* Set ARM page */ + DISP_CMD_OUT(DISP_CMD_SD_PSET); + DISP_DATA_OUT(0x00); + DISP_DATA_OUT(0x00); + DISP_DATA_OUT((QCIF_HEIGHT - 1) & 0xFF); + DISP_DATA_OUT((QCIF_HEIGHT - 1) >> 8); + + /* Set 64 gray scales */ + DISP_CMD_OUT(DISP_CMD_GSSET); + DISP_DATA_OUT(DISP_GS_64); + + DISP_CMD_OUT(DISP_CMD_OSSEL); + DISP_DATA_OUT(0); + + /* Sleep out */ + DISP_CMD_OUT(DISP_CMD_SLPOUT); + + WAIT_SEC(40000); + + /* Initialize power IC */ + DISP_CMD_OUT(DISP_CMD_VOLCTL); + DISP_DATA_OUT(DISP_VOLCTL_TONE); + + WAIT_SEC(40000); + + /* Set electronic volume, d'xx */ + DISP_CMD_OUT(DISP_CMD_VOLCTL); + DISP_DATA_OUT(DISP_DEFAULT_CONTRAST); /* value from 0 to 127 */ + + /* Initialize display data */ + DISP_SET_RECT(0, (QCIF_HEIGHT - 1), 0, (QCIF_WIDTH - 1)); + DISP_CMD_OUT(DISP_CMD_RAMWR); + for (i = 0; i < QCIF_HEIGHT * QCIF_WIDTH; i++) + DISP_DATA_OUT(0xffff); + + DISP_CMD_OUT(DISP_CMD_RAMRD); + databack = DISP_DATA_IN(); + databack = DISP_DATA_IN(); + databack = DISP_DATA_IN(); + databack = DISP_DATA_IN(); + + WAIT_SEC(80000); + + DISP_CMD_OUT(DISP_CMD_DISON); + + disp_area_start_row = 0; + disp_area_end_row = QCIF_HEIGHT - 1; + disp_powered_up = TRUE; + disp_initialized = TRUE; + epsonQcif_disp_set_display_area(0, QCIF_HEIGHT - 1); + display_on = TRUE; +} + +static void epsonQcif_disp_set_rect(int x, int y, int xres, int yres) +{ + if (!disp_initialized) + return; + + DISP_SET_RECT(y, y + yres - 1, x, x + xres - 1); + DISP_CMD_OUT(DISP_CMD_RAMWR); +} + +static void epsonQcif_disp_set_display_area(word start_row, word end_row) +{ + if (!disp_initialized) + return; + + if ((start_row == disp_area_start_row) + && (end_row == disp_area_end_row)) + return; + disp_area_start_row = start_row; + disp_area_end_row = end_row; + + /* Range checking + */ + if (end_row >= QCIF_HEIGHT) + end_row = QCIF_HEIGHT - 1; + if (start_row > end_row) + start_row = end_row; + + /* When display is not the full screen, gray scale is set to + ** 2; otherwise it is set to 64. + */ + if ((start_row == 0) && (end_row == (QCIF_HEIGHT - 1))) { + /* The whole screen */ + DISP_CMD_OUT(DISP_CMD_PTLOUT); + WAIT_SEC(10000); + DISP_CMD_OUT(DISP_CMD_DISOFF); + WAIT_SEC(100000); + DISP_CMD_OUT(DISP_CMD_GSSET); + DISP_DATA_OUT(DISP_GS_64); + WAIT_SEC(100000); + DISP_CMD_OUT(DISP_CMD_DISON); + } else { + /* partial screen */ + DISP_CMD_OUT(DISP_CMD_PTLIN); + DISP_DATA_OUT(start_row); + DISP_DATA_OUT(start_row >> 8); + DISP_DATA_OUT(end_row); + DISP_DATA_OUT(end_row >> 8); + DISP_CMD_OUT(DISP_CMD_GSSET); + DISP_DATA_OUT(DISP_GS_2); + } +} + +static int epsonQcif_disp_off(struct platform_device *pdev) +{ + if (!disp_initialized) + epsonQcif_disp_init(pdev); + + if (display_on) { + DISP_CMD_OUT(DISP_CMD_DISOFF); + DISP_CMD_OUT(DISP_CMD_SLPIN); + display_on = FALSE; + } + + return 0; +} + +static int epsonQcif_disp_on(struct platform_device *pdev) +{ + if (!disp_initialized) + epsonQcif_disp_init(pdev); + + if (!display_on) { + DISP_CMD_OUT(DISP_CMD_SLPOUT); + WAIT_SEC(40000); + DISP_CMD_OUT(DISP_CMD_DISON); + epsonQcif_disp_set_contrast(disp_contrast); + display_on = TRUE; + } + + return 0; +} + +static void epsonQcif_disp_set_contrast(word contrast) +{ + if (!disp_initialized) + return; + + /* Initialize power IC, d'24 */ + DISP_CMD_OUT(DISP_CMD_VOLCTL); + DISP_DATA_OUT(DISP_VOLCTL_TONE); + + WAIT_SEC(40000); + + /* Set electronic volume, d'xx */ + DISP_CMD_OUT(DISP_CMD_VOLCTL); + if (contrast > 127) + contrast = 127; + DISP_DATA_OUT(contrast); /* value from 0 to 127 */ + disp_contrast = (byte) contrast; +} /* End disp_set_contrast */ + +static void epsonQcif_disp_clear_screen_area( + word start_row, word end_row, word start_column, word end_column) { + int32 i; + + /* Clear the display screen */ + DISP_SET_RECT(start_row, end_row, start_column, end_column); + DISP_CMD_OUT(DISP_CMD_RAMWR); + i = (end_row - start_row + 1) * (end_column - start_column + 1); + for (; i > 0; i--) + DISP_DATA_OUT(0xffff); +} + +static int __init epsonQcif_probe(struct platform_device *pdev) +{ + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = epsonQcif_probe, + .driver = { + .name = "ebi2_epson_qcif", + }, +}; + +static struct msm_fb_panel_data epsonQcif_panel_data = { + .on = epsonQcif_disp_on, + .off = epsonQcif_disp_off, + .set_rect = epsonQcif_disp_set_rect, +}; + +static struct platform_device this_device = { + .name = "ebi2_epson_qcif", + .id = 0, + .dev = { + .platform_data = &epsonQcif_panel_data, + } +}; + +static int __init epsonQcif_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + + ret = platform_driver_register(&this_driver); + if (!ret) { + pinfo = &epsonQcif_panel_data.panel_info; + pinfo->xres = QCIF_WIDTH; + pinfo->yres = QCIF_HEIGHT; + MSM_FB_SINGLE_MODE_PANEL(pinfo); + pinfo->type = EBI2_PANEL; + pinfo->pdest = DISPLAY_2; + pinfo->wait_cycle = 0x808000; + pinfo->bpp = 16; + pinfo->fb_num = 2; + pinfo->lcd.vsync_enable = FALSE; + + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + } + + return ret; +} + +module_init(epsonQcif_init); diff --git a/drivers/video/msm/ebi2_lcd.c b/drivers/video/msm/ebi2_lcd.c new file mode 100644 index 000000000000..a19763c4666d --- /dev/null +++ b/drivers/video/msm/ebi2_lcd.c @@ -0,0 +1,308 @@ +/* Copyright (c) 2008-2009, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_fb.h" + +static int ebi2_lcd_probe(struct platform_device *pdev); +static int ebi2_lcd_remove(struct platform_device *pdev); + +static int ebi2_lcd_runtime_suspend(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: suspending...\n"); + return 0; +} + +static int ebi2_lcd_runtime_resume(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: resuming...\n"); + return 0; +} + +static struct dev_pm_ops ebi2_lcd_dev_pm_ops = { + .runtime_suspend = ebi2_lcd_runtime_suspend, + .runtime_resume = ebi2_lcd_runtime_resume, +}; + +static struct platform_driver ebi2_lcd_driver = { + .probe = ebi2_lcd_probe, + .remove = ebi2_lcd_remove, + .suspend = NULL, + .resume = NULL, + .shutdown = NULL, + .driver = { + .name = "ebi2_lcd", + .pm = &ebi2_lcd_dev_pm_ops, + }, +}; + +static void *ebi2_base; +static void *ebi2_lcd_cfg0; +static void *ebi2_lcd_cfg1; +static void __iomem *lcd01_base; +static void __iomem *lcd02_base; +static int lcd01_base_phys; +static int ebi2_lcd_resource_initialized; + +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; +static struct lcdc_platform_data *ebi2_pdata; + +static int ebi2_lcd_on(struct platform_device *pdev) +{ + int ret; + + if (ebi2_pdata && ebi2_pdata->lcdc_power_save) + ebi2_pdata->lcdc_power_save(1); + + ret = panel_next_on(pdev); + return ret; +} + +static int ebi2_lcd_off(struct platform_device *pdev) +{ + int ret; + + ret = panel_next_off(pdev); + + if (ebi2_pdata && ebi2_pdata->lcdc_power_save) + ebi2_pdata->lcdc_power_save(0); + + return ret; +} + +static int ebi2_lcd_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct platform_device *mdp_dev = NULL; + struct msm_fb_panel_data *pdata = NULL; + int rc, i, hw_version; + + if (pdev->id == 0) { + for (i = 0; i < pdev->num_resources; i++) { + if (!strncmp(pdev->resource[i].name, "base", 4)) { + ebi2_base = ioremap(pdev->resource[i].start, + pdev->resource[i].end - + pdev->resource[i].start + 1); + if (!ebi2_base) { + printk(KERN_ERR + "ebi2_base ioremap failed!\n"); + return -ENOMEM; + } + ebi2_lcd_cfg0 = (void *)(ebi2_base + 0x20); + ebi2_lcd_cfg1 = (void *)(ebi2_base + 0x24); + } else if (!strncmp(pdev->resource[i].name, + "lcd01", 5)) { + lcd01_base_phys = pdev->resource[i].start; + lcd01_base = ioremap(pdev->resource[i].start, + pdev->resource[i].end - + pdev->resource[i].start + 1); + if (!lcd01_base) { + printk(KERN_ERR + "lcd01_base ioremap failed!\n"); + return -ENOMEM; + } + } else if (!strncmp(pdev->resource[i].name, + "lcd02", 5)) { + lcd02_base = ioremap(pdev->resource[i].start, + pdev->resource[i].end - + pdev->resource[i].start + 1); + if (!lcd02_base) { + printk(KERN_ERR + "lcd02_base ioremap failed!\n"); + return -ENOMEM; + } + } + } + ebi2_pdata = pdev->dev.platform_data; + ebi2_lcd_resource_initialized = 1; + + return 0; + } + + if (!ebi2_lcd_resource_initialized) + return -EPERM; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) + return -ENOMEM; + + if (ebi2_base == NULL) + return -ENOMEM; + + mdp_dev = platform_device_alloc("mdp", pdev->id); + if (!mdp_dev) + return -ENOMEM; + + /* link to the latest pdev */ + mfd->pdev = mdp_dev; + mfd->dest = DISPLAY_LCD; + + /* add panel data */ + if (platform_device_add_data + (mdp_dev, pdev->dev.platform_data, + sizeof(struct msm_fb_panel_data))) { + printk(KERN_ERR "ebi2_lcd_probe: platform_device_add_data failed!\n"); + platform_device_put(mdp_dev); + return -ENOMEM; + } + + /* data chain */ + pdata = mdp_dev->dev.platform_data; + pdata->on = ebi2_lcd_on; + pdata->off = ebi2_lcd_off; + pdata->next = pdev; + + /* get/set panel specific fb info */ + mfd->panel_info = pdata->panel_info; + + hw_version = inp32((int)ebi2_base + 8); + + if (mfd->panel_info.bpp == 24) + mfd->fb_imgType = MDP_RGB_888; + else if (mfd->panel_info.bpp == 18) + mfd->fb_imgType = MDP_RGB_888; + else + mfd->fb_imgType = MDP_RGB_565; + + /* config msm ebi2 lcd register */ + if (mfd->panel_info.pdest == DISPLAY_1) { + outp32(ebi2_base, + (inp32(ebi2_base) & (~(EBI2_PRIM_LCD_CLR))) | + EBI2_PRIM_LCD_SEL); + /* + * current design has one set of cfg0/1 register to control + * both EBI2 channels. so, we're using the PRIM channel to + * configure both. + */ + outp32(ebi2_lcd_cfg0, mfd->panel_info.wait_cycle); + if (hw_version < 0x2020) { + if (mfd->panel_info.bpp == 18) + outp32(ebi2_lcd_cfg1, 0x01000000); + else + outp32(ebi2_lcd_cfg1, 0x0); + } + } else { +#ifdef DEBUG_EBI2_LCD + /* + * confliting with QCOM SURF FPGA CS. + * OEM should enable below for their CS mapping + */ + outp32(ebi2_base, (inp32(ebi2_base)&(~(EBI2_SECD_LCD_CLR))) + |EBI2_SECD_LCD_SEL); +#endif + } + + /* + * map cs (chip select) address + */ + if (mfd->panel_info.pdest == DISPLAY_1) { + mfd->cmd_port = lcd01_base; + if (hw_version >= 0x2020) { + mfd->data_port = + (void *)((uint32) mfd->cmd_port + 0x80); + mfd->data_port_phys = + (void *)(lcd01_base_phys + 0x80); + } else { + mfd->data_port = + (void *)((uint32) mfd->cmd_port + + EBI2_PRIM_LCD_RS_PIN); + mfd->data_port_phys = + (void *)(LCD_PRIM_BASE_PHYS + EBI2_PRIM_LCD_RS_PIN); + } + } else { + mfd->cmd_port = lcd01_base; + mfd->data_port = + (void *)((uint32) mfd->cmd_port + EBI2_SECD_LCD_RS_PIN); + mfd->data_port_phys = + (void *)(LCD_SECD_BASE_PHYS + EBI2_SECD_LCD_RS_PIN); + } + + /* + * set driver data + */ + platform_set_drvdata(mdp_dev, mfd); + + /* + * register in mdp driver + */ + rc = platform_device_add(mdp_dev); + if (rc) { + goto ebi2_lcd_probe_err; + } + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + + pdev_list[pdev_list_cnt++] = pdev; + return 0; + + ebi2_lcd_probe_err: + platform_device_put(mdp_dev); + return rc; +} + +static int ebi2_lcd_remove(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if (!mfd) + return 0; + + if (mfd->key != MFD_KEY) + return 0; + + iounmap(mfd->cmd_port); + pm_runtime_disable(&pdev->dev); + return 0; +} + +static int ebi2_lcd_register_driver(void) +{ + return platform_driver_register(&ebi2_lcd_driver); +} + +static int __init ebi2_lcd_driver_init(void) +{ + return ebi2_lcd_register_driver(); +} + +module_init(ebi2_lcd_driver_init); diff --git a/drivers/video/msm/ebi2_tmd20.c b/drivers/video/msm/ebi2_tmd20.c new file mode 100644 index 000000000000..7c7b0efd3301 --- /dev/null +++ b/drivers/video/msm/ebi2_tmd20.c @@ -0,0 +1,1120 @@ +/* Copyright (c) 2008-2010, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" + +#include +#include +#include +#include +#include +#include +#include "linux/proc_fs.h" + +#include + +#include +#include + +#include +#include + +/* #define TMD20QVGA_LCD_18BPP */ +#define QVGA_WIDTH 240 +#define QVGA_HEIGHT 320 + +#ifdef TMD20QVGA_LCD_18BPP +#define DISP_QVGA_18BPP(x) ((((x)<<2) & 0x3FC00)|(( (x)<<1)& 0x1FE)) +#define DISP_REG(name) uint32 register_##name; +#define OUTPORT(x, y) outpdw(x, y) +#define INPORT(x) inpdw(x) +#else +#define DISP_QVGA_18BPP(x) (x) +#define DISP_REG(name) uint16 register_##name; +#define OUTPORT(x, y) outpw(x, y) +#define INPORT(x) intpw(x) +#endif + +static void *DISP_CMD_PORT; +static void *DISP_DATA_PORT; + +#define DISP_RNTI 0x10 + +#define DISP_CMD_OUT(cmd) OUTPORT(DISP_CMD_PORT, DISP_QVGA_18BPP(cmd)) +#define DISP_DATA_OUT(data) OUTPORT(DISP_DATA_PORT, data) +#define DISP_DATA_IN() INPORT(DISP_DATA_PORT) + +#if (defined(TMD20QVGA_LCD_18BPP)) +#define DISP_DATA_OUT_16TO18BPP(x) \ + DISP_DATA_OUT((((x)&0xf800)<<2|((x)&0x80000)>>3) \ + | (((x)&0x7e0)<<1) \ + | (((x)&0x1F)<<1|((x)&0x10)>>4)) +#else +#define DISP_DATA_OUT_16TO18BPP(x) \ + DISP_DATA_OUT(x) +#endif + +#define DISP_WRITE_OUT(addr, data) \ + register_##addr = DISP_QVGA_18BPP(data); \ + DISP_CMD_OUT(addr); \ + DISP_DATA_OUT(register_##addr); + +#define DISP_UPDATE_VALUE(addr, bitmask, data) \ + DISP_WRITE_OUT(##addr, (register_##addr & ~(bitmask)) | (data)); + +#define DISP_VAL_IF(bitvalue, bitmask) \ + ((bitvalue) ? (bitmask) : 0) + +/* QVGA = 256 x 320 */ +/* actual display is 240 x 320...offset by 0x10 */ +#define DISP_ROW_COL_TO_ADDR(row, col) ((row) * 0x100 + col) +#define DISP_SET_RECT(ulhc_row, lrhc_row, ulhc_col, lrhc_col) \ + { \ + DISP_WRITE_OUT(DISP_HORZ_RAM_ADDR_POS_1_ADDR, (ulhc_col) + tmd20qvga_panel_offset); \ + DISP_WRITE_OUT(DISP_HORZ_RAM_ADDR_POS_2_ADDR, (lrhc_col) + tmd20qvga_panel_offset); \ + DISP_WRITE_OUT(DISP_VERT_RAM_ADDR_POS_1_ADDR, (ulhc_row)); \ + DISP_WRITE_OUT(DISP_VERT_RAM_ADDR_POS_2_ADDR, (lrhc_row)); \ + DISP_WRITE_OUT(DISP_RAM_ADDR_SET_1_ADDR, (ulhc_col) + tmd20qvga_panel_offset); \ + DISP_WRITE_OUT(DISP_RAM_ADDR_SET_2_ADDR, (ulhc_row)); \ + } + +#define WAIT_MSEC(msec) mdelay(msec) + +/* + * TMD QVGA Address + */ +/* Display Control */ +#define DISP_START_OSCILLATION_ADDR 0x000 +DISP_REG(DISP_START_OSCILLATION_ADDR) +#define DISP_DRIVER_OUTPUT_CTL_ADDR 0x001 + DISP_REG(DISP_DRIVER_OUTPUT_CTL_ADDR) +#define DISP_LCD_DRIVING_SIG_ADDR 0x002 + DISP_REG(DISP_LCD_DRIVING_SIG_ADDR) +#define DISP_ENTRY_MODE_ADDR 0x003 + DISP_REG(DISP_ENTRY_MODE_ADDR) +#define DISP_DISPLAY_CTL_1_ADDR 0x007 + DISP_REG(DISP_DISPLAY_CTL_1_ADDR) +#define DISP_DISPLAY_CTL_2_ADDR 0x008 + DISP_REG(DISP_DISPLAY_CTL_2_ADDR) + +/* DISPLAY MODE 0x009 partial display not supported */ +#define DISP_POWER_SUPPLY_INTF_ADDR 0x00A + DISP_REG(DISP_POWER_SUPPLY_INTF_ADDR) + +/* DISPLAY MODE 0x00B xZoom feature is not supported */ +#define DISP_EXT_DISPLAY_CTL_1_ADDR 0x00C + DISP_REG(DISP_EXT_DISPLAY_CTL_1_ADDR) + +#define DISP_FRAME_CYCLE_CTL_ADDR 0x00D + DISP_REG(DISP_FRAME_CYCLE_CTL_ADDR) + +#define DISP_EXT_DISPLAY_CTL_2_ADDR 0x00E + DISP_REG(DISP_EXT_DISPLAY_CTL_2_ADDR) + +#define DISP_EXT_DISPLAY_CTL_3_ADDR 0x00F + DISP_REG(DISP_EXT_DISPLAY_CTL_3_ADDR) + +#define DISP_LTPS_CTL_1_ADDR 0x012 + DISP_REG(DISP_LTPS_CTL_1_ADDR) +#define DISP_LTPS_CTL_2_ADDR 0x013 + DISP_REG(DISP_LTPS_CTL_2_ADDR) +#define DISP_LTPS_CTL_3_ADDR 0x014 + DISP_REG(DISP_LTPS_CTL_3_ADDR) +#define DISP_LTPS_CTL_4_ADDR 0x018 + DISP_REG(DISP_LTPS_CTL_4_ADDR) +#define DISP_LTPS_CTL_5_ADDR 0x019 + DISP_REG(DISP_LTPS_CTL_5_ADDR) +#define DISP_LTPS_CTL_6_ADDR 0x01A + DISP_REG(DISP_LTPS_CTL_6_ADDR) +#define DISP_AMP_SETTING_ADDR 0x01C + DISP_REG(DISP_AMP_SETTING_ADDR) +#define DISP_MODE_SETTING_ADDR 0x01D + DISP_REG(DISP_MODE_SETTING_ADDR) +#define DISP_POFF_LN_SETTING_ADDR 0x01E + DISP_REG(DISP_POFF_LN_SETTING_ADDR) +/* Power Contol */ +#define DISP_POWER_CTL_1_ADDR 0x100 + DISP_REG(DISP_POWER_CTL_1_ADDR) +#define DISP_POWER_CTL_2_ADDR 0x101 + DISP_REG(DISP_POWER_CTL_2_ADDR) +#define DISP_POWER_CTL_3_ADDR 0x102 + DISP_REG(DISP_POWER_CTL_3_ADDR) +#define DISP_POWER_CTL_4_ADDR 0x103 + DISP_REG(DISP_POWER_CTL_4_ADDR) +#define DISP_POWER_CTL_5_ADDR 0x104 + DISP_REG(DISP_POWER_CTL_5_ADDR) +#define DISP_POWER_CTL_6_ADDR 0x105 + DISP_REG(DISP_POWER_CTL_6_ADDR) +#define DISP_POWER_CTL_7_ADDR 0x106 + DISP_REG(DISP_POWER_CTL_7_ADDR) +/* RAM Access */ +#define DISP_RAM_ADDR_SET_1_ADDR 0x200 + DISP_REG(DISP_RAM_ADDR_SET_1_ADDR) +#define DISP_RAM_ADDR_SET_2_ADDR 0x201 + DISP_REG(DISP_RAM_ADDR_SET_2_ADDR) +#define DISP_CMD_RAMRD DISP_CMD_RAMWR +#define DISP_CMD_RAMWR 0x202 + DISP_REG(DISP_CMD_RAMWR) +#define DISP_RAM_DATA_MASK_1_ADDR 0x203 + DISP_REG(DISP_RAM_DATA_MASK_1_ADDR) +#define DISP_RAM_DATA_MASK_2_ADDR 0x204 + DISP_REG(DISP_RAM_DATA_MASK_2_ADDR) +/* Gamma Control, Contrast, Gray Scale Setting */ +#define DISP_GAMMA_CONTROL_1_ADDR 0x300 + DISP_REG(DISP_GAMMA_CONTROL_1_ADDR) +#define DISP_GAMMA_CONTROL_2_ADDR 0x301 + DISP_REG(DISP_GAMMA_CONTROL_2_ADDR) +#define DISP_GAMMA_CONTROL_3_ADDR 0x302 + DISP_REG(DISP_GAMMA_CONTROL_3_ADDR) +#define DISP_GAMMA_CONTROL_4_ADDR 0x303 + DISP_REG(DISP_GAMMA_CONTROL_4_ADDR) +#define DISP_GAMMA_CONTROL_5_ADDR 0x304 + DISP_REG(DISP_GAMMA_CONTROL_5_ADDR) +/* Coordinate Control */ +#define DISP_VERT_SCROLL_CTL_1_ADDR 0x400 + DISP_REG(DISP_VERT_SCROLL_CTL_1_ADDR) +#define DISP_VERT_SCROLL_CTL_2_ADDR 0x401 + DISP_REG(DISP_VERT_SCROLL_CTL_2_ADDR) +#define DISP_SCREEN_1_DRV_POS_1_ADDR 0x402 + DISP_REG(DISP_SCREEN_1_DRV_POS_1_ADDR) +#define DISP_SCREEN_1_DRV_POS_2_ADDR 0x403 + DISP_REG(DISP_SCREEN_1_DRV_POS_2_ADDR) +#define DISP_SCREEN_2_DRV_POS_1_ADDR 0x404 + DISP_REG(DISP_SCREEN_2_DRV_POS_1_ADDR) +#define DISP_SCREEN_2_DRV_POS_2_ADDR 0x405 + DISP_REG(DISP_SCREEN_2_DRV_POS_2_ADDR) +#define DISP_HORZ_RAM_ADDR_POS_1_ADDR 0x406 + DISP_REG(DISP_HORZ_RAM_ADDR_POS_1_ADDR) +#define DISP_HORZ_RAM_ADDR_POS_2_ADDR 0x407 + DISP_REG(DISP_HORZ_RAM_ADDR_POS_2_ADDR) +#define DISP_VERT_RAM_ADDR_POS_1_ADDR 0x408 + DISP_REG(DISP_VERT_RAM_ADDR_POS_1_ADDR) +#define DISP_VERT_RAM_ADDR_POS_2_ADDR 0x409 + DISP_REG(DISP_VERT_RAM_ADDR_POS_2_ADDR) +#define DISP_TMD_700_ADDR 0x700 /* 0x700 */ + DISP_REG(DISP_TMD_700_ADDR) +#define DISP_TMD_015_ADDR 0x015 /* 0x700 */ + DISP_REG(DISP_TMD_015_ADDR) +#define DISP_TMD_305_ADDR 0x305 /* 0x700 */ + DISP_REG(DISP_TMD_305_ADDR) + +/* + * TMD QVGA Bit Definations + */ + +#define DISP_BIT_IB15 0x8000 +#define DISP_BIT_IB14 0x4000 +#define DISP_BIT_IB13 0x2000 +#define DISP_BIT_IB12 0x1000 +#define DISP_BIT_IB11 0x0800 +#define DISP_BIT_IB10 0x0400 +#define DISP_BIT_IB09 0x0200 +#define DISP_BIT_IB08 0x0100 +#define DISP_BIT_IB07 0x0080 +#define DISP_BIT_IB06 0x0040 +#define DISP_BIT_IB05 0x0020 +#define DISP_BIT_IB04 0x0010 +#define DISP_BIT_IB03 0x0008 +#define DISP_BIT_IB02 0x0004 +#define DISP_BIT_IB01 0x0002 +#define DISP_BIT_IB00 0x0001 +/* + * Display Control + * DISP_START_OSCILLATION_ADDR Start Oscillation + * DISP_DRIVER_OUTPUT_CTL_ADDR Driver Output Control + */ +#define DISP_BITMASK_SS DISP_BIT_IB08 +#define DISP_BITMASK_NL5 DISP_BIT_IB05 +#define DISP_BITMASK_NL4 DISP_BIT_IB04 +#define DISP_BITMASK_NL3 DISP_BIT_IB03 +#define DISP_BITMASK_NL2 DISP_BIT_IB02 +#define DISP_BITMASK_NL1 DISP_BIT_IB01 +#define DISP_BITMASK_NL0 DISP_BIT_IB00 +/* DISP_LCD_DRIVING_SIG_ADDR LCD Driving Signal Setting */ +#define DISP_BITMASK_BC DISP_BIT_IB09 +/* DISP_ENTRY_MODE_ADDR Entry Mode */ +#define DISP_BITMASK_TRI DISP_BIT_IB15 +#define DISP_BITMASK_DFM1 DISP_BIT_IB14 +#define DISP_BITMASK_DFM0 DISP_BIT_IB13 +#define DISP_BITMASK_BGR DISP_BIT_IB12 +#define DISP_BITMASK_HWM0 DISP_BIT_IB08 +#define DISP_BITMASK_ID1 DISP_BIT_IB05 +#define DISP_BITMASK_ID0 DISP_BIT_IB04 +#define DISP_BITMASK_AM DISP_BIT_IB03 +/* DISP_DISPLAY_CTL_1_ADDR Display Control (1) */ +#define DISP_BITMASK_COL1 DISP_BIT_IB15 +#define DISP_BITMASK_COL0 DISP_BIT_IB14 +#define DISP_BITMASK_VLE2 DISP_BIT_IB10 +#define DISP_BITMASK_VLE1 DISP_BIT_IB09 +#define DISP_BITMASK_SPT DISP_BIT_IB08 +#define DISP_BITMASK_PT1 DISP_BIT_IB07 +#define DISP_BITMASK_PT0 DISP_BIT_IB06 +#define DISP_BITMASK_REV DISP_BIT_IB02 +/* DISP_DISPLAY_CTL_2_ADDR Display Control (2) */ +#define DISP_BITMASK_FP3 DISP_BIT_IB11 +#define DISP_BITMASK_FP2 DISP_BIT_IB10 +#define DISP_BITMASK_FP1 DISP_BIT_IB09 +#define DISP_BITMASK_FP0 DISP_BIT_IB08 +#define DISP_BITMASK_BP3 DISP_BIT_IB03 +#define DISP_BITMASK_BP2 DISP_BIT_IB02 +#define DISP_BITMASK_BP1 DISP_BIT_IB01 +#define DISP_BITMASK_BP0 DISP_BIT_IB00 +/* DISP_POWER_SUPPLY_INTF_ADDR Power Supply IC Interface Control */ +#define DISP_BITMASK_CSE DISP_BIT_IB12 +#define DISP_BITMASK_TE DISP_BIT_IB08 +#define DISP_BITMASK_IX3 DISP_BIT_IB03 +#define DISP_BITMASK_IX2 DISP_BIT_IB02 +#define DISP_BITMASK_IX1 DISP_BIT_IB01 +#define DISP_BITMASK_IX0 DISP_BIT_IB00 +/* DISP_EXT_DISPLAY_CTL_1_ADDR External Display Interface Control (1) */ +#define DISP_BITMASK_RM DISP_BIT_IB08 +#define DISP_BITMASK_DM1 DISP_BIT_IB05 +#define DISP_BITMASK_DM0 DISP_BIT_IB04 +#define DISP_BITMASK_RIM1 DISP_BIT_IB01 +#define DISP_BITMASK_RIM0 DISP_BIT_IB00 +/* DISP_FRAME_CYCLE_CTL_ADDR Frame Frequency Adjustment Control */ +#define DISP_BITMASK_DIVI1 DISP_BIT_IB09 +#define DISP_BITMASK_DIVI0 DISP_BIT_IB08 +#define DISP_BITMASK_RTNI4 DISP_BIT_IB04 +#define DISP_BITMASK_RTNI3 DISP_BIT_IB03 +#define DISP_BITMASK_RTNI2 DISP_BIT_IB02 +#define DISP_BITMASK_RTNI1 DISP_BIT_IB01 +#define DISP_BITMASK_RTNI0 DISP_BIT_IB00 +/* DISP_EXT_DISPLAY_CTL_2_ADDR External Display Interface Control (2) */ +#define DISP_BITMASK_DIVE1 DISP_BIT_IB09 +#define DISP_BITMASK_DIVE0 DISP_BIT_IB08 +#define DISP_BITMASK_RTNE7 DISP_BIT_IB07 +#define DISP_BITMASK_RTNE6 DISP_BIT_IB06 +#define DISP_BITMASK_RTNE5 DISP_BIT_IB05 +#define DISP_BITMASK_RTNE4 DISP_BIT_IB04 +#define DISP_BITMASK_RTNE3 DISP_BIT_IB03 +#define DISP_BITMASK_RTNE2 DISP_BIT_IB02 +#define DISP_BITMASK_RTNE1 DISP_BIT_IB01 +#define DISP_BITMASK_RTNE0 DISP_BIT_IB00 +/* DISP_EXT_DISPLAY_CTL_3_ADDR External Display Interface Control (3) */ +#define DISP_BITMASK_VSPL DISP_BIT_IB04 +#define DISP_BITMASK_HSPL DISP_BIT_IB03 +#define DISP_BITMASK_VPL DISP_BIT_IB02 +#define DISP_BITMASK_EPL DISP_BIT_IB01 +#define DISP_BITMASK_DPL DISP_BIT_IB00 +/* DISP_LTPS_CTL_1_ADDR LTPS Interface Control (1) */ +#define DISP_BITMASK_CLWI3 DISP_BIT_IB11 +#define DISP_BITMASK_CLWI2 DISP_BIT_IB10 +#define DISP_BITMASK_CLWI1 DISP_BIT_IB09 +#define DISP_BITMASK_CLWI0 DISP_BIT_IB08 +#define DISP_BITMASK_CLTI1 DISP_BIT_IB01 +#define DISP_BITMASK_CLTI0 DISP_BIT_IB00 +/* DISP_LTPS_CTL_2_ADDR LTPS Interface Control (2) */ +#define DISP_BITMASK_OEVBI1 DISP_BIT_IB09 +#define DISP_BITMASK_OEVBI0 DISP_BIT_IB08 +#define DISP_BITMASK_OEVFI1 DISP_BIT_IB01 +#define DISP_BITMASK_OEVFI0 DISP_BIT_IB00 +/* DISP_LTPS_CTL_3_ADDR LTPS Interface Control (3) */ +#define DISP_BITMASK_SHI1 DISP_BIT_IB01 +#define DISP_BITMASK_SHI0 DISP_BIT_IB00 +/* DISP_LTPS_CTL_4_ADDR LTPS Interface Control (4) */ +#define DISP_BITMASK_CLWE5 DISP_BIT_IB13 +#define DISP_BITMASK_CLWE4 DISP_BIT_IB12 +#define DISP_BITMASK_CLWE3 DISP_BIT_IB11 +#define DISP_BITMASK_CLWE2 DISP_BIT_IB10 +#define DISP_BITMASK_CLWE1 DISP_BIT_IB09 +#define DISP_BITMASK_CLWE0 DISP_BIT_IB08 +#define DISP_BITMASK_CLTE3 DISP_BIT_IB03 +#define DISP_BITMASK_CLTE2 DISP_BIT_IB02 +#define DISP_BITMASK_CLTE1 DISP_BIT_IB01 +#define DISP_BITMASK_CLTE0 DISP_BIT_IB00 +/* DISP_LTPS_CTL_5_ADDR LTPS Interface Control (5) */ +#define DISP_BITMASK_OEVBE3 DISP_BIT_IB11 +#define DISP_BITMASK_OEVBE2 DISP_BIT_IB10 +#define DISP_BITMASK_OEVBE1 DISP_BIT_IB09 +#define DISP_BITMASK_OEVBE0 DISP_BIT_IB08 +#define DISP_BITMASK_OEVFE3 DISP_BIT_IB03 +#define DISP_BITMASK_OEVFE2 DISP_BIT_IB02 +#define DISP_BITMASK_OEVFE1 DISP_BIT_IB01 +#define DISP_BITMASK_OEVFE0 DISP_BIT_IB00 +/* DISP_LTPS_CTL_6_ADDR LTPS Interface Control (6) */ +#define DISP_BITMASK_SHE3 DISP_BIT_IB03 +#define DISP_BITMASK_SHE2 DISP_BIT_IB02 +#define DISP_BITMASK_SHE1 DISP_BIT_IB01 +#define DISP_BITMASK_SHE0 DISP_BIT_IB00 +/* DISP_AMP_SETTING_ADDR Amplify Setting */ +#define DISP_BITMASK_ABSW1 DISP_BIT_IB01 +#define DISP_BITMASK_ABSW0 DISP_BIT_IB00 +/* DISP_MODE_SETTING_ADDR Mode Setting */ +#define DISP_BITMASK_DSTB DISP_BIT_IB02 +#define DISP_BITMASK_STB DISP_BIT_IB00 +/* DISP_POFF_LN_SETTING_ADDR Power Off Line Setting */ +#define DISP_BITMASK_POFH3 DISP_BIT_IB03 +#define DISP_BITMASK_POFH2 DISP_BIT_IB02 +#define DISP_BITMASK_POFH1 DISP_BIT_IB01 +#define DISP_BITMASK_POFH0 DISP_BIT_IB00 + +/* Power Contol */ +/* DISP_POWER_CTL_1_ADDR Power Control (1) */ +#define DISP_BITMASK_PO DISP_BIT_IB11 +#define DISP_BITMASK_VCD DISP_BIT_IB09 +#define DISP_BITMASK_VSC DISP_BIT_IB08 +#define DISP_BITMASK_CON DISP_BIT_IB07 +#define DISP_BITMASK_ASW1 DISP_BIT_IB06 +#define DISP_BITMASK_ASW0 DISP_BIT_IB05 +#define DISP_BITMASK_OEV DISP_BIT_IB04 +#define DISP_BITMASK_OEVE DISP_BIT_IB03 +#define DISP_BITMASK_FR DISP_BIT_IB02 +#define DISP_BITMASK_D1 DISP_BIT_IB01 +#define DISP_BITMASK_D0 DISP_BIT_IB00 +/* DISP_POWER_CTL_2_ADDR Power Control (2) */ +#define DISP_BITMASK_DC4 DISP_BIT_IB15 +#define DISP_BITMASK_DC3 DISP_BIT_IB14 +#define DISP_BITMASK_SAP2 DISP_BIT_IB13 +#define DISP_BITMASK_SAP1 DISP_BIT_IB12 +#define DISP_BITMASK_SAP0 DISP_BIT_IB11 +#define DISP_BITMASK_BT2 DISP_BIT_IB10 +#define DISP_BITMASK_BT1 DISP_BIT_IB09 +#define DISP_BITMASK_BT0 DISP_BIT_IB08 +#define DISP_BITMASK_DC2 DISP_BIT_IB07 +#define DISP_BITMASK_DC1 DISP_BIT_IB06 +#define DISP_BITMASK_DC0 DISP_BIT_IB05 +#define DISP_BITMASK_AP2 DISP_BIT_IB04 +#define DISP_BITMASK_AP1 DISP_BIT_IB03 +#define DISP_BITMASK_AP0 DISP_BIT_IB02 +/* DISP_POWER_CTL_3_ADDR Power Control (3) */ +#define DISP_BITMASK_VGL4 DISP_BIT_IB10 +#define DISP_BITMASK_VGL3 DISP_BIT_IB09 +#define DISP_BITMASK_VGL2 DISP_BIT_IB08 +#define DISP_BITMASK_VGL1 DISP_BIT_IB07 +#define DISP_BITMASK_VGL0 DISP_BIT_IB06 +#define DISP_BITMASK_VGH4 DISP_BIT_IB04 +#define DISP_BITMASK_VGH3 DISP_BIT_IB03 +#define DISP_BITMASK_VGH2 DISP_BIT_IB02 +#define DISP_BITMASK_VGH1 DISP_BIT_IB01 +#define DISP_BITMASK_VGH0 DISP_BIT_IB00 +/* DISP_POWER_CTL_4_ADDR Power Control (4) */ +#define DISP_BITMASK_VC2 DISP_BIT_IB02 +#define DISP_BITMASK_VC1 DISP_BIT_IB01 +#define DISP_BITMASK_VC0 DISP_BIT_IB00 +/* DISP_POWER_CTL_5_ADDR Power Control (5) */ +#define DISP_BITMASK_VRL3 DISP_BIT_IB11 +#define DISP_BITMASK_VRL2 DISP_BIT_IB10 +#define DISP_BITMASK_VRL1 DISP_BIT_IB09 +#define DISP_BITMASK_VRL0 DISP_BIT_IB08 +#define DISP_BITMASK_PON DISP_BIT_IB04 +#define DISP_BITMASK_VRH3 DISP_BIT_IB03 +#define DISP_BITMASK_VRH2 DISP_BIT_IB02 +#define DISP_BITMASK_VRH1 DISP_BIT_IB01 +#define DISP_BITMASK_VRH0 DISP_BIT_IB00 +/* DISP_POWER_CTL_6_ADDR Power Control (6) */ +#define DISP_BITMASK_VCOMG DISP_BIT_IB13 +#define DISP_BITMASK_VDV4 DISP_BIT_IB12 +#define DISP_BITMASK_VDV3 DISP_BIT_IB11 +#define DISP_BITMASK_VDV2 DISP_BIT_IB10 +#define DISP_BITMASK_VDV1 DISP_BIT_IB09 +#define DISP_BITMASK_VDV0 DISP_BIT_IB08 +#define DISP_BITMASK_VCM4 DISP_BIT_IB04 +#define DISP_BITMASK_VCM3 DISP_BIT_IB03 +#define DISP_BITMASK_VCM2 DISP_BIT_IB02 +#define DISP_BITMASK_VCM1 DISP_BIT_IB01 +#define DISP_BITMASK_VCM0 DISP_BIT_IB00 +/* RAM Access */ +/* DISP_RAM_ADDR_SET_1_ADDR RAM Address Set (1) */ +#define DISP_BITMASK_AD7 DISP_BIT_IB07 +#define DISP_BITMASK_AD6 DISP_BIT_IB06 +#define DISP_BITMASK_AD5 DISP_BIT_IB05 +#define DISP_BITMASK_AD4 DISP_BIT_IB04 +#define DISP_BITMASK_AD3 DISP_BIT_IB03 +#define DISP_BITMASK_AD2 DISP_BIT_IB02 +#define DISP_BITMASK_AD1 DISP_BIT_IB01 +#define DISP_BITMASK_AD0 DISP_BIT_IB00 +/* DISP_RAM_ADDR_SET_2_ADDR RAM Address Set (2) */ +#define DISP_BITMASK_AD16 DISP_BIT_IB08 +#define DISP_BITMASK_AD15 DISP_BIT_IB07 +#define DISP_BITMASK_AD14 DISP_BIT_IB06 +#define DISP_BITMASK_AD13 DISP_BIT_IB05 +#define DISP_BITMASK_AD12 DISP_BIT_IB04 +#define DISP_BITMASK_AD11 DISP_BIT_IB03 +#define DISP_BITMASK_AD10 DISP_BIT_IB02 +#define DISP_BITMASK_AD9 DISP_BIT_IB01 +#define DISP_BITMASK_AD8 DISP_BIT_IB00 +/* + * DISP_CMD_RAMWR RAM Data Read/Write + * Use Data Bit Configuration + */ +/* DISP_RAM_DATA_MASK_1_ADDR RAM Write Data Mask (1) */ +#define DISP_BITMASK_WM11 DISP_BIT_IB13 +#define DISP_BITMASK_WM10 DISP_BIT_IB12 +#define DISP_BITMASK_WM9 DISP_BIT_IB11 +#define DISP_BITMASK_WM8 DISP_BIT_IB10 +#define DISP_BITMASK_WM7 DISP_BIT_IB09 +#define DISP_BITMASK_WM6 DISP_BIT_IB08 +#define DISP_BITMASK_WM5 DISP_BIT_IB05 +#define DISP_BITMASK_WM4 DISP_BIT_IB04 +#define DISP_BITMASK_WM3 DISP_BIT_IB03 +#define DISP_BITMASK_WM2 DISP_BIT_IB02 +#define DISP_BITMASK_WM1 DISP_BIT_IB01 +#define DISP_BITMASK_WM0 DISP_BIT_IB00 +/* DISP_RAM_DATA_MASK_2_ADDR RAM Write Data Mask (2) */ +#define DISP_BITMASK_WM17 DISP_BIT_IB05 +#define DISP_BITMASK_WM16 DISP_BIT_IB04 +#define DISP_BITMASK_WM15 DISP_BIT_IB03 +#define DISP_BITMASK_WM14 DISP_BIT_IB02 +#define DISP_BITMASK_WM13 DISP_BIT_IB01 +#define DISP_BITMASK_WM12 DISP_BIT_IB00 +/*Gamma Control */ +/* DISP_GAMMA_CONTROL_1_ADDR Gamma Control (1) */ +#define DISP_BITMASK_PKP12 DISP_BIT_IB10 +#define DISP_BITMASK_PKP11 DISP_BIT_IB08 +#define DISP_BITMASK_PKP10 DISP_BIT_IB09 +#define DISP_BITMASK_PKP02 DISP_BIT_IB02 +#define DISP_BITMASK_PKP01 DISP_BIT_IB01 +#define DISP_BITMASK_PKP00 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_2_ADDR Gamma Control (2) */ +#define DISP_BITMASK_PKP32 DISP_BIT_IB10 +#define DISP_BITMASK_PKP31 DISP_BIT_IB09 +#define DISP_BITMASK_PKP30 DISP_BIT_IB08 +#define DISP_BITMASK_PKP22 DISP_BIT_IB02 +#define DISP_BITMASK_PKP21 DISP_BIT_IB01 +#define DISP_BITMASK_PKP20 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_3_ADDR Gamma Control (3) */ +#define DISP_BITMASK_PKP52 DISP_BIT_IB10 +#define DISP_BITMASK_PKP51 DISP_BIT_IB09 +#define DISP_BITMASK_PKP50 DISP_BIT_IB08 +#define DISP_BITMASK_PKP42 DISP_BIT_IB02 +#define DISP_BITMASK_PKP41 DISP_BIT_IB01 +#define DISP_BITMASK_PKP40 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_4_ADDR Gamma Control (4) */ +#define DISP_BITMASK_PRP12 DISP_BIT_IB10 +#define DISP_BITMASK_PRP11 DISP_BIT_IB08 +#define DISP_BITMASK_PRP10 DISP_BIT_IB09 +#define DISP_BITMASK_PRP02 DISP_BIT_IB02 +#define DISP_BITMASK_PRP01 DISP_BIT_IB01 +#define DISP_BITMASK_PRP00 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_5_ADDR Gamma Control (5) */ +#define DISP_BITMASK_VRP14 DISP_BIT_IB12 +#define DISP_BITMASK_VRP13 DISP_BIT_IB11 +#define DISP_BITMASK_VRP12 DISP_BIT_IB10 +#define DISP_BITMASK_VRP11 DISP_BIT_IB08 +#define DISP_BITMASK_VRP10 DISP_BIT_IB09 +#define DISP_BITMASK_VRP03 DISP_BIT_IB03 +#define DISP_BITMASK_VRP02 DISP_BIT_IB02 +#define DISP_BITMASK_VRP01 DISP_BIT_IB01 +#define DISP_BITMASK_VRP00 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_6_ADDR Gamma Control (6) */ +#define DISP_BITMASK_PKN12 DISP_BIT_IB10 +#define DISP_BITMASK_PKN11 DISP_BIT_IB08 +#define DISP_BITMASK_PKN10 DISP_BIT_IB09 +#define DISP_BITMASK_PKN02 DISP_BIT_IB02 +#define DISP_BITMASK_PKN01 DISP_BIT_IB01 +#define DISP_BITMASK_PKN00 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_7_ADDR Gamma Control (7) */ +#define DISP_BITMASK_PKN32 DISP_BIT_IB10 +#define DISP_BITMASK_PKN31 DISP_BIT_IB08 +#define DISP_BITMASK_PKN30 DISP_BIT_IB09 +#define DISP_BITMASK_PKN22 DISP_BIT_IB02 +#define DISP_BITMASK_PKN21 DISP_BIT_IB01 +#define DISP_BITMASK_PKN20 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_8_ADDR Gamma Control (8) */ +#define DISP_BITMASK_PKN52 DISP_BIT_IB10 +#define DISP_BITMASK_PKN51 DISP_BIT_IB08 +#define DISP_BITMASK_PKN50 DISP_BIT_IB09 +#define DISP_BITMASK_PKN42 DISP_BIT_IB02 +#define DISP_BITMASK_PKN41 DISP_BIT_IB01 +#define DISP_BITMASK_PKN40 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_9_ADDR Gamma Control (9) */ +#define DISP_BITMASK_PRN12 DISP_BIT_IB10 +#define DISP_BITMASK_PRN11 DISP_BIT_IB08 +#define DISP_BITMASK_PRN10 DISP_BIT_IB09 +#define DISP_BITMASK_PRN02 DISP_BIT_IB02 +#define DISP_BITMASK_PRN01 DISP_BIT_IB01 +#define DISP_BITMASK_PRN00 DISP_BIT_IB00 +/* DISP_GAMMA_CONTROL_10_ADDR Gamma Control (10) */ +#define DISP_BITMASK_VRN14 DISP_BIT_IB12 +#define DISP_BITMASK_VRN13 DISP_BIT_IB11 +#define DISP_BITMASK_VRN12 DISP_BIT_IB10 +#define DISP_BITMASK_VRN11 DISP_BIT_IB08 +#define DISP_BITMASK_VRN10 DISP_BIT_IB09 +#define DISP_BITMASK_VRN03 DISP_BIT_IB03 +#define DISP_BITMASK_VRN02 DISP_BIT_IB02 +#define DISP_BITMASK_VRN01 DISP_BIT_IB01 +#define DISP_BITMASK_VRN00 DISP_BIT_IB00 +/* Coordinate Control */ +/* DISP_VERT_SCROLL_CTL_1_ADDR Vertical Scroll Control (1) */ +#define DISP_BITMASK_VL18 DISP_BIT_IB08 +#define DISP_BITMASK_VL17 DISP_BIT_IB07 +#define DISP_BITMASK_VL16 DISP_BIT_IB06 +#define DISP_BITMASK_VL15 DISP_BIT_IB05 +#define DISP_BITMASK_VL14 DISP_BIT_IB04 +#define DISP_BITMASK_VL13 DISP_BIT_IB03 +#define DISP_BITMASK_VL12 DISP_BIT_IB02 +#define DISP_BITMASK_VL11 DISP_BIT_IB01 +#define DISP_BITMASK_VL10 DISP_BIT_IB00 +/* DISP_VERT_SCROLL_CTL_2_ADDR Vertical Scroll Control (2) */ +#define DISP_BITMASK_VL28 DISP_BIT_IB08 +#define DISP_BITMASK_VL27 DISP_BIT_IB07 +#define DISP_BITMASK_VL26 DISP_BIT_IB06 +#define DISP_BITMASK_VL25 DISP_BIT_IB05 +#define DISP_BITMASK_VL24 DISP_BIT_IB04 +#define DISP_BITMASK_VL23 DISP_BIT_IB03 +#define DISP_BITMASK_VL22 DISP_BIT_IB02 +#define DISP_BITMASK_VL21 DISP_BIT_IB01 +#define DISP_BITMASK_VL20 DISP_BIT_IB00 +/* DISP_SCREEN_1_DRV_POS_1_ADDR First Screen Driving Position (1) */ +#define DISP_BITMASK_SS18 DISP_BIT_IB08 +#define DISP_BITMASK_SS17 DISP_BIT_IB07 +#define DISP_BITMASK_SS16 DISP_BIT_IB06 +#define DISP_BITMASK_SS15 DISP_BIT_IB05 +#define DISP_BITMASK_SS14 DISP_BIT_IB04 +#define DISP_BITMASK_SS13 DISP_BIT_IB03 +#define DISP_BITMASK_SS12 DISP_BIT_IB02 +#define DISP_BITMASK_SS11 DISP_BIT_IB01 +#define DISP_BITMASK_SS10 DISP_BIT_IB00 +/* DISP_SCREEN_1_DRV_POS_2_ADDR First Screen Driving Position (2) */ +#define DISP_BITMASK_SE18 DISP_BIT_IB08 +#define DISP_BITMASK_SE17 DISP_BIT_IB07 +#define DISP_BITMASK_SE16 DISP_BIT_IB06 +#define DISP_BITMASK_SE15 DISP_BIT_IB05 +#define DISP_BITMASK_SE14 DISP_BIT_IB04 +#define DISP_BITMASK_SE13 DISP_BIT_IB03 +#define DISP_BITMASK_SE12 DISP_BIT_IB02 +#define DISP_BITMASK_SE11 DISP_BIT_IB01 +#define DISP_BITMASK_SE10 DISP_BIT_IB00 +/* DISP_SCREEN_2_DRV_POS_1_ADDR Second Screen Driving Position (1) */ +#define DISP_BITMASK_SS28 DISP_BIT_IB08 +#define DISP_BITMASK_SS27 DISP_BIT_IB07 +#define DISP_BITMASK_SS26 DISP_BIT_IB06 +#define DISP_BITMASK_SS25 DISP_BIT_IB05 +#define DISP_BITMASK_SS24 DISP_BIT_IB04 +#define DISP_BITMASK_SS23 DISP_BIT_IB03 +#define DISP_BITMASK_SS22 DISP_BIT_IB02 +#define DISP_BITMASK_SS21 DISP_BIT_IB01 +#define DISP_BITMASK_SS20 DISP_BIT_IB00 +/* DISP_SCREEN_3_DRV_POS_2_ADDR Second Screen Driving Position (2) */ +#define DISP_BITMASK_SE28 DISP_BIT_IB08 +#define DISP_BITMASK_SE27 DISP_BIT_IB07 +#define DISP_BITMASK_SE26 DISP_BIT_IB06 +#define DISP_BITMASK_SE25 DISP_BIT_IB05 +#define DISP_BITMASK_SE24 DISP_BIT_IB04 +#define DISP_BITMASK_SE23 DISP_BIT_IB03 +#define DISP_BITMASK_SE22 DISP_BIT_IB02 +#define DISP_BITMASK_SE21 DISP_BIT_IB01 +#define DISP_BITMASK_SE20 DISP_BIT_IB00 +/* DISP_HORZ_RAM_ADDR_POS_1_ADDR Horizontal RAM Address Position (1) */ +#define DISP_BITMASK_HSA7 DISP_BIT_IB07 +#define DISP_BITMASK_HSA6 DISP_BIT_IB06 +#define DISP_BITMASK_HSA5 DISP_BIT_IB05 +#define DISP_BITMASK_HSA4 DISP_BIT_IB04 +#define DISP_BITMASK_HSA3 DISP_BIT_IB03 +#define DISP_BITMASK_HSA2 DISP_BIT_IB02 +#define DISP_BITMASK_HSA1 DISP_BIT_IB01 +#define DISP_BITMASK_HSA0 DISP_BIT_IB00 +/* DISP_HORZ_RAM_ADDR_POS_2_ADDR Horizontal RAM Address Position (2) */ +#define DISP_BITMASK_HEA7 DISP_BIT_IB07 +#define DISP_BITMASK_HEA6 DISP_BIT_IB06 +#define DISP_BITMASK_HEA5 DISP_BIT_IB05 +#define DISP_BITMASK_HEA4 DISP_BIT_IB04 +#define DISP_BITMASK_HEA3 DISP_BIT_IB03 +#define DISP_BITMASK_HEA2 DISP_BIT_IB02 +#define DISP_BITMASK_HEA1 DISP_BIT_IB01 +#define DISP_BITMASK_HEA0 DISP_BIT_IB00 +/* DISP_VERT_RAM_ADDR_POS_1_ADDR Vertical RAM Address Position (1) */ +#define DISP_BITMASK_VSA8 DISP_BIT_IB08 +#define DISP_BITMASK_VSA7 DISP_BIT_IB07 +#define DISP_BITMASK_VSA6 DISP_BIT_IB06 +#define DISP_BITMASK_VSA5 DISP_BIT_IB05 +#define DISP_BITMASK_VSA4 DISP_BIT_IB04 +#define DISP_BITMASK_VSA3 DISP_BIT_IB03 +#define DISP_BITMASK_VSA2 DISP_BIT_IB02 +#define DISP_BITMASK_VSA1 DISP_BIT_IB01 +#define DISP_BITMASK_VSA0 DISP_BIT_IB00 +/* DISP_VERT_RAM_ADDR_POS_2_ADDR Vertical RAM Address Position (2) */ +#define DISP_BITMASK_VEA8 DISP_BIT_IB08 +#define DISP_BITMASK_VEA7 DISP_BIT_IB07 +#define DISP_BITMASK_VEA6 DISP_BIT_IB06 +#define DISP_BITMASK_VEA5 DISP_BIT_IB05 +#define DISP_BITMASK_VEA4 DISP_BIT_IB04 +#define DISP_BITMASK_VEA3 DISP_BIT_IB03 +#define DISP_BITMASK_VEA2 DISP_BIT_IB02 +#define DISP_BITMASK_VEA1 DISP_BIT_IB01 +#define DISP_BITMASK_VEA0 DISP_BIT_IB00 +static word disp_area_start_row; +static word disp_area_end_row; +static boolean disp_initialized = FALSE; +/* For some reason the contrast set at init time is not good. Need to do +* it again +*/ +static boolean display_on = FALSE; + +static uint32 tmd20qvga_lcd_rev; +uint16 tmd20qvga_panel_offset; + +#ifdef DISP_DEVICE_8BPP +static word convert_8_to_16_tbl[256] = { + 0x0000, 0x2000, 0x4000, 0x6000, 0x8000, 0xA000, 0xC000, 0xE000, + 0x0100, 0x2100, 0x4100, 0x6100, 0x8100, 0xA100, 0xC100, 0xE100, + 0x0200, 0x2200, 0x4200, 0x6200, 0x8200, 0xA200, 0xC200, 0xE200, + 0x0300, 0x2300, 0x4300, 0x6300, 0x8300, 0xA300, 0xC300, 0xE300, + 0x0400, 0x2400, 0x4400, 0x6400, 0x8400, 0xA400, 0xC400, 0xE400, + 0x0500, 0x2500, 0x4500, 0x6500, 0x8500, 0xA500, 0xC500, 0xE500, + 0x0600, 0x2600, 0x4600, 0x6600, 0x8600, 0xA600, 0xC600, 0xE600, + 0x0700, 0x2700, 0x4700, 0x6700, 0x8700, 0xA700, 0xC700, 0xE700, + 0x0008, 0x2008, 0x4008, 0x6008, 0x8008, 0xA008, 0xC008, 0xE008, + 0x0108, 0x2108, 0x4108, 0x6108, 0x8108, 0xA108, 0xC108, 0xE108, + 0x0208, 0x2208, 0x4208, 0x6208, 0x8208, 0xA208, 0xC208, 0xE208, + 0x0308, 0x2308, 0x4308, 0x6308, 0x8308, 0xA308, 0xC308, 0xE308, + 0x0408, 0x2408, 0x4408, 0x6408, 0x8408, 0xA408, 0xC408, 0xE408, + 0x0508, 0x2508, 0x4508, 0x6508, 0x8508, 0xA508, 0xC508, 0xE508, + 0x0608, 0x2608, 0x4608, 0x6608, 0x8608, 0xA608, 0xC608, 0xE608, + 0x0708, 0x2708, 0x4708, 0x6708, 0x8708, 0xA708, 0xC708, 0xE708, + 0x0010, 0x2010, 0x4010, 0x6010, 0x8010, 0xA010, 0xC010, 0xE010, + 0x0110, 0x2110, 0x4110, 0x6110, 0x8110, 0xA110, 0xC110, 0xE110, + 0x0210, 0x2210, 0x4210, 0x6210, 0x8210, 0xA210, 0xC210, 0xE210, + 0x0310, 0x2310, 0x4310, 0x6310, 0x8310, 0xA310, 0xC310, 0xE310, + 0x0410, 0x2410, 0x4410, 0x6410, 0x8410, 0xA410, 0xC410, 0xE410, + 0x0510, 0x2510, 0x4510, 0x6510, 0x8510, 0xA510, 0xC510, 0xE510, + 0x0610, 0x2610, 0x4610, 0x6610, 0x8610, 0xA610, 0xC610, 0xE610, + 0x0710, 0x2710, 0x4710, 0x6710, 0x8710, 0xA710, 0xC710, 0xE710, + 0x0018, 0x2018, 0x4018, 0x6018, 0x8018, 0xA018, 0xC018, 0xE018, + 0x0118, 0x2118, 0x4118, 0x6118, 0x8118, 0xA118, 0xC118, 0xE118, + 0x0218, 0x2218, 0x4218, 0x6218, 0x8218, 0xA218, 0xC218, 0xE218, + 0x0318, 0x2318, 0x4318, 0x6318, 0x8318, 0xA318, 0xC318, 0xE318, + 0x0418, 0x2418, 0x4418, 0x6418, 0x8418, 0xA418, 0xC418, 0xE418, + 0x0518, 0x2518, 0x4518, 0x6518, 0x8518, 0xA518, 0xC518, 0xE518, + 0x0618, 0x2618, 0x4618, 0x6618, 0x8618, 0xA618, 0xC618, 0xE618, + 0x0718, 0x2718, 0x4718, 0x6718, 0x8718, 0xA718, 0xC718, 0xE718 +}; +#endif /* DISP_DEVICE_8BPP */ + +static void tmd20qvga_disp_set_rect(int x, int y, int xres, int yres); +static void tmd20qvga_disp_init(struct platform_device *pdev); +static void tmd20qvga_disp_set_contrast(void); +static void tmd20qvga_disp_set_display_area(word start_row, word end_row); +static int tmd20qvga_disp_off(struct platform_device *pdev); +static int tmd20qvga_disp_on(struct platform_device *pdev); +static void tmd20qvga_set_revId(int); + +/* future use */ +void tmd20qvga_disp_clear_screen_area(word start_row, word end_row, + word start_column, word end_column); + +static void tmd20qvga_set_revId(int id) +{ + + tmd20qvga_lcd_rev = id; + + if (tmd20qvga_lcd_rev == 1) + tmd20qvga_panel_offset = 0x10; + else + tmd20qvga_panel_offset = 0; +} + +static void tmd20qvga_disp_init(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + if (disp_initialized) + return; + + mfd = platform_get_drvdata(pdev); + + DISP_CMD_PORT = mfd->cmd_port; + DISP_DATA_PORT = mfd->data_port; + +#ifdef TMD20QVGA_LCD_18BPP + tmd20qvga_set_revId(2); +#else + tmd20qvga_set_revId(1); +#endif + + disp_initialized = TRUE; + tmd20qvga_disp_set_contrast(); + tmd20qvga_disp_set_display_area(0, QVGA_HEIGHT - 1); +} + +static void tmd20qvga_disp_set_rect(int x, int y, int xres, int yres) +{ + if (!disp_initialized) + return; + + DISP_SET_RECT(y, y + yres - 1, x, x + xres - 1); + + DISP_CMD_OUT(DISP_CMD_RAMWR); +} + +static void tmd20qvga_disp_set_display_area(word start_row, word end_row) +{ + word start_driving = start_row; + word end_driving = end_row; + + if (!disp_initialized) + return; + + /* Range checking + */ + if (end_driving >= QVGA_HEIGHT) + end_driving = QVGA_HEIGHT - 1; + if (start_driving > end_driving) { + /* Probably Backwards Switch */ + start_driving = end_driving; + end_driving = start_row; /* Has not changed */ + if (end_driving >= QVGA_HEIGHT) + end_driving = QVGA_HEIGHT - 1; + } + + if ((start_driving == disp_area_start_row) + && (end_driving == disp_area_end_row)) + return; + + disp_area_start_row = start_driving; + disp_area_end_row = end_driving; + + DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_1_ADDR, + DISP_VAL_IF(start_driving & 0x100, + DISP_BITMASK_SS18) | + DISP_VAL_IF(start_driving & 0x080, + DISP_BITMASK_SS17) | + DISP_VAL_IF(start_driving & 0x040, + DISP_BITMASK_SS16) | + DISP_VAL_IF(start_driving & 0x020, + DISP_BITMASK_SS15) | + DISP_VAL_IF(start_driving & 0x010, + DISP_BITMASK_SS14) | + DISP_VAL_IF(start_driving & 0x008, + DISP_BITMASK_SS13) | + DISP_VAL_IF(start_driving & 0x004, + DISP_BITMASK_SS12) | + DISP_VAL_IF(start_driving & 0x002, + DISP_BITMASK_SS11) | + DISP_VAL_IF(start_driving & 0x001, DISP_BITMASK_SS10)); + + DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_2_ADDR, + DISP_VAL_IF(end_driving & 0x100, DISP_BITMASK_SE18) | + DISP_VAL_IF(end_driving & 0x080, DISP_BITMASK_SE17) | + DISP_VAL_IF(end_driving & 0x040, DISP_BITMASK_SE16) | + DISP_VAL_IF(end_driving & 0x020, DISP_BITMASK_SE15) | + DISP_VAL_IF(end_driving & 0x010, DISP_BITMASK_SE14) | + DISP_VAL_IF(end_driving & 0x008, DISP_BITMASK_SE13) | + DISP_VAL_IF(end_driving & 0x004, DISP_BITMASK_SE12) | + DISP_VAL_IF(end_driving & 0x002, DISP_BITMASK_SE11) | + DISP_VAL_IF(end_driving & 0x001, DISP_BITMASK_SE10)); +} + +static int tmd20qvga_disp_off(struct platform_device *pdev) +{ + if (!disp_initialized) + tmd20qvga_disp_init(pdev); + + if (display_on) { + if (tmd20qvga_lcd_rev == 2) { + DISP_WRITE_OUT(DISP_POFF_LN_SETTING_ADDR, 0x000A); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xFFEE); + WAIT_MSEC(40); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xF812); + WAIT_MSEC(40); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xE811); + WAIT_MSEC(40); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xC011); + WAIT_MSEC(40); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x4011); + WAIT_MSEC(20); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0010); + + } else { + DISP_WRITE_OUT(DISP_POFF_LN_SETTING_ADDR, 0x000F); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0BFE); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + WAIT_MSEC(40); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0BED); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + WAIT_MSEC(40); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x00CD); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + WAIT_MSEC(20); + DISP_WRITE_OUT(DISP_START_OSCILLATION_ADDR, 0x0); + } + + DISP_WRITE_OUT(DISP_MODE_SETTING_ADDR, 0x0004); + DISP_WRITE_OUT(DISP_MODE_SETTING_ADDR, 0x0000); + + display_on = FALSE; + } + + return 0; +} + +static int tmd20qvga_disp_on(struct platform_device *pdev) +{ + if (!disp_initialized) + tmd20qvga_disp_init(pdev); + + if (!display_on) { + /* Deep Stand-by -> Stand-by */ + DISP_CMD_OUT(DISP_START_OSCILLATION_ADDR); + WAIT_MSEC(1); + DISP_CMD_OUT(DISP_START_OSCILLATION_ADDR); + WAIT_MSEC(1); + DISP_CMD_OUT(DISP_START_OSCILLATION_ADDR); + WAIT_MSEC(1); + + /* OFF -> Deep Stan-By -> Stand-by */ + /* let's change the state from "Stand-by" to "Sleep" */ + DISP_WRITE_OUT(DISP_MODE_SETTING_ADDR, 0x0005); + WAIT_MSEC(1); + + /* Sleep -> Displaying */ + DISP_WRITE_OUT(DISP_START_OSCILLATION_ADDR, 0x0001); + DISP_WRITE_OUT(DISP_DRIVER_OUTPUT_CTL_ADDR, 0x0127); + DISP_WRITE_OUT(DISP_LCD_DRIVING_SIG_ADDR, 0x200); + /* fast write mode */ + DISP_WRITE_OUT(DISP_ENTRY_MODE_ADDR, 0x0130); + if (tmd20qvga_lcd_rev == 2) + DISP_WRITE_OUT(DISP_TMD_700_ADDR, 0x0003); + /* back porch = 14 + front porch = 2 --> 16 lines */ + if (tmd20qvga_lcd_rev == 2) { +#ifdef TMD20QVGA_LCD_18BPP + /* 256k color */ + DISP_WRITE_OUT(DISP_DISPLAY_CTL_1_ADDR, 0x0000); +#else + /* 65k color */ + DISP_WRITE_OUT(DISP_DISPLAY_CTL_1_ADDR, 0x4000); +#endif + DISP_WRITE_OUT(DISP_DISPLAY_CTL_2_ADDR, 0x0302); + } else { +#ifdef TMD20QVGA_LCD_18BPP + /* 256k color */ + DISP_WRITE_OUT(DISP_DISPLAY_CTL_1_ADDR, 0x0004); +#else + /* 65k color */ + DISP_WRITE_OUT(DISP_DISPLAY_CTL_1_ADDR, 0x4004); +#endif + DISP_WRITE_OUT(DISP_DISPLAY_CTL_2_ADDR, 0x020E); + } + /* 16 bit one transfer */ + if (tmd20qvga_lcd_rev == 2) { + DISP_WRITE_OUT(DISP_EXT_DISPLAY_CTL_1_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_FRAME_CYCLE_CTL_ADDR, 0x0010); + DISP_WRITE_OUT(DISP_LTPS_CTL_1_ADDR, 0x0302); + DISP_WRITE_OUT(DISP_LTPS_CTL_2_ADDR, 0x0102); + DISP_WRITE_OUT(DISP_LTPS_CTL_3_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_TMD_015_ADDR, 0x2000); + + DISP_WRITE_OUT(DISP_AMP_SETTING_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_1_ADDR, 0x0403); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_2_ADDR, 0x0304); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_3_ADDR, 0x0403); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_4_ADDR, 0x0303); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_5_ADDR, 0x0101); + DISP_WRITE_OUT(DISP_TMD_305_ADDR, 0); + + DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_1_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_2_ADDR, 0x013F); + + DISP_WRITE_OUT(DISP_POWER_CTL_3_ADDR, 0x077D); + + DISP_WRITE_OUT(DISP_POWER_CTL_4_ADDR, 0x0005); + DISP_WRITE_OUT(DISP_POWER_CTL_5_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_POWER_CTL_6_ADDR, 0x0015); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xC010); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_2_ADDR, 0x0001); + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xFFFE); + WAIT_MSEC(60); + } else { + DISP_WRITE_OUT(DISP_EXT_DISPLAY_CTL_1_ADDR, 0x0001); + DISP_WRITE_OUT(DISP_FRAME_CYCLE_CTL_ADDR, 0x0010); + DISP_WRITE_OUT(DISP_LTPS_CTL_1_ADDR, 0x0301); + DISP_WRITE_OUT(DISP_LTPS_CTL_2_ADDR, 0x0001); + DISP_WRITE_OUT(DISP_LTPS_CTL_3_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_AMP_SETTING_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_1_ADDR, 0x0507); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_2_ADDR, 0x0405); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_3_ADDR, 0x0607); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_4_ADDR, 0x0502); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_5_ADDR, 0x0301); + DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_1_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_2_ADDR, 0x013F); + DISP_WRITE_OUT(DISP_POWER_CTL_3_ADDR, 0x0795); + + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0102); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_4_ADDR, 0x0450); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0103); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_5_ADDR, 0x0008); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0104); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_6_ADDR, 0x0C00); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0105); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_7_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0106); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0801); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + WAIT_MSEC(1); + + DISP_WRITE_OUT(DISP_POWER_CTL_2_ADDR, 0x001F); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0101); + WAIT_MSEC(60); + + DISP_WRITE_OUT(DISP_POWER_CTL_2_ADDR, 0x009F); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0101); + WAIT_MSEC(10); + + DISP_WRITE_OUT(DISP_HORZ_RAM_ADDR_POS_1_ADDR, 0x0010); + DISP_WRITE_OUT(DISP_HORZ_RAM_ADDR_POS_2_ADDR, 0x00FF); + DISP_WRITE_OUT(DISP_VERT_RAM_ADDR_POS_1_ADDR, 0x0000); + DISP_WRITE_OUT(DISP_VERT_RAM_ADDR_POS_2_ADDR, 0x013F); + /* RAM starts at address 0x10 */ + DISP_WRITE_OUT(DISP_RAM_ADDR_SET_1_ADDR, 0x0010); + DISP_WRITE_OUT(DISP_RAM_ADDR_SET_2_ADDR, 0x0000); + + /* lcd controller uses internal clock, not ext. vsync */ + DISP_CMD_OUT(DISP_CMD_RAMWR); + + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0881); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + WAIT_MSEC(40); + + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0BE1); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + WAIT_MSEC(40); + + DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0BFF); + DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100); + } + display_on = TRUE; + } + + return 0; +} + +static void tmd20qvga_disp_set_contrast(void) +{ +#if (defined(TMD20QVGA_LCD_18BPP)) + + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_1_ADDR, 0x0403); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_2_ADDR, 0x0302); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_3_ADDR, 0x0403); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_4_ADDR, 0x0303); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_5_ADDR, 0x0F07); + +#else + int newcontrast = 0x46; + + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_1_ADDR, 0x0403); + + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_2_ADDR, + DISP_VAL_IF(newcontrast & 0x0001, DISP_BITMASK_PKP20) | + DISP_VAL_IF(newcontrast & 0x0002, DISP_BITMASK_PKP21) | + DISP_VAL_IF(newcontrast & 0x0004, DISP_BITMASK_PKP22) | + DISP_VAL_IF(newcontrast & 0x0010, DISP_BITMASK_PKP30) | + DISP_VAL_IF(newcontrast & 0x0020, DISP_BITMASK_PKP31) | + DISP_VAL_IF(newcontrast & 0x0040, DISP_BITMASK_PKP32)); + + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_3_ADDR, + DISP_VAL_IF(newcontrast & 0x0010, DISP_BITMASK_PKP40) | + DISP_VAL_IF(newcontrast & 0x0020, DISP_BITMASK_PKP41) | + DISP_VAL_IF(newcontrast & 0x0040, DISP_BITMASK_PKP42) | + DISP_VAL_IF(newcontrast & 0x0001, DISP_BITMASK_PKP50) | + DISP_VAL_IF(newcontrast & 0x0002, DISP_BITMASK_PKP51) | + DISP_VAL_IF(newcontrast & 0x0004, DISP_BITMASK_PKP52)); + + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_4_ADDR, 0x0303); + DISP_WRITE_OUT(DISP_GAMMA_CONTROL_5_ADDR, 0x0F07); + +#endif /* defined(TMD20QVGA_LCD_18BPP) */ + +} /* End disp_set_contrast */ + +void tmd20qvga_disp_clear_screen_area + (word start_row, word end_row, word start_column, word end_column) { + int32 i; + + /* Clear the display screen */ + DISP_SET_RECT(start_row, end_row, start_column, end_column); + DISP_CMD_OUT(DISP_CMD_RAMWR); + i = (end_row - start_row + 1) * (end_column - start_column + 1); + for (; i > 0; i--) + DISP_DATA_OUT_16TO18BPP(0x0); +} + +static int __init tmd20qvga_probe(struct platform_device *pdev) +{ + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = tmd20qvga_probe, + .driver = { + .name = "ebi2_tmd_qvga", + }, +}; + +static struct msm_fb_panel_data tmd20qvga_panel_data = { + .on = tmd20qvga_disp_on, + .off = tmd20qvga_disp_off, + .set_rect = tmd20qvga_disp_set_rect, +}; + +static struct platform_device this_device = { + .name = "ebi2_tmd_qvga", + .id = 0, + .dev = { + .platform_data = &tmd20qvga_panel_data, + } +}; + +static int __init tmd20qvga_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + + ret = platform_driver_register(&this_driver); + if (!ret) { + pinfo = &tmd20qvga_panel_data.panel_info; + pinfo->xres = 240; + pinfo->yres = 320; + MSM_FB_SINGLE_MODE_PANEL(pinfo); + pinfo->type = EBI2_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->wait_cycle = 0x808000; +#ifdef TMD20QVGA_LCD_18BPP + pinfo->bpp = 18; +#else + pinfo->bpp = 16; +#endif + pinfo->fb_num = 2; + pinfo->lcd.vsync_enable = TRUE; + pinfo->lcd.refx100 = 6000; + pinfo->lcd.v_back_porch = 16; + pinfo->lcd.v_front_porch = 4; + pinfo->lcd.v_pulse_width = 0; + pinfo->lcd.hw_vsync_mode = FALSE; + pinfo->lcd.vsync_notifier_period = 0; + + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + } + + return ret; +} + +module_init(tmd20qvga_init); + diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c new file mode 100644 index 000000000000..21d73740681c --- /dev/null +++ b/drivers/video/msm/external_common.c @@ -0,0 +1,2103 @@ +/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include + +/* #define DEBUG */ +#define DEV_DBG_PREFIX "EXT_COMMON: " + +/* The start of the data block collection within the CEA Extension Version 3 */ +#define DBC_START_OFFSET 4 + +#include "msm_fb.h" +#include "hdmi_msm.h" +#include "external_common.h" +#include "mhl_api.h" + +#include "mdp.h" + +struct external_common_state_type *external_common_state; +EXPORT_SYMBOL(external_common_state); +DEFINE_MUTEX(external_common_state_hpd_mutex); +EXPORT_SYMBOL(external_common_state_hpd_mutex); + + +static int atoi(const char *name) +{ + int val = 0; + + for (;; name++) { + switch (*name) { + case '0' ... '9': + val = 10*val+(*name-'0'); + break; + default: + return val; + } + } +} + +#ifdef DEBUG_EDID +/* + * Block 0 - 1920x1080p, 1360x768p + * Block 1 - 1280x720p, 1920x540i, 720x480p + */ +const char edid_blk0[0x100] = { +0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x4C, 0x2D, 0x03, 0x05, 0x00, +0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78, 0x0A, 0xEE, +0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26, 0x0F, 0x50, 0x54, 0xBD, 0xEF, 0x80, 0x71, +0x4F, 0x81, 0x00, 0x81, 0x40, 0x81, 0x80, 0x95, 0x00, 0x95, 0x0F, 0xB3, 0x00, +0xA9, 0x40, 0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C, 0x45, +0x00, 0xA0, 0x5A, 0x00, 0x00, 0x00, 0x1E, 0x66, 0x21, 0x50, 0xB0, 0x51, 0x00, +0x1B, 0x30, 0x40, 0x70, 0x36, 0x00, 0xA0, 0x5A, 0x00, 0x00, 0x00, 0x1E, 0x00, +0x00, 0x00, 0xFD, 0x00, 0x18, 0x4B, 0x1A, 0x51, 0x17, 0x00, 0x0A, 0x20, 0x20, +0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x53, 0x41, 0x4D, 0x53, +0x55, 0x4E, 0x47, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0x8F}; + +const char edid_blk1[0x100] = { +0x02, 0x03, 0x1E, 0xF1, 0x46, 0x90, 0x04, 0x05, 0x03, 0x20, 0x22, 0x23, 0x09, +0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0xE2, 0x00, 0x0F, 0x67, 0x03, 0x0C, 0x00, +0x10, 0x00, 0xB8, 0x2D, 0x01, 0x1D, 0x00, 0x72, 0x51, 0xD0, 0x1E, 0x20, 0x6E, +0x28, 0x55, 0x00, 0xA0, 0x5A, 0x00, 0x00, 0x00, 0x1E, 0x01, 0x1D, 0x80, 0x18, +0x71, 0x1C, 0x16, 0x20, 0x58, 0x2C, 0x25, 0x00, 0xA0, 0x5A, 0x00, 0x00, 0x00, +0x9E, 0x8C, 0x0A, 0xD0, 0x8A, 0x20, 0xE0, 0x2D, 0x10, 0x10, 0x3E, 0x96, 0x00, +0xA0, 0x5A, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF}; +#endif /* DEBUG_EDID */ + +#define DMA_E_BASE 0xB0000 +void mdp_vid_quant_set(void) +{ + if ((external_common_state->video_resolution == \ + HDMI_VFRMT_720x480p60_4_3) || \ + (external_common_state->video_resolution == \ + HDMI_VFRMT_720x480p60_16_9)) { + MDP_OUTP(MDP_BASE + DMA_E_BASE + 0x70, 0x00EB0010); + MDP_OUTP(MDP_BASE + DMA_E_BASE + 0x74, 0x00EB0010); + MDP_OUTP(MDP_BASE + DMA_E_BASE + 0x78, 0x00EB0010); + } else { + MDP_OUTP(MDP_BASE + DMA_E_BASE + 0x70, 0x00FF0000); + MDP_OUTP(MDP_BASE + DMA_E_BASE + 0x74, 0x00FF0000); + MDP_OUTP(MDP_BASE + DMA_E_BASE + 0x78, 0x00FF0000); + } +} + +const char *video_format_2string(uint32 format) +{ + switch (format) { + default: +#ifdef CONFIG_FB_MSM_HDMI_COMMON + case HDMI_VFRMT_640x480p60_4_3: return " 640x 480 p60 4/3"; + case HDMI_VFRMT_720x480p60_4_3: return " 720x 480 p60 4/3"; + case HDMI_VFRMT_720x480p60_16_9: return " 720x 480 p60 16/9"; + case HDMI_VFRMT_1280x720p60_16_9: return "1280x 720 p60 16/9"; + case HDMI_VFRMT_1920x1080i60_16_9: return "1920x1080 i60 16/9"; + case HDMI_VFRMT_1440x480i60_4_3: return "1440x 480 i60 4/3"; + case HDMI_VFRMT_1440x480i60_16_9: return "1440x 480 i60 16/9"; + case HDMI_VFRMT_1440x240p60_4_3: return "1440x 240 p60 4/3"; + case HDMI_VFRMT_1440x240p60_16_9: return "1440x 240 p60 16/9"; + case HDMI_VFRMT_2880x480i60_4_3: return "2880x 480 i60 4/3"; + case HDMI_VFRMT_2880x480i60_16_9: return "2880x 480 i60 16/9"; + case HDMI_VFRMT_2880x240p60_4_3: return "2880x 240 p60 4/3"; + case HDMI_VFRMT_2880x240p60_16_9: return "2880x 240 p60 16/9"; + case HDMI_VFRMT_1440x480p60_4_3: return "1440x 480 p60 4/3"; + case HDMI_VFRMT_1440x480p60_16_9: return "1440x 480 p60 16/9"; + case HDMI_VFRMT_1920x1080p60_16_9: return "1920x1080 p60 16/9"; + case HDMI_VFRMT_720x576p50_4_3: return " 720x 576 p50 4/3"; + case HDMI_VFRMT_720x576p50_16_9: return " 720x 576 p50 16/9"; + case HDMI_VFRMT_1280x720p50_16_9: return "1280x 720 p50 16/9"; + case HDMI_VFRMT_1920x1080i50_16_9: return "1920x1080 i50 16/9"; + case HDMI_VFRMT_1440x576i50_4_3: return "1440x 576 i50 4/3"; + case HDMI_VFRMT_1440x576i50_16_9: return "1440x 576 i50 16/9"; + case HDMI_VFRMT_1440x288p50_4_3: return "1440x 288 p50 4/3"; + case HDMI_VFRMT_1440x288p50_16_9: return "1440x 288 p50 16/9"; + case HDMI_VFRMT_2880x576i50_4_3: return "2880x 576 i50 4/3"; + case HDMI_VFRMT_2880x576i50_16_9: return "2880x 576 i50 16/9"; + case HDMI_VFRMT_2880x288p50_4_3: return "2880x 288 p50 4/3"; + case HDMI_VFRMT_2880x288p50_16_9: return "2880x 288 p50 16/9"; + case HDMI_VFRMT_1440x576p50_4_3: return "1440x 576 p50 4/3"; + case HDMI_VFRMT_1440x576p50_16_9: return "1440x 576 p50 16/9"; + case HDMI_VFRMT_1920x1080p50_16_9: return "1920x1080 p50 16/9"; + case HDMI_VFRMT_1920x1080p24_16_9: return "1920x1080 p24 16/9"; + case HDMI_VFRMT_1920x1080p25_16_9: return "1920x1080 p25 16/9"; + case HDMI_VFRMT_1920x1080p30_16_9: return "1920x1080 p30 16/9"; + case HDMI_VFRMT_2880x480p60_4_3: return "2880x 480 p60 4/3"; + case HDMI_VFRMT_2880x480p60_16_9: return "2880x 480 p60 16/9"; + case HDMI_VFRMT_2880x576p50_4_3: return "2880x 576 p50 4/3"; + case HDMI_VFRMT_2880x576p50_16_9: return "2880x 576 p50 16/9"; + case HDMI_VFRMT_1920x1250i50_16_9: return "1920x1250 i50 16/9"; + case HDMI_VFRMT_1920x1080i100_16_9:return "1920x1080 i100 16/9"; + case HDMI_VFRMT_1280x720p100_16_9: return "1280x 720 p100 16/9"; + case HDMI_VFRMT_720x576p100_4_3: return " 720x 576 p100 4/3"; + case HDMI_VFRMT_720x576p100_16_9: return " 720x 576 p100 16/9"; + case HDMI_VFRMT_1440x576i100_4_3: return "1440x 576 i100 4/3"; + case HDMI_VFRMT_1440x576i100_16_9: return "1440x 576 i100 16/9"; + case HDMI_VFRMT_1920x1080i120_16_9:return "1920x1080 i120 16/9"; + case HDMI_VFRMT_1280x720p120_16_9: return "1280x 720 p120 16/9"; + case HDMI_VFRMT_720x480p120_4_3: return " 720x 480 p120 4/3"; + case HDMI_VFRMT_720x480p120_16_9: return " 720x 480 p120 16/9"; + case HDMI_VFRMT_1440x480i120_4_3: return "1440x 480 i120 4/3"; + case HDMI_VFRMT_1440x480i120_16_9: return "1440x 480 i120 16/9"; + case HDMI_VFRMT_720x576p200_4_3: return " 720x 576 p200 4/3"; + case HDMI_VFRMT_720x576p200_16_9: return " 720x 576 p200 16/9"; + case HDMI_VFRMT_1440x576i200_4_3: return "1440x 576 i200 4/3"; + case HDMI_VFRMT_1440x576i200_16_9: return "1440x 576 i200 16/9"; + case HDMI_VFRMT_720x480p240_4_3: return " 720x 480 p240 4/3"; + case HDMI_VFRMT_720x480p240_16_9: return " 720x 480 p240 16/9"; + case HDMI_VFRMT_1440x480i240_4_3: return "1440x 480 i240 4/3"; + case HDMI_VFRMT_1440x480i240_16_9: return "1440x 480 i240 16/9"; +#elif defined(CONFIG_FB_MSM_TVOUT) + case TVOUT_VFRMT_NTSC_M_720x480i: return "NTSC_M_720x480i"; + case TVOUT_VFRMT_NTSC_J_720x480i: return "NTSC_J_720x480i"; + case TVOUT_VFRMT_PAL_BDGHIN_720x576i: return "PAL_BDGHIN_720x576i"; + case TVOUT_VFRMT_PAL_M_720x480i: return "PAL_M_720x480i"; + case TVOUT_VFRMT_PAL_N_720x480i: return "PAL_N_720x480i"; +#endif + + } +} +EXPORT_SYMBOL(video_format_2string); + +static ssize_t external_common_rda_video_mode_str(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = snprintf(buf, PAGE_SIZE, "%s\n", + video_format_2string(external_common_state->video_resolution)); + DEV_DBG("%s: '%s'\n", __func__, + video_format_2string(external_common_state->video_resolution)); + return ret; +} + +#ifdef CONFIG_FB_MSM_HDMI_COMMON +struct hdmi_disp_mode_timing_type + hdmi_common_supported_video_mode_lut[HDMI_VFRMT_MAX] = { + HDMI_SETTINGS_640x480p60_4_3, + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x240p60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x240p60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480i60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480i60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x240p60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x240p60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480p60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480p60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x288p50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x288p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576i50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576i50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x288p50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x288p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576p50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p24_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p25_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p30_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480p60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480p60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576p50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1250i50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i100_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p100_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p100_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p100_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i100_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i100_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i120_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p120_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p120_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p120_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i120_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i120_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p200_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p200_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i200_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i200_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_16_9), +}; +EXPORT_SYMBOL(hdmi_common_supported_video_mode_lut); + +struct hdmi_disp_mode_timing_type + hdmi_mhl_supported_video_mode_lut[HDMI_VFRMT_MAX] = { + HDMI_SETTINGS_640x480p60_4_3, + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p60_16_9), + HDMI_SETTINGS_1280x720p60_16_9, + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x240p60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x240p60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480i60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480i60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x240p60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x240p60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480p60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480p60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x288p50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x288p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576i50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576i50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x288p50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x288p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576p50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p50_16_9), + HDMI_SETTINGS_1920x1080p24_16_9, + HDMI_SETTINGS_1920x1080p25_16_9, + HDMI_SETTINGS_1920x1080p30_16_9, + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480p60_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480p60_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576p50_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576p50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1250i50_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i100_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p100_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p100_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p100_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i100_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i100_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i120_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p120_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p120_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p120_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i120_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i120_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p200_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p200_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i200_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i200_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_16_9), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_4_3), + VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_16_9), +}; +EXPORT_SYMBOL(hdmi_mhl_supported_video_mode_lut); + +static ssize_t hdmi_common_rda_edid_modes(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + int i; + + buf[0] = 0; + if (external_common_state->disp_mode_list.num_of_elements) { + uint32 *video_mode = external_common_state->disp_mode_list + .disp_mode_list; + for (i = 0; i < external_common_state->disp_mode_list + .num_of_elements; ++i) { + if (ret > 0) + ret += snprintf(buf+ret, PAGE_SIZE-ret, ",%d", + *video_mode++ + 1); + else + ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d", + *video_mode++ + 1); + } + } else + ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d", + external_common_state->video_resolution+1); + + DEV_DBG("%s: '%s'\n", __func__, buf); + ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n"); + return ret; +} + +static ssize_t hdmi_common_rda_edid_physical_address(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = snprintf(buf, PAGE_SIZE, "%d\n", + external_common_state->physical_address); + + DEV_DBG("%s: '%d'\n", __func__, + external_common_state->physical_address); + return ret; +} + + +static ssize_t hdmi_common_rda_edid_scan_info(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = snprintf(buf, PAGE_SIZE, "%d, %d, %d\n", + external_common_state->pt_scan_info, + external_common_state->it_scan_info, + external_common_state->ce_scan_info); + DEV_DBG("%s: '%s'\n", __func__, buf); + return ret; +} + +static ssize_t hdmi_common_wta_vendor_name(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + uint8 *s = (uint8 *) buf; + uint8 *d = external_common_state->spd_vendor_name; + ssize_t ret = strnlen(buf, PAGE_SIZE); + ret = (ret > 8) ? 8 : ret; + + memset(external_common_state->spd_vendor_name, 0, 8); + while (*s) { + if (*s & 0x60 && *s ^ 0x7f) { + *d = *s; + } else { + /* stop copying if control character found */ + break; + } + + if (++s > (uint8 *) (buf + ret)) + break; + + d++; + } + + DEV_DBG("%s: '%s'\n", __func__, + external_common_state->spd_vendor_name); + + return ret; +} + +static ssize_t hdmi_common_rda_vendor_name(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = snprintf(buf, PAGE_SIZE, "%s\n", + external_common_state->spd_vendor_name); + DEV_DBG("%s: '%s'\n", __func__, + external_common_state->spd_vendor_name); + + return ret; +} + +static ssize_t hdmi_common_wta_product_description(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + uint8 *s = (uint8 *) buf; + uint8 *d = external_common_state->spd_product_description; + ssize_t ret = strnlen(buf, PAGE_SIZE); + ret = (ret > 16) ? 16 : ret; + + memset(external_common_state->spd_product_description, 0, 16); + while (*s) { + if (*s & 0x60 && *s ^ 0x7f) { + *d = *s; + } else { + /* stop copying if control character found */ + break; + } + + if (++s > (uint8 *) (buf + ret)) + break; + + d++; + } + + DEV_DBG("%s: '%s'\n", __func__, + external_common_state->spd_product_description); + + return ret; +} + +static ssize_t hdmi_common_rda_product_description(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = snprintf(buf, PAGE_SIZE, "%s\n", + external_common_state->spd_product_description); + DEV_DBG("%s: '%s'\n", __func__, + external_common_state->spd_product_description); + + return ret; +} + +static ssize_t hdmi_common_rda_edid_3d_modes(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + int i; + char buff_3d[128]; + + buf[0] = 0; + if (external_common_state->disp_mode_list.num_of_elements) { + uint32 *video_mode = external_common_state->disp_mode_list + .disp_mode_list; + uint32 *video_3d_mode = external_common_state->disp_mode_list + .disp_3d_mode_list; + for (i = 0; i < external_common_state->disp_mode_list + .num_of_elements; ++i) { + video_3d_format_2string(*video_3d_mode++, buff_3d); + if (ret > 0) + ret += snprintf(buf+ret, PAGE_SIZE-ret, + ",%d=%s", + *video_mode++ + 1, buff_3d); + else + ret += snprintf(buf+ret, PAGE_SIZE-ret, + "%d=%s", + *video_mode++ + 1, buff_3d); + } + } else + ret += snprintf(buf+ret, PAGE_SIZE-ret, "%d", + external_common_state->video_resolution+1); + + DEV_DBG("%s: '%s'\n", __func__, buf); + ret += snprintf(buf+ret, PAGE_SIZE-ret, "\n"); + return ret; +} + +static ssize_t hdmi_common_rda_hdcp(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = snprintf(buf, PAGE_SIZE, "%d\n", + external_common_state->hdcp_active); + DEV_DBG("%s: '%d'\n", __func__, + external_common_state->hdcp_active); + return ret; +} + +static ssize_t hdmi_common_rda_hpd(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + if (external_common_state->hpd_feature) { + ret = snprintf(buf, PAGE_SIZE, "%d\n", + external_common_state->hpd_feature_on); + DEV_DBG("%s: '%d'\n", __func__, + external_common_state->hpd_feature_on); + } else { + ret = snprintf(buf, PAGE_SIZE, "-1\n"); + DEV_DBG("%s: 'not supported'\n", __func__); + } + return ret; +} + +static ssize_t hdmi_common_wta_hpd(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + ssize_t ret = strnlen(buf, PAGE_SIZE); + int hpd; + if (hdmi_prim_display) + hpd = 1; + else + hpd = atoi(buf); + + if (external_common_state->hpd_feature) { + if (hpd == 0 && external_common_state->hpd_feature_on) { + external_common_state->hpd_feature(0); + external_common_state->hpd_feature_on = 0; + DEV_DBG("%s: '%d'\n", __func__, + external_common_state->hpd_feature_on); + } else if (hpd == 1 && !external_common_state->hpd_feature_on) { + external_common_state->hpd_feature(1); + external_common_state->hpd_feature_on = 1; + DEV_DBG("%s: '%d'\n", __func__, + external_common_state->hpd_feature_on); + } else { + DEV_DBG("%s: '%d' (unchanged)\n", __func__, + external_common_state->hpd_feature_on); + } + } else { + DEV_DBG("%s: 'not supported'\n", __func__); + } + + return ret; +} + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT +/* + * This interface for CEC feature is defined to suit + * the current requirements. However, the actual functionality is + * added to accommodate different interfaces + */ +static ssize_t hdmi_msm_rda_cec(struct device *dev, + struct device_attribute *attr, char *buf) +{ + /* 0x028C CEC_CTRL */ + ssize_t ret = snprintf(buf, PAGE_SIZE, "%d\n", + (HDMI_INP(0x028C) & BIT(0))); + return ret; +} + +static ssize_t hdmi_msm_wta_cec(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + ssize_t ret = strnlen(buf, PAGE_SIZE); + int cec = atoi(buf); + + if (cec != 0) { + mutex_lock(&hdmi_msm_state_mutex); + hdmi_msm_state->cec_enabled = true; + hdmi_msm_state->cec_logical_addr = 4; + + /* flush CEC queue */ + hdmi_msm_state->cec_queue_wr = hdmi_msm_state->cec_queue_start; + hdmi_msm_state->cec_queue_rd = hdmi_msm_state->cec_queue_start; + hdmi_msm_state->cec_queue_full = false; + memset(hdmi_msm_state->cec_queue_rd, 0, + sizeof(struct hdmi_msm_cec_msg)*CEC_QUEUE_SIZE); + + mutex_unlock(&hdmi_msm_state_mutex); + hdmi_msm_cec_init(); + hdmi_msm_cec_write_logical_addr( + hdmi_msm_state->cec_logical_addr); + DEV_DBG("CEC enabled\n"); + } else { + mutex_lock(&hdmi_msm_state_mutex); + hdmi_msm_state->cec_enabled = false; + hdmi_msm_state->cec_logical_addr = 15; + mutex_unlock(&hdmi_msm_state_mutex); + hdmi_msm_cec_write_logical_addr( + hdmi_msm_state->cec_logical_addr); + /* 0x028C CEC_CTRL */ + HDMI_OUTP(0x028C, 0); + DEV_DBG("CEC disabled\n"); + } + return ret; +} + +static ssize_t hdmi_msm_rda_cec_logical_addr(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + + mutex_lock(&hdmi_msm_state_mutex); + ret = snprintf(buf, PAGE_SIZE, "%d\n", + hdmi_msm_state->cec_logical_addr); + mutex_unlock(&hdmi_msm_state_mutex); + return ret; +} + +static ssize_t hdmi_msm_wta_cec_logical_addr(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + +#ifdef DRVR_ONLY_CECT_NO_DAEMON + /* + * Only for testing + */ + hdmi_msm_cec_one_touch_play(); + return 0; +#else + ssize_t ret = strnlen(buf, PAGE_SIZE); + int logical_addr = atoi(buf); + + if (logical_addr < 0 || logical_addr > 15) + return -EINVAL; + + mutex_lock(&hdmi_msm_state_mutex); + hdmi_msm_state->cec_logical_addr = logical_addr; + mutex_unlock(&hdmi_msm_state_mutex); + + hdmi_msm_cec_write_logical_addr(logical_addr); + + return ret; +#endif +} + +static ssize_t hdmi_msm_rda_cec_frame(struct device *dev, + struct device_attribute *attr, char *buf) +{ + mutex_lock(&hdmi_msm_state_mutex); + if (hdmi_msm_state->cec_queue_rd == hdmi_msm_state->cec_queue_wr + && !hdmi_msm_state->cec_queue_full) { + mutex_unlock(&hdmi_msm_state_mutex); + DEV_ERR("CEC message queue is empty\n"); + return -EBUSY; + } + memcpy(buf, hdmi_msm_state->cec_queue_rd++, + sizeof(struct hdmi_msm_cec_msg)); + hdmi_msm_state->cec_queue_full = false; + if (hdmi_msm_state->cec_queue_rd == CEC_QUEUE_END) + hdmi_msm_state->cec_queue_rd = hdmi_msm_state->cec_queue_start; + mutex_unlock(&hdmi_msm_state_mutex); + + return sizeof(struct hdmi_msm_cec_msg); +} + +static ssize_t hdmi_msm_wta_cec_frame(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int i; + int retry = ((struct hdmi_msm_cec_msg *) buf)->retransmit; + + for (i = 0; i < RETRANSMIT_MAX_NUM; i++) { + hdmi_msm_cec_msg_send((struct hdmi_msm_cec_msg *) buf); + if (hdmi_msm_state->cec_frame_wr_status + & CEC_STATUS_WR_ERROR && retry--) { + mutex_lock(&hdmi_msm_state_mutex); + if (hdmi_msm_state->fsm_reset_done) + retry++; + mutex_unlock(&hdmi_msm_state_mutex); + msleep(20); + } else + break; + } + + if (hdmi_msm_state->cec_frame_wr_status & CEC_STATUS_WR_DONE) + return sizeof(struct hdmi_msm_cec_msg); + else + return -EINVAL; +} +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT */ + +static ssize_t hdmi_common_rda_3d_present(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = snprintf(buf, PAGE_SIZE, "%d\n", + external_common_state->present_3d); + DEV_DBG("%s: '%d'\n", __func__, + external_common_state->present_3d); + return ret; +} + +static ssize_t hdmi_common_rda_hdcp_present(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = snprintf(buf, PAGE_SIZE, "%d\n", + external_common_state->present_hdcp); + DEV_DBG("%s: '%d'\n", __func__, + external_common_state->present_hdcp); + return ret; +} +#endif + +#ifdef CONFIG_FB_MSM_HDMI_3D +static ssize_t hdmi_3d_rda_format_3d(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = snprintf(buf, PAGE_SIZE, "%d\n", + external_common_state->format_3d); + DEV_DBG("%s: '%d'\n", __func__, + external_common_state->format_3d); + return ret; +} + +static ssize_t hdmi_3d_wta_format_3d(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + ssize_t ret = strnlen(buf, PAGE_SIZE); + int format_3d = atoi(buf); + + if (format_3d >= 0 && format_3d <= 2) { + if (format_3d != external_common_state->format_3d) { + external_common_state->format_3d = format_3d; + if (external_common_state->switch_3d) + external_common_state->switch_3d(format_3d); + DEV_DBG("%s: '%d'\n", __func__, + external_common_state->format_3d); + } else { + DEV_DBG("%s: '%d' (unchanged)\n", __func__, + external_common_state->format_3d); + } + } else { + DEV_DBG("%s: '%d' (unknown)\n", __func__, format_3d); + } + + return ret; +} +#endif + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT +static DEVICE_ATTR(cec, S_IRUGO | S_IWUSR, + hdmi_msm_rda_cec, + hdmi_msm_wta_cec); + +static DEVICE_ATTR(cec_logical_addr, S_IRUGO | S_IWUSR, + hdmi_msm_rda_cec_logical_addr, + hdmi_msm_wta_cec_logical_addr); + +static DEVICE_ATTR(cec_rd_frame, S_IRUGO, + hdmi_msm_rda_cec_frame, NULL); + +static DEVICE_ATTR(cec_wr_frame, S_IWUSR, + NULL, hdmi_msm_wta_cec_frame); +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT */ + + +static ssize_t external_common_rda_video_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = snprintf(buf, PAGE_SIZE, "%d\n", + external_common_state->video_resolution+1); + DEV_DBG("%s: '%d'\n", __func__, + external_common_state->video_resolution+1); + return ret; +} + +static ssize_t external_common_wta_video_mode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + ssize_t ret = strnlen(buf, PAGE_SIZE); + uint32 video_mode; +#ifdef CONFIG_FB_MSM_HDMI_COMMON + const struct hdmi_disp_mode_timing_type *disp_mode; +#endif + mutex_lock(&external_common_state_hpd_mutex); + if (!external_common_state->hpd_state) { + mutex_unlock(&external_common_state_hpd_mutex); + DEV_INFO("%s: FAILED: display off or cable disconnected\n", + __func__); + return ret; + } + mutex_unlock(&external_common_state_hpd_mutex); + + video_mode = atoi(buf)-1; + DEV_INFO("%s: video_mode is %d\n", __func__, video_mode); + kobject_uevent(external_common_state->uevent_kobj, KOBJ_OFFLINE); +#ifdef CONFIG_FB_MSM_HDMI_COMMON + disp_mode = hdmi_common_get_supported_mode(video_mode); + if (!disp_mode) { + DEV_INFO("%s: FAILED: mode not supported (%d)\n", + __func__, video_mode); + return ret; + } + external_common_state->disp_mode_list.num_of_elements = 1; + external_common_state->disp_mode_list.disp_mode_list[0] = video_mode; +#elif defined(CONFIG_FB_MSM_TVOUT) + external_common_state->video_resolution = video_mode; +#endif + DEV_DBG("%s: 'mode=%d %s' successful (sending OFF/ONLINE)\n", __func__, + video_mode, video_format_2string(video_mode)); + kobject_uevent(external_common_state->uevent_kobj, KOBJ_ONLINE); + return ret; +} + +static ssize_t external_common_rda_connected(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + mutex_lock(&external_common_state_hpd_mutex); + ret = snprintf(buf, PAGE_SIZE, "%d\n", + external_common_state->hpd_state); + DEV_DBG("%s: '%d'\n", __func__, + external_common_state->hpd_state); + mutex_unlock(&external_common_state_hpd_mutex); + return ret; +} + +static ssize_t external_common_rda_hdmi_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + + ret = snprintf(buf, PAGE_SIZE, "%d\n", + external_common_state->hdmi_sink); + + DEV_DBG("%s: '%d'\n", __func__, + external_common_state->hdmi_sink); + + return ret; +} + +static ssize_t hdmi_common_rda_hdmi_primary(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = snprintf(buf, PAGE_SIZE, "%d\n", + hdmi_prim_display); + DEV_DBG("%s: '%d'\n", __func__, hdmi_prim_display); + return ret; +} + +static DEVICE_ATTR(video_mode, S_IRUGO | S_IWUGO, + external_common_rda_video_mode, external_common_wta_video_mode); +static DEVICE_ATTR(video_mode_str, S_IRUGO, external_common_rda_video_mode_str, + NULL); +static DEVICE_ATTR(connected, S_IRUGO, external_common_rda_connected, NULL); +static DEVICE_ATTR(hdmi_mode, S_IRUGO, external_common_rda_hdmi_mode, NULL); +#ifdef CONFIG_FB_MSM_HDMI_COMMON +static DEVICE_ATTR(edid_modes, S_IRUGO, hdmi_common_rda_edid_modes, NULL); +static DEVICE_ATTR(hpd, S_IRUGO | S_IWUGO, hdmi_common_rda_hpd, + hdmi_common_wta_hpd); +static DEVICE_ATTR(hdcp, S_IRUGO, hdmi_common_rda_hdcp, NULL); +static DEVICE_ATTR(pa, S_IRUGO, + hdmi_common_rda_edid_physical_address, NULL); +static DEVICE_ATTR(scan_info, S_IRUGO, + hdmi_common_rda_edid_scan_info, NULL); +static DEVICE_ATTR(vendor_name, S_IRUGO | S_IWUSR, hdmi_common_rda_vendor_name, + hdmi_common_wta_vendor_name); +static DEVICE_ATTR(product_description, S_IRUGO | S_IWUSR, + hdmi_common_rda_product_description, + hdmi_common_wta_product_description); +static DEVICE_ATTR(edid_3d_modes, S_IRUGO, + hdmi_common_rda_edid_3d_modes, NULL); +static DEVICE_ATTR(3d_present, S_IRUGO, hdmi_common_rda_3d_present, NULL); +static DEVICE_ATTR(hdcp_present, S_IRUGO, hdmi_common_rda_hdcp_present, NULL); +#endif +#ifdef CONFIG_FB_MSM_HDMI_3D +static DEVICE_ATTR(format_3d, S_IRUGO | S_IWUGO, hdmi_3d_rda_format_3d, + hdmi_3d_wta_format_3d); +#endif +static DEVICE_ATTR(hdmi_primary, S_IRUGO, hdmi_common_rda_hdmi_primary, NULL); + +static struct attribute *external_common_fs_attrs[] = { + &dev_attr_video_mode.attr, + &dev_attr_video_mode_str.attr, + &dev_attr_connected.attr, + &dev_attr_hdmi_mode.attr, +#ifdef CONFIG_FB_MSM_HDMI_COMMON + &dev_attr_edid_modes.attr, + &dev_attr_hdcp.attr, + &dev_attr_hpd.attr, + &dev_attr_pa.attr, + &dev_attr_scan_info.attr, + &dev_attr_vendor_name.attr, + &dev_attr_product_description.attr, + &dev_attr_edid_3d_modes.attr, + &dev_attr_3d_present.attr, + &dev_attr_hdcp_present.attr, +#endif +#ifdef CONFIG_FB_MSM_HDMI_3D + &dev_attr_format_3d.attr, +#endif +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT + &dev_attr_cec.attr, + &dev_attr_cec_logical_addr.attr, + &dev_attr_cec_rd_frame.attr, + &dev_attr_cec_wr_frame.attr, +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT */ + &dev_attr_hdmi_primary.attr, + NULL, +}; +static struct attribute_group external_common_fs_attr_group = { + .attrs = external_common_fs_attrs, +}; + +/* create external interface kobject and initialize */ +int external_common_state_create(struct platform_device *pdev) +{ + int rc; + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); + if (!mfd) { + DEV_ERR("%s: mfd not found\n", __func__); + return -ENODEV; + } + if (!mfd->fbi) { + DEV_ERR("%s: mfd->fbi not found\n", __func__); + return -ENODEV; + } + if (!mfd->fbi->dev) { + DEV_ERR("%s: mfd->fbi->dev not found\n", __func__); + return -ENODEV; + } + rc = sysfs_create_group(&mfd->fbi->dev->kobj, + &external_common_fs_attr_group); + if (rc) { + DEV_ERR("%s: sysfs group creation failed, rc=%d\n", __func__, + rc); + return rc; + } + external_common_state->uevent_kobj = &mfd->fbi->dev->kobj; + DEV_ERR("%s: sysfs group %p\n", __func__, + external_common_state->uevent_kobj); + + kobject_uevent(external_common_state->uevent_kobj, KOBJ_ADD); + DEV_DBG("%s: kobject_uevent(KOBJ_ADD)\n", __func__); + return 0; +} +EXPORT_SYMBOL(external_common_state_create); + +void external_common_state_remove(void) +{ + if (external_common_state->uevent_kobj) + sysfs_remove_group(external_common_state->uevent_kobj, + &external_common_fs_attr_group); + external_common_state->uevent_kobj = NULL; +} +EXPORT_SYMBOL(external_common_state_remove); + +#ifdef CONFIG_FB_MSM_HDMI_COMMON +/* The Logic ID for HDMI TX Core. Currently only support 1 HDMI TX Core. */ +struct hdmi_edid_video_mode_property_type { + uint32 video_code; + uint32 active_h; + uint32 active_v; + boolean interlaced; + uint32 total_h; + uint32 total_blank_h; + uint32 total_v; + uint32 total_blank_v; + /* Must divide by 1000 to get the frequency */ + uint32 freq_h; + /* Must divide by 1000 to get the frequency */ + uint32 freq_v; + /* Must divide by 1000 to get the frequency */ + uint32 pixel_freq; + /* Must divide by 1000 to get the frequency */ + uint32 refresh_rate; + boolean aspect_ratio_4_3; +}; + +/* LUT is sorted from lowest Active H to highest Active H - ease searching */ +static struct hdmi_edid_video_mode_property_type + hdmi_edid_disp_mode_lut[] = { + + /* All 640 H Active */ + {HDMI_VFRMT_640x480p60_4_3, 640, 480, FALSE, 800, 160, 525, 45, + 31465, 59940, 25175, 59940, TRUE}, + {HDMI_VFRMT_640x480p60_4_3, 640, 480, FALSE, 800, 160, 525, 45, + 31500, 60000, 25200, 60000, TRUE}, + + /* All 720 H Active */ + {HDMI_VFRMT_720x576p50_4_3, 720, 576, FALSE, 864, 144, 625, 49, + 31250, 50000, 27000, 50000, TRUE}, + {HDMI_VFRMT_720x480p60_4_3, 720, 480, FALSE, 858, 138, 525, 45, + 31465, 59940, 27000, 59940, TRUE}, + {HDMI_VFRMT_720x480p60_4_3, 720, 480, FALSE, 858, 138, 525, 45, + 31500, 60000, 27030, 60000, TRUE}, + {HDMI_VFRMT_720x576p100_4_3, 720, 576, FALSE, 864, 144, 625, 49, + 62500, 100000, 54000, 100000, TRUE}, + {HDMI_VFRMT_720x480p120_4_3, 720, 480, FALSE, 858, 138, 525, 45, + 62937, 119880, 54000, 119880, TRUE}, + {HDMI_VFRMT_720x480p120_4_3, 720, 480, FALSE, 858, 138, 525, 45, + 63000, 120000, 54054, 120000, TRUE}, + {HDMI_VFRMT_720x576p200_4_3, 720, 576, FALSE, 864, 144, 625, 49, + 125000, 200000, 108000, 200000, TRUE}, + {HDMI_VFRMT_720x480p240_4_3, 720, 480, FALSE, 858, 138, 525, 45, + 125874, 239760, 108000, 239000, TRUE}, + {HDMI_VFRMT_720x480p240_4_3, 720, 480, FALSE, 858, 138, 525, 45, + 126000, 240000, 108108, 240000, TRUE}, + + /* All 1280 H Active */ + {HDMI_VFRMT_1280x720p50_16_9, 1280, 720, FALSE, 1980, 700, 750, 30, + 37500, 50000, 74250, 50000, FALSE}, + {HDMI_VFRMT_1280x720p60_16_9, 1280, 720, FALSE, 1650, 370, 750, 30, + 44955, 59940, 74176, 59940, FALSE}, + {HDMI_VFRMT_1280x720p60_16_9, 1280, 720, FALSE, 1650, 370, 750, 30, + 45000, 60000, 74250, 60000, FALSE}, + {HDMI_VFRMT_1280x720p100_16_9, 1280, 720, FALSE, 1980, 700, 750, 30, + 75000, 100000, 148500, 100000, FALSE}, + {HDMI_VFRMT_1280x720p120_16_9, 1280, 720, FALSE, 1650, 370, 750, 30, + 89909, 119880, 148352, 119880, FALSE}, + {HDMI_VFRMT_1280x720p120_16_9, 1280, 720, FALSE, 1650, 370, 750, 30, + 90000, 120000, 148500, 120000, FALSE}, + + /* All 1440 H Active */ + {HDMI_VFRMT_1440x576i50_4_3, 1440, 576, TRUE, 1728, 288, 625, 24, + 15625, 50000, 27000, 50000, TRUE}, + {HDMI_VFRMT_720x288p50_4_3, 1440, 288, FALSE, 1728, 288, 312, 24, + 15625, 50080, 27000, 50000, TRUE}, + {HDMI_VFRMT_720x288p50_4_3, 1440, 288, FALSE, 1728, 288, 313, 25, + 15625, 49920, 27000, 50000, TRUE}, + {HDMI_VFRMT_720x288p50_4_3, 1440, 288, FALSE, 1728, 288, 314, 26, + 15625, 49761, 27000, 50000, TRUE}, + {HDMI_VFRMT_1440x576p50_4_3, 1440, 576, FALSE, 1728, 288, 625, 49, + 31250, 50000, 54000, 50000, TRUE}, + {HDMI_VFRMT_1440x480i60_4_3, 1440, 480, TRUE, 1716, 276, 525, 22, + 15734, 59940, 27000, 59940, TRUE}, + {HDMI_VFRMT_1440x240p60_4_3, 1440, 240, FALSE, 1716, 276, 262, 22, + 15734, 60054, 27000, 59940, TRUE}, + {HDMI_VFRMT_1440x240p60_4_3, 1440, 240, FALSE, 1716, 276, 263, 23, + 15734, 59826, 27000, 59940, TRUE}, + {HDMI_VFRMT_1440x480p60_4_3, 1440, 480, FALSE, 1716, 276, 525, 45, + 31469, 59940, 54000, 59940, TRUE}, + {HDMI_VFRMT_1440x480i60_4_3, 1440, 480, TRUE, 1716, 276, 525, 22, + 15750, 60000, 27027, 60000, TRUE}, + {HDMI_VFRMT_1440x240p60_4_3, 1440, 240, FALSE, 1716, 276, 262, 22, + 15750, 60115, 27027, 60000, TRUE}, + {HDMI_VFRMT_1440x240p60_4_3, 1440, 240, FALSE, 1716, 276, 263, 23, + 15750, 59886, 27027, 60000, TRUE}, + {HDMI_VFRMT_1440x480p60_4_3, 1440, 480, FALSE, 1716, 276, 525, 45, + 31500, 60000, 54054, 60000, TRUE}, + {HDMI_VFRMT_1440x576i100_4_3, 1440, 576, TRUE, 1728, 288, 625, 24, + 31250, 100000, 54000, 100000, TRUE}, + {HDMI_VFRMT_1440x480i120_4_3, 1440, 480, TRUE, 1716, 276, 525, 22, + 31469, 119880, 54000, 119880, TRUE}, + {HDMI_VFRMT_1440x480i120_4_3, 1440, 480, TRUE, 1716, 276, 525, 22, + 31500, 120000, 54054, 120000, TRUE}, + {HDMI_VFRMT_1440x576i200_4_3, 1440, 576, TRUE, 1728, 288, 625, 24, + 62500, 200000, 108000, 200000, TRUE}, + {HDMI_VFRMT_1440x480i240_4_3, 1440, 480, TRUE, 1716, 276, 525, 22, + 62937, 239760, 108000, 239000, TRUE}, + {HDMI_VFRMT_1440x480i240_4_3, 1440, 480, TRUE, 1716, 276, 525, 22, + 63000, 240000, 108108, 240000, TRUE}, + + /* All 1920 H Active */ + {HDMI_VFRMT_1920x1080p60_16_9, 1920, 1080, FALSE, 2200, 280, 1125, + 45, 67433, 59940, 148352, 59940, FALSE}, + {HDMI_VFRMT_1920x1080p60_16_9, 1920, 1080, TRUE, 2200, 280, 1125, + 45, 67500, 60000, 148500, 60000, FALSE}, + {HDMI_VFRMT_1920x1080p50_16_9, 1920, 1080, FALSE, 2640, 720, 1125, + 45, 56250, 50000, 148500, 50000, FALSE}, + {HDMI_VFRMT_1920x1080p24_16_9, 1920, 1080, FALSE, 2750, 830, 1125, + 45, 26973, 23976, 74176, 24000, FALSE}, + {HDMI_VFRMT_1920x1080p24_16_9, 1920, 1080, FALSE, 2750, 830, 1125, + 45, 27000, 24000, 74250, 24000, FALSE}, + {HDMI_VFRMT_1920x1080p25_16_9, 1920, 1080, FALSE, 2640, 720, 1125, + 45, 28125, 25000, 74250, 25000, FALSE}, + {HDMI_VFRMT_1920x1080p30_16_9, 1920, 1080, FALSE, 2200, 280, 1125, + 45, 33716, 29970, 74176, 30000, FALSE}, + {HDMI_VFRMT_1920x1080p30_16_9, 1920, 1080, FALSE, 2200, 280, 1125, + 45, 33750, 30000, 74250, 30000, FALSE}, + {HDMI_VFRMT_1920x1080i50_16_9, 1920, 1080, TRUE, 2304, 384, 1250, + 85, 31250, 50000, 72000, 50000, FALSE}, + {HDMI_VFRMT_1920x1080i60_16_9, 1920, 1080, TRUE, 2200, 280, 1125, + 22, 33716, 59940, 74176, 59940, FALSE}, + {HDMI_VFRMT_1920x1080i60_16_9, 1920, 1080, TRUE, 2200, 280, 1125, + 22, 33750, 60000, 74250, 60000, FALSE}, + {HDMI_VFRMT_1920x1080i100_16_9, 1920, 1080, TRUE, 2640, 720, 1125, + 22, 56250, 100000, 148500, 100000, FALSE}, + {HDMI_VFRMT_1920x1080i120_16_9, 1920, 1080, TRUE, 2200, 280, 1125, + 22, 67432, 119880, 148352, 119980, FALSE}, + {HDMI_VFRMT_1920x1080i120_16_9, 1920, 1080, TRUE, 2200, 280, 1125, + 22, 67500, 120000, 148500, 120000, FALSE}, + + /* All 2880 H Active */ + {HDMI_VFRMT_2880x576i50_4_3, 2880, 576, TRUE, 3456, 576, 625, 24, + 15625, 50000, 54000, 50000, TRUE}, + {HDMI_VFRMT_2880x288p50_4_3, 2880, 576, FALSE, 3456, 576, 312, 24, + 15625, 50080, 54000, 50000, TRUE}, + {HDMI_VFRMT_2880x288p50_4_3, 2880, 576, FALSE, 3456, 576, 313, 25, + 15625, 49920, 54000, 50000, TRUE}, + {HDMI_VFRMT_2880x288p50_4_3, 2880, 576, FALSE, 3456, 576, 314, 26, + 15625, 49761, 54000, 50000, TRUE}, + {HDMI_VFRMT_2880x576p50_4_3, 2880, 576, FALSE, 3456, 576, 625, 49, + 31250, 50000, 108000, 50000, TRUE}, + {HDMI_VFRMT_2880x480i60_4_3, 2880, 480, TRUE, 3432, 552, 525, 22, + 15734, 59940, 54000, 59940, TRUE}, + {HDMI_VFRMT_2880x240p60_4_3, 2880, 480, FALSE, 3432, 552, 262, 22, + 15734, 60054, 54000, 59940, TRUE}, + {HDMI_VFRMT_2880x240p60_4_3, 2880, 480, FALSE, 3432, 552, 263, 23, + 15734, 59940, 54000, 59940, TRUE}, + {HDMI_VFRMT_2880x480p60_4_3, 2880, 480, FALSE, 3432, 552, 525, 45, + 31469, 59940, 108000, 59940, TRUE}, + {HDMI_VFRMT_2880x480i60_4_3, 2880, 480, TRUE, 3432, 552, 525, 22, + 15750, 60000, 54054, 60000, TRUE}, + {HDMI_VFRMT_2880x240p60_4_3, 2880, 240, FALSE, 3432, 552, 262, 22, + 15750, 60115, 54054, 60000, TRUE}, + {HDMI_VFRMT_2880x240p60_4_3, 2880, 240, FALSE, 3432, 552, 262, 23, + 15750, 59886, 54054, 60000, TRUE}, + {HDMI_VFRMT_2880x480p60_4_3, 2880, 480, FALSE, 3432, 552, 525, 45, + 31500, 60000, 108108, 60000, TRUE}, +}; + +static const uint8 *hdmi_edid_find_block(const uint8 *in_buf, + uint32 start_offset, uint8 type, uint8 *len) +{ + /* the start of data block collection, start of Video Data Block */ + uint32 offset = start_offset; + uint32 end_dbc_offset = in_buf[2]; + + *len = 0; + + /*edid buffer 1, byte 2 being 4 means no non-DTD/Data block collection + present. + edid buffer 1, byte 2 being 0 menas no non-DTD/DATA block collection + present and no DTD data present.*/ + if ((end_dbc_offset == 0) || (end_dbc_offset == 4)) { + DEV_WARN("EDID: no DTD or non-DTD data present\n"); + return NULL; + } + while (offset < end_dbc_offset) { + uint8 block_len = in_buf[offset] & 0x1F; + if ((in_buf[offset] >> 5) == type) { + *len = block_len; + DEV_DBG("EDID: block=%d found @ %d with length=%d\n", + type, offset, block_len); + return in_buf+offset; + } + offset += 1 + block_len; + } + DEV_WARN("EDID: type=%d block not found in EDID block\n", type); + return NULL; +} + +static void hdmi_edid_extract_vendor_id(const uint8 *in_buf, + char *vendor_id) +{ + uint32 id_codes = ((uint32)in_buf[8] << 8) + in_buf[9]; + + vendor_id[0] = 'A' - 1 + ((id_codes >> 10) & 0x1F); + vendor_id[1] = 'A' - 1 + ((id_codes >> 5) & 0x1F); + vendor_id[2] = 'A' - 1 + (id_codes & 0x1F); + vendor_id[3] = 0; +} + +static uint32 hdmi_edid_extract_ieee_reg_id(const uint8 *in_buf) +{ + uint8 len; + const uint8 *vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, + &len); + + if (vsd == NULL) + return 0; + + DEV_DBG("EDID: VSD PhyAddr=%04x, MaxTMDS=%dMHz\n", + ((uint32)vsd[4] << 8) + (uint32)vsd[5], (uint32)vsd[7] * 5); + external_common_state->physical_address = + ((uint16)vsd[4] << 8) + (uint16)vsd[5]; + return ((uint32)vsd[3] << 16) + ((uint32)vsd[2] << 8) + (uint32)vsd[1]; +} + +#define HDMI_VSDB_3D_DATA_OFFSET(vsd) \ + (!((vsd)[8] & BIT(7)) ? 9 : (!((vsd)[8] & BIT(6)) ? 11 : 13)) + +static void hdmi_edid_extract_3d_present(const uint8 *in_buf) +{ + uint8 len, offset; + const uint8 *vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, + &len); + + external_common_state->present_3d = 0; + if (vsd == NULL || len < 9) { + DEV_DBG("EDID[3D]: block-id 3 not found or not long enough\n"); + return; + } + + offset = HDMI_VSDB_3D_DATA_OFFSET(vsd); + DEV_DBG("EDID: 3D present @ %d = %02x\n", offset, vsd[offset]); + if (vsd[offset] >> 7) { /* 3D format indication present */ + DEV_INFO("EDID: 3D present, 3D-len=%d\n", vsd[offset+1] & 0x1F); + external_common_state->present_3d = 1; + } +} + + +static void hdmi_edid_extract_latency_fields(const uint8 *in_buf) +{ + uint8 len; + const uint8 *vsd = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 3, + &len); + + if (vsd == NULL || len < 12 || !(vsd[8] & BIT(7))) { + external_common_state->video_latency = (uint16)-1; + external_common_state->audio_latency = (uint16)-1; + DEV_DBG("EDID: No audio/video latency present\n"); + } else { + external_common_state->video_latency = vsd[9]; + external_common_state->audio_latency = vsd[10]; + DEV_DBG("EDID: video-latency=%04x, audio-latency=%04x\n", + external_common_state->video_latency, + external_common_state->audio_latency); + } +} + +static void hdmi_edid_extract_speaker_allocation_data(const uint8 *in_buf) +{ + uint8 len; + const uint8 *sad = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 4, + &len); + + if (sad == NULL) + return; + + external_common_state->speaker_allocation_block = sad[1]; + DEV_DBG("EDID: speaker allocation data SP byte = %08x %s%s%s%s%s%s%s\n", + sad[1], + (sad[1] & BIT(0)) ? "FL/FR," : "", + (sad[1] & BIT(1)) ? "LFE," : "", + (sad[1] & BIT(2)) ? "FC," : "", + (sad[1] & BIT(3)) ? "RL/RR," : "", + (sad[1] & BIT(4)) ? "RC," : "", + (sad[1] & BIT(5)) ? "FLC/FRC," : "", + (sad[1] & BIT(6)) ? "RLC/RRC," : ""); +} + +static void hdmi_edid_extract_audio_data_blocks(const uint8 *in_buf) +{ + uint8 len; + const uint8 *sad = hdmi_edid_find_block(in_buf, DBC_START_OFFSET, 1, + &len); + uint32 *adb = external_common_state->audio_data_blocks; + + if (sad == NULL) + return; + + external_common_state->audio_data_block_cnt = 0; + while (len >= 3 && external_common_state->audio_data_block_cnt < 16) { + DEV_DBG("EDID: Audio Data Block=\n", + (sad[1] & 0x7)+1, sad[1] >> 3, sad[2], sad[3]); + *adb++ = (uint32)sad[1] + ((uint32)sad[2] << 8) + + ((uint32)sad[2] << 16); + ++external_common_state->audio_data_block_cnt; + len -= 3; + sad += 3; + } +} + +static void hdmi_edid_extract_extended_data_blocks(const uint8 *in_buf) +{ + uint8 len = 0; + uint32 start_offset = DBC_START_OFFSET; + + /* A Tage code of 7 identifies extended data blocks */ + uint8 const *etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len); + + while (etag != NULL) { + /* The extended data block should at least be 2 bytes long */ + if (len < 2) { + DEV_DBG("EDID: Found an extended data block of length" + "less than 2 bytes. Ignoring ...\n"); + } else { + /* + * The second byte of the extended data block has the + * extended tag code + */ + switch (etag[1]) { + case 0: + /* Video Capability Data Block */ + DEV_DBG("EDID: VCDB=%02X %02X\n", etag[1], + etag[2]); + + /* + * Check if the sink specifies underscan + * support for: + * BIT 5: preferred video format + * BIT 3: IT video format + * BIT 1: CE video format + */ + external_common_state->pt_scan_info = (etag[2] & + (BIT(4) | BIT(5))) >> 4; + external_common_state->it_scan_info = (etag[2] & + (BIT(3) | BIT(2))) >> 2; + external_common_state->ce_scan_info = etag[2] & + (BIT(1) | BIT(0)); + DEV_DBG("EDID: Scan Information (pt|it|ce): " + "(%d|%d|%d)", + external_common_state->pt_scan_info, + external_common_state->it_scan_info, + external_common_state->ce_scan_info); + break; + default: + DEV_DBG("EDID: Extend Tag Code %d not" + "supported\n", etag[1]); + break; + } + } + + /* There could be more that one extended data block */ + start_offset = etag - in_buf + len + 1; + etag = hdmi_edid_find_block(in_buf, start_offset, 7, &len); + } +} + +static void hdmi_edid_detail_desc(const uint8 *data_buf, uint32 *disp_mode) +{ + boolean aspect_ratio_4_3 = FALSE; + boolean interlaced = FALSE; + uint32 active_h = 0; + uint32 active_v = 0; + uint32 blank_h = 0; + uint32 blank_v = 0; + uint32 ndx = 0; + uint32 max_num_of_elements = 0; + uint32 img_size_h = 0; + uint32 img_size_v = 0; + + /* See VESA Spec */ + /* EDID_TIMING_DESC_UPPER_H_NIBBLE[0x4]: Relative Offset to the EDID + * detailed timing descriptors - Upper 4 bit for each H active/blank + * field */ + /* EDID_TIMING_DESC_H_ACTIVE[0x2]: Relative Offset to the EDID detailed + * timing descriptors - H active */ + active_h = ((((uint32)data_buf[0x4] >> 0x4) & 0xF) << 8) + | data_buf[0x2]; + + /* EDID_TIMING_DESC_H_BLANK[0x3]: Relative Offset to the EDID detailed + * timing descriptors - H blank */ + blank_h = (((uint32)data_buf[0x4] & 0xF) << 8) + | data_buf[0x3]; + + /* EDID_TIMING_DESC_UPPER_V_NIBBLE[0x7]: Relative Offset to the EDID + * detailed timing descriptors - Upper 4 bit for each V active/blank + * field */ + /* EDID_TIMING_DESC_V_ACTIVE[0x5]: Relative Offset to the EDID detailed + * timing descriptors - V active */ + active_v = ((((uint32)data_buf[0x7] >> 0x4) & 0xF) << 8) + | data_buf[0x5]; + + /* EDID_TIMING_DESC_V_BLANK[0x6]: Relative Offset to the EDID detailed + * timing descriptors - V blank */ + blank_v = (((uint32)data_buf[0x7] & 0xF) << 8) + | data_buf[0x6]; + + /* EDID_TIMING_DESC_IMAGE_SIZE_UPPER_NIBBLE[0xE]: Relative Offset to the + * EDID detailed timing descriptors - Image Size upper nibble + * V and H */ + /* EDID_TIMING_DESC_H_IMAGE_SIZE[0xC]: Relative Offset to the EDID + * detailed timing descriptors - H image size */ + /* EDID_TIMING_DESC_V_IMAGE_SIZE[0xD]: Relative Offset to the EDID + * detailed timing descriptors - V image size */ + img_size_h = ((((uint32)data_buf[0xE] >> 0x4) & 0xF) << 8) + | data_buf[0xC]; + img_size_v = (((uint32)data_buf[0xE] & 0xF) << 8) + | data_buf[0xD]; + + /* + * aspect ratio as 4:3 if within specificed range , rathaer than being + * absolute value + */ + aspect_ratio_4_3 = (abs(img_size_h * 3 - img_size_v * 4) < 5) ? 1 : 0; + + max_num_of_elements = sizeof(hdmi_edid_disp_mode_lut) + / sizeof(*hdmi_edid_disp_mode_lut); + + /* EDID_TIMING_DESC_INTERLACE[0x11:7]: Relative Offset to the EDID + * detailed timing descriptors - Interlace flag */ + DEV_DBG("Interlaced mode byte data_buf[0x11]=[%x]\n", data_buf[0x11]); + /* + * CEA 861-D: interlaced bit is bit[7] of byte[0x11] + */ + interlaced = (data_buf[0x11] & 0x80) >> 7; + + DEV_DBG("%s: A[%ux%u] B[%ux%u] V[%ux%u] %s\n", __func__, + active_h, active_v, blank_h, blank_v, img_size_h, img_size_v, + interlaced ? "i" : "p"); + + *disp_mode = HDMI_VFRMT_FORCE_32BIT; + while (ndx < max_num_of_elements) { + const struct hdmi_edid_video_mode_property_type *edid = + hdmi_edid_disp_mode_lut+ndx; + + if ((interlaced == edid->interlaced) && + (active_h == edid->active_h) && + (blank_h == edid->total_blank_h) && + (blank_v == edid->total_blank_v) && + ((active_v == edid->active_v) || + (active_v == (edid->active_v + 1))) + ) { + if (edid->aspect_ratio_4_3 && !aspect_ratio_4_3) + /* Aspect ratio 16:9 */ + *disp_mode = edid->video_code + 1; + else + /* Aspect ratio 4:3 */ + *disp_mode = edid->video_code; + + DEV_DBG("%s: mode found:%d\n", __func__, *disp_mode); + break; + } + ++ndx; + } + if (ndx == max_num_of_elements) + DEV_INFO("%s: *no mode* found\n", __func__); +} + +static void add_supported_video_format( + struct hdmi_disp_mode_list_type *disp_mode_list, + uint32 video_format) +{ + const struct hdmi_disp_mode_timing_type *timing = + hdmi_common_get_supported_mode(video_format); + boolean supported = timing != NULL; + + if (video_format >= HDMI_VFRMT_MAX) + return; + + DEV_DBG("EDID: format: %d [%s], %s\n", + video_format, video_format_2string(video_format), + supported ? "Supported" : "Not-Supported"); + if (supported) { + if (mhl_is_connected()) { + const struct hdmi_disp_mode_timing_type *mhl_timing = + hdmi_mhl_get_supported_mode(video_format); + boolean mhl_supported = mhl_timing != NULL; + DEV_DBG("EDID: format: %d [%s], %s by MHL\n", + video_format, video_format_2string(video_format), + mhl_supported ? "Supported" : "Not-Supported"); + if (mhl_supported) + disp_mode_list->disp_mode_list[ + disp_mode_list->num_of_elements++] = video_format; + } else + disp_mode_list->disp_mode_list[ + disp_mode_list->num_of_elements++] = video_format; + } +} + +const char *single_video_3d_format_2string(uint32 format) +{ + switch (format) { + case TOP_AND_BOTTOM: return "TAB"; + case FRAME_PACKING: return "FP"; + case SIDE_BY_SIDE_HALF: return "SSH"; + } + return ""; +} + +ssize_t video_3d_format_2string(uint32 format, char *buf) +{ + ssize_t ret, len = 0; + ret = snprintf(buf, PAGE_SIZE, "%s", + single_video_3d_format_2string(format & FRAME_PACKING)); + len += ret; + + if (len && (format & TOP_AND_BOTTOM)) + ret = snprintf(buf + len, PAGE_SIZE, ":%s", + single_video_3d_format_2string( + format & TOP_AND_BOTTOM)); + else + ret = snprintf(buf + len, PAGE_SIZE, "%s", + single_video_3d_format_2string( + format & TOP_AND_BOTTOM)); + len += ret; + + if (len && (format & SIDE_BY_SIDE_HALF)) + ret = snprintf(buf + len, PAGE_SIZE, ":%s", + single_video_3d_format_2string( + format & SIDE_BY_SIDE_HALF)); + else + ret = snprintf(buf + len, PAGE_SIZE, "%s", + single_video_3d_format_2string( + format & SIDE_BY_SIDE_HALF)); + len += ret; + + return len; +} + +static void add_supported_3d_format( + struct hdmi_disp_mode_list_type *disp_mode_list, + uint32 video_format, + uint32 video_3d_format) +{ + char string[128]; + boolean added = FALSE; + int i; + for (i = 0; i < disp_mode_list->num_of_elements; ++i) { + if (disp_mode_list->disp_mode_list[i] == video_format) { + disp_mode_list->disp_3d_mode_list[i] |= + video_3d_format; + added = TRUE; + break; + } + } + video_3d_format_2string(video_3d_format, string); + DEV_DBG("EDID[3D]: format: %d [%s], %s %s\n", + video_format, video_format_2string(video_format), + string, added ? "added" : "NOT added"); +} + +static void hdmi_edid_get_display_vsd_3d_mode(const uint8 *data_buf, + struct hdmi_disp_mode_list_type *disp_mode_list, + uint32 num_og_cea_blocks) +{ + uint8 len, offset, present_multi_3d, hdmi_vic_len, hdmi_3d_len; + uint16 structure_all, structure_mask; + const uint8 *vsd = num_og_cea_blocks ? + hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET, + 3, &len) : NULL; + int i; + + offset = HDMI_VSDB_3D_DATA_OFFSET(vsd); + present_multi_3d = (vsd[offset] & 0x60) >> 5; + + offset += 1; + hdmi_vic_len = (vsd[offset] >> 5) & 0x7; + hdmi_3d_len = vsd[offset] & 0x1F; + DEV_DBG("EDID[3D]: HDMI_VIC_LEN = %d, HDMI_3D_LEN = %d\n", + hdmi_vic_len, hdmi_3d_len); + + offset += (hdmi_vic_len + 1); + if (present_multi_3d == 1 || present_multi_3d == 2) { + DEV_DBG("EDID[3D]: multi 3D present (%d)\n", present_multi_3d); + /* 3d_structure_all */ + structure_all = (vsd[offset] << 8) | vsd[offset + 1]; + offset += 2; + hdmi_3d_len -= 2; + if (present_multi_3d == 2) { + /* 3d_structure_mask */ + structure_mask = (vsd[offset] << 8) | vsd[offset + 1]; + offset += 2; + hdmi_3d_len -= 2; + } else + structure_mask = 0xffff; + + i = 0; + while (i < 16) { + if (i >= disp_mode_list->disp_multi_3d_mode_list_cnt) + break; + + if (!(structure_mask & BIT(i))) { + ++i; + continue; + } + + /* BIT0: FRAME PACKING */ + if (structure_all & BIT(0)) + add_supported_3d_format(disp_mode_list, + disp_mode_list-> + disp_multi_3d_mode_list[i], + FRAME_PACKING); + + /* BIT6: TOP AND BOTTOM */ + if (structure_all & BIT(6)) + add_supported_3d_format(disp_mode_list, + disp_mode_list-> + disp_multi_3d_mode_list[i], + TOP_AND_BOTTOM); + + /* BIT8: SIDE BY SIDE HALF */ + if (structure_all & BIT(8)) + add_supported_3d_format(disp_mode_list, + disp_mode_list-> + disp_multi_3d_mode_list[i], + SIDE_BY_SIDE_HALF); + + ++i; + } + } + + i = 0; + while (hdmi_3d_len > 0) { + DEV_DBG("EDID[3D]: 3D_Structure_%d @ %d: %02x\n", + i + 1, offset, vsd[offset]); + + if ((vsd[offset] >> 4) >= + disp_mode_list->disp_multi_3d_mode_list_cnt) { + if ((vsd[offset] & 0x0F) >= 8) { + offset += 1; + hdmi_3d_len -= 1; + DEV_DBG("EDID[3D]: 3D_Detail_%d @ %d: %02x\n", + i + 1, offset, vsd[offset]); + } + i += 1; + offset += 1; + hdmi_3d_len -= 1; + continue; + } + + switch (vsd[offset] & 0x0F) { + case 0: + /* 0000b: FRAME PACKING */ + add_supported_3d_format(disp_mode_list, + disp_mode_list->disp_multi_3d_mode_list + [vsd[offset] >> 4], + FRAME_PACKING); + break; + case 6: + /* 0110b: TOP AND BOTTOM */ + add_supported_3d_format(disp_mode_list, + disp_mode_list->disp_multi_3d_mode_list + [vsd[offset] >> 4], + TOP_AND_BOTTOM); + break; + case 8: + /* 1000b: SIDE BY SIDE HALF */ + add_supported_3d_format(disp_mode_list, + disp_mode_list->disp_multi_3d_mode_list + [vsd[offset] >> 4], + SIDE_BY_SIDE_HALF); + break; + } + if ((vsd[offset] & 0x0F) >= 8) { + offset += 1; + hdmi_3d_len -= 1; + DEV_DBG("EDID[3D]: 3D_Detail_%d @ %d: %02x\n", + i + 1, offset, vsd[offset]); + } + i += 1; + offset += 1; + hdmi_3d_len -= 1; + } +} + +static void hdmi_edid_get_display_mode(const uint8 *data_buf, + struct hdmi_disp_mode_list_type *disp_mode_list, + uint32 num_og_cea_blocks) +{ + uint8 i = 0; + uint32 video_format = HDMI_VFRMT_640x480p60_4_3; + boolean has480p = FALSE; + uint8 len; + const uint8 *edid_blk0 = &data_buf[0x0]; + const uint8 *edid_blk1 = &data_buf[0x80]; + const uint8 *svd = num_og_cea_blocks ? + hdmi_edid_find_block(data_buf+0x80, DBC_START_OFFSET, + 2, &len) : NULL; + boolean has60hz_mode = FALSE; + boolean has50hz_mode = FALSE; + + + disp_mode_list->num_of_elements = 0; + disp_mode_list->disp_multi_3d_mode_list_cnt = 0; + if (svd != NULL) { + ++svd; + for (i = 0; i < len; ++i, ++svd) { + /* Subtract 1 because it is zero based in the driver, + * while the Video identification code is 1 based in the + * CEA_861D spec */ + video_format = (*svd & 0x7F) - 1; + add_supported_video_format(disp_mode_list, + video_format); + /* Make a note of the preferred video format */ + if (i == 0) { + external_common_state->preferred_video_format = + video_format; + } + if (i < 16) { + disp_mode_list->disp_multi_3d_mode_list[i] + = video_format; + disp_mode_list->disp_multi_3d_mode_list_cnt++; + } + + if (video_format <= HDMI_VFRMT_1920x1080p60_16_9 || + video_format == HDMI_VFRMT_2880x480p60_4_3 || + video_format == HDMI_VFRMT_2880x480p60_16_9) + has60hz_mode = TRUE; + + if ((video_format >= HDMI_VFRMT_720x576p50_4_3 && + video_format <= HDMI_VFRMT_1920x1080p50_16_9) || + video_format == HDMI_VFRMT_2880x576p50_4_3 || + video_format == HDMI_VFRMT_2880x576p50_16_9 || + video_format == HDMI_VFRMT_1920x1250i50_16_9) + has50hz_mode = TRUE; + if (video_format == HDMI_VFRMT_640x480p60_4_3) + has480p = TRUE; + } + } else if (!num_og_cea_blocks) { + /* Detailed timing descriptors */ + uint32 desc_offset = 0; + /* Maximum 4 timing descriptor in block 0 - No CEA + * extension in this case */ + /* EDID_FIRST_TIMING_DESC[0x36] - 1st detailed timing + * descriptor */ + /* EDID_DETAIL_TIMING_DESC_BLCK_SZ[0x12] - Each detailed timing + * descriptor has block size of 18 */ + while (4 > i && 0 != edid_blk0[0x36+desc_offset]) { + hdmi_edid_detail_desc(edid_blk0+0x36+desc_offset, + &video_format); + DEV_DBG("[%s:%d] Block-0 Adding vid fmt = [%s]\n", + __func__, __LINE__, + video_format_2string(video_format)); + add_supported_video_format(disp_mode_list, + video_format); + if (video_format == HDMI_VFRMT_640x480p60_4_3) + has480p = TRUE; + /* Make a note of the preferred video format */ + if (i == 0) { + external_common_state->preferred_video_format = + video_format; + } + desc_offset += 0x12; + ++i; + } + } else if (1 == num_og_cea_blocks) { + uint32 desc_offset = 0; + + /* + * Read from both block 0 and block 1 + * Read EDID block[0] as above + */ + while (4 > i && 0 != edid_blk0[0x36+desc_offset]) { + hdmi_edid_detail_desc(edid_blk0+0x36+desc_offset, + &video_format); + DEV_DBG("[%s:%d] Block-0 Adding vid fmt = [%s]\n", + __func__, __LINE__, + video_format_2string(video_format)); + add_supported_video_format(disp_mode_list, + video_format); + if (video_format == HDMI_VFRMT_640x480p60_4_3) + has480p = TRUE; + /* Make a note of the preferred video format */ + if (i == 0) { + external_common_state->preferred_video_format = + video_format; + } + desc_offset += 0x12; + ++i; + } + + /* Parse block 1 - CEA extension byte offset of first + * detailed timing generation - offset is relevant to + * the offset of block 1 */ + + /* EDID_CEA_EXTENSION_FIRST_DESC[0x82]: Offset to CEA + * extension first timing desc - indicate the offset of + * the first detailed timing descriptor */ + /* EDID_BLOCK_SIZE = 0x80 Each page size in the EDID ROM */ + desc_offset = edid_blk1[0x02]; + while (0 != edid_blk1[desc_offset]) { + hdmi_edid_detail_desc(edid_blk1+desc_offset, + &video_format); + DEV_DBG("[%s:%d] Block-1 Adding vid fmt = [%s]\n", + __func__, __LINE__, + video_format_2string(video_format)); + add_supported_video_format(disp_mode_list, + video_format); + if (video_format == HDMI_VFRMT_640x480p60_4_3) + has480p = TRUE; + /* Make a note of the preferred video format */ + if (i == 0) { + external_common_state->preferred_video_format = + video_format; + } + desc_offset += 0x12; + ++i; + } + } + + /* mandaroty 3d format */ + if (external_common_state->present_3d) { + if (has60hz_mode) { + add_supported_3d_format(disp_mode_list, + HDMI_VFRMT_1920x1080p24_16_9, + FRAME_PACKING | TOP_AND_BOTTOM); + add_supported_3d_format(disp_mode_list, + HDMI_VFRMT_1280x720p60_16_9, + FRAME_PACKING | TOP_AND_BOTTOM); + add_supported_3d_format(disp_mode_list, + HDMI_VFRMT_1920x1080i60_16_9, + SIDE_BY_SIDE_HALF); + } + if (has50hz_mode) { + add_supported_3d_format(disp_mode_list, + HDMI_VFRMT_1920x1080p24_16_9, + FRAME_PACKING | TOP_AND_BOTTOM); + add_supported_3d_format(disp_mode_list, + HDMI_VFRMT_1280x720p50_16_9, + FRAME_PACKING | TOP_AND_BOTTOM); + add_supported_3d_format(disp_mode_list, + HDMI_VFRMT_1920x1080i50_16_9, + SIDE_BY_SIDE_HALF); + } + + /* 3d format described in Vendor Specific Data */ + hdmi_edid_get_display_vsd_3d_mode(data_buf, disp_mode_list, + num_og_cea_blocks); + } + + if (!has480p) + /* Need to add default 640 by 480 timings, in case not described + * in the EDID structure. + * All DTV sink devices should support this mode */ + add_supported_video_format(disp_mode_list, + HDMI_VFRMT_640x480p60_4_3); +} + +static int hdmi_common_read_edid_block(int block, uint8 *edid_buf) +{ + uint32 ndx, check_sum, print_len; +#ifdef DEBUG + const u8 *b = edid_buf; +#endif + int status = external_common_state->read_edid_block(block, edid_buf); + if (status) + goto error; + + /* Calculate checksum */ + check_sum = 0; + for (ndx = 0; ndx < 0x80; ++ndx) + check_sum += edid_buf[ndx]; + + if (check_sum & 0xFF) { + DEV_ERR("%s: failed CHECKSUM (read:%x, expected:%x)\n", + __func__, (uint8)edid_buf[0x7F], (uint8)check_sum); +#ifdef DEBUG + for (ndx = 0; ndx < 0x100; ndx += 16) + DEV_DBG("EDID[%02x-%02x] %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x\n", ndx, ndx+15, + b[ndx+0], b[ndx+1], b[ndx+2], b[ndx+3], + b[ndx+4], b[ndx+5], b[ndx+6], b[ndx+7], + b[ndx+8], b[ndx+9], b[ndx+10], b[ndx+11], + b[ndx+12], b[ndx+13], b[ndx+14], b[ndx+15]); +#endif + status = -EPROTO; + goto error; + } + print_len = 0x80; + for (ndx = 0; ndx < print_len; ndx += 16) + DEV_DBG("EDID[%02x-%02x] %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x\n", ndx, ndx+15, + b[ndx+0], b[ndx+1], b[ndx+2], b[ndx+3], + b[ndx+4], b[ndx+5], b[ndx+6], b[ndx+7], + b[ndx+8], b[ndx+9], b[ndx+10], b[ndx+11], + b[ndx+12], b[ndx+13], b[ndx+14], b[ndx+15]); + + +error: + return status; +} + +static boolean check_edid_header(const uint8 *edid_buf) +{ + return (edid_buf[0] == 0x00) && (edid_buf[1] == 0xff) + && (edid_buf[2] == 0xff) && (edid_buf[3] == 0xff) + && (edid_buf[4] == 0xff) && (edid_buf[5] == 0xff) + && (edid_buf[6] == 0xff) && (edid_buf[7] == 0x00); +} + +int hdmi_common_read_edid(void) +{ + int status = 0; + uint32 cea_extension_ver = 0; + uint32 num_og_cea_blocks = 0; + uint32 ieee_reg_id = 0; + uint32 i = 1; + char vendor_id[5]; + /* EDID_BLOCK_SIZE[0x80] Each page size in the EDID ROM */ + uint8 edid_buf[0x80 * 4]; + + external_common_state->preferred_video_format = 0; + external_common_state->present_3d = 0; + memset(&external_common_state->disp_mode_list, 0, + sizeof(external_common_state->disp_mode_list)); + memset(edid_buf, 0, sizeof(edid_buf)); + + status = hdmi_common_read_edid_block(0, edid_buf); + if (status || !check_edid_header(edid_buf)) { + if (!status) + status = -EPROTO; + DEV_ERR("%s: edid read block(0) failed: %d " + "[%02x%02x%02x%02x%02x%02x%02x%02x]\n", __func__, + status, + edid_buf[0], edid_buf[1], edid_buf[2], edid_buf[3], + edid_buf[4], edid_buf[5], edid_buf[6], edid_buf[7]); + goto error; + } + hdmi_edid_extract_vendor_id(edid_buf, vendor_id); + + /* EDID_CEA_EXTENSION_FLAG[0x7E] - CEC extension byte */ + num_og_cea_blocks = edid_buf[0x7E]; + + DEV_DBG("[JSR] (%s): No. of CEA blocks is [%u]\n", __func__, + num_og_cea_blocks); + /* Find out any CEA extension blocks following block 0 */ + switch (num_og_cea_blocks) { + case 0: /* No CEA extension */ + external_common_state->hdmi_sink = false; + DEV_DBG("HDMI DVI mode: %s\n", + external_common_state->hdmi_sink ? "no" : "yes"); + break; + case 1: /* Read block 1 */ + status = hdmi_common_read_edid_block(1, &edid_buf[0x80]); + if (status) { + DEV_ERR("%s: ddc read block(1) failed: %d\n", __func__, + status); + goto error; + } + if (edid_buf[0x80] != 2) + num_og_cea_blocks = 0; + if (num_og_cea_blocks) { + ieee_reg_id = + hdmi_edid_extract_ieee_reg_id(edid_buf+0x80); + if (ieee_reg_id == 0x0c03) + external_common_state->hdmi_sink = TRUE ; + else + external_common_state->hdmi_sink = FALSE ; + hdmi_edid_extract_latency_fields(edid_buf+0x80); + hdmi_edid_extract_speaker_allocation_data( + edid_buf+0x80); + hdmi_edid_extract_audio_data_blocks(edid_buf+0x80); + hdmi_edid_extract_3d_present(edid_buf+0x80); + hdmi_edid_extract_extended_data_blocks(edid_buf+0x80); + } + break; + case 2: + case 3: + case 4: + for (i = 1; i <= num_og_cea_blocks; i++) { + if (!(i % 2)) { + status = hdmi_common_read_edid_block(i, + edid_buf+0x00); + if (status) { + DEV_ERR("%s: ddc read block(%d)" + "failed: %d\n", __func__, i, + status); + goto error; + } + } else { + status = hdmi_common_read_edid_block(i, + edid_buf+0x80); + if (status) { + DEV_ERR("%s: ddc read block(%d)" + "failed:%d\n", __func__, i, + status); + goto error; + } + } + } + break; + default: + DEV_ERR("%s: ddc read failed, not supported multi-blocks: %d\n", + __func__, num_og_cea_blocks); + status = -EPROTO; + goto error; + } + + if (num_og_cea_blocks) { + /* EDID_CEA_EXTENSION_VERSION[0x81]: Offset to CEA extension + * version number - v1,v2,v3 (v1 is seldom, v2 is obsolete, + * v3 most common) */ + cea_extension_ver = edid_buf[0x81]; + } + + /* EDID_VERSION[0x12] - EDID Version */ + /* EDID_REVISION[0x13] - EDID Revision */ + DEV_INFO("EDID (V=%d.%d, #CEABlocks=%d[V%d], ID=%s, IEEE=%04x, " + "EDID-Ext=0x%02x)\n", edid_buf[0x12], edid_buf[0x13], + num_og_cea_blocks, cea_extension_ver, vendor_id, ieee_reg_id, + edid_buf[0x80]); + + hdmi_edid_get_display_mode(edid_buf, + &external_common_state->disp_mode_list, num_og_cea_blocks); + + return 0; + +error: + external_common_state->disp_mode_list.num_of_elements = 1; + external_common_state->disp_mode_list.disp_mode_list[0] = + external_common_state->video_resolution; + return status; +} +EXPORT_SYMBOL(hdmi_common_read_edid); + +bool hdmi_common_get_video_format_from_drv_data(struct msm_fb_data_type *mfd) +{ + uint32 format; + struct fb_var_screeninfo *var = &mfd->fbi->var; + bool changed = TRUE; + + if (var->reserved[2]) { + format = var->reserved[2]-1; + DEV_DBG("reserved format is %d\n", format); + } else { + DEV_DBG("detecting resolution from %dx%d use var->reserved[3]" + " to specify mode", mfd->var_xres, mfd->var_yres); + switch (mfd->var_xres) { + default: + case 640: + format = HDMI_VFRMT_640x480p60_4_3; + break; + case 720: + format = (mfd->var_yres == 480) + ? HDMI_VFRMT_720x480p60_16_9 + : HDMI_VFRMT_720x576p50_16_9; + break; + case 1280: + format = HDMI_VFRMT_1280x720p60_16_9; + break; + case 1440: + format = (mfd->var_yres == 480) + ? HDMI_VFRMT_1440x480i60_16_9 + : HDMI_VFRMT_1440x576i50_16_9; + break; + case 1920: + format = HDMI_VFRMT_1920x1080p60_16_9; + break; + } + } + + changed = external_common_state->video_resolution != format; + if (external_common_state->video_resolution != format) + DEV_DBG("switching %s => %s", video_format_2string( + external_common_state->video_resolution), + video_format_2string(format)); + else + DEV_DBG("resolution %s", video_format_2string( + external_common_state->video_resolution)); + external_common_state->video_resolution = format; + return changed; +} +EXPORT_SYMBOL(hdmi_common_get_video_format_from_drv_data); + +const struct hdmi_disp_mode_timing_type *hdmi_common_get_mode(uint32 mode) +{ + if (mode >= HDMI_VFRMT_MAX) + return NULL; + + return &hdmi_common_supported_video_mode_lut[mode]; +} +EXPORT_SYMBOL(hdmi_common_get_mode); + +const struct hdmi_disp_mode_timing_type *hdmi_common_get_supported_mode( + uint32 mode) +{ + const struct hdmi_disp_mode_timing_type *ret + = hdmi_common_get_mode(mode); + + if (ret == NULL || !ret->supported) + return NULL; + return ret; +} +EXPORT_SYMBOL(hdmi_common_get_supported_mode); + +const struct hdmi_disp_mode_timing_type *hdmi_mhl_get_mode(uint32 mode) +{ + if (mode >= HDMI_VFRMT_MAX) + return NULL; + + return &hdmi_mhl_supported_video_mode_lut[mode]; +} +EXPORT_SYMBOL(hdmi_mhl_get_mode); + +const struct hdmi_disp_mode_timing_type *hdmi_mhl_get_supported_mode( + uint32 mode) +{ + const struct hdmi_disp_mode_timing_type *ret + = hdmi_mhl_get_mode(mode); + + if (ret == NULL || !ret->supported) + return NULL; + return ret; +} +EXPORT_SYMBOL(hdmi_mhl_get_supported_mode); + +void hdmi_common_init_panel_info(struct msm_panel_info *pinfo) +{ + const struct hdmi_disp_mode_timing_type *timing = + hdmi_common_get_supported_mode( + external_common_state->video_resolution); + + if (timing == NULL) + return; + + pinfo->xres = timing->active_h; + pinfo->yres = timing->active_v; + pinfo->clk_rate = timing->pixel_freq*1000; + pinfo->frame_rate = 60; + + pinfo->lcdc.h_back_porch = timing->back_porch_h; + pinfo->lcdc.h_front_porch = timing->front_porch_h; + pinfo->lcdc.h_pulse_width = timing->pulse_width_h; + pinfo->lcdc.v_back_porch = timing->back_porch_v; + pinfo->lcdc.v_front_porch = timing->front_porch_v; + pinfo->lcdc.v_pulse_width = timing->pulse_width_v; + + pinfo->type = DTV_PANEL; + pinfo->pdest = DISPLAY_2; + pinfo->wait_cycle = 0; + pinfo->bpp = 24; + if (hdmi_prim_display) + pinfo->fb_num = 2; + else + pinfo->fb_num = 1; + + /* blk */ + pinfo->lcdc.border_clr = 0; + /* blue */ + pinfo->lcdc.underflow_clr = 0xff; + pinfo->lcdc.hsync_skew = 0; +} +EXPORT_SYMBOL(hdmi_common_init_panel_info); +#endif diff --git a/drivers/video/msm/external_common.h b/drivers/video/msm/external_common.h new file mode 100644 index 000000000000..f27e50dec598 --- /dev/null +++ b/drivers/video/msm/external_common.h @@ -0,0 +1,272 @@ +/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __EXTERNAL_COMMON_H__ +#define __EXTERNAL_COMMON_H__ +#include + +#ifdef DEBUG +#ifndef DEV_DBG_PREFIX +#define DEV_DBG_PREFIX "EXT_INTERFACE: " +#endif +#define DEV_DBG(args...) pr_debug(DEV_DBG_PREFIX args) +#else +#define DEV_DBG(args...) (void)0 +#endif /* DEBUG */ +#define DEV_INFO(args...) dev_info(external_common_state->dev, args) +#define DEV_WARN(args...) dev_warn(external_common_state->dev, args) +#define DEV_ERR(args...) dev_err(external_common_state->dev, args) + +#ifdef CONFIG_FB_MSM_TVOUT +#define TVOUT_VFRMT_NTSC_M_720x480i 0 +#define TVOUT_VFRMT_NTSC_J_720x480i 1 +#define TVOUT_VFRMT_PAL_BDGHIN_720x576i 2 +#define TVOUT_VFRMT_PAL_M_720x480i 3 +#define TVOUT_VFRMT_PAL_N_720x480i 4 +#elif defined(CONFIG_FB_MSM_HDMI_COMMON) +/* all video formats defined by EIA CEA 861D */ +#define HDMI_VFRMT_640x480p60_4_3 0 +#define HDMI_VFRMT_720x480p60_4_3 1 +#define HDMI_VFRMT_720x480p60_16_9 2 +#define HDMI_VFRMT_1280x720p60_16_9 3 +#define HDMI_VFRMT_1920x1080i60_16_9 4 +#define HDMI_VFRMT_720x480i60_4_3 5 +#define HDMI_VFRMT_1440x480i60_4_3 HDMI_VFRMT_720x480i60_4_3 +#define HDMI_VFRMT_720x480i60_16_9 6 +#define HDMI_VFRMT_1440x480i60_16_9 HDMI_VFRMT_720x480i60_16_9 +#define HDMI_VFRMT_720x240p60_4_3 7 +#define HDMI_VFRMT_1440x240p60_4_3 HDMI_VFRMT_720x240p60_4_3 +#define HDMI_VFRMT_720x240p60_16_9 8 +#define HDMI_VFRMT_1440x240p60_16_9 HDMI_VFRMT_720x240p60_16_9 +#define HDMI_VFRMT_2880x480i60_4_3 9 +#define HDMI_VFRMT_2880x480i60_16_9 10 +#define HDMI_VFRMT_2880x240p60_4_3 11 +#define HDMI_VFRMT_2880x240p60_16_9 12 +#define HDMI_VFRMT_1440x480p60_4_3 13 +#define HDMI_VFRMT_1440x480p60_16_9 14 +#define HDMI_VFRMT_1920x1080p60_16_9 15 +#define HDMI_VFRMT_720x576p50_4_3 16 +#define HDMI_VFRMT_720x576p50_16_9 17 +#define HDMI_VFRMT_1280x720p50_16_9 18 +#define HDMI_VFRMT_1920x1080i50_16_9 19 +#define HDMI_VFRMT_720x576i50_4_3 20 +#define HDMI_VFRMT_1440x576i50_4_3 HDMI_VFRMT_720x576i50_4_3 +#define HDMI_VFRMT_720x576i50_16_9 21 +#define HDMI_VFRMT_1440x576i50_16_9 HDMI_VFRMT_720x576i50_16_9 +#define HDMI_VFRMT_720x288p50_4_3 22 +#define HDMI_VFRMT_1440x288p50_4_3 HDMI_VFRMT_720x288p50_4_3 +#define HDMI_VFRMT_720x288p50_16_9 23 +#define HDMI_VFRMT_1440x288p50_16_9 HDMI_VFRMT_720x288p50_16_9 +#define HDMI_VFRMT_2880x576i50_4_3 24 +#define HDMI_VFRMT_2880x576i50_16_9 25 +#define HDMI_VFRMT_2880x288p50_4_3 26 +#define HDMI_VFRMT_2880x288p50_16_9 27 +#define HDMI_VFRMT_1440x576p50_4_3 28 +#define HDMI_VFRMT_1440x576p50_16_9 29 +#define HDMI_VFRMT_1920x1080p50_16_9 30 +#define HDMI_VFRMT_1920x1080p24_16_9 31 +#define HDMI_VFRMT_1920x1080p25_16_9 32 +#define HDMI_VFRMT_1920x1080p30_16_9 33 +#define HDMI_VFRMT_2880x480p60_4_3 34 +#define HDMI_VFRMT_2880x480p60_16_9 35 +#define HDMI_VFRMT_2880x576p50_4_3 36 +#define HDMI_VFRMT_2880x576p50_16_9 37 +#define HDMI_VFRMT_1920x1250i50_16_9 38 +#define HDMI_VFRMT_1920x1080i100_16_9 39 +#define HDMI_VFRMT_1280x720p100_16_9 40 +#define HDMI_VFRMT_720x576p100_4_3 41 +#define HDMI_VFRMT_720x576p100_16_9 42 +#define HDMI_VFRMT_720x576i100_4_3 43 +#define HDMI_VFRMT_1440x576i100_4_3 HDMI_VFRMT_720x576i100_4_3 +#define HDMI_VFRMT_720x576i100_16_9 44 +#define HDMI_VFRMT_1440x576i100_16_9 HDMI_VFRMT_720x576i100_16_9 +#define HDMI_VFRMT_1920x1080i120_16_9 45 +#define HDMI_VFRMT_1280x720p120_16_9 46 +#define HDMI_VFRMT_720x480p120_4_3 47 +#define HDMI_VFRMT_720x480p120_16_9 48 +#define HDMI_VFRMT_720x480i120_4_3 49 +#define HDMI_VFRMT_1440x480i120_4_3 HDMI_VFRMT_720x480i120_4_3 +#define HDMI_VFRMT_720x480i120_16_9 50 +#define HDMI_VFRMT_1440x480i120_16_9 HDMI_VFRMT_720x480i120_16_9 +#define HDMI_VFRMT_720x576p200_4_3 51 +#define HDMI_VFRMT_720x576p200_16_9 52 +#define HDMI_VFRMT_720x576i200_4_3 53 +#define HDMI_VFRMT_1440x576i200_4_3 HDMI_VFRMT_720x576i200_4_3 +#define HDMI_VFRMT_720x576i200_16_9 54 +#define HDMI_VFRMT_1440x576i200_16_9 HDMI_VFRMT_720x576i200_16_9 +#define HDMI_VFRMT_720x480p240_4_3 55 +#define HDMI_VFRMT_720x480p240_16_9 56 +#define HDMI_VFRMT_720x480i240_4_3 57 +#define HDMI_VFRMT_1440x480i240_4_3 HDMI_VFRMT_720x480i240_4_3 +#define HDMI_VFRMT_720x480i240_16_9 58 +#define HDMI_VFRMT_1440x480i240_16_9 HDMI_VFRMT_720x480i240_16_9 +#define HDMI_VFRMT_MAX 59 +#define HDMI_VFRMT_FORCE_32BIT 0x7FFFFFFF + +struct hdmi_disp_mode_timing_type { + uint32 video_format; + uint32 active_h; + uint32 front_porch_h; + uint32 pulse_width_h; + uint32 back_porch_h; + boolean active_low_h; + uint32 active_v; + uint32 front_porch_v; + uint32 pulse_width_v; + uint32 back_porch_v; + boolean active_low_v; + /* Must divide by 1000 to get the actual frequency in MHZ */ + uint32 pixel_freq; + /* Must divide by 1000 to get the actual frequency in HZ */ + uint32 refresh_rate; + boolean interlaced; + boolean supported; +}; + +#define HDMI_SETTINGS_640x480p60_4_3 \ + {HDMI_VFRMT_640x480p60_4_3, 640, 16, 96, 48, TRUE, \ + 480, 10, 2, 33, TRUE, 25200, 60000, FALSE, TRUE} +#define HDMI_SETTINGS_720x480p60_4_3 \ + {HDMI_VFRMT_720x480p60_4_3, 720, 16, 62, 60, TRUE, \ + 480, 9, 6, 30, TRUE, 27030, 60000, FALSE, TRUE} +#define HDMI_SETTINGS_720x480p60_16_9 \ + {HDMI_VFRMT_720x480p60_16_9, 720, 16, 62, 60, TRUE, \ + 480, 9, 6, 30, TRUE, 27030, 60000, FALSE, TRUE} +#define HDMI_SETTINGS_1280x720p60_16_9 \ + {HDMI_VFRMT_1280x720p60_16_9, 1280, 110, 40, 220, FALSE, \ + 720, 5, 5, 20, FALSE, 74250, 60000, FALSE, TRUE} +#define HDMI_SETTINGS_1920x1080i60_16_9 \ + {HDMI_VFRMT_1920x1080i60_16_9, 1920, 88, 44, 148, FALSE, \ + 540, 2, 5, 5, FALSE, 74250, 60000, FALSE, TRUE} +#define HDMI_SETTINGS_1440x480i60_4_3 \ + {HDMI_VFRMT_1440x480i60_4_3, 1440, 38, 124, 114, TRUE, \ + 240, 4, 3, 15, TRUE, 27000, 60000, TRUE, TRUE} +#define HDMI_SETTINGS_1440x480i60_16_9 \ + {HDMI_VFRMT_1440x480i60_16_9, 1440, 38, 124, 114, TRUE, \ + 240, 4, 3, 15, TRUE, 27000, 60000, TRUE, TRUE} +#define HDMI_SETTINGS_1920x1080p60_16_9 \ + {HDMI_VFRMT_1920x1080p60_16_9, 1920, 88, 44, 148, FALSE, \ + 1080, 4, 5, 36, FALSE, 148500, 60000, FALSE, TRUE} +#define HDMI_SETTINGS_720x576p50_4_3 \ + {HDMI_VFRMT_720x576p50_4_3, 720, 12, 64, 68, TRUE, \ + 576, 5, 5, 39, TRUE, 27000, 50000, FALSE, TRUE} +#define HDMI_SETTINGS_720x576p50_16_9 \ + {HDMI_VFRMT_720x576p50_16_9, 720, 12, 64, 68, TRUE, \ + 576, 5, 5, 39, TRUE, 27000, 50000, FALSE, TRUE} +#define HDMI_SETTINGS_1280x720p50_16_9 \ + {HDMI_VFRMT_1280x720p50_16_9, 1280, 440, 40, 220, FALSE, \ + 720, 5, 5, 20, FALSE, 74250, 50000, FALSE, TRUE} +#define HDMI_SETTINGS_1440x576i50_4_3 \ + {HDMI_VFRMT_1440x576i50_4_3, 1440, 24, 126, 138, TRUE, \ + 288, 2, 3, 19, TRUE, 27000, 50000, TRUE, TRUE} +#define HDMI_SETTINGS_1440x576i50_16_9 \ + {HDMI_VFRMT_1440x576i50_16_9, 1440, 24, 126, 138, TRUE, \ + 288, 2, 3, 19, TRUE, 27000, 50000, TRUE, TRUE} +#define HDMI_SETTINGS_1920x1080p50_16_9 \ + {HDMI_VFRMT_1920x1080p50_16_9, 1920, 528, 44, 148, FALSE, \ + 1080, 4, 5, 36, FALSE, 148500, 50000, FALSE, TRUE} +#define HDMI_SETTINGS_1920x1080p24_16_9 \ + {HDMI_VFRMT_1920x1080p24_16_9, 1920, 638, 44, 148, FALSE, \ + 1080, 4, 5, 36, FALSE, 74250, 24000, FALSE, TRUE} +#define HDMI_SETTINGS_1920x1080p25_16_9 \ + {HDMI_VFRMT_1920x1080p25_16_9, 1920, 528, 44, 148, FALSE, \ + 1080, 4, 5, 36, FALSE, 74250, 25000, FALSE, TRUE} +#define HDMI_SETTINGS_1920x1080p30_16_9 \ + {HDMI_VFRMT_1920x1080p30_16_9, 1920, 88, 44, 148, FALSE, \ + 1080, 4, 5, 36, FALSE, 74250, 30000, FALSE, TRUE} + +/* A lookup table for all the supported display modes by the HDMI + * hardware and driver. Use HDMI_SETUP_LUT in the module init to + * setup the LUT with the supported modes. */ +extern struct hdmi_disp_mode_timing_type + hdmi_common_supported_video_mode_lut[HDMI_VFRMT_MAX]; + +/* Structure that encapsulates all the supported display modes by the HDMI sink + * device */ +struct hdmi_disp_mode_list_type { + uint32 disp_mode_list[HDMI_VFRMT_MAX]; +#define TOP_AND_BOTTOM 0x10 +#define FRAME_PACKING 0x20 +#define SIDE_BY_SIDE_HALF 0x40 + uint32 disp_3d_mode_list[HDMI_VFRMT_MAX]; + uint32 disp_multi_3d_mode_list[16]; + uint32 disp_multi_3d_mode_list_cnt; + uint32 num_of_elements; +}; +#endif + +struct external_common_state_type { + boolean hpd_state; + struct kobject *uevent_kobj; + uint32 video_resolution; + struct device *dev; + struct switch_dev sdev; +#ifdef CONFIG_FB_MSM_HDMI_3D + boolean format_3d; + void (*switch_3d)(boolean on); +#endif +#ifdef CONFIG_FB_MSM_HDMI_COMMON + boolean hdcp_active; + boolean hpd_feature_on; + boolean hdmi_sink; + struct hdmi_disp_mode_list_type disp_mode_list; + uint8 speaker_allocation_block; + uint16 video_latency, audio_latency; + uint8 audio_data_block_cnt; + uint16 physical_address; + uint32 preferred_video_format; + uint8 pt_scan_info; + uint8 it_scan_info; + uint8 ce_scan_info; + uint8 spd_vendor_name[8]; + uint8 spd_product_description[16]; + boolean present_3d; + boolean present_hdcp; + uint32 audio_data_blocks[16]; + int (*read_edid_block)(int block, uint8 *edid_buf); + int (*hpd_feature)(int on); +#endif +}; + +/* The external interface driver needs to initialize the common state. */ +extern struct external_common_state_type *external_common_state; +extern struct mutex external_common_state_hpd_mutex; +extern struct mutex hdmi_msm_state_mutex; + +#ifdef CONFIG_FB_MSM_HDMI_COMMON +#define VFRMT_NOT_SUPPORTED(VFRMT) \ + {VFRMT, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FALSE} +#define HDMI_SETUP_LUT(MODE) do { \ + struct hdmi_disp_mode_timing_type mode \ + = HDMI_SETTINGS_ ## MODE; \ + hdmi_common_supported_video_mode_lut[mode.video_format] \ + = mode; \ + } while (0) + +int hdmi_common_read_edid(void); +const char *video_format_2string(uint32 format); +bool hdmi_common_get_video_format_from_drv_data(struct msm_fb_data_type *mfd); +const struct hdmi_disp_mode_timing_type *hdmi_common_get_mode(uint32 mode); +const struct hdmi_disp_mode_timing_type *hdmi_common_get_supported_mode( + uint32 mode); +const struct hdmi_disp_mode_timing_type *hdmi_mhl_get_mode(uint32 mode); +const struct hdmi_disp_mode_timing_type *hdmi_mhl_get_supported_mode( + uint32 mode); +void hdmi_common_init_panel_info(struct msm_panel_info *pinfo); + +ssize_t video_3d_format_2string(uint32 format, char *buf); +#endif + +int external_common_state_create(struct platform_device *pdev); +void external_common_state_remove(void); + +#endif /* __EXTERNAL_COMMON_H__ */ diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c new file mode 100644 index 000000000000..f02c24daf050 --- /dev/null +++ b/drivers/video/msm/hdmi_msm.c @@ -0,0 +1,4817 @@ +/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* #define DEBUG */ +#define DEV_DBG_PREFIX "HDMI: " +/* #define REG_DUMP */ + +#define CEC_MSG_PRINT +#define TOGGLE_CEC_HARDWARE_FSM + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_fb.h" +#include "hdmi_msm.h" + +/* Supported HDMI Audio channels */ +#define MSM_HDMI_AUDIO_CHANNEL_2 0 +#define MSM_HDMI_AUDIO_CHANNEL_4 1 +#define MSM_HDMI_AUDIO_CHANNEL_6 2 +#define MSM_HDMI_AUDIO_CHANNEL_8 3 +#define MSM_HDMI_AUDIO_CHANNEL_MAX 4 +#define MSM_HDMI_AUDIO_CHANNEL_FORCE_32BIT 0x7FFFFFFF + +/* Supported HDMI Audio sample rates */ +#define MSM_HDMI_SAMPLE_RATE_32KHZ 0 +#define MSM_HDMI_SAMPLE_RATE_44_1KHZ 1 +#define MSM_HDMI_SAMPLE_RATE_48KHZ 2 +#define MSM_HDMI_SAMPLE_RATE_88_2KHZ 3 +#define MSM_HDMI_SAMPLE_RATE_96KHZ 4 +#define MSM_HDMI_SAMPLE_RATE_176_4KHZ 5 +#define MSM_HDMI_SAMPLE_RATE_192KHZ 6 +#define MSM_HDMI_SAMPLE_RATE_MAX 7 +#define MSM_HDMI_SAMPLE_RATE_FORCE_32BIT 0x7FFFFFFF + +static int msm_hdmi_sample_rate = MSM_HDMI_SAMPLE_RATE_48KHZ; + +/* HDMI/HDCP Registers */ +#define HDCP_DDC_STATUS 0x0128 +#define HDCP_DDC_CTRL_0 0x0120 +#define HDCP_DDC_CTRL_1 0x0124 +#define HDMI_DDC_CTRL 0x020C + +struct workqueue_struct *hdmi_work_queue; +struct hdmi_msm_state_type *hdmi_msm_state; + +DEFINE_MUTEX(hdmi_msm_state_mutex); +EXPORT_SYMBOL(hdmi_msm_state_mutex); +static DEFINE_MUTEX(hdcp_auth_state_mutex); + +static void hdmi_msm_dump_regs(const char *prefix); + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT +static void hdmi_msm_hdcp_enable(void); +#else +static inline void hdmi_msm_hdcp_enable(void) {} +#endif + +static void hdmi_msm_turn_on(void); +static int hdmi_msm_audio_off(void); +static int hdmi_msm_read_edid(void); +static void hdmi_msm_hpd_off(void); + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT + +static void hdmi_msm_cec_line_latch_detect(void); + +#ifdef TOGGLE_CEC_HARDWARE_FSM +static boolean msg_send_complete = TRUE; +static boolean msg_recv_complete = TRUE; +#endif + +#define HDMI_MSM_CEC_REFTIMER_REFTIMER_ENABLE BIT(16) +#define HDMI_MSM_CEC_REFTIMER_REFTIMER(___t) (((___t)&0xFFFF) << 0) + +#define HDMI_MSM_CEC_TIME_SIGNAL_FREE_TIME(___t) (((___t)&0x1FF) << 7) +#define HDMI_MSM_CEC_TIME_ENABLE BIT(0) + +#define HDMI_MSM_CEC_ADDR_LOGICAL_ADDR(___la) (((___la)&0xFF) << 0) + +#define HDMI_MSM_CEC_CTRL_LINE_OE BIT(9) +#define HDMI_MSM_CEC_CTRL_FRAME_SIZE(___sz) (((___sz)&0x1F) << 4) +#define HDMI_MSM_CEC_CTRL_SOFT_RESET BIT(2) +#define HDMI_MSM_CEC_CTRL_SEND_TRIG BIT(1) +#define HDMI_MSM_CEC_CTRL_ENABLE BIT(0) + +#define HDMI_MSM_CEC_INT_FRAME_RD_DONE_MASK BIT(7) +#define HDMI_MSM_CEC_INT_FRAME_RD_DONE_ACK BIT(6) +#define HDMI_MSM_CEC_INT_FRAME_RD_DONE_INT BIT(6) +#define HDMI_MSM_CEC_INT_MONITOR_MASK BIT(5) +#define HDMI_MSM_CEC_INT_MONITOR_ACK BIT(4) +#define HDMI_MSM_CEC_INT_MONITOR_INT BIT(4) +#define HDMI_MSM_CEC_INT_FRAME_ERROR_MASK BIT(3) +#define HDMI_MSM_CEC_INT_FRAME_ERROR_ACK BIT(2) +#define HDMI_MSM_CEC_INT_FRAME_ERROR_INT BIT(2) +#define HDMI_MSM_CEC_INT_FRAME_WR_DONE_MASK BIT(1) +#define HDMI_MSM_CEC_INT_FRAME_WR_DONE_ACK BIT(0) +#define HDMI_MSM_CEC_INT_FRAME_WR_DONE_INT BIT(0) + +#define HDMI_MSM_CEC_FRAME_WR_SUCCESS(___st) (((___st)&0xB) ==\ + (HDMI_MSM_CEC_INT_FRAME_WR_DONE_INT |\ + HDMI_MSM_CEC_INT_FRAME_WR_DONE_MASK |\ + HDMI_MSM_CEC_INT_FRAME_ERROR_MASK)) + +#define HDMI_MSM_CEC_RETRANSMIT_NUM(___num) (((___num)&0xF) << 4) +#define HDMI_MSM_CEC_RETRANSMIT_ENABLE BIT(0) + +#define HDMI_MSM_CEC_WR_DATA_DATA(___d) (((___d)&0xFF) << 8) + + +void hdmi_msm_cec_init(void) +{ + /* 0x02A8 CEC_REFTIMER */ + HDMI_OUTP(0x02A8, + HDMI_MSM_CEC_REFTIMER_REFTIMER_ENABLE + | HDMI_MSM_CEC_REFTIMER_REFTIMER(27 * 50) + ); + + /* + * 0x02A0 CEC_ADDR + * Starting with a default address of 4 + */ + HDMI_OUTP(0x02A0, HDMI_MSM_CEC_ADDR_LOGICAL_ADDR(4)); + + hdmi_msm_state->first_monitor = 0; + hdmi_msm_state->fsm_reset_done = false; + + /* 0x029C CEC_INT */ + /* Enable CEC interrupts */ + HDMI_OUTP(0x029C, \ + HDMI_MSM_CEC_INT_FRAME_WR_DONE_MASK \ + | HDMI_MSM_CEC_INT_FRAME_ERROR_MASK \ + | HDMI_MSM_CEC_INT_MONITOR_MASK \ + | HDMI_MSM_CEC_INT_FRAME_RD_DONE_MASK); + + HDMI_OUTP(0x02B0, 0x7FF << 4 | 1); + + /* + * Slight adjustment to logic 1 low periods on read, + * CEC Test 8.2-3 was failing, 8 for the + * BIT_1_ERR_RANGE_HI = 8 => 750us, the test used 775us, + * so increased this to 9 which => 800us. + */ + /* + * CEC latch up issue - To fire monitor interrupt + * for every start of message + */ + HDMI_OUTP(0x02E0, 0x880000); + + /* + * Slight adjustment to logic 0 low period on write + */ + HDMI_OUTP(0x02DC, 0x8888A888); + + /* + * Enable Signal Free Time counter and set to 7 bit periods + */ + HDMI_OUTP(0x02A4, 0x1 | (7 * 0x30) << 7); + + /* 0x028C CEC_CTRL */ + HDMI_OUTP(0x028C, HDMI_MSM_CEC_CTRL_ENABLE); +} + +void hdmi_msm_cec_write_logical_addr(int addr) +{ + /* 0x02A0 CEC_ADDR + * LOGICAL_ADDR 7:0 NUM + */ + HDMI_OUTP(0x02A0, addr & 0xFF); +} + +void hdmi_msm_dump_cec_msg(struct hdmi_msm_cec_msg *msg) +{ +#ifdef CEC_MSG_PRINT + int i; + DEV_DBG("sender_id : %d", msg->sender_id); + DEV_DBG("recvr_id : %d", msg->recvr_id); + if (msg->frame_size < 2) { + DEV_DBG("polling message"); + return; + } + DEV_DBG("opcode : %02x", msg->opcode); + for (i = 0; i < msg->frame_size - 2; i++) + DEV_DBG("operand(%2d) : %02x", i + 1, msg->operand[i]); +#endif /* CEC_MSG_PRINT */ +} + +void hdmi_msm_cec_msg_send(struct hdmi_msm_cec_msg *msg) +{ + int i; + uint32 timeout_count = 1; + int retry = 10; + + boolean frameType = (msg->recvr_id == 15 ? BIT(0) : 0); + + mutex_lock(&hdmi_msm_state_mutex); + hdmi_msm_state->fsm_reset_done = false; + mutex_unlock(&hdmi_msm_state_mutex); +#ifdef TOGGLE_CEC_HARDWARE_FSM + msg_send_complete = FALSE; +#endif + + INIT_COMPLETION(hdmi_msm_state->cec_frame_wr_done); + hdmi_msm_state->cec_frame_wr_status = 0; + + /* 0x0294 HDMI_MSM_CEC_RETRANSMIT */ + HDMI_OUTP(0x0294, +#ifdef DRVR_ONLY_CECT_NO_DAEMON + HDMI_MSM_CEC_RETRANSMIT_NUM(msg->retransmit) + | (msg->retransmit > 0) ? HDMI_MSM_CEC_RETRANSMIT_ENABLE : 0); +#else + HDMI_MSM_CEC_RETRANSMIT_NUM(0) | + HDMI_MSM_CEC_RETRANSMIT_ENABLE); +#endif + + /* 0x028C CEC_CTRL */ + HDMI_OUTP(0x028C, 0x1 | msg->frame_size << 4); + + /* 0x0290 CEC_WR_DATA */ + + /* header block */ + HDMI_OUTP(0x0290, + HDMI_MSM_CEC_WR_DATA_DATA(msg->sender_id << 4 | msg->recvr_id) + | frameType); + + /* data block 0 : opcode */ + HDMI_OUTP(0x0290, + HDMI_MSM_CEC_WR_DATA_DATA(msg->frame_size < 2 ? 0 : msg->opcode) + | frameType); + + /* data block 1-14 : operand 0-13 */ + for (i = 0; i < msg->frame_size - 1; i++) + HDMI_OUTP(0x0290, + HDMI_MSM_CEC_WR_DATA_DATA(msg->operand[i]) + | (msg->recvr_id == 15 ? BIT(0) : 0)); + + for (; i < 14; i++) + HDMI_OUTP(0x0290, + HDMI_MSM_CEC_WR_DATA_DATA(0) + | (msg->recvr_id == 15 ? BIT(0) : 0)); + + while ((HDMI_INP(0x0298) & 1) && retry--) { + DEV_DBG("CEC line is busy(%d)\n", retry); + schedule(); + } + + /* 0x028C CEC_CTRL */ + HDMI_OUTP(0x028C, + HDMI_MSM_CEC_CTRL_LINE_OE + | HDMI_MSM_CEC_CTRL_FRAME_SIZE(msg->frame_size) + | HDMI_MSM_CEC_CTRL_SEND_TRIG + | HDMI_MSM_CEC_CTRL_ENABLE); + + timeout_count = wait_for_completion_interruptible_timeout( + &hdmi_msm_state->cec_frame_wr_done, HZ); + + if (!timeout_count) { + hdmi_msm_state->cec_frame_wr_status |= CEC_STATUS_WR_TMOUT; + DEV_ERR("%s: timedout", __func__); + hdmi_msm_dump_cec_msg(msg); + } else { + DEV_DBG("CEC write frame done (frame len=%d)", + msg->frame_size); + hdmi_msm_dump_cec_msg(msg); + } + +#ifdef TOGGLE_CEC_HARDWARE_FSM + if (!msg_recv_complete) { + /* Toggle CEC hardware FSM */ + HDMI_OUTP(0x028C, 0x0); + HDMI_OUTP(0x028C, HDMI_MSM_CEC_CTRL_ENABLE); + msg_recv_complete = TRUE; + } + msg_send_complete = TRUE; +#else + HDMI_OUTP(0x028C, 0x0); + HDMI_OUTP(0x028C, HDMI_MSM_CEC_CTRL_ENABLE); +#endif +} + +void hdmi_msm_cec_line_latch_detect(void) +{ + /* + * CECT 9-5-1 + * The timer period needs to be changed to appropriate value + */ + /* + * Timedout without RD_DONE, WR_DONE or ERR_INT + * Toggle CEC hardware FSM + */ + mutex_lock(&hdmi_msm_state_mutex); + if (hdmi_msm_state->first_monitor == 1) { + DEV_WARN("CEC line is probably latched up - CECT 9-5-1"); + if (!msg_recv_complete) + hdmi_msm_state->fsm_reset_done = true; + HDMI_OUTP(0x028C, 0x0); + HDMI_OUTP(0x028C, HDMI_MSM_CEC_CTRL_ENABLE); + hdmi_msm_state->first_monitor = 0; + } + mutex_unlock(&hdmi_msm_state_mutex); +} + +void hdmi_msm_cec_msg_recv(void) +{ + uint32 data; + int i; +#ifdef DRVR_ONLY_CECT_NO_DAEMON + struct hdmi_msm_cec_msg temp_msg; +#endif + mutex_lock(&hdmi_msm_state_mutex); + if (hdmi_msm_state->cec_queue_wr == hdmi_msm_state->cec_queue_rd + && hdmi_msm_state->cec_queue_full) { + mutex_unlock(&hdmi_msm_state_mutex); + DEV_ERR("CEC message queue is overflowing\n"); +#ifdef DRVR_ONLY_CECT_NO_DAEMON + /* + * Without CEC daemon: + * Compliance tests fail once the queue gets filled up. + * so reset the pointers to the start of the queue. + */ + hdmi_msm_state->cec_queue_wr = hdmi_msm_state->cec_queue_start; + hdmi_msm_state->cec_queue_rd = hdmi_msm_state->cec_queue_start; + hdmi_msm_state->cec_queue_full = false; +#else + return; +#endif + } + if (hdmi_msm_state->cec_queue_wr == NULL) { + DEV_ERR("%s: wp is NULL\n", __func__); + return; + } + mutex_unlock(&hdmi_msm_state_mutex); + + /* 0x02AC CEC_RD_DATA */ + data = HDMI_INP(0x02AC); + + hdmi_msm_state->cec_queue_wr->sender_id = (data & 0xF0) >> 4; + hdmi_msm_state->cec_queue_wr->recvr_id = (data & 0x0F); + hdmi_msm_state->cec_queue_wr->frame_size = (data & 0x1F00) >> 8; + DEV_DBG("Recvd init=[%u] dest=[%u] size=[%u]\n", + hdmi_msm_state->cec_queue_wr->sender_id, + hdmi_msm_state->cec_queue_wr->recvr_id, + hdmi_msm_state->cec_queue_wr->frame_size); + + if (hdmi_msm_state->cec_queue_wr->frame_size < 1) { + DEV_ERR("%s: invalid message (frame length = %d)", + __func__, hdmi_msm_state->cec_queue_wr->frame_size); + return; + } else if (hdmi_msm_state->cec_queue_wr->frame_size == 1) { + DEV_DBG("%s: polling message (dest[%x] <- init[%x])", + __func__, + hdmi_msm_state->cec_queue_wr->recvr_id, + hdmi_msm_state->cec_queue_wr->sender_id); + return; + } + + /* data block 0 : opcode */ + data = HDMI_INP(0x02AC); + hdmi_msm_state->cec_queue_wr->opcode = data & 0xFF; + + /* data block 1-14 : operand 0-13 */ + for (i = 0; i < hdmi_msm_state->cec_queue_wr->frame_size - 2; i++) { + data = HDMI_INP(0x02AC); + hdmi_msm_state->cec_queue_wr->operand[i] = data & 0xFF; + } + + for (; i < 14; i++) + hdmi_msm_state->cec_queue_wr->operand[i] = 0; + + DEV_DBG("CEC read frame done\n"); + DEV_DBG("=======================================\n"); + hdmi_msm_dump_cec_msg(hdmi_msm_state->cec_queue_wr); + DEV_DBG("=======================================\n"); + +#ifdef DRVR_ONLY_CECT_NO_DAEMON + switch (hdmi_msm_state->cec_queue_wr->opcode) { + case 0x64: + /* Set OSD String */ + DEV_INFO("Recvd OSD Str=[%x]\n",\ + hdmi_msm_state->cec_queue_wr->operand[3]); + break; + case 0x83: + /* Give Phy Addr */ + DEV_INFO("Recvd a Give Phy Addr cmd\n"); + memset(&temp_msg, 0x00, sizeof(struct hdmi_msm_cec_msg)); + /* Setup a frame for sending out phy addr */ + temp_msg.sender_id = 0x4; + + /* Broadcast */ + temp_msg.recvr_id = 0xf; + temp_msg.opcode = 0x84; + i = 0; + temp_msg.operand[i++] = 0x10; + temp_msg.operand[i++] = 0x00; + temp_msg.operand[i++] = 0x04; + temp_msg.frame_size = i + 2; + hdmi_msm_cec_msg_send(&temp_msg); + break; + case 0xFF: + /* Abort */ + DEV_INFO("Recvd an abort cmd 0xFF\n"); + memset(&temp_msg, 0x00, sizeof(struct hdmi_msm_cec_msg)); + temp_msg.sender_id = 0x4; + temp_msg.recvr_id = hdmi_msm_state->cec_queue_wr->sender_id; + i = 0; + + /*feature abort */ + temp_msg.opcode = 0x00; + temp_msg.operand[i++] = + hdmi_msm_state->cec_queue_wr->opcode; + + /*reason for abort = "Refused" */ + temp_msg.operand[i++] = 0x04; + temp_msg.frame_size = i + 2; + hdmi_msm_dump_cec_msg(&temp_msg); + hdmi_msm_cec_msg_send(&temp_msg); + break; + case 0x046: + /* Give OSD name */ + DEV_INFO("Recvd cmd 0x046\n"); + memset(&temp_msg, 0x00, sizeof(struct hdmi_msm_cec_msg)); + temp_msg.sender_id = 0x4; + temp_msg.recvr_id = hdmi_msm_state->cec_queue_wr->sender_id; + i = 0; + + /* OSD Name */ + temp_msg.opcode = 0x47; + + /* Display control byte */ + temp_msg.operand[i++] = 0x00; + temp_msg.operand[i++] = 'H'; + temp_msg.operand[i++] = 'e'; + temp_msg.operand[i++] = 'l'; + temp_msg.operand[i++] = 'l'; + temp_msg.operand[i++] = 'o'; + temp_msg.operand[i++] = ' '; + temp_msg.operand[i++] = 'W'; + temp_msg.operand[i++] = 'o'; + temp_msg.operand[i++] = 'r'; + temp_msg.operand[i++] = 'l'; + temp_msg.operand[i++] = 'd'; + temp_msg.frame_size = i + 2; + hdmi_msm_cec_msg_send(&temp_msg); + break; + case 0x08F: + /* Give Device Power status */ + DEV_INFO("Recvd a Power status message\n"); + memset(&temp_msg, 0x00, sizeof(struct hdmi_msm_cec_msg)); + temp_msg.sender_id = 0x4; + temp_msg.recvr_id = hdmi_msm_state->cec_queue_wr->sender_id; + i = 0; + + /* OSD String */ + temp_msg.opcode = 0x90; + temp_msg.operand[i++] = 'H'; + temp_msg.operand[i++] = 'e'; + temp_msg.operand[i++] = 'l'; + temp_msg.operand[i++] = 'l'; + temp_msg.operand[i++] = 'o'; + temp_msg.operand[i++] = ' '; + temp_msg.operand[i++] = 'W'; + temp_msg.operand[i++] = 'o'; + temp_msg.operand[i++] = 'r'; + temp_msg.operand[i++] = 'l'; + temp_msg.operand[i++] = 'd'; + temp_msg.frame_size = i + 2; + hdmi_msm_cec_msg_send(&temp_msg); + break; + case 0x080: + /* Routing Change cmd */ + case 0x086: + /* Set Stream Path */ + DEV_INFO("Recvd Set Stream\n"); + memset(&temp_msg, 0x00, sizeof(struct hdmi_msm_cec_msg)); + temp_msg.sender_id = 0x4; + + /*Broadcast this message*/ + temp_msg.recvr_id = 0xf; + i = 0; + temp_msg.opcode = 0x82; /* Active Source */ + temp_msg.operand[i++] = 0x10; + temp_msg.operand[i++] = 0x00; + temp_msg.frame_size = i + 2; + hdmi_msm_cec_msg_send(&temp_msg); + + /* + * sending message + */ + memset(&temp_msg, 0x00, sizeof(struct hdmi_msm_cec_msg)); + temp_msg.sender_id = 0x4; + temp_msg.recvr_id = hdmi_msm_state->cec_queue_wr->sender_id; + i = 0; + /* opcode for Image View On */ + temp_msg.opcode = 0x04; + temp_msg.frame_size = i + 2; + hdmi_msm_cec_msg_send(&temp_msg); + break; + case 0x44: + /* User Control Pressed */ + DEV_INFO("User Control Pressed\n"); + break; + case 0x45: + /* User Control Released */ + DEV_INFO("User Control Released\n"); + break; + default: + DEV_INFO("Recvd an unknown cmd = [%u]\n", + hdmi_msm_state->cec_queue_wr->opcode); +#ifdef __SEND_ABORT__ + memset(&temp_msg, 0x00, sizeof(struct hdmi_msm_cec_msg)); + temp_msg.sender_id = 0x4; + temp_msg.recvr_id = hdmi_msm_state->cec_queue_wr->sender_id; + i = 0; + /* opcode for feature abort */ + temp_msg.opcode = 0x00; + temp_msg.operand[i++] = + hdmi_msm_state->cec_queue_wr->opcode; + /*reason for abort = "Unrecognized opcode" */ + temp_msg.operand[i++] = 0x00; + temp_msg.frame_size = i + 2; + hdmi_msm_cec_msg_send(&temp_msg); + break; +#else + memset(&temp_msg, 0x00, sizeof(struct hdmi_msm_cec_msg)); + temp_msg.sender_id = 0x4; + temp_msg.recvr_id = hdmi_msm_state->cec_queue_wr->sender_id; + i = 0; + /* OSD String */ + temp_msg.opcode = 0x64; + temp_msg.operand[i++] = 0x0; + temp_msg.operand[i++] = 'H'; + temp_msg.operand[i++] = 'e'; + temp_msg.operand[i++] = 'l'; + temp_msg.operand[i++] = 'l'; + temp_msg.operand[i++] = 'o'; + temp_msg.operand[i++] = ' '; + temp_msg.operand[i++] = 'W'; + temp_msg.operand[i++] = 'o'; + temp_msg.operand[i++] = 'r'; + temp_msg.operand[i++] = 'l'; + temp_msg.operand[i++] = 'd'; + temp_msg.frame_size = i + 2; + hdmi_msm_cec_msg_send(&temp_msg); + break; +#endif /* __SEND_ABORT__ */ + } + +#endif /* DRVR_ONLY_CECT_NO_DAEMON */ + mutex_lock(&hdmi_msm_state_mutex); + hdmi_msm_state->cec_queue_wr++; + if (hdmi_msm_state->cec_queue_wr == CEC_QUEUE_END) + hdmi_msm_state->cec_queue_wr = hdmi_msm_state->cec_queue_start; + if (hdmi_msm_state->cec_queue_wr == hdmi_msm_state->cec_queue_rd) + hdmi_msm_state->cec_queue_full = true; + mutex_unlock(&hdmi_msm_state_mutex); + DEV_DBG("Exiting %s()\n", __func__); +} + +void hdmi_msm_cec_one_touch_play(void) +{ + struct hdmi_msm_cec_msg temp_msg; + uint32 i = 0; + memset(&temp_msg, 0x00, sizeof(struct hdmi_msm_cec_msg)); + temp_msg.sender_id = 0x4; + /* + * Broadcast this message + */ + temp_msg.recvr_id = 0xf; + i = 0; + /* Active Source */ + temp_msg.opcode = 0x82; + temp_msg.operand[i++] = 0x10; + temp_msg.operand[i++] = 0x00; + /*temp_msg.operand[i++] = 0x04;*/ + temp_msg.frame_size = i + 2; + hdmi_msm_cec_msg_send(&temp_msg); + /* + * sending message + */ + memset(&temp_msg, 0x00, sizeof(struct hdmi_msm_cec_msg)); + temp_msg.sender_id = 0x4; + temp_msg.recvr_id = hdmi_msm_state->cec_queue_wr->sender_id; + i = 0; + /* Image View On */ + temp_msg.opcode = 0x04; + temp_msg.frame_size = i + 2; + hdmi_msm_cec_msg_send(&temp_msg); + +} +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT */ + +uint32 hdmi_msm_get_io_base(void) +{ + return (uint32)MSM_HDMI_BASE; +} +EXPORT_SYMBOL(hdmi_msm_get_io_base); + +/* Table indicating the video format supported by the HDMI TX Core v1.0 */ +/* Valid Pixel-Clock rates: 25.2MHz, 27MHz, 27.03MHz, 74.25MHz, 148.5MHz */ +static void hdmi_msm_setup_video_mode_lut(void) +{ + HDMI_SETUP_LUT(640x480p60_4_3); + HDMI_SETUP_LUT(720x480p60_4_3); + HDMI_SETUP_LUT(720x480p60_16_9); + HDMI_SETUP_LUT(1280x720p60_16_9); + HDMI_SETUP_LUT(1920x1080i60_16_9); + HDMI_SETUP_LUT(1440x480i60_4_3); + HDMI_SETUP_LUT(1440x480i60_16_9); + HDMI_SETUP_LUT(1920x1080p60_16_9); + HDMI_SETUP_LUT(720x576p50_4_3); + HDMI_SETUP_LUT(720x576p50_16_9); + HDMI_SETUP_LUT(1280x720p50_16_9); + HDMI_SETUP_LUT(1440x576i50_4_3); + HDMI_SETUP_LUT(1440x576i50_16_9); + HDMI_SETUP_LUT(1920x1080p50_16_9); + HDMI_SETUP_LUT(1920x1080p24_16_9); + HDMI_SETUP_LUT(1920x1080p25_16_9); + HDMI_SETUP_LUT(1920x1080p30_16_9); +} + +#ifdef PORT_DEBUG +const char *hdmi_msm_name(uint32 offset) +{ + switch (offset) { + case 0x0000: return "CTRL"; + case 0x0020: return "AUDIO_PKT_CTRL1"; + case 0x0024: return "ACR_PKT_CTRL"; + case 0x0028: return "VBI_PKT_CTRL"; + case 0x002C: return "INFOFRAME_CTRL0"; +#ifdef CONFIG_FB_MSM_HDMI_3D + case 0x0034: return "GEN_PKT_CTRL"; +#endif + case 0x003C: return "ACP"; + case 0x0040: return "GC"; + case 0x0044: return "AUDIO_PKT_CTRL2"; + case 0x0048: return "ISRC1_0"; + case 0x004C: return "ISRC1_1"; + case 0x0050: return "ISRC1_2"; + case 0x0054: return "ISRC1_3"; + case 0x0058: return "ISRC1_4"; + case 0x005C: return "ISRC2_0"; + case 0x0060: return "ISRC2_1"; + case 0x0064: return "ISRC2_2"; + case 0x0068: return "ISRC2_3"; + case 0x006C: return "AVI_INFO0"; + case 0x0070: return "AVI_INFO1"; + case 0x0074: return "AVI_INFO2"; + case 0x0078: return "AVI_INFO3"; +#ifdef CONFIG_FB_MSM_HDMI_3D + case 0x0084: return "GENERIC0_HDR"; + case 0x0088: return "GENERIC0_0"; + case 0x008C: return "GENERIC0_1"; +#endif + case 0x00C4: return "ACR_32_0"; + case 0x00C8: return "ACR_32_1"; + case 0x00CC: return "ACR_44_0"; + case 0x00D0: return "ACR_44_1"; + case 0x00D4: return "ACR_48_0"; + case 0x00D8: return "ACR_48_1"; + case 0x00E4: return "AUDIO_INFO0"; + case 0x00E8: return "AUDIO_INFO1"; +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + case 0x0110: return "HDCP_CTRL"; + case 0x0114: return "HDCP_DEBUG_CTRL"; + case 0x0118: return "HDCP_INT_CTRL"; + case 0x011C: return "HDCP_LINK0_STATUS"; + case 0x012C: return "HDCP_ENTROPY_CTRL0"; + case 0x0130: return "HDCP_RESET"; + case 0x0134: return "HDCP_RCVPORT_DATA0"; + case 0x0138: return "HDCP_RCVPORT_DATA1"; + case 0x013C: return "HDCP_RCVPORT_DATA2"; + case 0x0144: return "HDCP_RCVPORT_DATA3"; + case 0x0148: return "HDCP_RCVPORT_DATA4"; + case 0x014C: return "HDCP_RCVPORT_DATA5"; + case 0x0150: return "HDCP_RCVPORT_DATA6"; + case 0x0168: return "HDCP_RCVPORT_DATA12"; +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ + case 0x01D0: return "AUDIO_CFG"; + case 0x0208: return "USEC_REFTIMER"; + case 0x020C: return "DDC_CTRL"; + case 0x0214: return "DDC_INT_CTRL"; + case 0x0218: return "DDC_SW_STATUS"; + case 0x021C: return "DDC_HW_STATUS"; + case 0x0220: return "DDC_SPEED"; + case 0x0224: return "DDC_SETUP"; + case 0x0228: return "DDC_TRANS0"; + case 0x022C: return "DDC_TRANS1"; + case 0x0238: return "DDC_DATA"; + case 0x0250: return "HPD_INT_STATUS"; + case 0x0254: return "HPD_INT_CTRL"; + case 0x0258: return "HPD_CTRL"; +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + case 0x025C: return "HDCP_ENTROPY_CTRL1"; +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ + case 0x027C: return "DDC_REF"; +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + case 0x0284: return "HDCP_SW_UPPER_AKSV"; + case 0x0288: return "HDCP_SW_LOWER_AKSV"; +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ + case 0x02B4: return "ACTIVE_H"; + case 0x02B8: return "ACTIVE_V"; + case 0x02BC: return "ACTIVE_V_F2"; + case 0x02C0: return "TOTAL"; + case 0x02C4: return "V_TOTAL_F2"; + case 0x02C8: return "FRAME_CTRL"; + case 0x02CC: return "AUD_INT"; + case 0x0300: return "PHY_REG0"; + case 0x0304: return "PHY_REG1"; + case 0x0308: return "PHY_REG2"; + case 0x030C: return "PHY_REG3"; + case 0x0310: return "PHY_REG4"; + case 0x0314: return "PHY_REG5"; + case 0x0318: return "PHY_REG6"; + case 0x031C: return "PHY_REG7"; + case 0x0320: return "PHY_REG8"; + case 0x0324: return "PHY_REG9"; + case 0x0328: return "PHY_REG10"; + case 0x032C: return "PHY_REG11"; + case 0x0330: return "PHY_REG12"; + default: return "???"; + } +} + +void hdmi_outp(uint32 offset, uint32 value) +{ + uint32 in_val; + + outpdw(MSM_HDMI_BASE+offset, value); + in_val = inpdw(MSM_HDMI_BASE+offset); + DEV_DBG("HDMI[%04x] => %08x [%08x] %s\n", + offset, value, in_val, hdmi_msm_name(offset)); +} + +uint32 hdmi_inp(uint32 offset) +{ + uint32 value = inpdw(MSM_HDMI_BASE+offset); + DEV_DBG("HDMI[%04x] <= %08x %s\n", + offset, value, hdmi_msm_name(offset)); + return value; +} +#endif /* DEBUG */ + +static void hdmi_msm_turn_on(void); +static int hdmi_msm_audio_off(void); +static int hdmi_msm_read_edid(void); +static void hdmi_msm_hpd_off(void); + +static void hdmi_msm_hpd_state_work(struct work_struct *work) +{ + boolean hpd_state; + char *envp[2]; + + if (!hdmi_msm_state || !hdmi_msm_state->hpd_initialized || + !MSM_HDMI_BASE) { + DEV_DBG("%s: ignored, probe failed\n", __func__); + return; + } + + DEV_DBG("%s:Got interrupt\n", __func__); + /* HPD_INT_STATUS[0x0250] */ + hpd_state = (HDMI_INP(0x0250) & 0x2) >> 1; + mutex_lock(&external_common_state_hpd_mutex); + mutex_lock(&hdmi_msm_state_mutex); + if ((external_common_state->hpd_state != hpd_state) || (hdmi_msm_state-> + hpd_prev_state != external_common_state->hpd_state)) { + external_common_state->hpd_state = hpd_state; + hdmi_msm_state->hpd_prev_state = + external_common_state->hpd_state; + DEV_DBG("%s: state not stable yet, wait again (%d|%d|%d)\n", + __func__, hdmi_msm_state->hpd_prev_state, + external_common_state->hpd_state, hpd_state); + mutex_unlock(&external_common_state_hpd_mutex); + hdmi_msm_state->hpd_stable = 0; + mutex_unlock(&hdmi_msm_state_mutex); + mod_timer(&hdmi_msm_state->hpd_state_timer, jiffies + HZ/2); + return; + } + mutex_unlock(&external_common_state_hpd_mutex); + + if (hdmi_msm_state->hpd_stable++) { + mutex_unlock(&hdmi_msm_state_mutex); + DEV_DBG("%s: no more timer, depending for IRQ now\n", + __func__); + return; + } + + hdmi_msm_state->hpd_stable = 1; + DEV_INFO("HDMI HPD: event detected\n"); + + if (!hdmi_msm_state->hpd_cable_chg_detected) { + mutex_unlock(&hdmi_msm_state_mutex); + if (hpd_state) { + if (!external_common_state-> + disp_mode_list.num_of_elements) + hdmi_msm_read_edid(); + hdmi_msm_turn_on(); + } + } else { + hdmi_msm_state->hpd_cable_chg_detected = FALSE; + mutex_unlock(&hdmi_msm_state_mutex); + /* QDSP OFF preceding the HPD event notification */ + envp[0] = "HDCP_STATE=FAIL"; + envp[1] = NULL; + DEV_INFO("HDMI HPD: QDSP OFF\n"); + kobject_uevent_env(external_common_state->uevent_kobj, + KOBJ_CHANGE, envp); + switch_set_state(&external_common_state->sdev, 0); + DEV_INFO("Hdmi state switch to %d: %s\n", + external_common_state->sdev.state, __func__); + if (hpd_state) { + hdmi_msm_read_edid(); +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + hdmi_msm_state->reauth = FALSE ; +#endif + /* Build EDID table */ + hdmi_msm_turn_on(); + DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n"); + kobject_uevent(external_common_state->uevent_kobj, + KOBJ_ONLINE); + hdmi_msm_hdcp_enable(); +#ifndef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + /* Send Audio for HDMI Compliance Cases*/ + envp[0] = "HDCP_STATE=PASS"; + envp[1] = NULL; + DEV_INFO("HDMI HPD: sense : send HDCP_PASS\n"); + kobject_uevent_env(external_common_state->uevent_kobj, + KOBJ_CHANGE, envp); + switch_set_state(&external_common_state->sdev, 1); + DEV_INFO("Hdmi state switch to %d: %s\n", + external_common_state->sdev.state, __func__); +#endif + } else { + DEV_INFO("HDMI HPD: sense DISCONNECTED: send OFFLINE\n" + ); + kobject_uevent(external_common_state->uevent_kobj, + KOBJ_OFFLINE); + switch_set_state(&external_common_state->sdev, 0); + DEV_INFO("Hdmi state switch to %d: %s\n", + external_common_state->sdev.state, __func__); + } + } + + /* HPD_INT_CTRL[0x0254] + * 31:10 Reserved + * 9 RCV_PLUGIN_DET_MASK receiver plug in interrupt mask. + * When programmed to 1, + * RCV_PLUGIN_DET_INT will toggle + * the interrupt line + * 8:6 Reserved + * 5 RX_INT_EN Panel RX interrupt enable + * 0: Disable + * 1: Enable + * 4 RX_INT_ACK WRITE ONLY. Panel RX interrupt + * ack + * 3 Reserved + * 2 INT_EN Panel interrupt control + * 0: Disable + * 1: Enable + * 1 INT_POLARITY Panel interrupt polarity + * 0: generate interrupt on disconnect + * 1: generate interrupt on connect + * 0 INT_ACK WRITE ONLY. Panel interrupt ack */ + /* Set IRQ for HPD */ + HDMI_OUTP(0x0254, 4 | (hpd_state ? 0 : 2)); +} + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT +static void hdmi_msm_cec_latch_work(struct work_struct *work) +{ + hdmi_msm_cec_line_latch_detect(); +} +#endif + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT +static void hdcp_deauthenticate(void); +static void hdmi_msm_hdcp_reauth_work(struct work_struct *work) +{ + + /* Don't process recursive actions */ + mutex_lock(&hdmi_msm_state_mutex); + if (hdmi_msm_state->hdcp_activating) { + mutex_unlock(&hdmi_msm_state_mutex); + return; + } + mutex_unlock(&hdmi_msm_state_mutex); + + /* + * Reauth=>deauth, hdcp_auth + * hdcp_auth=>turn_on() which calls + * HDMI Core reset without informing the Audio QDSP + * this can do bad things to video playback on the HDTV + * Therefore, as surprising as it may sound do reauth + * only if the device is HDCP-capable + */ + if (external_common_state->present_hdcp) { + hdcp_deauthenticate(); + mod_timer(&hdmi_msm_state->hdcp_timer, jiffies + HZ/2); + } +} + +static void hdmi_msm_hdcp_work(struct work_struct *work) +{ + + /* Only re-enable if cable still connected */ + mutex_lock(&external_common_state_hpd_mutex); + if (external_common_state->hpd_state && + !(hdmi_msm_state->full_auth_done)) { + mutex_unlock(&external_common_state_hpd_mutex); + hdmi_msm_state->reauth = TRUE; + hdmi_msm_turn_on(); + } else + mutex_unlock(&external_common_state_hpd_mutex); +} +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ + +static irqreturn_t hdmi_msm_isr(int irq, void *dev_id) +{ + uint32 hpd_int_status; + uint32 hpd_int_ctrl; +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT + uint32 cec_intr_status; +#endif + uint32 ddc_int_ctrl; + uint32 audio_int_val; +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + uint32 hdcp_int_val; + char *envp[2]; +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ + static uint32 fifo_urun_int_occurred; + static uint32 sample_drop_int_occurred; + const uint32 occurrence_limit = 5; + + if (!hdmi_msm_state || !hdmi_msm_state->hpd_initialized || + !MSM_HDMI_BASE) { + DEV_DBG("ISR ignored, probe failed\n"); + return IRQ_HANDLED; + } + + /* Process HPD Interrupt */ + /* HDMI_HPD_INT_STATUS[0x0250] */ + hpd_int_status = HDMI_INP_ND(0x0250); + /* HDMI_HPD_INT_CTRL[0x0254] */ + hpd_int_ctrl = HDMI_INP_ND(0x0254); + if ((hpd_int_ctrl & (1 << 2)) && (hpd_int_status & (1 << 0))) { + boolean cable_detected = (hpd_int_status & 2) >> 1; + + /* HDMI_HPD_INT_CTRL[0x0254] */ + /* Clear all interrupts, timer will turn IRQ back on + * Leaving the bit[2] on, else core goes off + * on getting HPD during power off + */ + HDMI_OUTP(0x0254, (1 << 2) | (1 << 0)); + + DEV_DBG("%s: HPD IRQ, Ctrl=%04x, State=%04x\n", __func__, + hpd_int_ctrl, hpd_int_status); + mutex_lock(&hdmi_msm_state_mutex); + hdmi_msm_state->hpd_cable_chg_detected = TRUE; + + /* ensure 2 readouts */ + hdmi_msm_state->hpd_prev_state = cable_detected ? 0 : 1; + external_common_state->hpd_state = cable_detected ? 1 : 0; + hdmi_msm_state->hpd_stable = 0; + mod_timer(&hdmi_msm_state->hpd_state_timer, jiffies + HZ/2); + mutex_unlock(&hdmi_msm_state_mutex); + /* + * HDCP Compliance 1A-01: + * The Quantum Data Box 882 triggers two consecutive + * HPD events very close to each other as a part of this + * test which can trigger two parallel HDCP auth threads + * if HDCP authentication is going on and we get ISR + * then stop the authentication , rather than + * reauthenticating it again + */ + if (!(hdmi_msm_state->full_auth_done)) { + DEV_DBG("%s getting hpd while authenticating\n",\ + __func__); + mutex_lock(&hdcp_auth_state_mutex); + hdmi_msm_state->hpd_during_auth = TRUE; + mutex_unlock(&hdcp_auth_state_mutex); + } + return IRQ_HANDLED; + } + + /* Process DDC Interrupts */ + /* HDMI_DDC_INT_CTRL[0x0214] */ + ddc_int_ctrl = HDMI_INP_ND(0x0214); + if ((ddc_int_ctrl & (1 << 2)) && (ddc_int_ctrl & (1 << 0))) { + /* SW_DONE INT occured, clr it */ + HDMI_OUTP_ND(0x0214, ddc_int_ctrl | (1 << 1)); + complete(&hdmi_msm_state->ddc_sw_done); + return IRQ_HANDLED; + } + + /* FIFO Underrun Int is enabled */ + /* HDMI_AUD_INT[0x02CC] + * [3] AUD_SAM_DROP_MASK [R/W] + * [2] AUD_SAM_DROP_ACK [W], AUD_SAM_DROP_INT [R] + * [1] AUD_FIFO_URUN_MASK [R/W] + * [0] AUD_FIFO_URUN_ACK [W], AUD_FIFO_URUN_INT [R] */ + audio_int_val = HDMI_INP_ND(0x02CC); + if ((audio_int_val & (1 << 1)) && (audio_int_val & (1 << 0))) { + /* FIFO Underrun occured, clr it */ + HDMI_OUTP(0x02CC, audio_int_val | (1 << 0)); + + ++fifo_urun_int_occurred; + DEV_INFO("HDMI AUD_FIFO_URUN: %d\n", fifo_urun_int_occurred); + + if (fifo_urun_int_occurred >= occurrence_limit) { + HDMI_OUTP(0x02CC, HDMI_INP(0x02CC) & ~(1 << 1)); + DEV_INFO("HDMI AUD_FIFO_URUN: INT has been disabled " + "by the ISR after %d occurences...\n", + fifo_urun_int_occurred); + } + return IRQ_HANDLED; + } + + /* Audio Sample Drop int is enabled */ + if ((audio_int_val & (1 << 3)) && (audio_int_val & (1 << 2))) { + /* Audio Sample Drop occured, clr it */ + HDMI_OUTP(0x02CC, audio_int_val | (1 << 2)); + DEV_DBG("%s: AUD_SAM_DROP", __func__); + + ++sample_drop_int_occurred; + if (sample_drop_int_occurred >= occurrence_limit) { + HDMI_OUTP(0x02CC, HDMI_INP(0x02CC) & ~(1 << 3)); + DEV_INFO("HDMI AUD_SAM_DROP: INT has been disabled " + "by the ISR after %d occurences...\n", + sample_drop_int_occurred); + } + return IRQ_HANDLED; + } + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + /* HDCP_INT_CTRL[0x0118] + * [0] AUTH_SUCCESS_INT [R] HDCP Authentication Success + * interrupt status + * [1] AUTH_SUCCESS_ACK [W] Acknowledge bit for HDCP + * Authentication Success bit - write 1 to clear + * [2] AUTH_SUCCESS_MASK [R/W] Mask bit for HDCP Authentication + * Success interrupt - set to 1 to enable interrupt */ + hdcp_int_val = HDMI_INP_ND(0x0118); + if ((hdcp_int_val & (1 << 2)) && (hdcp_int_val & (1 << 0))) { + /* AUTH_SUCCESS_INT */ + HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 1)) & ~(1 << 0)); + DEV_INFO("HDCP: AUTH_SUCCESS_INT received\n"); + complete_all(&hdmi_msm_state->hdcp_success_done); + return IRQ_HANDLED; + } + /* [4] AUTH_FAIL_INT [R] HDCP Authentication Lost + * interrupt Status + * [5] AUTH_FAIL_ACK [W] Acknowledge bit for HDCP + * Authentication Lost bit - write 1 to clear + * [6] AUTH_FAIL_MASK [R/W] Mask bit fo HDCP Authentication + * Lost interrupt set to 1 to enable interrupt + * [7] AUTH_FAIL_INFO_ACK [W] Acknowledge bit for HDCP + * Authentication Failure Info field - write 1 to clear */ + if ((hdcp_int_val & (1 << 6)) && (hdcp_int_val & (1 << 4))) { + /* AUTH_FAIL_INT */ + /* Clear and Disable */ + HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 5)) + & ~((1 << 6) | (1 << 4))); + DEV_INFO("HDCP: AUTH_FAIL_INT received, LINK0_STATUS=0x%08x\n", + HDMI_INP_ND(0x011C)); + if (hdmi_msm_state->full_auth_done) { + envp[0] = "HDCP_STATE=FAIL"; + envp[1] = NULL; + DEV_INFO("HDMI HPD:QDSP OFF\n"); + kobject_uevent_env(external_common_state->uevent_kobj, + KOBJ_CHANGE, envp); + switch_set_state(&external_common_state->sdev, 0); + DEV_INFO("Hdmi state switch to %d: %s\n", + external_common_state->sdev.state, __func__); + mutex_lock(&hdcp_auth_state_mutex); + hdmi_msm_state->full_auth_done = FALSE; + mutex_unlock(&hdcp_auth_state_mutex); + /* Calling reauth only when authentication + * is sucessful or else we always go into + * the reauth loop + */ + queue_work(hdmi_work_queue, + &hdmi_msm_state->hdcp_reauth_work); + } + mutex_lock(&hdcp_auth_state_mutex); + /* This flag prevents other threads from re-authenticating + * after we've just authenticated (i.e., finished part3) + */ + hdmi_msm_state->full_auth_done = FALSE; + + mutex_unlock(&hdcp_auth_state_mutex); + DEV_DBG("calling reauthenticate from %s HDCP FAIL INT ", + __func__); + + /* Clear AUTH_FAIL_INFO as well */ + HDMI_OUTP(0x0118, (hdcp_int_val | (1 << 7))); + return IRQ_HANDLED; + } + /* [8] DDC_XFER_REQ_INT [R] HDCP DDC Transfer Request + * interrupt status + * [9] DDC_XFER_REQ_ACK [W] Acknowledge bit for HDCP DDC + * Transfer Request bit - write 1 to clear + * [10] DDC_XFER_REQ_MASK [R/W] Mask bit for HDCP DDC Transfer + * Request interrupt - set to 1 to enable interrupt */ + if ((hdcp_int_val & (1 << 10)) && (hdcp_int_val & (1 << 8))) { + /* DDC_XFER_REQ_INT */ + HDMI_OUTP_ND(0x0118, (hdcp_int_val | (1 << 9)) & ~(1 << 8)); + if (!(hdcp_int_val & (1 << 12))) + return IRQ_HANDLED; + } + /* [12] DDC_XFER_DONE_INT [R] HDCP DDC Transfer done interrupt + * status + * [13] DDC_XFER_DONE_ACK [W] Acknowledge bit for HDCP DDC + * Transfer done bit - write 1 to clear + * [14] DDC_XFER_DONE_MASK [R/W] Mask bit for HDCP DDC Transfer + * done interrupt - set to 1 to enable interrupt */ + if ((hdcp_int_val & (1 << 14)) && (hdcp_int_val & (1 << 12))) { + /* DDC_XFER_DONE_INT */ + HDMI_OUTP_ND(0x0118, (hdcp_int_val | (1 << 13)) & ~(1 << 12)); + DEV_INFO("HDCP: DDC_XFER_DONE received\n"); + return IRQ_HANDLED; + } +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT + /* Process CEC Interrupt */ + /* HDMI_MSM_CEC_INT[0x029C] */ + cec_intr_status = HDMI_INP_ND(0x029C); + + DEV_DBG("cec interrupt status is [%u]\n", cec_intr_status); + + if (HDMI_MSM_CEC_FRAME_WR_SUCCESS(cec_intr_status)) { + DEV_DBG("CEC_IRQ_FRAME_WR_DONE\n"); + HDMI_OUTP(0x029C, cec_intr_status | + HDMI_MSM_CEC_INT_FRAME_WR_DONE_ACK); + mutex_lock(&hdmi_msm_state_mutex); + hdmi_msm_state->cec_frame_wr_status |= CEC_STATUS_WR_DONE; + hdmi_msm_state->first_monitor = 0; + del_timer(&hdmi_msm_state->cec_read_timer); + mutex_unlock(&hdmi_msm_state_mutex); + complete(&hdmi_msm_state->cec_frame_wr_done); + return IRQ_HANDLED; + } + if ((cec_intr_status & (1 << 2)) && (cec_intr_status & (1 << 3))) { + DEV_DBG("CEC_IRQ_FRAME_ERROR\n"); +#ifdef TOGGLE_CEC_HARDWARE_FSM + /* Toggle CEC hardware FSM */ + HDMI_OUTP(0x028C, 0x0); + HDMI_OUTP(0x028C, HDMI_MSM_CEC_CTRL_ENABLE); +#endif + HDMI_OUTP(0x029C, cec_intr_status); + mutex_lock(&hdmi_msm_state_mutex); + hdmi_msm_state->first_monitor = 0; + del_timer(&hdmi_msm_state->cec_read_timer); + hdmi_msm_state->cec_frame_wr_status |= CEC_STATUS_WR_ERROR; + mutex_unlock(&hdmi_msm_state_mutex); + complete(&hdmi_msm_state->cec_frame_wr_done); + return IRQ_HANDLED; + } + + if ((cec_intr_status & (1 << 4)) && (cec_intr_status & (1 << 5))) { + DEV_DBG("CEC_IRQ_MONITOR\n"); + HDMI_OUTP(0x029C, cec_intr_status | + HDMI_MSM_CEC_INT_MONITOR_ACK); + + /* + * CECT 9-5-1 + * On the first occassion start a timer + * for few hundred ms, if it expires then + * reset the CEC block else go on with + * frame transactions as usual. + * Below adds hdmi_msm_cec_msg_recv() as an + * item into the work queue instead of running in + * interrupt context + */ + mutex_lock(&hdmi_msm_state_mutex); + if (hdmi_msm_state->first_monitor == 0) { + /* This timer might have to be changed + * worst case theoritical = + * 16 bytes * 8 * 2.7msec = 346 msec + */ + mod_timer(&hdmi_msm_state->cec_read_timer, + jiffies + HZ/2); + hdmi_msm_state->first_monitor = 1; + } + mutex_unlock(&hdmi_msm_state_mutex); + return IRQ_HANDLED; + } + + if ((cec_intr_status & (1 << 6)) && (cec_intr_status & (1 << 7))) { + DEV_DBG("CEC_IRQ_FRAME_RD_DONE\n"); + + mutex_lock(&hdmi_msm_state_mutex); + hdmi_msm_state->first_monitor = 0; + del_timer(&hdmi_msm_state->cec_read_timer); + mutex_unlock(&hdmi_msm_state_mutex); + HDMI_OUTP(0x029C, cec_intr_status | + HDMI_MSM_CEC_INT_FRAME_RD_DONE_ACK); + hdmi_msm_cec_msg_recv(); + +#ifdef TOGGLE_CEC_HARDWARE_FSM + if (!msg_send_complete) + msg_recv_complete = FALSE; + else { + /* Toggle CEC hardware FSM */ + HDMI_OUTP(0x028C, 0x0); + HDMI_OUTP(0x028C, HDMI_MSM_CEC_CTRL_ENABLE); + } +#else + HDMI_OUTP(0x028C, 0x0); + HDMI_OUTP(0x028C, HDMI_MSM_CEC_CTRL_ENABLE); +#endif + + return IRQ_HANDLED; + } +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT */ + + DEV_DBG("%s: HPD, ddc_int_ctrl=%04x, " + "aud_int=%04x, cec_intr_status=%04x\n", __func__, hpd_int_ctrl, + hpd_int_status, ddc_int_ctrl, audio_int_val, + HDMI_INP_ND(0x029C)); + + return IRQ_HANDLED; +} + +static int check_hdmi_features(void) +{ + /* RAW_FEAT_CONFIG_ROW0_LSB */ + uint32 val = inpdw(QFPROM_BASE + 0x0238); + /* HDMI_DISABLE */ + boolean hdmi_disabled = (val & 0x00200000) >> 21; + /* HDCP_DISABLE */ + boolean hdcp_disabled = (val & 0x00400000) >> 22; + + DEV_DBG("Features \n", val, + hdmi_disabled ? "OFF" : "ON", hdcp_disabled ? "OFF" : "ON"); + if (hdmi_disabled) { + DEV_ERR("ERROR: HDMI disabled\n"); + return -ENODEV; + } + + if (hdcp_disabled) + DEV_WARN("WARNING: HDCP disabled\n"); + + return 0; +} + +static boolean hdmi_msm_has_hdcp(void) +{ + /* RAW_FEAT_CONFIG_ROW0_LSB, HDCP_DISABLE */ + return (inpdw(QFPROM_BASE + 0x0238) & 0x00400000) ? FALSE : TRUE; +} + +static boolean hdmi_msm_is_power_on(void) +{ + /* HDMI_CTRL, ENABLE */ + return (HDMI_INP_ND(0x0000) & 0x00000001) ? TRUE : FALSE; +} + +/* 1.2.1.2.1 DVI Operation + * HDMI compliance requires the HDMI core to support DVI as well. The + * HDMI core also supports DVI. In DVI operation there are no preambles + * and guardbands transmitted. THe TMDS encoding of video data remains + * the same as HDMI. There are no VBI or audio packets transmitted. In + * order to enable DVI mode in HDMI core, HDMI_DVI_SEL field of + * HDMI_CTRL register needs to be programmed to 0. */ +static boolean hdmi_msm_is_dvi_mode(void) +{ + /* HDMI_CTRL, HDMI_DVI_SEL */ + return (HDMI_INP_ND(0x0000) & 0x00000002) ? FALSE : TRUE; +} + +void hdmi_msm_set_mode(boolean power_on) +{ + uint32 reg_val = 0; + if (power_on) { + /* ENABLE */ + reg_val |= 0x00000001; /* Enable the block */ + if (external_common_state->hdmi_sink == 0) { + /* HDMI_DVI_SEL */ + reg_val |= 0x00000002; + if (external_common_state->present_hdcp) + /* HDMI Encryption */ + reg_val |= 0x00000004; + /* HDMI_CTRL */ + HDMI_OUTP(0x0000, reg_val); + /* HDMI_DVI_SEL */ + reg_val &= ~0x00000002; + } else { + if (external_common_state->present_hdcp) + /* HDMI_Encryption_ON */ + reg_val |= 0x00000006; + else + reg_val |= 0x00000002; + } + } else + reg_val = 0x00000002; + + /* HDMI_CTRL */ + HDMI_OUTP(0x0000, reg_val); + DEV_DBG("HDMI Core: %s\n", power_on ? "Enable" : "Disable"); +} + +static void msm_hdmi_init_ddc(void) +{ + /* 0x0220 HDMI_DDC_SPEED + [31:16] PRESCALE prescale = (m * xtal_frequency) / + (desired_i2c_speed), where m is multiply + factor, default: m = 1 + [1:0] THRESHOLD Select threshold to use to determine whether value + sampled on SDA is a 1 or 0. Specified in terms of the ratio + between the number of sampled ones and the total number of times + SDA is sampled. + * 0x0: >0 + * 0x1: 1/4 of total samples + * 0x2: 1/2 of total samples + * 0x3: 3/4 of total samples */ + /* Configure the Pre-Scale multiplier + * Configure the Threshold */ + HDMI_OUTP_ND(0x0220, (10 << 16) | (2 << 0)); + + /* + * 0x0224 HDMI_DDC_SETUP + * Setting 31:24 bits : Time units to wait before timeout + * when clock is being stalled by external sink device + */ + HDMI_OUTP_ND(0x0224, 0xff000000); + + /* 0x027C HDMI_DDC_REF + [6] REFTIMER_ENABLE Enable the timer + * 0: Disable + * 1: Enable + [15:0] REFTIMER Value to set the register in order to generate + DDC strobe. This register counts on HDCP application clock */ + /* Enable reference timer + * 27 micro-seconds */ + HDMI_OUTP_ND(0x027C, (1 << 16) | (27 << 0)); +} + +static int hdmi_msm_ddc_clear_irq(const char *what) +{ + const uint32 time_out = 0xFFFF; + uint32 time_out_count, reg_val; + + /* clear pending and enable interrupt */ + time_out_count = time_out; + do { + --time_out_count; + /* HDMI_DDC_INT_CTRL[0x0214] + [2] SW_DONE_MK Mask bit for SW_DONE_INT. Set to 1 to enable + interrupt. + [1] SW_DONE_ACK WRITE ONLY. Acknowledge bit for SW_DONE_INT. + Write 1 to clear interrupt. + [0] SW_DONE_INT READ ONLY. SW_DONE interrupt status */ + /* Clear and Enable DDC interrupt */ + /* Write */ + HDMI_OUTP_ND(0x0214, (1 << 2) | (1 << 1)); + /* Read back */ + reg_val = HDMI_INP_ND(0x0214); + } while ((reg_val & 0x1) && time_out_count); + if (!time_out_count) { + DEV_ERR("%s[%s]: timedout\n", __func__, what); + return -ETIMEDOUT; + } + + return 0; +} + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT +static int hdmi_msm_ddc_write(uint32 dev_addr, uint32 offset, + const uint8 *data_buf, uint32 data_len, const char *what) +{ + uint32 reg_val, ndx; + int status = 0, retry = 10; + uint32 time_out_count; + + if (NULL == data_buf) { + status = -EINVAL; + DEV_ERR("%s[%s]: invalid input paramter\n", __func__, what); + goto error; + } + +again: + status = hdmi_msm_ddc_clear_irq(what); + if (status) + goto error; + + /* Ensure Device Address has LSB set to 0 to indicate Slave addr read */ + dev_addr &= 0xFE; + + /* 0x0238 HDMI_DDC_DATA + [31] INDEX_WRITE WRITE ONLY. To write index field, set this bit to + 1 while writing HDMI_DDC_DATA. + [23:16] INDEX Use to set index into DDC buffer for next read or + current write, or to read index of current read or next write. + Writable only when INDEX_WRITE=1. + [15:8] DATA Use to fill or read the DDC buffer + [0] DATA_RW Select whether buffer access will be a read or write. + For writes, address auto-increments on write to HDMI_DDC_DATA. + For reads, address autoincrements on reads to HDMI_DDC_DATA. + * 0: Write + * 1: Read */ + + /* 1. Write to HDMI_I2C_DATA with the following fields set in order to + * handle portion #1 + * DATA_RW = 0x1 (write) + * DATA = linkAddress (primary link address and writing) + * INDEX = 0x0 (initial offset into buffer) + * INDEX_WRITE = 0x1 (setting initial offset) */ + HDMI_OUTP_ND(0x0238, (0x1UL << 31) | (dev_addr << 8)); + + /* 2. Write to HDMI_I2C_DATA with the following fields set in order to + * handle portion #2 + * DATA_RW = 0x0 (write) + * DATA = offsetAddress + * INDEX = 0x0 + * INDEX_WRITE = 0x0 (auto-increment by hardware) */ + HDMI_OUTP_ND(0x0238, offset << 8); + + /* 3. Write to HDMI_I2C_DATA with the following fields set in order to + * handle portion #3 + * DATA_RW = 0x0 (write) + * DATA = data_buf[ndx] + * INDEX = 0x0 + * INDEX_WRITE = 0x0 (auto-increment by hardware) */ + for (ndx = 0; ndx < data_len; ++ndx) + HDMI_OUTP_ND(0x0238, ((uint32)data_buf[ndx]) << 8); + + /* Data setup is complete, now setup the transaction characteristics */ + + /* 0x0228 HDMI_DDC_TRANS0 + [23:16] CNT0 Byte count for first transaction (excluding the first + byte, which is usually the address). + [13] STOP0 Determines whether a stop bit will be sent after the first + transaction + * 0: NO STOP + * 1: STOP + [12] START0 Determines whether a start bit will be sent before the + first transaction + * 0: NO START + * 1: START + [8] STOP_ON_NACK0 Determines whether the current transfer will stop + if a NACK is received during the first transaction (current + transaction always stops). + * 0: STOP CURRENT TRANSACTION, GO TO NEXT TRANSACTION + * 1: STOP ALL TRANSACTIONS, SEND STOP BIT + [0] RW0 Read/write indicator for first transaction - set to 0 for + write, 1 for read. This bit only controls HDMI_DDC behaviour - + the R/W bit in the transaction is programmed into the DDC buffer + as the LSB of the address byte. + * 0: WRITE + * 1: READ */ + + /* 4. Write to HDMI_I2C_TRANSACTION0 with the following fields set in + order to handle characteristics of portion #1 and portion #2 + * RW0 = 0x0 (write) + * START0 = 0x1 (insert START bit) + * STOP0 = 0x0 (do NOT insert STOP bit) + * CNT0 = 0x1 (single byte transaction excluding address) */ + HDMI_OUTP_ND(0x0228, (1 << 12) | (1 << 16)); + + /* 0x022C HDMI_DDC_TRANS1 + [23:16] CNT1 Byte count for second transaction (excluding the first + byte, which is usually the address). + [13] STOP1 Determines whether a stop bit will be sent after the second + transaction + * 0: NO STOP + * 1: STOP + [12] START1 Determines whether a start bit will be sent before the + second transaction + * 0: NO START + * 1: START + [8] STOP_ON_NACK1 Determines whether the current transfer will stop if + a NACK is received during the second transaction (current + transaction always stops). + * 0: STOP CURRENT TRANSACTION, GO TO NEXT TRANSACTION + * 1: STOP ALL TRANSACTIONS, SEND STOP BIT + [0] RW1 Read/write indicator for second transaction - set to 0 for + write, 1 for read. This bit only controls HDMI_DDC behaviour - + the R/W bit in the transaction is programmed into the DDC buffer + as the LSB of the address byte. + * 0: WRITE + * 1: READ */ + + /* 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in + order to handle characteristics of portion #3 + * RW1 = 0x1 (read) + * START1 = 0x1 (insert START bit) + * STOP1 = 0x1 (insert STOP bit) + * CNT1 = data_len (0xN (write N bytes of data)) + * Byte count for second transition (excluding the first + * Byte which is usually the address) */ + HDMI_OUTP_ND(0x022C, (1 << 13) | ((data_len-1) << 16)); + + /* Trigger the I2C transfer */ + /* 0x020C HDMI_DDC_CTRL + [21:20] TRANSACTION_CNT + Number of transactions to be done in current transfer. + * 0x0: transaction0 only + * 0x1: transaction0, transaction1 + * 0x2: transaction0, transaction1, transaction2 + * 0x3: transaction0, transaction1, transaction2, transaction3 + [3] SW_STATUS_RESET + Write 1 to reset HDMI_DDC_SW_STATUS flags, will reset SW_DONE, + ABORTED, TIMEOUT, SW_INTERRUPTED, BUFFER_OVERFLOW, + STOPPED_ON_NACK, NACK0, NACK1, NACK2, NACK3 + [2] SEND_RESET Set to 1 to send reset sequence (9 clocks with no + data) at start of transfer. This sequence is sent after GO is + written to 1, before the first transaction only. + [1] SOFT_RESET Write 1 to reset DDC controller + [0] GO WRITE ONLY. Write 1 to start DDC transfer. */ + + /* 6. Write to HDMI_I2C_CONTROL to kick off the hardware. + * Note that NOTHING has been transmitted on the DDC lines up to this + * point. + * TRANSACTION_CNT = 0x1 (execute transaction0 followed by + * transaction1) + * GO = 0x1 (kicks off hardware) */ + INIT_COMPLETION(hdmi_msm_state->ddc_sw_done); + HDMI_OUTP_ND(0x020C, (1 << 0) | (1 << 20)); + + time_out_count = wait_for_completion_interruptible_timeout( + &hdmi_msm_state->ddc_sw_done, HZ/2); + HDMI_OUTP_ND(0x0214, 0x2); + if (!time_out_count) { + if (retry-- > 0) { + DEV_INFO("%s[%s]: failed timout, retry=%d\n", __func__, + what, retry); + goto again; + } + status = -ETIMEDOUT; + DEV_ERR("%s[%s]: timedout, DDC SW Status=%08x, HW " + "Status=%08x, Int Ctrl=%08x\n", __func__, what, + HDMI_INP_ND(0x0218), HDMI_INP_ND(0x021C), + HDMI_INP_ND(0x0214)); + goto error; + } + + /* Read DDC status */ + reg_val = HDMI_INP_ND(0x0218); + reg_val &= 0x00001000 | 0x00002000 | 0x00004000 | 0x00008000; + + /* Check if any NACK occurred */ + if (reg_val) { + if (retry > 1) + HDMI_OUTP_ND(0x020C, BIT(3)); /* SW_STATUS_RESET */ + else + HDMI_OUTP_ND(0x020C, BIT(1)); /* SOFT_RESET */ + if (retry-- > 0) { + DEV_DBG("%s[%s]: failed NACK=%08x, retry=%d\n", + __func__, what, reg_val, retry); + msleep(100); + goto again; + } + status = -EIO; + DEV_ERR("%s[%s]: failed NACK: %08x\n", __func__, what, reg_val); + goto error; + } + + DEV_DBG("%s[%s] success\n", __func__, what); + +error: + return status; +} +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ + +static int hdmi_msm_ddc_read_retry(uint32 dev_addr, uint32 offset, + uint8 *data_buf, uint32 data_len, uint32 request_len, int retry, + const char *what) +{ + uint32 reg_val, ndx; + int status = 0; + uint32 time_out_count; + int log_retry_fail = retry != 1; + + if (NULL == data_buf) { + status = -EINVAL; + DEV_ERR("%s: invalid input paramter\n", __func__); + goto error; + } + +again: + status = hdmi_msm_ddc_clear_irq(what); + if (status) + goto error; + + /* Ensure Device Address has LSB set to 0 to indicate Slave addr read */ + dev_addr &= 0xFE; + + /* 0x0238 HDMI_DDC_DATA + [31] INDEX_WRITE WRITE ONLY. To write index field, set this bit to + 1 while writing HDMI_DDC_DATA. + [23:16] INDEX Use to set index into DDC buffer for next read or + current write, or to read index of current read or next write. + Writable only when INDEX_WRITE=1. + [15:8] DATA Use to fill or read the DDC buffer + [0] DATA_RW Select whether buffer access will be a read or write. + For writes, address auto-increments on write to HDMI_DDC_DATA. + For reads, address autoincrements on reads to HDMI_DDC_DATA. + * 0: Write + * 1: Read */ + + /* 1. Write to HDMI_I2C_DATA with the following fields set in order to + * handle portion #1 + * DATA_RW = 0x0 (write) + * DATA = linkAddress (primary link address and writing) + * INDEX = 0x0 (initial offset into buffer) + * INDEX_WRITE = 0x1 (setting initial offset) */ + HDMI_OUTP_ND(0x0238, (0x1UL << 31) | (dev_addr << 8)); + + /* 2. Write to HDMI_I2C_DATA with the following fields set in order to + * handle portion #2 + * DATA_RW = 0x0 (write) + * DATA = offsetAddress + * INDEX = 0x0 + * INDEX_WRITE = 0x0 (auto-increment by hardware) */ + HDMI_OUTP_ND(0x0238, offset << 8); + + /* 3. Write to HDMI_I2C_DATA with the following fields set in order to + * handle portion #3 + * DATA_RW = 0x0 (write) + * DATA = linkAddress + 1 (primary link address 0x74 and reading) + * INDEX = 0x0 + * INDEX_WRITE = 0x0 (auto-increment by hardware) */ + HDMI_OUTP_ND(0x0238, (dev_addr | 1) << 8); + + /* Data setup is complete, now setup the transaction characteristics */ + + /* 0x0228 HDMI_DDC_TRANS0 + [23:16] CNT0 Byte count for first transaction (excluding the first + byte, which is usually the address). + [13] STOP0 Determines whether a stop bit will be sent after the first + transaction + * 0: NO STOP + * 1: STOP + [12] START0 Determines whether a start bit will be sent before the + first transaction + * 0: NO START + * 1: START + [8] STOP_ON_NACK0 Determines whether the current transfer will stop + if a NACK is received during the first transaction (current + transaction always stops). + * 0: STOP CURRENT TRANSACTION, GO TO NEXT TRANSACTION + * 1: STOP ALL TRANSACTIONS, SEND STOP BIT + [0] RW0 Read/write indicator for first transaction - set to 0 for + write, 1 for read. This bit only controls HDMI_DDC behaviour - + the R/W bit in the transaction is programmed into the DDC buffer + as the LSB of the address byte. + * 0: WRITE + * 1: READ */ + + /* 4. Write to HDMI_I2C_TRANSACTION0 with the following fields set in + order to handle characteristics of portion #1 and portion #2 + * RW0 = 0x0 (write) + * START0 = 0x1 (insert START bit) + * STOP0 = 0x0 (do NOT insert STOP bit) + * CNT0 = 0x1 (single byte transaction excluding address) */ + HDMI_OUTP_ND(0x0228, (1 << 12) | (1 << 16)); + + /* 0x022C HDMI_DDC_TRANS1 + [23:16] CNT1 Byte count for second transaction (excluding the first + byte, which is usually the address). + [13] STOP1 Determines whether a stop bit will be sent after the second + transaction + * 0: NO STOP + * 1: STOP + [12] START1 Determines whether a start bit will be sent before the + second transaction + * 0: NO START + * 1: START + [8] STOP_ON_NACK1 Determines whether the current transfer will stop if + a NACK is received during the second transaction (current + transaction always stops). + * 0: STOP CURRENT TRANSACTION, GO TO NEXT TRANSACTION + * 1: STOP ALL TRANSACTIONS, SEND STOP BIT + [0] RW1 Read/write indicator for second transaction - set to 0 for + write, 1 for read. This bit only controls HDMI_DDC behaviour - + the R/W bit in the transaction is programmed into the DDC buffer + as the LSB of the address byte. + * 0: WRITE + * 1: READ */ + + /* 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in + order to handle characteristics of portion #3 + * RW1 = 0x1 (read) + * START1 = 0x1 (insert START bit) + * STOP1 = 0x1 (insert STOP bit) + * CNT1 = data_len (it's 128 (0x80) for a blk read) */ + HDMI_OUTP_ND(0x022C, 1 | (1 << 12) | (1 << 13) | (request_len << 16)); + + /* Trigger the I2C transfer */ + /* 0x020C HDMI_DDC_CTRL + [21:20] TRANSACTION_CNT + Number of transactions to be done in current transfer. + * 0x0: transaction0 only + * 0x1: transaction0, transaction1 + * 0x2: transaction0, transaction1, transaction2 + * 0x3: transaction0, transaction1, transaction2, transaction3 + [3] SW_STATUS_RESET + Write 1 to reset HDMI_DDC_SW_STATUS flags, will reset SW_DONE, + ABORTED, TIMEOUT, SW_INTERRUPTED, BUFFER_OVERFLOW, + STOPPED_ON_NACK, NACK0, NACK1, NACK2, NACK3 + [2] SEND_RESET Set to 1 to send reset sequence (9 clocks with no + data) at start of transfer. This sequence is sent after GO is + written to 1, before the first transaction only. + [1] SOFT_RESET Write 1 to reset DDC controller + [0] GO WRITE ONLY. Write 1 to start DDC transfer. */ + + /* 6. Write to HDMI_I2C_CONTROL to kick off the hardware. + * Note that NOTHING has been transmitted on the DDC lines up to this + * point. + * TRANSACTION_CNT = 0x1 (execute transaction0 followed by + * transaction1) + * SEND_RESET = Set to 1 to send reset sequence + * GO = 0x1 (kicks off hardware) */ + INIT_COMPLETION(hdmi_msm_state->ddc_sw_done); + HDMI_OUTP_ND(0x020C, (1 << 0) | (1 << 20)); + + time_out_count = wait_for_completion_interruptible_timeout( + &hdmi_msm_state->ddc_sw_done, HZ/2); + HDMI_OUTP_ND(0x0214, 0x2); + if (!time_out_count) { + if (retry-- > 0) { + DEV_INFO("%s: failed timout, retry=%d\n", __func__, + retry); + goto again; + } + status = -ETIMEDOUT; + DEV_ERR("%s: timedout(7), DDC SW Status=%08x, HW " + "Status=%08x, Int Ctrl=%08x\n", __func__, + HDMI_INP(0x0218), HDMI_INP(0x021C), HDMI_INP(0x0214)); + goto error; + } + + /* Read DDC status */ + reg_val = HDMI_INP_ND(0x0218); + reg_val &= 0x00001000 | 0x00002000 | 0x00004000 | 0x00008000; + + /* Check if any NACK occurred */ + if (reg_val) { + HDMI_OUTP_ND(0x020C, BIT(3)); /* SW_STATUS_RESET */ + if (retry == 1) + HDMI_OUTP_ND(0x020C, BIT(1)); /* SOFT_RESET */ + if (retry-- > 0) { + DEV_DBG("%s(%s): failed NACK=0x%08x, retry=%d, " + "dev-addr=0x%02x, offset=0x%02x, " + "length=%d\n", __func__, what, + reg_val, retry, dev_addr, + offset, data_len); + goto again; + } + status = -EIO; + if (log_retry_fail) + DEV_ERR("%s(%s): failed NACK=0x%08x, dev-addr=0x%02x, " + "offset=0x%02x, length=%d\n", __func__, what, + reg_val, dev_addr, offset, data_len); + goto error; + } + + /* 0x0238 HDMI_DDC_DATA + [31] INDEX_WRITE WRITE ONLY. To write index field, set this bit to 1 + while writing HDMI_DDC_DATA. + [23:16] INDEX Use to set index into DDC buffer for next read or + current write, or to read index of current read or next write. + Writable only when INDEX_WRITE=1. + [15:8] DATA Use to fill or read the DDC buffer + [0] DATA_RW Select whether buffer access will be a read or write. + For writes, address auto-increments on write to HDMI_DDC_DATA. + For reads, address autoincrements on reads to HDMI_DDC_DATA. + * 0: Write + * 1: Read */ + + /* 8. ALL data is now available and waiting in the DDC buffer. + * Read HDMI_I2C_DATA with the following fields set + * RW = 0x1 (read) + * DATA = BCAPS (this is field where data is pulled from) + * INDEX = 0x3 (where the data has been placed in buffer by hardware) + * INDEX_WRITE = 0x1 (explicitly define offset) */ + /* Write this data to DDC buffer */ + HDMI_OUTP_ND(0x0238, 0x1 | (3 << 16) | (1 << 31)); + + /* Discard first byte */ + HDMI_INP_ND(0x0238); + for (ndx = 0; ndx < data_len; ++ndx) { + reg_val = HDMI_INP_ND(0x0238); + data_buf[ndx] = (uint8) ((reg_val & 0x0000FF00) >> 8); + } + + DEV_DBG("%s[%s] success\n", __func__, what); + +error: + return status; +} + +static int hdmi_msm_ddc_read_edid_seg(uint32 dev_addr, uint32 offset, + uint8 *data_buf, uint32 data_len, uint32 request_len, int retry, + const char *what) +{ + uint32 reg_val, ndx; + int status = 0; + uint32 time_out_count; + int log_retry_fail = retry != 1; + int seg_addr = 0x60, seg_num = 0x01; + + if (NULL == data_buf) { + status = -EINVAL; + DEV_ERR("%s: invalid input paramter\n", __func__); + goto error; + } + +again: + status = hdmi_msm_ddc_clear_irq(what); + if (status) + goto error; + + /* Ensure Device Address has LSB set to 0 to indicate Slave addr read */ + dev_addr &= 0xFE; + + /* 0x0238 HDMI_DDC_DATA + [31] INDEX_WRITE WRITE ONLY. To write index field, set this bit to + 1 while writing HDMI_DDC_DATA. + [23:16] INDEX Use to set index into DDC buffer for next read or + current write, or to read index of current read or next write. + Writable only when INDEX_WRITE=1. + [15:8] DATA Use to fill or read the DDC buffer + [0] DATA_RW Select whether buffer access will be a read or write. + For writes, address auto-increments on write to HDMI_DDC_DATA. + For reads, address autoincrements on reads to HDMI_DDC_DATA. + * 0: Write + * 1: Read */ + + /* 1. Write to HDMI_I2C_DATA with the following fields set in order to + * handle portion #1 + * DATA_RW = 0x0 (write) + * DATA = linkAddress (primary link address and writing) + * INDEX = 0x0 (initial offset into buffer) + * INDEX_WRITE = 0x1 (setting initial offset) */ + HDMI_OUTP_ND(0x0238, (0x1UL << 31) | (seg_addr << 8)); + + /* 2. Write to HDMI_I2C_DATA with the following fields set in order to + * handle portion #2 + * DATA_RW = 0x0 (write) + * DATA = offsetAddress + * INDEX = 0x0 + * INDEX_WRITE = 0x0 (auto-increment by hardware) */ + HDMI_OUTP_ND(0x0238, seg_num << 8); + + /* 3. Write to HDMI_I2C_DATA with the following fields set in order to + * handle portion #3 + * DATA_RW = 0x0 (write) + * DATA = linkAddress + 1 (primary link address 0x74 and reading) + * INDEX = 0x0 + * INDEX_WRITE = 0x0 (auto-increment by hardware) */ + HDMI_OUTP_ND(0x0238, dev_addr << 8); + HDMI_OUTP_ND(0x0238, offset << 8); + HDMI_OUTP_ND(0x0238, (dev_addr | 1) << 8); + + /* Data setup is complete, now setup the transaction characteristics */ + + /* 0x0228 HDMI_DDC_TRANS0 + [23:16] CNT0 Byte count for first transaction (excluding the first + byte, which is usually the address). + [13] STOP0 Determines whether a stop bit will be sent after the first + transaction + * 0: NO STOP + * 1: STOP + [12] START0 Determines whether a start bit will be sent before the + first transaction + * 0: NO START + * 1: START + [8] STOP_ON_NACK0 Determines whether the current transfer will stop + if a NACK is received during the first transaction (current + transaction always stops). + * 0: STOP CURRENT TRANSACTION, GO TO NEXT TRANSACTION + * 1: STOP ALL TRANSACTIONS, SEND STOP BIT + [0] RW0 Read/write indicator for first transaction - set to 0 for + write, 1 for read. This bit only controls HDMI_DDC behaviour - + the R/W bit in the transaction is programmed into the DDC buffer + as the LSB of the address byte. + * 0: WRITE + * 1: READ */ + + /* 4. Write to HDMI_I2C_TRANSACTION0 with the following fields set in + order to handle characteristics of portion #1 and portion #2 + * RW0 = 0x0 (write) + * START0 = 0x1 (insert START bit) + * STOP0 = 0x0 (do NOT insert STOP bit) + * CNT0 = 0x1 (single byte transaction excluding address) */ + HDMI_OUTP_ND(0x0228, (1 << 12) | (1 << 16)); + + /* 0x022C HDMI_DDC_TRANS1 + [23:16] CNT1 Byte count for second transaction (excluding the first + byte, which is usually the address). + [13] STOP1 Determines whether a stop bit will be sent after the second + transaction + * 0: NO STOP + * 1: STOP + [12] START1 Determines whether a start bit will be sent before the + second transaction + * 0: NO START + * 1: START + [8] STOP_ON_NACK1 Determines whether the current transfer will stop if + a NACK is received during the second transaction (current + transaction always stops). + * 0: STOP CURRENT TRANSACTION, GO TO NEXT TRANSACTION + * 1: STOP ALL TRANSACTIONS, SEND STOP BIT + [0] RW1 Read/write indicator for second transaction - set to 0 for + write, 1 for read. This bit only controls HDMI_DDC behaviour - + the R/W bit in the transaction is programmed into the DDC buffer + as the LSB of the address byte. + * 0: WRITE + * 1: READ */ + + /* 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in + order to handle characteristics of portion #3 + * RW1 = 0x1 (read) + * START1 = 0x1 (insert START bit) + * STOP1 = 0x1 (insert STOP bit) + * CNT1 = data_len (it's 128 (0x80) for a blk read) */ + HDMI_OUTP_ND(0x022C, (1 << 12) | (1 << 16)); + + /* 0x022C HDMI_DDC_TRANS2 + [23:16] CNT1 Byte count for second transaction (excluding the first + byte, which is usually the address). + [13] STOP1 Determines whether a stop bit will be sent after the second + transaction + * 0: NO STOP + * 1: STOP + [12] START1 Determines whether a start bit will be sent before the + second transaction + * 0: NO START + * 1: START + [8] STOP_ON_NACK1 Determines whether the current transfer will stop if + a NACK is received during the second transaction (current + transaction always stops). + * 0: STOP CURRENT TRANSACTION, GO TO NEXT TRANSACTION + * 1: STOP ALL TRANSACTIONS, SEND STOP BIT + [0] RW1 Read/write indicator for second transaction - set to 0 for + write, 1 for read. This bit only controls HDMI_DDC behaviour - + the R/W bit in the transaction is programmed into the DDC buffer + as the LSB of the address byte. + * 0: WRITE + * 1: READ */ + + /* 5. Write to HDMI_I2C_TRANSACTION1 with the following fields set in + order to handle characteristics of portion #3 + * RW1 = 0x1 (read) + * START1 = 0x1 (insert START bit) + * STOP1 = 0x1 (insert STOP bit) + * CNT1 = data_len (it's 128 (0x80) for a blk read) */ + HDMI_OUTP_ND(0x0230, 1 | (1 << 12) | (1 << 13) | (request_len << 16)); + + /* Trigger the I2C transfer */ + /* 0x020C HDMI_DDC_CTRL + [21:20] TRANSACTION_CNT + Number of transactions to be done in current transfer. + * 0x0: transaction0 only + * 0x1: transaction0, transaction1 + * 0x2: transaction0, transaction1, transaction2 + * 0x3: transaction0, transaction1, transaction2, transaction3 + [3] SW_STATUS_RESET + Write 1 to reset HDMI_DDC_SW_STATUS flags, will reset SW_DONE, + ABORTED, TIMEOUT, SW_INTERRUPTED, BUFFER_OVERFLOW, + STOPPED_ON_NACK, NACK0, NACK1, NACK2, NACK3 + [2] SEND_RESET Set to 1 to send reset sequence (9 clocks with no + data) at start of transfer. This sequence is sent after GO is + written to 1, before the first transaction only. + [1] SOFT_RESET Write 1 to reset DDC controller + [0] GO WRITE ONLY. Write 1 to start DDC transfer. */ + + /* 6. Write to HDMI_I2C_CONTROL to kick off the hardware. + * Note that NOTHING has been transmitted on the DDC lines up to this + * point. + * TRANSACTION_CNT = 0x2 (execute transaction0 followed by + * transaction1) + * GO = 0x1 (kicks off hardware) */ + INIT_COMPLETION(hdmi_msm_state->ddc_sw_done); + HDMI_OUTP_ND(0x020C, (1 << 0) | (2 << 20)); + + time_out_count = wait_for_completion_interruptible_timeout( + &hdmi_msm_state->ddc_sw_done, HZ/2); + HDMI_OUTP_ND(0x0214, 0x2); + if (!time_out_count) { + if (retry-- > 0) { + DEV_INFO("%s: failed timout, retry=%d\n", __func__, + retry); + goto again; + } + status = -ETIMEDOUT; + DEV_ERR("%s: timedout(7), DDC SW Status=%08x, HW " + "Status=%08x, Int Ctrl=%08x\n", __func__, + HDMI_INP(0x0218), HDMI_INP(0x021C), HDMI_INP(0x0214)); + goto error; + } + + /* Read DDC status */ + reg_val = HDMI_INP_ND(0x0218); + reg_val &= 0x00001000 | 0x00002000 | 0x00004000 | 0x00008000; + + /* Check if any NACK occurred */ + if (reg_val) { + HDMI_OUTP_ND(0x020C, BIT(3)); /* SW_STATUS_RESET */ + if (retry == 1) + HDMI_OUTP_ND(0x020C, BIT(1)); /* SOFT_RESET */ + if (retry-- > 0) { + DEV_DBG("%s(%s): failed NACK=0x%08x, retry=%d, " + "dev-addr=0x%02x, offset=0x%02x, " + "length=%d\n", __func__, what, + reg_val, retry, dev_addr, + offset, data_len); + goto again; + } + status = -EIO; + if (log_retry_fail) + DEV_ERR("%s(%s): failed NACK=0x%08x, dev-addr=0x%02x, " + "offset=0x%02x, length=%d\n", __func__, what, + reg_val, dev_addr, offset, data_len); + goto error; + } + + /* 0x0238 HDMI_DDC_DATA + [31] INDEX_WRITE WRITE ONLY. To write index field, set this bit to 1 + while writing HDMI_DDC_DATA. + [23:16] INDEX Use to set index into DDC buffer for next read or + current write, or to read index of current read or next write. + Writable only when INDEX_WRITE=1. + [15:8] DATA Use to fill or read the DDC buffer + [0] DATA_RW Select whether buffer access will be a read or write. + For writes, address auto-increments on write to HDMI_DDC_DATA. + For reads, address autoincrements on reads to HDMI_DDC_DATA. + * 0: Write + * 1: Read */ + + /* 8. ALL data is now available and waiting in the DDC buffer. + * Read HDMI_I2C_DATA with the following fields set + * RW = 0x1 (read) + * DATA = BCAPS (this is field where data is pulled from) + * INDEX = 0x5 (where the data has been placed in buffer by hardware) + * INDEX_WRITE = 0x1 (explicitly define offset) */ + /* Write this data to DDC buffer */ + HDMI_OUTP_ND(0x0238, 0x1 | (5 << 16) | (1 << 31)); + + /* Discard first byte */ + HDMI_INP_ND(0x0238); + + for (ndx = 0; ndx < data_len; ++ndx) { + reg_val = HDMI_INP_ND(0x0238); + data_buf[ndx] = (uint8) ((reg_val & 0x0000FF00) >> 8); + } + + DEV_DBG("%s[%s] success\n", __func__, what); + +error: + return status; +} + + +static int hdmi_msm_ddc_read(uint32 dev_addr, uint32 offset, uint8 *data_buf, + uint32 data_len, int retry, const char *what, boolean no_align) +{ + int ret = hdmi_msm_ddc_read_retry(dev_addr, offset, data_buf, data_len, + data_len, retry, what); + if (!ret) + return 0; + if (no_align) { + return hdmi_msm_ddc_read_retry(dev_addr, offset, data_buf, + data_len, data_len, retry, what); + } else { + return hdmi_msm_ddc_read_retry(dev_addr, offset, data_buf, + data_len, 32 * ((data_len + 31) / 32), retry, what); + } +} + + +static int hdmi_msm_read_edid_block(int block, uint8 *edid_buf) +{ + int i, rc = 0; + int block_size = 0x80; + + do { + DEV_DBG("EDID: reading block(%d) with block-size=%d\n", + block, block_size); + for (i = 0; i < 0x80; i += block_size) { + /*Read EDID twice with 32bit alighnment too */ + if (block < 2) { + rc = hdmi_msm_ddc_read(0xA0, block*0x80 + i, + edid_buf+i, block_size, 1, + "EDID", FALSE); + } else { + rc = hdmi_msm_ddc_read_edid_seg(0xA0, + block*0x80 + i, edid_buf+i, block_size, + block_size, 1, "EDID"); + } + if (rc) + break; + } + + block_size /= 2; + } while (rc && (block_size >= 16)); + + return rc; +} + +static int hdmi_msm_read_edid(void) +{ + int status; + + msm_hdmi_init_ddc(); + /* Looks like we need to turn on HDMI engine before any + * DDC transaction */ + if (!hdmi_msm_is_power_on()) { + DEV_ERR("%s: failed: HDMI power is off", __func__); + status = -ENXIO; + goto error; + } + + external_common_state->read_edid_block = hdmi_msm_read_edid_block; + status = hdmi_common_read_edid(); + if (!status) + DEV_DBG("EDID: successfully read\n"); + +error: + return status; +} + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT +static void hdcp_auth_info(uint32 auth_info) +{ + switch (auth_info) { + case 0: + DEV_INFO("%s: None", __func__); + break; + case 1: + DEV_INFO("%s: Software Disabled Authentication", __func__); + break; + case 2: + DEV_INFO("%s: An Written", __func__); + break; + case 3: + DEV_INFO("%s: Invalid Aksv", __func__); + break; + case 4: + DEV_INFO("%s: Invalid Bksv", __func__); + break; + case 5: + DEV_INFO("%s: RI Mismatch (including RO)", __func__); + break; + case 6: + DEV_INFO("%s: consecutive Pj Mismatches", __func__); + break; + case 7: + DEV_INFO("%s: HPD Disconnect", __func__); + break; + case 8: + default: + DEV_INFO("%s: Reserved", __func__); + break; + } +} + +static void hdcp_key_state(uint32 key_state) +{ + switch (key_state) { + case 0: + DEV_WARN("%s: No HDCP Keys", __func__); + break; + case 1: + DEV_WARN("%s: Not Checked", __func__); + break; + case 2: + DEV_DBG("%s: Checking", __func__); + break; + case 3: + DEV_DBG("%s: HDCP Keys Valid", __func__); + break; + case 4: + DEV_WARN("%s: AKSV not valid", __func__); + break; + case 5: + DEV_WARN("%s: Checksum Mismatch", __func__); + break; + case 6: + DEV_DBG("%s: Production AKSV" + "with ENABLE_USER_DEFINED_AN=1", __func__); + break; + case 7: + default: + DEV_INFO("%s: Reserved", __func__); + break; + } +} + +static int hdmi_msm_count_one(uint8 *array, uint8 len) +{ + int i, j, count = 0; + for (i = 0; i < len; i++) + for (j = 0; j < 8; j++) + count += (((array[i] >> j) & 0x1) ? 1 : 0); + return count; +} + +static void hdcp_deauthenticate(void) +{ + int hdcp_link_status = HDMI_INP(0x011C); + + /* Disable HDCP interrupts */ + HDMI_OUTP(0x0118, 0x0); + + external_common_state->hdcp_active = FALSE; + /* 0x0130 HDCP_RESET + [0] LINK0_DEAUTHENTICATE */ + HDMI_OUTP(0x0130, 0x1); + + /* 0x0110 HDCP_CTRL + [8] ENCRYPTION_ENABLE + [0] ENABLE */ + /* encryption_enable = 0 | hdcp block enable = 1 */ + HDMI_OUTP(0x0110, 0x0); + + if (hdcp_link_status & 0x00000004) + hdcp_auth_info((hdcp_link_status & 0x000000F0) >> 4); +} + +static void check_and_clear_HDCP_DDC_Failure(void) +{ + int hdcp_ddc_ctrl1_reg; + int hdcp_ddc_status; + int failure; + int nack0; + + /* + * Check for any DDC transfer failures + * 0x0128 HDCP_DDC_STATUS + * [16] FAILED Indicates that the last HDCP HW DDC transer + * failed. This occurs when a transfer is + * attempted with HDCP DDC disabled + * (HDCP_DDC_DISABLE=1) or the number of retries + * match HDCP_DDC_RETRY_CNT + * + * [14] NACK0 Indicates that the last HDCP HW DDC transfer + * was aborted due to a NACK on the first + * transaction - cleared by writing 0 to GO bit + */ + hdcp_ddc_status = HDMI_INP(HDCP_DDC_STATUS); + failure = (hdcp_ddc_status >> 16) & 0x1; + nack0 = (hdcp_ddc_status >> 14) & 0x1; + DEV_DBG("%s: On Entry: HDCP_DDC_STATUS = 0x%x, FAILURE = %d," + "NACK0 = %d\n", __func__ , hdcp_ddc_status, failure, nack0); + + if (failure == 0x1) { + /* + * Indicates that the last HDCP HW DDC transfer failed. + * This occurs when a transfer is attempted with HDCP DDC + * disabled (HDCP_DDC_DISABLE=1) or the number of retries + * matches HDCP_DDC_RETRY_CNT. + * Failure occured, let's clear it. + */ + DEV_INFO("%s: DDC failure detected. HDCP_DDC_STATUS=0x%08x\n", + __func__, hdcp_ddc_status); + /* + * First, Disable DDC + * 0x0120 HDCP_DDC_CTRL_0 + * [0] DDC_DISABLE Determines whether HDCP Ri and Pj reads + * are done unassisted by hardware or by + * software via HDMI_DDC (HDCP provides + * interrupts to request software + * transfers) + * 0 : Use Hardware DDC + * 1 : Use Software DDC + */ + HDMI_OUTP(HDCP_DDC_CTRL_0, 0x1); + + /* + * ACK the Failure to Clear it + * 0x0124 HDCP_DDC_CTRL_1 + * [0] DDC_FAILED_ACK Write 1 to clear + * HDCP_STATUS.HDCP_DDC_FAILED + */ + hdcp_ddc_ctrl1_reg = HDMI_INP(HDCP_DDC_CTRL_1); + HDMI_OUTP(HDCP_DDC_CTRL_1, hdcp_ddc_ctrl1_reg | 0x1); + + /* Check if the FAILURE got Cleared */ + hdcp_ddc_status = HDMI_INP(HDCP_DDC_STATUS); + hdcp_ddc_status = (hdcp_ddc_status >> 16) & 0x1; + if (hdcp_ddc_status == 0x0) { + DEV_INFO("%s: HDCP DDC Failure has been cleared\n", + __func__); + } else { + DEV_WARN("%s: Error: HDCP DDC Failure DID NOT get" + "cleared\n", __func__); + } + + /* Re-Enable HDCP DDC */ + HDMI_OUTP(HDCP_DDC_CTRL_0, 0x0); + } + + if (nack0 == 0x1) { + /* + * 0x020C HDMI_DDC_CTRL + * [3] SW_STATUS_RESET Write 1 to reset HDMI_DDC_SW_STATUS + * flags, will reset SW_DONE, ABORTED, + * TIMEOUT, SW_INTERRUPTED, + * BUFFER_OVERFLOW, STOPPED_ON_NACK, NACK0, + * NACK1, NACK2, NACK3 + */ + HDMI_OUTP_ND(HDMI_DDC_CTRL, + HDMI_INP(HDMI_DDC_CTRL) | (0x1 << 3)); + msleep(20); + HDMI_OUTP_ND(HDMI_DDC_CTRL, + HDMI_INP(HDMI_DDC_CTRL) & ~(0x1 << 3)); + } + + hdcp_ddc_status = HDMI_INP(HDCP_DDC_STATUS); + + failure = (hdcp_ddc_status >> 16) & 0x1; + nack0 = (hdcp_ddc_status >> 14) & 0x1; + DEV_DBG("%s: On Exit: HDCP_DDC_STATUS = 0x%x, FAILURE = %d," + "NACK0 = %d\n", __func__ , hdcp_ddc_status, failure, nack0); +} + + +static int hdcp_authentication_part1(void) +{ + int ret = 0; + boolean is_match; + boolean is_part1_done = FALSE; + uint32 timeout_count; + uint8 bcaps; + uint8 aksv[5]; + uint32 qfprom_aksv_0, qfprom_aksv_1, link0_aksv_0, link0_aksv_1; + uint8 bksv[5]; + uint32 link0_bksv_0, link0_bksv_1; + uint8 an[8]; + uint32 link0_an_0, link0_an_1; + uint32 hpd_int_status, hpd_int_ctrl; + + + static uint8 buf[0xFF]; + memset(buf, 0, sizeof(buf)); + + if (!is_part1_done) { + is_part1_done = TRUE; + + /* Fetch aksv from QFprom, this info should be public. */ + qfprom_aksv_0 = inpdw(QFPROM_BASE + 0x000060D8); + qfprom_aksv_1 = inpdw(QFPROM_BASE + 0x000060DC); + + /* copy an and aksv to byte arrays for transmission */ + aksv[0] = qfprom_aksv_0 & 0xFF; + aksv[1] = (qfprom_aksv_0 >> 8) & 0xFF; + aksv[2] = (qfprom_aksv_0 >> 16) & 0xFF; + aksv[3] = (qfprom_aksv_0 >> 24) & 0xFF; + aksv[4] = qfprom_aksv_1 & 0xFF; + /* check there are 20 ones in AKSV */ + if (hdmi_msm_count_one(aksv, 5) != 20) { + DEV_ERR("HDCP: AKSV read from QFPROM doesn't have " + "20 1's and 20 0's, FAIL (AKSV=%02x%08x)\n", + qfprom_aksv_1, qfprom_aksv_0); + ret = -EINVAL; + goto error; + } + DEV_DBG("HDCP: AKSV=%02x%08x\n", qfprom_aksv_1, qfprom_aksv_0); + + /* 0x0288 HDCP_SW_LOWER_AKSV + [31:0] LOWER_AKSV */ + /* 0x0284 HDCP_SW_UPPER_AKSV + [7:0] UPPER_AKSV */ + + /* This is the lower 32 bits of the SW + * injected AKSV value(AKSV[31:0]) read + * from the EFUSE. It is needed for HDCP + * authentication and must be written + * before enabling HDCP. */ + HDMI_OUTP(0x0288, qfprom_aksv_0); + HDMI_OUTP(0x0284, qfprom_aksv_1); + + msm_hdmi_init_ddc(); + + /* read Bcaps at 0x40 in HDCP Port */ + ret = hdmi_msm_ddc_read(0x74, 0x40, &bcaps, 1, 5, "Bcaps", + TRUE); + if (ret) { + DEV_ERR("%s(%d): Read Bcaps failed", __func__, + __LINE__); + goto error; + } + DEV_DBG("HDCP: Bcaps=%02x\n", bcaps); + + /* HDCP setup prior to HDCP enabled */ + + /* 0x0148 HDCP_RCVPORT_DATA4 + [15:8] LINK0_AINFO + [7:0] LINK0_AKSV_1 */ + /* LINK0_AINFO = 0x2 FEATURE 1.1 on. + * = 0x0 FEATURE 1.1 off*/ + HDMI_OUTP(0x0148, 0x0); + + /* 0x012C HDCP_ENTROPY_CTRL0 + [31:0] BITS_OF_INFLUENCE_0 */ + /* 0x025C HDCP_ENTROPY_CTRL1 + [31:0] BITS_OF_INFLUENCE_1 */ + HDMI_OUTP(0x012C, 0xB1FFB0FF); + HDMI_OUTP(0x025C, 0xF00DFACE); + + /* 0x0114 HDCP_DEBUG_CTRL + [2] DEBUG_RNG_CIPHER + else default 0 */ + HDMI_OUTP(0x0114, HDMI_INP(0x0114) & 0xFFFFFFFB); + + /* 0x0110 HDCP_CTRL + [8] ENCRYPTION_ENABLE + [0] ENABLE */ + /* encryption_enable | enable */ + HDMI_OUTP(0x0110, (1 << 8) | (1 << 0)); + + /* + * Check to see if a HDCP DDC Failure is indicated in + * HDCP_DDC_STATUS. If yes, clear it. + */ + check_and_clear_HDCP_DDC_Failure(); + + /* 0x0118 HDCP_INT_CTRL + * [2] AUTH_SUCCESS_MASK [R/W] Mask bit for\ + * HDCP Authentication + * Success interrupt - set to 1 to enable interrupt + * + * [6] AUTH_FAIL_MASK [R/W] Mask bit for HDCP + * Authentication + * Lost interrupt set to 1 to enable interrupt + * + * [7] AUTH_FAIL_INFO_ACK [W] Acknwledge bit for HDCP + * Auth Failure Info field - write 1 to clear + * + * [10] DDC_XFER_REQ_MASK [R/W] Mask bit for HDCP\ + * DDC Transfer + * Request interrupt - set to 1 to enable interrupt + * + * [14] DDC_XFER_DONE_MASK [R/W] Mask bit for HDCP\ + * DDC Transfer + * done interrupt - set to 1 to enable interrupt */ + /* enable all HDCP ints */ + HDMI_OUTP(0x0118, (1 << 2) | (1 << 6) | (1 << 7)); + + /* 0x011C HDCP_LINK0_STATUS + [8] AN_0_READY + [9] AN_1_READY */ + /* wait for an0 and an1 ready bits to be set in LINK0_STATUS */ + + mutex_lock(&hdcp_auth_state_mutex); + timeout_count = 100; + while (((HDMI_INP_ND(0x011C) & (0x3 << 8)) != (0x3 << 8)) + && timeout_count--) + msleep(20); + if (!timeout_count) { + ret = -ETIMEDOUT; + DEV_ERR("%s(%d): timedout, An0=%d, An1=%d\n", + __func__, __LINE__, + (HDMI_INP_ND(0x011C) & BIT(8)) >> 8, + (HDMI_INP_ND(0x011C) & BIT(9)) >> 9); + mutex_unlock(&hdcp_auth_state_mutex); + goto error; + } + + /* 0x0168 HDCP_RCVPORT_DATA12 + [23:8] BSTATUS + [7:0] BCAPS */ + HDMI_OUTP(0x0168, bcaps); + + /* 0x014C HDCP_RCVPORT_DATA5 + [31:0] LINK0_AN_0 */ + /* read an0 calculation */ + link0_an_0 = HDMI_INP(0x014C); + + /* 0x0150 HDCP_RCVPORT_DATA6 + [31:0] LINK0_AN_1 */ + /* read an1 calculation */ + link0_an_1 = HDMI_INP(0x0150); + mutex_unlock(&hdcp_auth_state_mutex); + + /* three bits 28..30 */ + hdcp_key_state((HDMI_INP(0x011C) >> 28) & 0x7); + + /* 0x0144 HDCP_RCVPORT_DATA3 + [31:0] LINK0_AKSV_0 public key + 0x0148 HDCP_RCVPORT_DATA4 + [15:8] LINK0_AINFO + [7:0] LINK0_AKSV_1 public key */ + link0_aksv_0 = HDMI_INP(0x0144); + link0_aksv_1 = HDMI_INP(0x0148); + + /* copy an and aksv to byte arrays for transmission */ + aksv[0] = link0_aksv_0 & 0xFF; + aksv[1] = (link0_aksv_0 >> 8) & 0xFF; + aksv[2] = (link0_aksv_0 >> 16) & 0xFF; + aksv[3] = (link0_aksv_0 >> 24) & 0xFF; + aksv[4] = link0_aksv_1 & 0xFF; + + an[0] = link0_an_0 & 0xFF; + an[1] = (link0_an_0 >> 8) & 0xFF; + an[2] = (link0_an_0 >> 16) & 0xFF; + an[3] = (link0_an_0 >> 24) & 0xFF; + an[4] = link0_an_1 & 0xFF; + an[5] = (link0_an_1 >> 8) & 0xFF; + an[6] = (link0_an_1 >> 16) & 0xFF; + an[7] = (link0_an_1 >> 24) & 0xFF; + + /* Write An 8 bytes to offset 0x18 */ + ret = hdmi_msm_ddc_write(0x74, 0x18, an, 8, "An"); + if (ret) { + DEV_ERR("%s(%d): Write An failed", __func__, __LINE__); + goto error; + } + + /* Write Aksv 5 bytes to offset 0x10 */ + ret = hdmi_msm_ddc_write(0x74, 0x10, aksv, 5, "Aksv"); + if (ret) { + DEV_ERR("%s(%d): Write Aksv failed", __func__, + __LINE__); + goto error; + } + DEV_DBG("HDCP: Link0-AKSV=%02x%08x\n", + link0_aksv_1 & 0xFF, link0_aksv_0); + + /* Read Bksv 5 bytes at 0x00 in HDCP port */ + ret = hdmi_msm_ddc_read(0x74, 0x00, bksv, 5, 5, "Bksv", TRUE); + if (ret) { + DEV_ERR("%s(%d): Read BKSV failed", __func__, __LINE__); + goto error; + } + /* check there are 20 ones in BKSV */ + if (hdmi_msm_count_one(bksv, 5) != 20) { + DEV_ERR("HDCP: BKSV read from Sink doesn't have " + "20 1's and 20 0's, FAIL (BKSV=" + "%02x%02x%02x%02x%02x)\n", + bksv[4], bksv[3], bksv[2], bksv[1], bksv[0]); + ret = -EINVAL; + goto error; + } + + link0_bksv_0 = bksv[3]; + link0_bksv_0 = (link0_bksv_0 << 8) | bksv[2]; + link0_bksv_0 = (link0_bksv_0 << 8) | bksv[1]; + link0_bksv_0 = (link0_bksv_0 << 8) | bksv[0]; + link0_bksv_1 = bksv[4]; + DEV_DBG("HDCP: BKSV=%02x%08x\n", link0_bksv_1, link0_bksv_0); + + /* 0x0134 HDCP_RCVPORT_DATA0 + [31:0] LINK0_BKSV_0 */ + HDMI_OUTP(0x0134, link0_bksv_0); + /* 0x0138 HDCP_RCVPORT_DATA1 + [31:0] LINK0_BKSV_1 */ + HDMI_OUTP(0x0138, link0_bksv_1); + DEV_DBG("HDCP: Link0-BKSV=%02x%08x\n", link0_bksv_1, + link0_bksv_0); + + /* HDMI_HPD_INT_STATUS[0x0250] */ + hpd_int_status = HDMI_INP_ND(0x0250); + /* HDMI_HPD_INT_CTRL[0x0254] */ + hpd_int_ctrl = HDMI_INP_ND(0x0254); + DEV_DBG("[SR-DEUG]: HPD_INTR_CTRL=[%u] HPD_INTR_STATUS=[%u] " + "before reading R0'\n", hpd_int_ctrl, hpd_int_status); + + /* + * HDCP Compliace Test case 1B-01: + * Wait here until all the ksv bytes have been + * read from the KSV FIFO register. + */ + msleep(125); + + /* Reading R0' 2 bytes at offset 0x08 */ + ret = hdmi_msm_ddc_read(0x74, 0x08, buf, 2, 5, "RO'", TRUE); + if (ret) { + DEV_ERR("%s(%d): Read RO's failed", __func__, + __LINE__); + goto error; + } + + DEV_DBG("HDCP: R0'=%02x%02x\n", buf[1], buf[0]); + INIT_COMPLETION(hdmi_msm_state->hdcp_success_done); + /* 0x013C HDCP_RCVPORT_DATA2_0 + [15:0] LINK0_RI */ + HDMI_OUTP(0x013C, (((uint32)buf[1]) << 8) | buf[0]); + + timeout_count = wait_for_completion_interruptible_timeout( + &hdmi_msm_state->hdcp_success_done, HZ*2); + + if (!timeout_count) { + ret = -ETIMEDOUT; + is_match = HDMI_INP(0x011C) & BIT(12); + DEV_ERR("%s(%d): timedout, Link0=<%s>\n", __func__, + __LINE__, + is_match ? "RI_MATCH" : "No RI Match INTR in time"); + if (!is_match) + goto error; + } + + /* 0x011C HDCP_LINK0_STATUS + [12] RI_MATCHES [0] MISMATCH, [1] MATCH + [0] AUTH_SUCCESS */ + /* Checking for RI, R0 Match */ + /* RI_MATCHES */ + if ((HDMI_INP(0x011C) & BIT(12)) != BIT(12)) { + ret = -EINVAL; + DEV_ERR("%s: HDCP_LINK0_STATUS[RI_MATCHES]: MISMATCH\n", + __func__); + goto error; + } + + DEV_INFO("HDCP: authentication part I, successful\n"); + is_part1_done = FALSE; + return 0; +error: + DEV_ERR("[%s]: HDCP Reauthentication\n", __func__); + is_part1_done = FALSE; + return ret; + } else { + return 1; + } +} + +static int hdmi_msm_transfer_v_h(void) +{ + /* Read V'.HO 4 Byte at offset 0x20 */ + char what[20]; + int ret; + uint8 buf[4]; + + snprintf(what, sizeof(what), "V' H0"); + ret = hdmi_msm_ddc_read(0x74, 0x20, buf, 4, 5, what, TRUE); + if (ret) { + DEV_ERR("%s: Read %s failed", __func__, what); + return ret; + } + DEV_DBG("buf[0]= %x , buf[1] = %x , buf[2] = %x , buf[3] = %x\n ", + buf[0] , buf[1] , buf[2] , buf[3]); + + /* 0x0154 HDCP_RCVPORT_DATA7 + [31:0] V_HO */ + HDMI_OUTP(0x0154 , + (buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0])); + + snprintf(what, sizeof(what), "V' H1"); + ret = hdmi_msm_ddc_read(0x74, 0x24, buf, 4, 5, what, TRUE); + if (ret) { + DEV_ERR("%s: Read %s failed", __func__, what); + return ret; + } + DEV_DBG("buf[0]= %x , buf[1] = %x , buf[2] = %x , buf[3] = %x\n ", + buf[0] , buf[1] , buf[2] , buf[3]); + + /* 0x0158 HDCP_RCVPORT_ DATA8 + [31:0] V_H1 */ + HDMI_OUTP(0x0158, + (buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0])); + + + snprintf(what, sizeof(what), "V' H2"); + ret = hdmi_msm_ddc_read(0x74, 0x28, buf, 4, 5, what, TRUE); + if (ret) { + DEV_ERR("%s: Read %s failed", __func__, what); + return ret; + } + DEV_DBG("buf[0]= %x , buf[1] = %x , buf[2] = %x , buf[3] = %x\n ", + buf[0] , buf[1] , buf[2] , buf[3]); + + /* 0x015c HDCP_RCVPORT_DATA9 + [31:0] V_H2 */ + HDMI_OUTP(0x015c , + (buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0])); + + snprintf(what, sizeof(what), "V' H3"); + ret = hdmi_msm_ddc_read(0x74, 0x2c, buf, 4, 5, what, TRUE); + if (ret) { + DEV_ERR("%s: Read %s failed", __func__, what); + return ret; + } + DEV_DBG("buf[0]= %x , buf[1] = %x , buf[2] = %x , buf[3] = %x\n ", + buf[0] , buf[1] , buf[2] , buf[3]); + + /* 0x0160 HDCP_RCVPORT_DATA10 + [31:0] V_H3 */ + HDMI_OUTP(0x0160, + (buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0])); + + snprintf(what, sizeof(what), "V' H4"); + ret = hdmi_msm_ddc_read(0x74, 0x30, buf, 4, 5, what, TRUE); + if (ret) { + DEV_ERR("%s: Read %s failed", __func__, what); + return ret; + } + DEV_DBG("buf[0]= %x , buf[1] = %x , buf[2] = %x , buf[3] = %x\n ", + buf[0] , buf[1] , buf[2] , buf[3]); + /* 0x0164 HDCP_RCVPORT_DATA11 + [31:0] V_H4 */ + HDMI_OUTP(0x0164, + (buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0])); + + return 0; +} + +static int hdcp_authentication_part2(void) +{ + int ret = 0; + uint32 timeout_count; + int i = 0; + int cnt = 0; + uint bstatus; + uint8 bcaps; + uint32 down_stream_devices; + uint32 ksv_bytes; + + static uint8 buf[0xFF]; + static uint8 kvs_fifo[5 * 127]; + + boolean max_devs_exceeded = 0; + boolean max_cascade_exceeded = 0; + + boolean ksv_done = FALSE; + + memset(buf, 0, sizeof(buf)); + memset(kvs_fifo, 0, sizeof(kvs_fifo)); + + /* wait until READY bit is set in bcaps */ + timeout_count = 50; + do { + timeout_count--; + /* read bcaps 1 Byte at offset 0x40 */ + ret = hdmi_msm_ddc_read(0x74, 0x40, &bcaps, 1, 1, + "Bcaps", FALSE); + if (ret) { + DEV_ERR("%s(%d): Read Bcaps failed", __func__, + __LINE__); + goto error; + } + msleep(100); + } while ((0 == (bcaps & 0x20)) && timeout_count); /* READY (Bit 5) */ + if (!timeout_count) { + ret = -ETIMEDOUT; + DEV_ERR("%s:timedout(1)", __func__); + goto error; + } + + /* read bstatus 2 bytes at offset 0x41 */ + + ret = hdmi_msm_ddc_read(0x74, 0x41, buf, 2, 5, "Bstatus", FALSE); + if (ret) { + DEV_ERR("%s(%d): Read Bstatus failed", __func__, __LINE__); + goto error; + } + bstatus = buf[1]; + bstatus = (bstatus << 8) | buf[0]; + /* 0x0168 DCP_RCVPORT_DATA12 + [7:0] BCAPS + [23:8 BSTATUS */ + HDMI_OUTP(0x0168, bcaps | (bstatus << 8)); + /* BSTATUS [6:0] DEVICE_COUNT Number of HDMI device attached to repeater + * - see HDCP spec */ + down_stream_devices = bstatus & 0x7F; + + if (down_stream_devices == 0x0) { + /* There isn't any devices attaced to the Repeater */ + DEV_ERR("%s: there isn't any devices attached to the " + "Repeater\n", __func__); + ret = -EINVAL; + goto error; + } + + /* + * HDCP Compliance 1B-05: + * Check if no. of devices connected to repeater + * exceed max_devices_connected from bit 7 of Bstatus. + */ + max_devs_exceeded = (bstatus & 0x80) >> 7; + if (max_devs_exceeded == 0x01) { + DEV_ERR("%s: Number of devs connected to repeater " + "exceeds max_devs\n", __func__); + ret = -EINVAL; + goto hdcp_error; + } + + /* + * HDCP Compliance 1B-06: + * Check if no. of cascade connected to repeater + * exceed max_cascade_connected from bit 11 of Bstatus. + */ + max_cascade_exceeded = (bstatus & 0x800) >> 11; + if (max_cascade_exceeded == 0x01) { + DEV_ERR("%s: Number of cascade connected to repeater " + "exceeds max_cascade\n", __func__); + ret = -EINVAL; + goto hdcp_error; + } + + /* Read KSV FIFO over DDC + * Key Slection vector FIFO + * Used to pull downstream KSVs from HDCP Repeaters. + * All bytes (DEVICE_COUNT * 5) must be read in a single, + * auto incrementing access. + * All bytes read as 0x00 for HDCP Receivers that are not + * HDCP Repeaters (REPEATER == 0). */ + ksv_bytes = 5 * down_stream_devices; + /* Reading KSV FIFO / KSV FIFO */ + ksv_done = FALSE; + + ret = hdmi_msm_ddc_read(0x74, 0x43, kvs_fifo, ksv_bytes, 5, + "KSV FIFO", TRUE); + do { + if (ret) { + DEV_ERR("%s(%d): Read KSV FIFO failed", + __func__, __LINE__); + /* + * HDCP Compliace Test case 1B-01: + * Wait here until all the ksv bytes have been + * read from the KSV FIFO register. + */ + msleep(25); + } else { + ksv_done = TRUE; + } + cnt++; + } while (!ksv_done && cnt != 20); + + if (ksv_done == FALSE) + goto error; + + ret = hdmi_msm_transfer_v_h(); + if (ret) + goto error; + + /* Next: Write KSV FIFO to HDCP_SHA_DATA. + * This is done 1 byte at time starting with the LSB. + * On the very last byte write, + * the HDCP_SHA_DATA_DONE bit[0] + */ + + /* 0x023C HDCP_SHA_CTRL + [0] RESET [0] Enable, [1] Reset + [4] SELECT [0] DIGA_HDCP, [1] DIGB_HDCP */ + /* reset SHA engine */ + HDMI_OUTP(0x023C, 1); + /* enable SHA engine, SEL=DIGA_HDCP */ + HDMI_OUTP(0x023C, 0); + + for (i = 0; i < ksv_bytes - 1; i++) { + /* Write KSV byte and do not set DONE bit[0] */ + HDMI_OUTP_ND(0x0244, kvs_fifo[i] << 16); + + /* Once 64 bytes have been written, we need to poll for + * HDCP_SHA_BLOCK_DONE before writing any further + */ + if (i && !((i+1)%64)) { + timeout_count = 100; + while (!(HDMI_INP_ND(0x0240) & 0x1) + && (--timeout_count)) { + DEV_DBG("HDCP Auth Part II: Waiting for the " + "computation of the current 64 byte to " + "complete. HDCP_SHA_STATUS=%08x. " + "timeout_count=%d\n", + HDMI_INP_ND(0x0240), timeout_count); + msleep(20); + } + if (!timeout_count) { + ret = -ETIMEDOUT; + DEV_ERR("%s(%d): timedout", __func__, __LINE__); + goto error; + } + } + + } + + /* Write l to DONE bit[0] */ + HDMI_OUTP_ND(0x0244, (kvs_fifo[ksv_bytes - 1] << 16) | 0x1); + + /* 0x0240 HDCP_SHA_STATUS + [4] COMP_DONE */ + /* Now wait for HDCP_SHA_COMP_DONE */ + timeout_count = 100; + while ((0x10 != (HDMI_INP_ND(0x0240) & 0xFFFFFF10)) && --timeout_count) + msleep(20); + + if (!timeout_count) { + ret = -ETIMEDOUT; + DEV_ERR("%s(%d): timedout", __func__, __LINE__); + goto error; + } + + /* 0x011C HDCP_LINK0_STATUS + [20] V_MATCHES */ + timeout_count = 100; + while (((HDMI_INP_ND(0x011C) & (1 << 20)) != (1 << 20)) + && --timeout_count) { + msleep(20); + } + + if (!timeout_count) { + ret = -ETIMEDOUT; + DEV_ERR("%s(%d): timedout", __func__, __LINE__); + goto error; + } + + DEV_INFO("HDCP: authentication part II, successful\n"); + +hdcp_error: +error: + return ret; +} + +static int hdcp_authentication_part3(uint32 found_repeater) +{ + int ret = 0; + int poll = 3000; + while (poll) { + /* 0x011C HDCP_LINK0_STATUS + [30:28] KEYS_STATE = 3 = "Valid" + [24] RO_COMPUTATION_DONE [0] Not Done, [1] Done + [20] V_MATCHES [0] Mismtach, [1] Match + [12] RI_MATCHES [0] Mismatch, [1] Match + [0] AUTH_SUCCESS */ + if (HDMI_INP_ND(0x011C) != (0x31001001 | + (found_repeater << 20))) { + DEV_ERR("HDCP: autentication part III, FAILED, " + "Link Status=%08x\n", HDMI_INP(0x011C)); + ret = -EINVAL; + goto error; + } + poll--; + } + + DEV_INFO("HDCP: authentication part III, successful\n"); + +error: + return ret; +} + +static void hdmi_msm_hdcp_enable(void) +{ + int ret = 0; + uint8 bcaps; + uint32 found_repeater = 0x0; + char *envp[2]; + + if (!hdmi_msm_has_hdcp()) { + switch_set_state(&external_common_state->sdev, 1); + DEV_INFO("Hdmi state switch to %d: %s\n", + external_common_state->sdev.state, __func__); + return; + } + + mutex_lock(&hdmi_msm_state_mutex); + hdmi_msm_state->hdcp_activating = TRUE; + mutex_unlock(&hdmi_msm_state_mutex); + + fill_black_screen(); + + mutex_lock(&hdcp_auth_state_mutex); + /* + * Initialize this to zero here to make + * sure HPD has not happened yet + */ + hdmi_msm_state->hpd_during_auth = FALSE; + /* This flag prevents other threads from re-authenticating + * after we've just authenticated (i.e., finished part3) + * We probably need to protect this in a mutex lock */ + hdmi_msm_state->full_auth_done = FALSE; + mutex_unlock(&hdcp_auth_state_mutex); + + /* PART I Authentication*/ + ret = hdcp_authentication_part1(); + if (ret) + goto error; + + /* PART II Authentication*/ + /* read Bcaps at 0x40 in HDCP Port */ + ret = hdmi_msm_ddc_read(0x74, 0x40, &bcaps, 1, 5, "Bcaps", FALSE); + if (ret) { + DEV_ERR("%s(%d): Read Bcaps failed\n", __func__, __LINE__); + goto error; + } + DEV_DBG("HDCP: Bcaps=0x%02x (%s)\n", bcaps, + (bcaps & BIT(6)) ? "repeater" : "no repeater"); + + /* if REPEATER (Bit 6), perform Part2 Authentication */ + if (bcaps & BIT(6)) { + found_repeater = 0x1; + ret = hdcp_authentication_part2(); + if (ret) + goto error; + } else + DEV_INFO("HDCP: authentication part II skipped, no repeater\n"); + + /* PART III Authentication*/ + ret = hdcp_authentication_part3(found_repeater); + if (ret) + goto error; + + unfill_black_screen(); + + external_common_state->hdcp_active = TRUE; + mutex_lock(&hdmi_msm_state_mutex); + hdmi_msm_state->hdcp_activating = FALSE; + mutex_unlock(&hdmi_msm_state_mutex); + + mutex_lock(&hdcp_auth_state_mutex); + /* + * This flag prevents other threads from re-authenticating + * after we've just authenticated (i.e., finished part3) + */ + hdmi_msm_state->full_auth_done = TRUE; + mutex_unlock(&hdcp_auth_state_mutex); + + if (!hdmi_msm_is_dvi_mode()) { + DEV_INFO("HDMI HPD: sense : send HDCP_PASS\n"); + envp[0] = "HDCP_STATE=PASS"; + envp[1] = NULL; + kobject_uevent_env(external_common_state->uevent_kobj, + KOBJ_CHANGE, envp); + } + switch_set_state(&external_common_state->sdev, 1); + DEV_INFO("Hdmi state switch to %d: %s\n", + external_common_state->sdev.state, __func__); + return; + +error: + mutex_lock(&hdmi_msm_state_mutex); + hdmi_msm_state->hdcp_activating = FALSE; + mutex_unlock(&hdmi_msm_state_mutex); + if (hdmi_msm_state->hpd_during_auth) { + DEV_WARN("Calling Deauthentication: HPD occured during " + "authentication from [%s]\n", __func__); + hdcp_deauthenticate(); + mutex_lock(&hdcp_auth_state_mutex); + hdmi_msm_state->hpd_during_auth = FALSE; + mutex_unlock(&hdcp_auth_state_mutex); + } else { + DEV_WARN("[DEV_DBG]: Calling reauth from [%s]\n", __func__); + if (hdmi_msm_state->panel_power_on) + queue_work(hdmi_work_queue, + &hdmi_msm_state->hdcp_reauth_work); + } + switch_set_state(&external_common_state->sdev, 0); + DEV_INFO("Hdmi state switch to %d: %s\n", + external_common_state->sdev.state, __func__); +} +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ + +static void hdmi_msm_video_setup(int video_format) +{ + uint32 total_v = 0; + uint32 total_h = 0; + uint32 start_h = 0; + uint32 end_h = 0; + uint32 start_v = 0; + uint32 end_v = 0; + const struct hdmi_disp_mode_timing_type *timing = + hdmi_common_get_supported_mode(video_format); + + /* timing register setup */ + if (timing == NULL) { + DEV_ERR("video format not supported: %d\n", video_format); + return; + } + + /* Hsync Total and Vsync Total */ + total_h = timing->active_h + timing->front_porch_h + + timing->back_porch_h + timing->pulse_width_h - 1; + total_v = timing->active_v + timing->front_porch_v + + timing->back_porch_v + timing->pulse_width_v - 1; + /* 0x02C0 HDMI_TOTAL + [27:16] V_TOTAL Vertical Total + [11:0] H_TOTAL Horizontal Total */ + HDMI_OUTP(0x02C0, ((total_v << 16) & 0x0FFF0000) + | ((total_h << 0) & 0x00000FFF)); + + /* Hsync Start and Hsync End */ + start_h = timing->back_porch_h + timing->pulse_width_h; + end_h = (total_h + 1) - timing->front_porch_h; + /* 0x02B4 HDMI_ACTIVE_H + [27:16] END Horizontal end + [11:0] START Horizontal start */ + HDMI_OUTP(0x02B4, ((end_h << 16) & 0x0FFF0000) + | ((start_h << 0) & 0x00000FFF)); + + start_v = timing->back_porch_v + timing->pulse_width_v - 1; + end_v = total_v - timing->front_porch_v; + /* 0x02B8 HDMI_ACTIVE_V + [27:16] END Vertical end + [11:0] START Vertical start */ + HDMI_OUTP(0x02B8, ((end_v << 16) & 0x0FFF0000) + | ((start_v << 0) & 0x00000FFF)); + + if (timing->interlaced) { + /* 0x02C4 HDMI_V_TOTAL_F2 + [11:0] V_TOTAL_F2 Vertical total for field2 */ + HDMI_OUTP(0x02C4, ((total_v + 1) << 0) & 0x00000FFF); + + /* 0x02BC HDMI_ACTIVE_V_F2 + [27:16] END_F2 Vertical end for field2 + [11:0] START_F2 Vertical start for Field2 */ + HDMI_OUTP(0x02BC, + (((start_v + 1) << 0) & 0x00000FFF) + | (((end_v + 1) << 16) & 0x0FFF0000)); + } else { + /* HDMI_V_TOTAL_F2 */ + HDMI_OUTP(0x02C4, 0); + /* HDMI_ACTIVE_V_F2 */ + HDMI_OUTP(0x02BC, 0); + } + + hdmi_frame_ctrl_cfg(timing); +} + +struct hdmi_msm_audio_acr { + uint32 n; /* N parameter for clock regeneration */ + uint32 cts; /* CTS parameter for clock regeneration */ +}; + +struct hdmi_msm_audio_arcs { + uint32 pclk; + struct hdmi_msm_audio_acr lut[MSM_HDMI_SAMPLE_RATE_MAX]; +}; + +#define HDMI_MSM_AUDIO_ARCS(pclk, ...) { pclk, __VA_ARGS__ } + +/* Audio constants lookup table for hdmi_msm_audio_acr_setup */ +/* Valid Pixel-Clock rates: 25.2MHz, 27MHz, 27.03MHz, 74.25MHz, 148.5MHz */ +static const struct hdmi_msm_audio_arcs hdmi_msm_audio_acr_lut[] = { + /* 25.200MHz */ + HDMI_MSM_AUDIO_ARCS(25200, { + {4096, 25200}, {6272, 28000}, {6144, 25200}, {12544, 28000}, + {12288, 25200}, {25088, 28000}, {24576, 25200} }), + /* 27.000MHz */ + HDMI_MSM_AUDIO_ARCS(27000, { + {4096, 27000}, {6272, 30000}, {6144, 27000}, {12544, 30000}, + {12288, 27000}, {25088, 30000}, {24576, 27000} }), + /* 27.027MHz */ + HDMI_MSM_AUDIO_ARCS(27030, { + {4096, 27027}, {6272, 30030}, {6144, 27027}, {12544, 30030}, + {12288, 27027}, {25088, 30030}, {24576, 27027} }), + /* 74.250MHz */ + HDMI_MSM_AUDIO_ARCS(74250, { + {4096, 74250}, {6272, 82500}, {6144, 74250}, {12544, 82500}, + {12288, 74250}, {25088, 82500}, {24576, 74250} }), + /* 148.500MHz */ + HDMI_MSM_AUDIO_ARCS(148500, { + {4096, 148500}, {6272, 165000}, {6144, 148500}, {12544, 165000}, + {12288, 148500}, {25088, 165000}, {24576, 148500} }), +}; + +static void hdmi_msm_audio_acr_setup(boolean enabled, int video_format, + int audio_sample_rate, int num_of_channels) +{ + /* Read first before writing */ + /* HDMI_ACR_PKT_CTRL[0x0024] */ + uint32 acr_pck_ctrl_reg = HDMI_INP(0x0024); + + if (enabled) { + const struct hdmi_disp_mode_timing_type *timing = + hdmi_common_get_supported_mode(video_format); + const struct hdmi_msm_audio_arcs *audio_arc = + &hdmi_msm_audio_acr_lut[0]; + const int lut_size = sizeof(hdmi_msm_audio_acr_lut) + /sizeof(*hdmi_msm_audio_acr_lut); + uint32 i, n, cts, layout, multiplier, aud_pck_ctrl_2_reg; + + if (timing == NULL) { + DEV_WARN("%s: video format %d not supported\n", + __func__, video_format); + return; + } + + for (i = 0; i < lut_size; + audio_arc = &hdmi_msm_audio_acr_lut[++i]) { + if (audio_arc->pclk == timing->pixel_freq) + break; + } + if (i >= lut_size) { + DEV_WARN("%s: pixel clock %d not supported\n", __func__, + timing->pixel_freq); + return; + } + + n = audio_arc->lut[audio_sample_rate].n; + cts = audio_arc->lut[audio_sample_rate].cts; + layout = (MSM_HDMI_AUDIO_CHANNEL_2 == num_of_channels) ? 0 : 1; + + if ((MSM_HDMI_SAMPLE_RATE_192KHZ == audio_sample_rate) || + (MSM_HDMI_SAMPLE_RATE_176_4KHZ == audio_sample_rate)) { + multiplier = 4; + n >>= 2; /* divide N by 4 and use multiplier */ + } else if ((MSM_HDMI_SAMPLE_RATE_96KHZ == audio_sample_rate) || + (MSM_HDMI_SAMPLE_RATE_88_2KHZ == audio_sample_rate)) { + multiplier = 2; + n >>= 1; /* divide N by 2 and use multiplier */ + } else { + multiplier = 1; + } + DEV_DBG("%s: n=%u, cts=%u, layout=%u\n", __func__, n, cts, + layout); + + /* AUDIO_PRIORITY | SOURCE */ + acr_pck_ctrl_reg |= 0x80000100; + /* N_MULTIPLE(multiplier) */ + acr_pck_ctrl_reg |= (multiplier & 7) << 16; + + if ((MSM_HDMI_SAMPLE_RATE_48KHZ == audio_sample_rate) || + (MSM_HDMI_SAMPLE_RATE_96KHZ == audio_sample_rate) || + (MSM_HDMI_SAMPLE_RATE_192KHZ == audio_sample_rate)) { + /* SELECT(3) */ + acr_pck_ctrl_reg |= 3 << 4; + /* CTS_48 */ + cts <<= 12; + + /* CTS: need to determine how many fractional bits */ + /* HDMI_ACR_48_0 */ + HDMI_OUTP(0x00D4, cts); + /* N */ + /* HDMI_ACR_48_1 */ + HDMI_OUTP(0x00D8, n); + } else if ((MSM_HDMI_SAMPLE_RATE_44_1KHZ == audio_sample_rate) + || (MSM_HDMI_SAMPLE_RATE_88_2KHZ == + audio_sample_rate) + || (MSM_HDMI_SAMPLE_RATE_176_4KHZ == + audio_sample_rate)) { + /* SELECT(2) */ + acr_pck_ctrl_reg |= 2 << 4; + /* CTS_44 */ + cts <<= 12; + + /* CTS: need to determine how many fractional bits */ + /* HDMI_ACR_44_0 */ + HDMI_OUTP(0x00CC, cts); + /* N */ + /* HDMI_ACR_44_1 */ + HDMI_OUTP(0x00D0, n); + } else { /* default to 32k */ + /* SELECT(1) */ + acr_pck_ctrl_reg |= 1 << 4; + /* CTS_32 */ + cts <<= 12; + + /* CTS: need to determine how many fractional bits */ + /* HDMI_ACR_32_0 */ + HDMI_OUTP(0x00C4, cts); + /* N */ + /* HDMI_ACR_32_1 */ + HDMI_OUTP(0x00C8, n); + } + /* Payload layout depends on number of audio channels */ + /* LAYOUT_SEL(layout) */ + aud_pck_ctrl_2_reg = 1 | (layout << 1); + /* override | layout */ + /* HDMI_AUDIO_PKT_CTRL2[0x00044] */ + HDMI_OUTP(0x00044, aud_pck_ctrl_2_reg); + + /* SEND | CONT */ + acr_pck_ctrl_reg |= 0x00000003; + } else { + /* ~(SEND | CONT) */ + acr_pck_ctrl_reg &= ~0x00000003; + } + /* HDMI_ACR_PKT_CTRL[0x0024] */ + HDMI_OUTP(0x0024, acr_pck_ctrl_reg); +} + +static void hdmi_msm_outpdw_chk(uint32 offset, uint32 data) +{ + uint32 check, i = 0; + +#ifdef DEBUG + HDMI_OUTP(offset, data); +#endif + do { + outpdw(MSM_HDMI_BASE+offset, data); + check = inpdw(MSM_HDMI_BASE+offset); + } while (check != data && i++ < 10); + + if (check != data) + DEV_ERR("%s: failed addr=%08x, data=%x, check=%x", + __func__, offset, data, check); +} + +static void hdmi_msm_rmw32or(uint32 offset, uint32 data) +{ + uint32 reg_data; + reg_data = inpdw(MSM_HDMI_BASE+offset); + reg_data = inpdw(MSM_HDMI_BASE+offset); + hdmi_msm_outpdw_chk(offset, reg_data | data); +} + + +#define HDMI_AUDIO_CFG 0x01D0 +#define HDMI_AUDIO_ENGINE_ENABLE 1 +#define HDMI_AUDIO_FIFO_MASK 0x000000F0 +#define HDMI_AUDIO_FIFO_WATERMARK_SHIFT 4 +#define HDMI_AUDIO_FIFO_MAX_WATER_MARK 8 + + +int hdmi_audio_enable(bool on , u32 fifo_water_mark) +{ + u32 hdmi_audio_config; + + hdmi_audio_config = HDMI_INP(HDMI_AUDIO_CFG); + + if (on) { + + if (fifo_water_mark > HDMI_AUDIO_FIFO_MAX_WATER_MARK) { + pr_err("%s : HDMI audio fifo water mark can not be more" + " than %u\n", __func__, + HDMI_AUDIO_FIFO_MAX_WATER_MARK); + return -EINVAL; + } + + /* + * Enable HDMI Audio engine. + * MUST be enabled after Audio DMA is enabled. + */ + hdmi_audio_config &= ~(HDMI_AUDIO_FIFO_MASK); + + hdmi_audio_config |= (HDMI_AUDIO_ENGINE_ENABLE | + (fifo_water_mark << HDMI_AUDIO_FIFO_WATERMARK_SHIFT)); + + } else + hdmi_audio_config &= ~(HDMI_AUDIO_ENGINE_ENABLE); + + HDMI_OUTP(HDMI_AUDIO_CFG, hdmi_audio_config); + + mb(); + pr_info("%s :HDMI_AUDIO_CFG 0x%08x\n", __func__, + HDMI_INP(HDMI_AUDIO_CFG)); + + return 0; +} +EXPORT_SYMBOL(hdmi_audio_enable); + +#define HDMI_AUDIO_PKT_CTRL 0x0020 +#define HDMI_AUDIO_SAMPLE_SEND_ENABLE 1 + +int hdmi_audio_packet_enable(bool on) +{ + u32 hdmi_audio_pkt_ctrl; + hdmi_audio_pkt_ctrl = HDMI_INP(HDMI_AUDIO_PKT_CTRL); + + if (on) + hdmi_audio_pkt_ctrl |= HDMI_AUDIO_SAMPLE_SEND_ENABLE; + else + hdmi_audio_pkt_ctrl &= ~(HDMI_AUDIO_SAMPLE_SEND_ENABLE); + + HDMI_OUTP(HDMI_AUDIO_PKT_CTRL, hdmi_audio_pkt_ctrl); + + mb(); + pr_info("%s : HDMI_AUDIO_PKT_CTRL 0x%08x\n", __func__, + HDMI_INP(HDMI_AUDIO_PKT_CTRL)); + return 0; +} +EXPORT_SYMBOL(hdmi_audio_packet_enable); + + +/* TO-DO: return -EINVAL when num_of_channels and channel_allocation + * does not match CEA 861-D spec. +*/ +int hdmi_msm_audio_info_setup(bool enabled, u32 num_of_channels, + u32 channel_allocation, u32 level_shift, bool down_mix) +{ + uint32 channel_count = 1; /* Default to 2 channels + -> See Table 17 in CEA-D spec */ + uint32 check_sum, audio_info_0_reg, audio_info_1_reg; + uint32 audio_info_ctrl_reg; + u32 aud_pck_ctrl_2_reg; + u32 layout; + + layout = (MSM_HDMI_AUDIO_CHANNEL_2 == num_of_channels) ? 0 : 1; + aud_pck_ctrl_2_reg = 1 | (layout << 1); + HDMI_OUTP(0x00044, aud_pck_ctrl_2_reg); + + /* Please see table 20 Audio InfoFrame in HDMI spec + FL = front left + FC = front Center + FR = front right + FLC = front left center + FRC = front right center + RL = rear left + RC = rear center + RR = rear right + RLC = rear left center + RRC = rear right center + LFE = low frequency effect + */ + + /* Read first then write because it is bundled with other controls */ + /* HDMI_INFOFRAME_CTRL0[0x002C] */ + audio_info_ctrl_reg = HDMI_INP(0x002C); + + if (enabled) { + switch (num_of_channels) { + case MSM_HDMI_AUDIO_CHANNEL_2: + channel_allocation = 0; /* Default to FR,FL */ + break; + case MSM_HDMI_AUDIO_CHANNEL_4: + channel_count = 3; + /* FC,LFE,FR,FL */ + channel_allocation = 0x3; + break; + case MSM_HDMI_AUDIO_CHANNEL_6: + channel_count = 5; + /* RR,RL,FC,LFE,FR,FL */ + channel_allocation = 0xB; + break; + case MSM_HDMI_AUDIO_CHANNEL_8: + channel_count = 7; + /* FRC,FLC,RR,RL,FC,LFE,FR,FL */ + channel_allocation = 0x1f; + break; + default: + pr_err("%s(): Unsupported num_of_channels = %u\n", + __func__, num_of_channels); + return -EINVAL; + break; + } + + /* Program the Channel-Speaker allocation */ + audio_info_1_reg = 0; + /* CA(channel_allocation) */ + audio_info_1_reg |= channel_allocation & 0xff; + /* Program the Level shifter */ + /* LSV(level_shift) */ + audio_info_1_reg |= (level_shift << 11) & 0x00007800; + /* Program the Down-mix Inhibit Flag */ + /* DM_INH(down_mix) */ + audio_info_1_reg |= (down_mix << 15) & 0x00008000; + + /* HDMI_AUDIO_INFO1[0x00E8] */ + HDMI_OUTP(0x00E8, audio_info_1_reg); + + /* Calculate CheckSum + Sum of all the bytes in the Audio Info Packet bytes + (See table 8.4 in HDMI spec) */ + check_sum = 0; + /* HDMI_AUDIO_INFO_FRAME_PACKET_HEADER_TYPE[0x84] */ + check_sum += 0x84; + /* HDMI_AUDIO_INFO_FRAME_PACKET_HEADER_VERSION[0x01] */ + check_sum += 1; + /* HDMI_AUDIO_INFO_FRAME_PACKET_LENGTH[0x0A] */ + check_sum += 0x0A; + check_sum += channel_count; + check_sum += channel_allocation; + /* See Table 8.5 in HDMI spec */ + check_sum += (level_shift & 0xF) << 3 | (down_mix & 0x1) << 7; + check_sum &= 0xFF; + check_sum = (uint8) (256 - check_sum); + + audio_info_0_reg = 0; + /* CHECKSUM(check_sum) */ + audio_info_0_reg |= check_sum & 0xff; + /* CC(channel_count) */ + audio_info_0_reg |= (channel_count << 8) & 0x00000700; + + /* HDMI_AUDIO_INFO0[0x00E4] */ + HDMI_OUTP(0x00E4, audio_info_0_reg); + + /* Set these flags */ + /* AUDIO_INFO_UPDATE | AUDIO_INFO_SOURCE | AUDIO_INFO_CONT + | AUDIO_INFO_SEND */ + audio_info_ctrl_reg |= 0x000000F0; + } else { + /* Clear these flags */ + /* ~(AUDIO_INFO_UPDATE | AUDIO_INFO_SOURCE | AUDIO_INFO_CONT + | AUDIO_INFO_SEND) */ + audio_info_ctrl_reg &= ~0x000000F0; + } + /* HDMI_INFOFRAME_CTRL0[0x002C] */ + HDMI_OUTP(0x002C, audio_info_ctrl_reg); + + + hdmi_msm_dump_regs("HDMI-AUDIO-ON: "); + + return 0; + +} +EXPORT_SYMBOL(hdmi_msm_audio_info_setup); + +static void hdmi_msm_en_gc_packet(boolean av_mute_is_requested) +{ + /* HDMI_GC[0x0040] */ + HDMI_OUTP(0x0040, av_mute_is_requested ? 1 : 0); + + /* GC packet enable (every frame) */ + /* HDMI_VBI_PKT_CTRL[0x0028] */ + hdmi_msm_rmw32or(0x0028, 3 << 4); +} + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_ISRC_ACP_SUPPORT +static void hdmi_msm_en_isrc_packet(boolean isrc_is_continued) +{ + static const char isrc_psuedo_data[] = + "ISRC1:0123456789isrc2=ABCDEFGHIJ"; + const uint32 * isrc_data = (const uint32 *) isrc_psuedo_data; + + /* ISRC_STATUS =0b010 | ISRC_CONTINUE | ISRC_VALID */ + /* HDMI_ISRC1_0[0x00048] */ + HDMI_OUTP(0x00048, 2 | (isrc_is_continued ? 1 : 0) << 6 | 0 << 7); + + /* HDMI_ISRC1_1[0x004C] */ + HDMI_OUTP(0x004C, *isrc_data++); + /* HDMI_ISRC1_2[0x0050] */ + HDMI_OUTP(0x0050, *isrc_data++); + /* HDMI_ISRC1_3[0x0054] */ + HDMI_OUTP(0x0054, *isrc_data++); + /* HDMI_ISRC1_4[0x0058] */ + HDMI_OUTP(0x0058, *isrc_data++); + + /* HDMI_ISRC2_0[0x005C] */ + HDMI_OUTP(0x005C, *isrc_data++); + /* HDMI_ISRC2_1[0x0060] */ + HDMI_OUTP(0x0060, *isrc_data++); + /* HDMI_ISRC2_2[0x0064] */ + HDMI_OUTP(0x0064, *isrc_data++); + /* HDMI_ISRC2_3[0x0068] */ + HDMI_OUTP(0x0068, *isrc_data); + + /* HDMI_VBI_PKT_CTRL[0x0028] */ + /* ISRC Send + Continuous */ + hdmi_msm_rmw32or(0x0028, 3 << 8); +} +#else +static void hdmi_msm_en_isrc_packet(boolean isrc_is_continued) +{ + /* + * Until end-to-end support for various audio packets + */ +} +#endif + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_ISRC_ACP_SUPPORT +static void hdmi_msm_en_acp_packet(uint32 byte1) +{ + /* HDMI_ACP[0x003C] */ + HDMI_OUTP(0x003C, 2 | 1 << 8 | byte1 << 16); + + /* HDMI_VBI_PKT_CTRL[0x0028] */ + /* ACP send, s/w source */ + hdmi_msm_rmw32or(0x0028, 3 << 12); +} +#else +static void hdmi_msm_en_acp_packet(uint32 byte1) +{ + /* + * Until end-to-end support for various audio packets + */ +} +#endif + +int hdmi_msm_audio_get_sample_rate(void) +{ + return msm_hdmi_sample_rate; +} +EXPORT_SYMBOL(hdmi_msm_audio_get_sample_rate); + +void hdmi_msm_audio_sample_rate_reset(int rate) +{ + msm_hdmi_sample_rate = rate; + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + if (hdmi_msm_has_hdcp()) + hdcp_deauthenticate(); + else +#endif + hdmi_msm_turn_on(); +} +EXPORT_SYMBOL(hdmi_msm_audio_sample_rate_reset); + +static void hdmi_msm_audio_setup(void) +{ + const int channels = MSM_HDMI_AUDIO_CHANNEL_2; + + /* (0) for clr_avmute, (1) for set_avmute */ + hdmi_msm_en_gc_packet(0); + /* (0) for isrc1 only, (1) for isrc1 and isrc2 */ + hdmi_msm_en_isrc_packet(1); + /* arbitrary bit pattern for byte1 */ + hdmi_msm_en_acp_packet(0x5a); + DEV_DBG("Not setting ACP, ISRC1, ISRC2 packets\n"); + hdmi_msm_audio_acr_setup(TRUE, + external_common_state->video_resolution, + msm_hdmi_sample_rate, channels); + hdmi_msm_audio_info_setup(TRUE, channels, 0, 0, FALSE); + + /* Turn on Audio FIFO and SAM DROP ISR */ + HDMI_OUTP(0x02CC, HDMI_INP(0x02CC) | BIT(1) | BIT(3)); + DEV_INFO("HDMI Audio: Enabled\n"); +} + +static int hdmi_msm_audio_off(void) +{ + uint32 audio_pkt_ctrl, audio_cfg; + /* Number of wait iterations */ + int i = 10; + audio_pkt_ctrl = HDMI_INP_ND(0x0020); + audio_cfg = HDMI_INP_ND(0x01D0); + + /* Checking BIT[0] of AUDIO PACKET CONTROL and */ + /* AUDIO CONFIGURATION register */ + while (((audio_pkt_ctrl & 0x00000001) || (audio_cfg & 0x00000001)) + && (i--)) { + audio_pkt_ctrl = HDMI_INP_ND(0x0020); + audio_cfg = HDMI_INP_ND(0x01D0); + DEV_DBG("%d times :: HDMI AUDIO PACKET is %08x and " + "AUDIO CFG is %08x", i, audio_pkt_ctrl, audio_cfg); + msleep(100); + if (!i) { + DEV_ERR("%s:failed to set BIT[0] AUDIO PACKET" + "CONTROL or AUDIO CONFIGURATION REGISTER\n", + __func__); + return -ETIMEDOUT; + } + } + hdmi_msm_audio_info_setup(FALSE, 0, 0, 0, FALSE); + hdmi_msm_audio_acr_setup(FALSE, 0, 0, 0); + DEV_INFO("HDMI Audio: Disabled\n"); + return 0; +} + + +static uint8 hdmi_msm_avi_iframe_lut[][16] = { +/* 480p60 480i60 576p50 576i50 720p60 720p50 1080p60 1080i60 1080p50 + 1080i50 1080p24 1080p30 1080p25 640x480p 480p60_16_9 576p50_4_3 */ + {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, /*00*/ + {0x18, 0x18, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x18, 0x28, 0x18}, /*01*/ + {0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x88, 0x00, 0x04}, /*02*/ + {0x02, 0x06, 0x11, 0x15, 0x04, 0x13, 0x10, 0x05, 0x1F, + 0x14, 0x20, 0x22, 0x21, 0x01, 0x03, 0x11}, /*03*/ + {0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*04*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*05*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*06*/ + {0xE1, 0xE1, 0x41, 0x41, 0xD1, 0xd1, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0xe1, 0xE1, 0x41}, /*07*/ + {0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x01, 0x01, 0x02}, /*08*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*09*/ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*10*/ + {0xD1, 0xD1, 0xD1, 0xD1, 0x01, 0x01, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0xD1, 0xD1}, /*11*/ + {0x02, 0x02, 0x02, 0x02, 0x05, 0x05, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x02, 0x02, 0x02} /*12*/ +}; + +static void hdmi_msm_avi_info_frame(void) +{ + /* two header + length + 13 data */ + uint8 aviInfoFrame[16]; + uint8 checksum; + uint32 sum; + uint32 regVal; + int i; + int mode = 0; + boolean use_ce_scan_info = TRUE; + + switch (external_common_state->video_resolution) { + case HDMI_VFRMT_720x480p60_4_3: + mode = 0; + break; + case HDMI_VFRMT_720x480i60_16_9: + mode = 1; + break; + case HDMI_VFRMT_720x576p50_16_9: + mode = 2; + break; + case HDMI_VFRMT_720x576i50_16_9: + mode = 3; + break; + case HDMI_VFRMT_1280x720p60_16_9: + mode = 4; + break; + case HDMI_VFRMT_1280x720p50_16_9: + mode = 5; + break; + case HDMI_VFRMT_1920x1080p60_16_9: + mode = 6; + break; + case HDMI_VFRMT_1920x1080i60_16_9: + mode = 7; + break; + case HDMI_VFRMT_1920x1080p50_16_9: + mode = 8; + break; + case HDMI_VFRMT_1920x1080i50_16_9: + mode = 9; + break; + case HDMI_VFRMT_1920x1080p24_16_9: + mode = 10; + break; + case HDMI_VFRMT_1920x1080p30_16_9: + mode = 11; + break; + case HDMI_VFRMT_1920x1080p25_16_9: + mode = 12; + break; + case HDMI_VFRMT_640x480p60_4_3: + mode = 13; + break; + case HDMI_VFRMT_720x480p60_16_9: + mode = 14; + break; + case HDMI_VFRMT_720x576p50_4_3: + mode = 15; + break; + default: + DEV_INFO("%s: mode %d not supported\n", __func__, + external_common_state->video_resolution); + return; + } + + /* InfoFrame Type = 82 */ + aviInfoFrame[0] = 0x82; + /* Version = 2 */ + aviInfoFrame[1] = 2; + /* Length of AVI InfoFrame = 13 */ + aviInfoFrame[2] = 13; + + /* Data Byte 01: 0 Y1 Y0 A0 B1 B0 S1 S0 */ + aviInfoFrame[3] = hdmi_msm_avi_iframe_lut[0][mode]; + + /* + * If the sink specified support for both underscan/overscan + * then, by default, set the underscan bit. + * Only checking underscan support for preferred format and cea formats + */ + if ((external_common_state->video_resolution == + external_common_state->preferred_video_format)) { + use_ce_scan_info = FALSE; + switch (external_common_state->pt_scan_info) { + case 0: + /* + * Need to use the info specified for the corresponding + * IT or CE format + */ + DEV_DBG("%s: No underscan information specified for the" + " preferred video format\n", __func__); + use_ce_scan_info = TRUE; + break; + case 3: + DEV_DBG("%s: Setting underscan bit for the preferred" + " video format\n", __func__); + aviInfoFrame[3] |= 0x02; + break; + default: + DEV_DBG("%s: Underscan information not set for the" + " preferred video format\n", __func__); + break; + } + } + + if (use_ce_scan_info) { + if (3 == external_common_state->ce_scan_info) { + DEV_DBG("%s: Setting underscan bit for the CE video" + " format\n", __func__); + aviInfoFrame[3] |= 0x02; + } else { + DEV_DBG("%s: Not setting underscan bit for the CE video" + " format\n", __func__); + } + } + + /* Data Byte 02: C1 C0 M1 M0 R3 R2 R1 R0 */ + aviInfoFrame[4] = hdmi_msm_avi_iframe_lut[1][mode]; + /* Data Byte 03: ITC EC2 EC1 EC0 Q1 Q0 SC1 SC0 */ + aviInfoFrame[5] = hdmi_msm_avi_iframe_lut[2][mode]; + /* Data Byte 04: 0 VIC6 VIC5 VIC4 VIC3 VIC2 VIC1 VIC0 */ + aviInfoFrame[6] = hdmi_msm_avi_iframe_lut[3][mode]; + /* Data Byte 05: 0 0 0 0 PR3 PR2 PR1 PR0 */ + aviInfoFrame[7] = hdmi_msm_avi_iframe_lut[4][mode]; + /* Data Byte 06: LSB Line No of End of Top Bar */ + aviInfoFrame[8] = hdmi_msm_avi_iframe_lut[5][mode]; + /* Data Byte 07: MSB Line No of End of Top Bar */ + aviInfoFrame[9] = hdmi_msm_avi_iframe_lut[6][mode]; + /* Data Byte 08: LSB Line No of Start of Bottom Bar */ + aviInfoFrame[10] = hdmi_msm_avi_iframe_lut[7][mode]; + /* Data Byte 09: MSB Line No of Start of Bottom Bar */ + aviInfoFrame[11] = hdmi_msm_avi_iframe_lut[8][mode]; + /* Data Byte 10: LSB Pixel Number of End of Left Bar */ + aviInfoFrame[12] = hdmi_msm_avi_iframe_lut[9][mode]; + /* Data Byte 11: MSB Pixel Number of End of Left Bar */ + aviInfoFrame[13] = hdmi_msm_avi_iframe_lut[10][mode]; + /* Data Byte 12: LSB Pixel Number of Start of Right Bar */ + aviInfoFrame[14] = hdmi_msm_avi_iframe_lut[11][mode]; + /* Data Byte 13: MSB Pixel Number of Start of Right Bar */ + aviInfoFrame[15] = hdmi_msm_avi_iframe_lut[12][mode]; + + sum = 0; + for (i = 0; i < 16; i++) + sum += aviInfoFrame[i]; + sum &= 0xFF; + sum = 256 - sum; + checksum = (uint8) sum; + + regVal = aviInfoFrame[5]; + regVal = regVal << 8 | aviInfoFrame[4]; + regVal = regVal << 8 | aviInfoFrame[3]; + regVal = regVal << 8 | checksum; + HDMI_OUTP(0x006C, regVal); + + regVal = aviInfoFrame[9]; + regVal = regVal << 8 | aviInfoFrame[8]; + regVal = regVal << 8 | aviInfoFrame[7]; + regVal = regVal << 8 | aviInfoFrame[6]; + HDMI_OUTP(0x0070, regVal); + + regVal = aviInfoFrame[13]; + regVal = regVal << 8 | aviInfoFrame[12]; + regVal = regVal << 8 | aviInfoFrame[11]; + regVal = regVal << 8 | aviInfoFrame[10]; + HDMI_OUTP(0x0074, regVal); + + regVal = aviInfoFrame[1]; + regVal = regVal << 16 | aviInfoFrame[15]; + regVal = regVal << 8 | aviInfoFrame[14]; + HDMI_OUTP(0x0078, regVal); + + /* INFOFRAME_CTRL0[0x002C] */ + /* 0x3 for AVI InfFrame enable (every frame) */ + HDMI_OUTP(0x002C, HDMI_INP(0x002C) | 0x00000003L); +} + +#ifdef CONFIG_FB_MSM_HDMI_3D +static void hdmi_msm_vendor_infoframe_packetsetup(void) +{ + uint32 packet_header = 0; + uint32 check_sum = 0; + uint32 packet_payload = 0; + + if (!external_common_state->format_3d) { + HDMI_OUTP(0x0034, 0); + return; + } + + /* 0x0084 GENERIC0_HDR + * HB0 7:0 NUM + * HB1 15:8 NUM + * HB2 23:16 NUM */ + /* Setup Packet header and payload */ + /* 0x81 VS_INFO_FRAME_ID + 0x01 VS_INFO_FRAME_VERSION + 0x1B VS_INFO_FRAME_PAYLOAD_LENGTH */ + packet_header = 0x81 | (0x01 << 8) | (0x1B << 16); + HDMI_OUTP(0x0084, packet_header); + + check_sum = packet_header & 0xff; + check_sum += (packet_header >> 8) & 0xff; + check_sum += (packet_header >> 16) & 0xff; + + /* 0x008C GENERIC0_1 + * BYTE4 7:0 NUM + * BYTE5 15:8 NUM + * BYTE6 23:16 NUM + * BYTE7 31:24 NUM */ + /* 0x02 VS_INFO_FRAME_3D_PRESENT */ + packet_payload = 0x02 << 5; + switch (external_common_state->format_3d) { + case 1: + /* 0b1000 VIDEO_3D_FORMAT_SIDE_BY_SIDE_HALF */ + packet_payload |= (0x08 << 8) << 4; + break; + case 2: + /* 0b0110 VIDEO_3D_FORMAT_TOP_AND_BOTTOM_HALF */ + packet_payload |= (0x06 << 8) << 4; + break; + } + HDMI_OUTP(0x008C, packet_payload); + + check_sum += packet_payload & 0xff; + check_sum += (packet_payload >> 8) & 0xff; + + #define IEEE_REGISTRATION_ID 0xC03 + /* Next 3 bytes are IEEE Registration Identifcation */ + /* 0x0088 GENERIC0_0 + * BYTE0 7:0 NUM (checksum) + * BYTE1 15:8 NUM + * BYTE2 23:16 NUM + * BYTE3 31:24 NUM */ + check_sum += IEEE_REGISTRATION_ID & 0xff; + check_sum += (IEEE_REGISTRATION_ID >> 8) & 0xff; + check_sum += (IEEE_REGISTRATION_ID >> 16) & 0xff; + + HDMI_OUTP(0x0088, (0x100 - (0xff & check_sum)) + | ((IEEE_REGISTRATION_ID & 0xff) << 8) + | (((IEEE_REGISTRATION_ID >> 8) & 0xff) << 16) + | (((IEEE_REGISTRATION_ID >> 16) & 0xff) << 24)); + + /* 0x0034 GEN_PKT_CTRL + * GENERIC0_SEND 0 0 = Disable Generic0 Packet Transmission + * 1 = Enable Generic0 Packet Transmission + * GENERIC0_CONT 1 0 = Send Generic0 Packet on next frame only + * 1 = Send Generic0 Packet on every frame + * GENERIC0_UPDATE 2 NUM + * GENERIC1_SEND 4 0 = Disable Generic1 Packet Transmission + * 1 = Enable Generic1 Packet Transmission + * GENERIC1_CONT 5 0 = Send Generic1 Packet on next frame only + * 1 = Send Generic1 Packet on every frame + * GENERIC0_LINE 21:16 NUM + * GENERIC1_LINE 29:24 NUM + */ + /* GENERIC0_LINE | GENERIC0_UPDATE | GENERIC0_CONT | GENERIC0_SEND + * Setup HDMI TX generic packet control + * Enable this packet to transmit every frame + * Enable this packet to transmit every frame + * Enable HDMI TX engine to transmit Generic packet 0 */ + HDMI_OUTP(0x0034, (1 << 16) | (1 << 2) | BIT(1) | BIT(0)); +} + +static void hdmi_msm_switch_3d(boolean on) +{ + mutex_lock(&external_common_state_hpd_mutex); + if (external_common_state->hpd_state) + hdmi_msm_vendor_infoframe_packetsetup(); + mutex_unlock(&external_common_state_hpd_mutex); +} +#endif + +#define IFRAME_CHECKSUM_32(d) \ + ((d & 0xff) + ((d >> 8) & 0xff) + \ + ((d >> 16) & 0xff) + ((d >> 24) & 0xff)) + +static void hdmi_msm_spd_infoframe_packetsetup(void) +{ + uint32 packet_header = 0; + uint32 check_sum = 0; + uint32 packet_payload = 0; + uint32 packet_control = 0; + + uint8 *vendor_name = external_common_state->spd_vendor_name; + uint8 *product_description = + external_common_state->spd_product_description; + + /* 0x00A4 GENERIC1_HDR + * HB0 7:0 NUM + * HB1 15:8 NUM + * HB2 23:16 NUM */ + /* Setup Packet header and payload */ + /* 0x83 InfoFrame Type Code + 0x01 InfoFrame Version Number + 0x19 Length of Source Product Description InfoFrame + */ + packet_header = 0x83 | (0x01 << 8) | (0x19 << 16); + HDMI_OUTP(0x00A4, packet_header); + check_sum += IFRAME_CHECKSUM_32(packet_header); + + /* Vendor Name (7bit ASCII code) */ + /* 0x00A8 GENERIC1_0 + * BYTE0 7:0 CheckSum + * BYTE1 15:8 VENDOR_NAME[0] + * BYTE2 23:16 VENDOR_NAME[1] + * BYTE3 31:24 VENDOR_NAME[2] */ + packet_payload = ((vendor_name[0] & 0x7f) << 8) + | ((vendor_name[1] & 0x7f) << 16) + | ((vendor_name[2] & 0x7f) << 24); + check_sum += IFRAME_CHECKSUM_32(packet_payload); + packet_payload |= ((0x100 - (0xff & check_sum)) & 0xff); + HDMI_OUTP(0x00A8, packet_payload); + + /* 0x00AC GENERIC1_1 + * BYTE4 7:0 VENDOR_NAME[3] + * BYTE5 15:8 VENDOR_NAME[4] + * BYTE6 23:16 VENDOR_NAME[5] + * BYTE7 31:24 VENDOR_NAME[6] */ + packet_payload = (vendor_name[3] & 0x7f) + | ((vendor_name[4] & 0x7f) << 8) + | ((vendor_name[5] & 0x7f) << 16) + | ((vendor_name[6] & 0x7f) << 24); + HDMI_OUTP(0x00AC, packet_payload); + check_sum += IFRAME_CHECKSUM_32(packet_payload); + + /* Product Description (7-bit ASCII code) */ + /* 0x00B0 GENERIC1_2 + * BYTE8 7:0 VENDOR_NAME[7] + * BYTE9 15:8 PRODUCT_NAME[ 0] + * BYTE10 23:16 PRODUCT_NAME[ 1] + * BYTE11 31:24 PRODUCT_NAME[ 2] */ + packet_payload = (vendor_name[7] & 0x7f) + | ((product_description[0] & 0x7f) << 8) + | ((product_description[1] & 0x7f) << 16) + | ((product_description[2] & 0x7f) << 24); + HDMI_OUTP(0x00B0, packet_payload); + check_sum += IFRAME_CHECKSUM_32(packet_payload); + + /* 0x00B4 GENERIC1_3 + * BYTE12 7:0 PRODUCT_NAME[ 3] + * BYTE13 15:8 PRODUCT_NAME[ 4] + * BYTE14 23:16 PRODUCT_NAME[ 5] + * BYTE15 31:24 PRODUCT_NAME[ 6] */ + packet_payload = (product_description[3] & 0x7f) + | ((product_description[4] & 0x7f) << 8) + | ((product_description[5] & 0x7f) << 16) + | ((product_description[6] & 0x7f) << 24); + HDMI_OUTP(0x00B4, packet_payload); + check_sum += IFRAME_CHECKSUM_32(packet_payload); + + /* 0x00B8 GENERIC1_4 + * BYTE16 7:0 PRODUCT_NAME[ 7] + * BYTE17 15:8 PRODUCT_NAME[ 8] + * BYTE18 23:16 PRODUCT_NAME[ 9] + * BYTE19 31:24 PRODUCT_NAME[10] */ + packet_payload = (product_description[7] & 0x7f) + | ((product_description[8] & 0x7f) << 8) + | ((product_description[9] & 0x7f) << 16) + | ((product_description[10] & 0x7f) << 24); + HDMI_OUTP(0x00B8, packet_payload); + check_sum += IFRAME_CHECKSUM_32(packet_payload); + + /* 0x00BC GENERIC1_5 + * BYTE20 7:0 PRODUCT_NAME[11] + * BYTE21 15:8 PRODUCT_NAME[12] + * BYTE22 23:16 PRODUCT_NAME[13] + * BYTE23 31:24 PRODUCT_NAME[14] */ + packet_payload = (product_description[11] & 0x7f) + | ((product_description[12] & 0x7f) << 8) + | ((product_description[13] & 0x7f) << 16) + | ((product_description[14] & 0x7f) << 24); + HDMI_OUTP(0x00BC, packet_payload); + check_sum += IFRAME_CHECKSUM_32(packet_payload); + + /* 0x00C0 GENERIC1_6 + * BYTE24 7:0 PRODUCT_NAME[15] + * BYTE25 15:8 Source Device Information + * BYTE26 23:16 NUM + * BYTE27 31:24 NUM */ + /* Source Device Information + * 00h unknown + * 01h Digital STB + * 02h DVD + * 03h D-VHS + * 04h HDD Video + * 05h DVC + * 06h DSC + * 07h Video CD + * 08h Game + * 09h PC general */ + packet_payload = (product_description[15] & 0x7f) | 0x00 << 8; + HDMI_OUTP(0x00C0, packet_payload); + check_sum += IFRAME_CHECKSUM_32(packet_payload); + + /* GENERIC1_LINE | GENERIC1_CONT | GENERIC1_SEND + * Setup HDMI TX generic packet control + * Enable this packet to transmit every frame + * Enable HDMI TX engine to transmit Generic packet 1 */ + packet_control = HDMI_INP_ND(0x0034); + packet_control |= ((0x1 << 24) | (1 << 5) | (1 << 4)); + HDMI_OUTP(0x0034, packet_control); +} + +int hdmi_msm_clk(int on) +{ + int rc; + + DEV_DBG("HDMI Clk: %s\n", on ? "Enable" : "Disable"); + if (on) { + rc = clk_prepare_enable(hdmi_msm_state->hdmi_app_clk); + if (rc) { + DEV_ERR("'hdmi_app_clk' clock enable failed, rc=%d\n", + rc); + return rc; + } + + rc = clk_prepare_enable(hdmi_msm_state->hdmi_m_pclk); + if (rc) { + DEV_ERR("'hdmi_m_pclk' clock enable failed, rc=%d\n", + rc); + return rc; + } + + rc = clk_prepare_enable(hdmi_msm_state->hdmi_s_pclk); + if (rc) { + DEV_ERR("'hdmi_s_pclk' clock enable failed, rc=%d\n", + rc); + return rc; + } + } else { + clk_disable_unprepare(hdmi_msm_state->hdmi_app_clk); + clk_disable_unprepare(hdmi_msm_state->hdmi_m_pclk); + clk_disable_unprepare(hdmi_msm_state->hdmi_s_pclk); + } + + return 0; +} + +static void hdmi_msm_turn_on(void) +{ + uint32 hpd_ctrl; + uint32 audio_pkt_ctrl, audio_cfg; + /* + * Number of wait iterations for QDSP to disable Audio Engine + * before resetting HDMI core + */ + int i = 10; + audio_pkt_ctrl = HDMI_INP_ND(0x0020); + audio_cfg = HDMI_INP_ND(0x01D0); + + /* + * Checking BIT[0] of AUDIO PACKET CONTROL and + * AUDIO CONFIGURATION register + */ + while (((audio_pkt_ctrl & 0x00000001) || (audio_cfg & 0x00000001)) + && (i--)) { + audio_pkt_ctrl = HDMI_INP_ND(0x0020); + audio_cfg = HDMI_INP_ND(0x01D0); + DEV_DBG("%d times :: HDMI AUDIO PACKET is %08x and " + "AUDIO CFG is %08x", i, audio_pkt_ctrl, audio_cfg); + msleep(20); + } + + mutex_lock(&hdcp_auth_state_mutex); + hdmi_msm_reset_core(); + mutex_unlock(&hdcp_auth_state_mutex); + + hdmi_msm_init_phy(external_common_state->video_resolution); + /* HDMI_USEC_REFTIMER[0x0208] */ + HDMI_OUTP(0x0208, 0x0001001B); + + hdmi_msm_set_mode(TRUE); + + hdmi_msm_video_setup(external_common_state->video_resolution); + if (!hdmi_msm_is_dvi_mode()) + hdmi_msm_audio_setup(); + hdmi_msm_avi_info_frame(); +#ifdef CONFIG_FB_MSM_HDMI_3D + hdmi_msm_vendor_infoframe_packetsetup(); +#endif + hdmi_msm_spd_infoframe_packetsetup(); + + /* set timeout to 4.1ms (max) for hardware debounce */ + hpd_ctrl = (HDMI_INP(0x0258) & ~0xFFF) | 0xFFF; + + /* Toggle HPD circuit to trigger HPD sense */ + HDMI_OUTP(0x0258, ~(1 << 28) & hpd_ctrl); + HDMI_OUTP(0x0258, (1 << 28) | hpd_ctrl); + + /* Setup HPD IRQ */ + HDMI_OUTP(0x0254, 4 | (external_common_state->hpd_state ? 0 : 2)); + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + if (hdmi_msm_state->reauth) { + hdmi_msm_hdcp_enable(); + hdmi_msm_state->reauth = FALSE ; + } +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT + /* re-initialize CEC if enabled */ + mutex_lock(&hdmi_msm_state_mutex); + if (hdmi_msm_state->cec_enabled == true) { + hdmi_msm_cec_init(); + hdmi_msm_cec_write_logical_addr( + hdmi_msm_state->cec_logical_addr); + } + mutex_unlock(&hdmi_msm_state_mutex); +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT */ + DEV_INFO("HDMI Core: Initialized\n"); +} + +static void hdmi_msm_hpd_state_timer(unsigned long data) +{ + queue_work(hdmi_work_queue, &hdmi_msm_state->hpd_state_work); +} + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT +static void hdmi_msm_hdcp_timer(unsigned long data) +{ + queue_work(hdmi_work_queue, &hdmi_msm_state->hdcp_work); +} +#endif + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT +static void hdmi_msm_cec_read_timer_func(unsigned long data) +{ + queue_work(hdmi_work_queue, &hdmi_msm_state->cec_latch_detect_work); +} +#endif + +static void hdmi_msm_hpd_read_work(struct work_struct *work) +{ + uint32 hpd_ctrl; + + clk_prepare_enable(hdmi_msm_state->hdmi_app_clk); + hdmi_msm_state->pd->core_power(1, 1); + hdmi_msm_state->pd->enable_5v(1); + hdmi_msm_set_mode(FALSE); + hdmi_msm_init_phy(external_common_state->video_resolution); + /* HDMI_USEC_REFTIMER[0x0208] */ + HDMI_OUTP(0x0208, 0x0001001B); + hpd_ctrl = (HDMI_INP(0x0258) & ~0xFFF) | 0xFFF; + + /* Toggle HPD circuit to trigger HPD sense */ + HDMI_OUTP(0x0258, ~(1 << 28) & hpd_ctrl); + HDMI_OUTP(0x0258, (1 << 28) | hpd_ctrl); + + hdmi_msm_set_mode(TRUE); + msleep(1000); + external_common_state->hpd_state = (HDMI_INP(0x0250) & 0x2) >> 1; + if (external_common_state->hpd_state) { + hdmi_msm_read_edid(); + DEV_DBG("%s: sense CONNECTED: send ONLINE\n", __func__); + kobject_uevent(external_common_state->uevent_kobj, + KOBJ_ONLINE); + } + hdmi_msm_hpd_off(); + hdmi_msm_set_mode(FALSE); + hdmi_msm_state->pd->core_power(0, 1); + hdmi_msm_state->pd->enable_5v(0); + clk_disable_unprepare(hdmi_msm_state->hdmi_app_clk); +} + +static void hdmi_msm_hpd_off(void) +{ + if (!hdmi_msm_state->hpd_initialized) { + DEV_DBG("%s: HPD is already OFF, returning\n", __func__); + return; + } + + DEV_DBG("%s: (timer, clk, 5V, core, IRQ off)\n", __func__); + del_timer(&hdmi_msm_state->hpd_state_timer); + disable_irq(hdmi_msm_state->irq); + + hdmi_msm_set_mode(FALSE); + hdmi_msm_state->hpd_initialized = FALSE; + hdmi_msm_powerdown_phy(); + hdmi_msm_state->pd->cec_power(0); + hdmi_msm_state->pd->enable_5v(0); + hdmi_msm_state->pd->core_power(0, 1); + hdmi_msm_clk(0); + hdmi_msm_state->hpd_initialized = FALSE; +} + +static void hdmi_msm_dump_regs(const char *prefix) +{ +#ifdef REG_DUMP + print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, 32, 4, + (void *)MSM_HDMI_BASE, 0x0334, false); +#endif +} + +static int hdmi_msm_hpd_on(bool trigger_handler) +{ + static int phy_reset_done; + uint32 hpd_ctrl; + + if (hdmi_msm_state->hpd_initialized) { + DEV_DBG("%s: HPD is already ON, returning\n", __func__); + return 0; + } + + hdmi_msm_clk(1); + hdmi_msm_state->pd->core_power(1, 1); + hdmi_msm_state->pd->enable_5v(1); + hdmi_msm_state->pd->cec_power(1); + hdmi_msm_dump_regs("HDMI-INIT: "); + hdmi_msm_set_mode(FALSE); + + if (!phy_reset_done) { + hdmi_phy_reset(); + phy_reset_done = 1; + } + + /* HDMI_USEC_REFTIMER[0x0208] */ + HDMI_OUTP(0x0208, 0x0001001B); + + /* Check HPD State */ + enable_irq(hdmi_msm_state->irq); + + /* set timeout to 4.1ms (max) for hardware debounce */ + hpd_ctrl = (HDMI_INP(0x0258) & ~0xFFF) | 0xFFF; + + /* Toggle HPD circuit to trigger HPD sense */ + HDMI_OUTP(0x0258, ~(1 << 28) & hpd_ctrl); + HDMI_OUTP(0x0258, (1 << 28) | hpd_ctrl); + + DEV_DBG("%s: (clk, 5V, core, IRQ on) \n", __func__, + trigger_handler ? "true" : "false"); + + if (trigger_handler) { + /* Set HPD state machine: ensure at least 2 readouts */ + mutex_lock(&hdmi_msm_state_mutex); + hdmi_msm_state->hpd_stable = 0; + hdmi_msm_state->hpd_prev_state = TRUE; + mutex_lock(&external_common_state_hpd_mutex); + external_common_state->hpd_state = FALSE; + mutex_unlock(&external_common_state_hpd_mutex); + hdmi_msm_state->hpd_cable_chg_detected = TRUE; + mutex_unlock(&hdmi_msm_state_mutex); + mod_timer(&hdmi_msm_state->hpd_state_timer, + jiffies + HZ/2); + } + + hdmi_msm_state->hpd_initialized = TRUE; + + hdmi_msm_set_mode(TRUE); + + return 0; +} + +static int hdmi_msm_power_ctrl(boolean enable) +{ + if (!external_common_state->hpd_feature_on) + return 0; + + if (enable) + hdmi_msm_hpd_on(true); + else + hdmi_msm_hpd_off(); + + return 0; +} + +static int hdmi_msm_power_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); + bool changed; + + if (!hdmi_msm_state || !hdmi_msm_state->hdmi_app_clk || !MSM_HDMI_BASE) + return -ENODEV; + + DEV_INFO("power: ON (%dx%d %d)\n", mfd->var_xres, mfd->var_yres, + mfd->var_pixclock); + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + mutex_lock(&hdmi_msm_state_mutex); + if (hdmi_msm_state->hdcp_activating) { + hdmi_msm_state->panel_power_on = TRUE; + DEV_INFO("HDCP: activating, returning\n"); + } + mutex_unlock(&hdmi_msm_state_mutex); +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ + + changed = hdmi_common_get_video_format_from_drv_data(mfd); + if (!external_common_state->hpd_feature_on || mfd->ref_cnt) { + int rc = hdmi_msm_hpd_on(true); + DEV_INFO("HPD: panel power without 'hpd' feature on\n"); + if (rc) { + DEV_WARN("HPD: activation failed: rc=%d\n", rc); + return rc; + } + } + hdmi_msm_audio_info_setup(TRUE, 0, 0, 0, FALSE); + + mutex_lock(&external_common_state_hpd_mutex); + hdmi_msm_state->panel_power_on = TRUE; + if ((external_common_state->hpd_state && !hdmi_msm_is_power_on()) + || changed) { + mutex_unlock(&external_common_state_hpd_mutex); + hdmi_msm_turn_on(); + } else + mutex_unlock(&external_common_state_hpd_mutex); + + hdmi_msm_dump_regs("HDMI-ON: "); + + DEV_INFO("power=%s DVI= %s\n", + hdmi_msm_is_power_on() ? "ON" : "OFF" , + hdmi_msm_is_dvi_mode() ? "ON" : "OFF"); + return 0; +} + +/* Note that power-off will also be called when the cable-remove event is + * processed on the user-space and as a result the framebuffer is powered + * down. However, we are still required to be able to detect a cable-insert + * event; so for now leave the HDMI engine running; so that the HPD IRQ is + * still being processed. + */ +static int hdmi_msm_power_off(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); + + if (!hdmi_msm_state->hdmi_app_clk) + return -ENODEV; + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + mutex_lock(&hdmi_msm_state_mutex); + if (hdmi_msm_state->hdcp_activating) { + hdmi_msm_state->panel_power_on = FALSE; + mutex_unlock(&hdmi_msm_state_mutex); + DEV_INFO("HDCP: activating, returning\n"); + return 0; + } + mutex_unlock(&hdmi_msm_state_mutex); +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ + + DEV_INFO("power: OFF (audio off, Reset Core)\n"); + hdmi_msm_audio_off(); +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + hdcp_deauthenticate(); +#endif + hdmi_msm_hpd_off(); + hdmi_msm_powerdown_phy(); + hdmi_msm_dump_regs("HDMI-OFF: "); + hdmi_msm_hpd_on(true); + + mutex_lock(&external_common_state_hpd_mutex); + if (!external_common_state->hpd_feature_on || mfd->ref_cnt) + hdmi_msm_hpd_off(); + mutex_unlock(&external_common_state_hpd_mutex); + + hdmi_msm_state->panel_power_on = FALSE; + return 0; +} + +static int hdmi_msm_probe(struct platform_device *pdev) +{ + int rc; + struct platform_device *fb_dev; + + if (!hdmi_msm_state) { + pr_err("%s: hdmi_msm_state is NULL\n", __func__); + return -ENOMEM; + } + + external_common_state->dev = &pdev->dev; + DEV_DBG("probe\n"); + if (pdev->id == 0) { + struct resource *res; + + #define GET_RES(name, mode) do { \ + res = platform_get_resource_byname(pdev, mode, name); \ + if (!res) { \ + DEV_ERR("'" name "' resource not found\n"); \ + rc = -ENODEV; \ + goto error; \ + } \ + } while (0) + + #define IO_REMAP(var, name) do { \ + GET_RES(name, IORESOURCE_MEM); \ + var = ioremap(res->start, resource_size(res)); \ + if (!var) { \ + DEV_ERR("'" name "' ioremap failed\n"); \ + rc = -ENOMEM; \ + goto error; \ + } \ + } while (0) + + #define GET_IRQ(var, name) do { \ + GET_RES(name, IORESOURCE_IRQ); \ + var = res->start; \ + } while (0) + + IO_REMAP(hdmi_msm_state->qfprom_io, "hdmi_msm_qfprom_addr"); + hdmi_msm_state->hdmi_io = MSM_HDMI_BASE; + GET_IRQ(hdmi_msm_state->irq, "hdmi_msm_irq"); + + hdmi_msm_state->pd = pdev->dev.platform_data; + + #undef GET_RES + #undef IO_REMAP + #undef GET_IRQ + return 0; + } + + hdmi_msm_state->hdmi_app_clk = clk_get(&pdev->dev, "core_clk"); + if (IS_ERR(hdmi_msm_state->hdmi_app_clk)) { + DEV_ERR("'core_clk' clk not found\n"); + rc = IS_ERR(hdmi_msm_state->hdmi_app_clk); + goto error; + } + + hdmi_msm_state->hdmi_m_pclk = clk_get(&pdev->dev, "master_iface_clk"); + if (IS_ERR(hdmi_msm_state->hdmi_m_pclk)) { + DEV_ERR("'master_iface_clk' clk not found\n"); + rc = IS_ERR(hdmi_msm_state->hdmi_m_pclk); + goto error; + } + + hdmi_msm_state->hdmi_s_pclk = clk_get(&pdev->dev, "slave_iface_clk"); + if (IS_ERR(hdmi_msm_state->hdmi_s_pclk)) { + DEV_ERR("'slave_iface_clk' clk not found\n"); + rc = IS_ERR(hdmi_msm_state->hdmi_s_pclk); + goto error; + } + + rc = check_hdmi_features(); + if (rc) { + DEV_ERR("Init FAILED: check_hdmi_features rc=%d\n", rc); + goto error; + } + + if (!hdmi_msm_state->pd->core_power) { + DEV_ERR("Init FAILED: core_power function missing\n"); + rc = -ENODEV; + goto error; + } + if (!hdmi_msm_state->pd->enable_5v) { + DEV_ERR("Init FAILED: enable_5v function missing\n"); + rc = -ENODEV; + goto error; + } + + if (!hdmi_msm_state->pd->cec_power) { + DEV_ERR("Init FAILED: cec_power function missing\n"); + rc = -ENODEV; + goto error; + } + + rc = request_threaded_irq(hdmi_msm_state->irq, NULL, &hdmi_msm_isr, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "hdmi_msm_isr", NULL); + if (rc) { + DEV_ERR("Init FAILED: IRQ request, rc=%d\n", rc); + goto error; + } + disable_irq(hdmi_msm_state->irq); + + init_timer(&hdmi_msm_state->hpd_state_timer); + hdmi_msm_state->hpd_state_timer.function = + hdmi_msm_hpd_state_timer; + hdmi_msm_state->hpd_state_timer.data = (uint32)NULL; + + hdmi_msm_state->hpd_state_timer.expires = 0xffffffffL; + add_timer(&hdmi_msm_state->hpd_state_timer); + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + init_timer(&hdmi_msm_state->hdcp_timer); + hdmi_msm_state->hdcp_timer.function = + hdmi_msm_hdcp_timer; + hdmi_msm_state->hdcp_timer.data = (uint32)NULL; + + hdmi_msm_state->hdcp_timer.expires = 0xffffffffL; +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT + init_timer(&hdmi_msm_state->cec_read_timer); + hdmi_msm_state->cec_read_timer.function = + hdmi_msm_cec_read_timer_func; + hdmi_msm_state->cec_read_timer.data = (uint32)NULL; + + hdmi_msm_state->cec_read_timer.expires = 0xffffffffL; + #endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT */ + + fb_dev = msm_fb_add_device(pdev); + if (fb_dev) { + rc = external_common_state_create(fb_dev); + if (rc) { + DEV_ERR("Init FAILED: hdmi_msm_state_create, rc=%d\n", + rc); + goto error; + } + } else + DEV_ERR("Init FAILED: failed to add fb device\n"); + + DEV_INFO("HDMI HPD: ON\n"); + + rc = hdmi_msm_hpd_on(true); + if (rc) + goto error; + + if (hdmi_msm_has_hdcp()) { + /* Don't Set Encryption in case of non HDCP builds */ + external_common_state->present_hdcp = FALSE; +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + external_common_state->present_hdcp = TRUE; +#endif + } else { + external_common_state->present_hdcp = FALSE; +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + /* + * If the device is not hdcp capable do + * not start hdcp timer. + */ + del_timer(&hdmi_msm_state->hdcp_timer); +#endif + } + + queue_work(hdmi_work_queue, &hdmi_msm_state->hpd_read_work); + + /* Initialize hdmi node and register with switch driver */ + if (hdmi_prim_display) + external_common_state->sdev.name = "hdmi_as_primary"; + else + external_common_state->sdev.name = "hdmi"; + if (switch_dev_register(&external_common_state->sdev) < 0) + DEV_ERR("Hdmi switch registration failed\n"); + + return 0; + +error: + if (hdmi_msm_state->qfprom_io) + iounmap(hdmi_msm_state->qfprom_io); + hdmi_msm_state->qfprom_io = NULL; + + if (hdmi_msm_state->hdmi_io) + iounmap(hdmi_msm_state->hdmi_io); + hdmi_msm_state->hdmi_io = NULL; + + external_common_state_remove(); + + if (hdmi_msm_state->hdmi_app_clk) + clk_put(hdmi_msm_state->hdmi_app_clk); + if (hdmi_msm_state->hdmi_m_pclk) + clk_put(hdmi_msm_state->hdmi_m_pclk); + if (hdmi_msm_state->hdmi_s_pclk) + clk_put(hdmi_msm_state->hdmi_s_pclk); + + hdmi_msm_state->hdmi_app_clk = NULL; + hdmi_msm_state->hdmi_m_pclk = NULL; + hdmi_msm_state->hdmi_s_pclk = NULL; + + return rc; +} + +static int hdmi_msm_remove(struct platform_device *pdev) +{ + DEV_INFO("HDMI device: remove\n"); + + DEV_INFO("HDMI HPD: OFF\n"); + + /* Unregister hdmi node from switch driver */ + switch_dev_unregister(&external_common_state->sdev); + + hdmi_msm_hpd_off(); + free_irq(hdmi_msm_state->irq, NULL); + + if (hdmi_msm_state->qfprom_io) + iounmap(hdmi_msm_state->qfprom_io); + hdmi_msm_state->qfprom_io = NULL; + + if (hdmi_msm_state->hdmi_io) + iounmap(hdmi_msm_state->hdmi_io); + hdmi_msm_state->hdmi_io = NULL; + + external_common_state_remove(); + + if (hdmi_msm_state->hdmi_app_clk) + clk_put(hdmi_msm_state->hdmi_app_clk); + if (hdmi_msm_state->hdmi_m_pclk) + clk_put(hdmi_msm_state->hdmi_m_pclk); + if (hdmi_msm_state->hdmi_s_pclk) + clk_put(hdmi_msm_state->hdmi_s_pclk); + + hdmi_msm_state->hdmi_app_clk = NULL; + hdmi_msm_state->hdmi_m_pclk = NULL; + hdmi_msm_state->hdmi_s_pclk = NULL; + + kfree(hdmi_msm_state); + hdmi_msm_state = NULL; + + return 0; +} + +static int hdmi_msm_hpd_feature(int on) +{ + int rc = 0; + + DEV_INFO("%s: %d\n", __func__, on); + if (on) { + rc = hdmi_msm_hpd_on(true); + } else { + hdmi_msm_hpd_off(); + /* Set HDMI switch node to 0 on HPD feature disable */ + switch_set_state(&external_common_state->sdev, 0); + } + + return rc; +} + +static struct platform_driver this_driver = { + .probe = hdmi_msm_probe, + .remove = hdmi_msm_remove, + .driver.name = "hdmi_msm", +}; + +static struct msm_fb_panel_data hdmi_msm_panel_data = { + .on = hdmi_msm_power_on, + .off = hdmi_msm_power_off, + .power_ctrl = hdmi_msm_power_ctrl, +}; + +static struct platform_device this_device = { + .name = "hdmi_msm", + .id = 1, + .dev.platform_data = &hdmi_msm_panel_data, +}; + +static int __init hdmi_msm_init(void) +{ + int rc; + + if (msm_fb_detect_client("hdmi_msm")) + return 0; + +#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY + hdmi_prim_display = 1; +#endif + + hdmi_msm_setup_video_mode_lut(); + hdmi_msm_state = kzalloc(sizeof(*hdmi_msm_state), GFP_KERNEL); + if (!hdmi_msm_state) { + pr_err("hdmi_msm_init FAILED: out of memory\n"); + rc = -ENOMEM; + goto init_exit; + } + + external_common_state = &hdmi_msm_state->common; + external_common_state->video_resolution = HDMI_VFRMT_1920x1080p60_16_9; +#ifdef CONFIG_FB_MSM_HDMI_3D + external_common_state->switch_3d = hdmi_msm_switch_3d; +#endif + memset(external_common_state->spd_vendor_name, 0, + sizeof(external_common_state->spd_vendor_name)); + memset(external_common_state->spd_product_description, 0, + sizeof(external_common_state->spd_product_description)); + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT + hdmi_msm_state->cec_queue_start = + kzalloc(sizeof(struct hdmi_msm_cec_msg)*CEC_QUEUE_SIZE, + GFP_KERNEL); + if (!hdmi_msm_state->cec_queue_start) { + pr_err("hdmi_msm_init FAILED: CEC queue out of memory\n"); + rc = -ENOMEM; + goto init_exit; + } + + hdmi_msm_state->cec_queue_wr = hdmi_msm_state->cec_queue_start; + hdmi_msm_state->cec_queue_rd = hdmi_msm_state->cec_queue_start; + hdmi_msm_state->cec_queue_full = false; +#endif + + /* + * Create your work queue + * allocs and returns ptr + */ + hdmi_work_queue = create_workqueue("hdmi_hdcp"); + external_common_state->hpd_feature = hdmi_msm_hpd_feature; + + rc = platform_driver_register(&this_driver); + if (rc) { + pr_err("hdmi_msm_init FAILED: platform_driver_register rc=%d\n", + rc); + goto init_exit; + } + + hdmi_common_init_panel_info(&hdmi_msm_panel_data.panel_info); + init_completion(&hdmi_msm_state->ddc_sw_done); + INIT_WORK(&hdmi_msm_state->hpd_state_work, hdmi_msm_hpd_state_work); + INIT_WORK(&hdmi_msm_state->hpd_read_work, hdmi_msm_hpd_read_work); +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + init_completion(&hdmi_msm_state->hdcp_success_done); + INIT_WORK(&hdmi_msm_state->hdcp_reauth_work, hdmi_msm_hdcp_reauth_work); + INIT_WORK(&hdmi_msm_state->hdcp_work, hdmi_msm_hdcp_work); +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT + INIT_WORK(&hdmi_msm_state->cec_latch_detect_work, + hdmi_msm_cec_latch_work); + init_completion(&hdmi_msm_state->cec_frame_wr_done); + init_completion(&hdmi_msm_state->cec_line_latch_wait); +#endif + + rc = platform_device_register(&this_device); + if (rc) { + pr_err("hdmi_msm_init FAILED: platform_device_register rc=%d\n", + rc); + platform_driver_unregister(&this_driver); + goto init_exit; + } + + pr_debug("%s: success:" +#ifdef DEBUG + " DEBUG" +#else + " RELEASE" +#endif + " AUDIO EDID HPD HDCP" +#ifndef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + ":0" +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ + " DVI" +#ifndef CONFIG_FB_MSM_HDMI_MSM_PANEL_DVI_SUPPORT + ":0" +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_DVI_SUPPORT */ + "\n", __func__); + + return 0; + +init_exit: + kfree(hdmi_msm_state); + hdmi_msm_state = NULL; + + return rc; +} + +static void __exit hdmi_msm_exit(void) +{ + platform_device_unregister(&this_device); + platform_driver_unregister(&this_driver); +} + +module_init(hdmi_msm_init); +module_exit(hdmi_msm_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("0.3"); +MODULE_AUTHOR("Qualcomm Innovation Center, Inc."); +MODULE_DESCRIPTION("HDMI MSM TX driver"); diff --git a/drivers/video/msm/hdmi_msm.h b/drivers/video/msm/hdmi_msm.h new file mode 100644 index 000000000000..489dce8fcdc3 --- /dev/null +++ b/drivers/video/msm/hdmi_msm.h @@ -0,0 +1,138 @@ +/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __HDMI_MSM_H__ +#define __HDMI_MSM_H__ + +#include +#include "external_common.h" +/* #define PORT_DEBUG */ + +#ifdef PORT_DEBUG +const char *hdmi_msm_name(uint32 offset); +void hdmi_outp(uint32 offset, uint32 value); +uint32 hdmi_inp(uint32 offset); + +#define HDMI_OUTP_ND(offset, value) outpdw(MSM_HDMI_BASE+(offset), (value)) +#define HDMI_OUTP(offset, value) hdmi_outp((offset), (value)) +#define HDMI_INP_ND(offset) inpdw(MSM_HDMI_BASE+(offset)) +#define HDMI_INP(offset) hdmi_inp((offset)) +#else +#define HDMI_OUTP_ND(offset, value) outpdw(MSM_HDMI_BASE+(offset), (value)) +#define HDMI_OUTP(offset, value) outpdw(MSM_HDMI_BASE+(offset), (value)) +#define HDMI_INP_ND(offset) inpdw(MSM_HDMI_BASE+(offset)) +#define HDMI_INP(offset) inpdw(MSM_HDMI_BASE+(offset)) +#endif + + +/* + * Ref. HDMI 1.4a + * Supplement-1 CEC Section 6, 7 + */ +struct hdmi_msm_cec_msg { + uint8 sender_id; + uint8 recvr_id; + uint8 opcode; + uint8 operand[15]; + uint8 frame_size; + uint8 retransmit; +}; + +#define QFPROM_BASE ((uint32)hdmi_msm_state->qfprom_io) +#define HDMI_BASE ((uint32)hdmi_msm_state->hdmi_io) + +struct hdmi_msm_state_type { + boolean panel_power_on; + boolean hpd_initialized; +#ifdef CONFIG_SUSPEND + boolean pm_suspended; +#endif + int hpd_stable; + boolean hpd_prev_state; + boolean hpd_cable_chg_detected; + boolean full_auth_done; + boolean hpd_during_auth; + struct work_struct hpd_state_work, hpd_read_work; + struct timer_list hpd_state_timer; + struct completion ddc_sw_done; + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT + boolean hdcp_activating; + boolean reauth ; + struct work_struct hdcp_reauth_work, hdcp_work; + struct completion hdcp_success_done; + struct timer_list hdcp_timer; +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */ + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT + boolean cec_enabled; + unsigned int first_monitor; + int cec_logical_addr; + struct completion cec_frame_wr_done; + struct timer_list cec_read_timer; +#define CEC_STATUS_WR_ERROR 0x0001 +#define CEC_STATUS_WR_DONE 0x0002 +#define CEC_STATUS_WR_TMOUT 0x0004 + uint32 cec_frame_wr_status; + + struct hdmi_msm_cec_msg *cec_queue_start; + struct hdmi_msm_cec_msg *cec_queue_wr; + struct hdmi_msm_cec_msg *cec_queue_rd; + boolean cec_queue_full; + boolean fsm_reset_done; + + /* + * CECT 9-5-1 + */ + struct completion cec_line_latch_wait; + struct work_struct cec_latch_detect_work; + +#define CEC_QUEUE_SIZE 16 +#define CEC_QUEUE_END (hdmi_msm_state->cec_queue_start + CEC_QUEUE_SIZE) +#define RETRANSMIT_MAX_NUM 5 +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT */ + + int irq; + struct msm_hdmi_platform_data *pd; + struct clk *hdmi_app_clk; + struct clk *hdmi_m_pclk; + struct clk *hdmi_s_pclk; + void __iomem *qfprom_io; + void __iomem *hdmi_io; + + struct external_common_state_type common; +}; + +extern struct hdmi_msm_state_type *hdmi_msm_state; + +uint32 hdmi_msm_get_io_base(void); + +#ifdef CONFIG_FB_MSM_HDMI_COMMON +void hdmi_msm_set_mode(boolean power_on); +int hdmi_msm_clk(int on); +void hdmi_phy_reset(void); +void hdmi_msm_reset_core(void); +void hdmi_msm_init_phy(int video_format); +void hdmi_msm_powerdown_phy(void); +void hdmi_frame_ctrl_cfg(const struct hdmi_disp_mode_timing_type *timing); +void hdmi_msm_phy_status_poll(void); +#endif + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT +void hdmi_msm_cec_init(void); +void hdmi_msm_cec_write_logical_addr(int addr); +void hdmi_msm_cec_msg_recv(void); +void hdmi_msm_cec_one_touch_play(void); +void hdmi_msm_cec_msg_send(struct hdmi_msm_cec_msg *msg); +#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT */ + +#endif /* __HDMI_MSM_H__ */ diff --git a/drivers/video/msm/hdmi_sii9022.c b/drivers/video/msm/hdmi_sii9022.c new file mode 100644 index 000000000000..c1b5e03caf94 --- /dev/null +++ b/drivers/video/msm/hdmi_sii9022.c @@ -0,0 +1,245 @@ +/* Copyright (c) 2009-2010, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include "msm_fb.h" + +#define DEVICE_NAME "sii9022" +#define SII9022_DEVICE_ID 0xB0 + +struct sii9022_i2c_addr_data{ + u8 addr; + u8 data; +}; + +/* video mode data */ +static u8 video_mode_data[] = { + 0x00, + 0xF9, 0x1C, 0x70, 0x17, 0x72, 0x06, 0xEE, 0x02, +}; + +static u8 avi_io_format[] = { + 0x09, + 0x00, 0x00, +}; + +/* power state */ +static struct sii9022_i2c_addr_data regset0[] = { + { 0x60, 0x04 }, + { 0x63, 0x00 }, + { 0x1E, 0x00 }, +}; + +static u8 video_infoframe[] = { + 0x0C, + 0xF0, 0x00, 0x68, 0x00, 0x04, 0x00, 0x19, 0x00, + 0xE9, 0x02, 0x04, 0x01, 0x04, 0x06, +}; + +/* configure audio */ +static struct sii9022_i2c_addr_data regset1[] = { + { 0x26, 0x90 }, + { 0x20, 0x90 }, + { 0x1F, 0x80 }, + { 0x26, 0x80 }, + { 0x24, 0x02 }, + { 0x25, 0x0B }, + { 0xBC, 0x02 }, + { 0xBD, 0x24 }, + { 0xBE, 0x02 }, +}; + +/* enable audio */ +static u8 misc_infoframe[] = { + 0xBF, + 0xC2, 0x84, 0x01, 0x0A, 0x6F, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +/* set HDMI, active */ +static struct sii9022_i2c_addr_data regset2[] = { + { 0x1A, 0x01 }, + { 0x3D, 0x00 }, +}; + +static int send_i2c_data(struct i2c_client *client, + struct sii9022_i2c_addr_data *regset, + int size) +{ + int i; + int rc = 0; + + for (i = 0; i < size; i++) { + rc = i2c_smbus_write_byte_data( + client, + regset[i].addr, regset[i].data); + if (rc) + break; + } + return rc; +} + +static int hdmi_sii_enable(struct i2c_client *client) +{ + int rc; + int retries = 10; + int count; + + rc = i2c_smbus_write_byte_data(client, 0xC7, 0x00); + if (rc) + goto enable_exit; + + do { + msleep(1); + rc = i2c_smbus_read_byte_data(client, 0x1B); + } while ((rc != SII9022_DEVICE_ID) && retries--); + + if (rc != SII9022_DEVICE_ID) + return -ENODEV; + + rc = i2c_smbus_write_byte_data(client, 0x1A, 0x11); + if (rc) + goto enable_exit; + + count = ARRAY_SIZE(video_mode_data); + rc = i2c_master_send(client, video_mode_data, count); + if (rc != count) { + rc = -EIO; + goto enable_exit; + } + + rc = i2c_smbus_write_byte_data(client, 0x08, 0x20); + if (rc) + goto enable_exit; + count = ARRAY_SIZE(avi_io_format); + rc = i2c_master_send(client, avi_io_format, count); + if (rc != count) { + rc = -EIO; + goto enable_exit; + } + + rc = send_i2c_data(client, regset0, ARRAY_SIZE(regset0)); + if (rc) + goto enable_exit; + + count = ARRAY_SIZE(video_infoframe); + rc = i2c_master_send(client, video_infoframe, count); + if (rc != count) { + rc = -EIO; + goto enable_exit; + } + + rc = send_i2c_data(client, regset1, ARRAY_SIZE(regset1)); + if (rc) + goto enable_exit; + + count = ARRAY_SIZE(misc_infoframe); + rc = i2c_master_send(client, misc_infoframe, count); + if (rc != count) { + rc = -EIO; + goto enable_exit; + } + + rc = send_i2c_data(client, regset2, ARRAY_SIZE(regset2)); + if (rc) + goto enable_exit; + + return 0; +enable_exit: + printk(KERN_ERR "%s: exited rc=%d\n", __func__, rc); + return rc; +} + +static const struct i2c_device_id hmdi_sii_id[] = { + { DEVICE_NAME, 0 }, + { } +}; + +static int hdmi_sii_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C)) + return -ENODEV; + rc = hdmi_sii_enable(client); + return rc; +} + + +static struct i2c_driver hdmi_sii_i2c_driver = { + .driver = { + .name = DEVICE_NAME, + .owner = THIS_MODULE, + }, + .probe = hdmi_sii_probe, + .remove = __exit_p(hdmi_sii_remove), + .id_table = hmdi_sii_id, +}; + +static int __init hdmi_sii_init(void) +{ + int ret; + struct msm_panel_info pinfo; + + if (msm_fb_detect_client("hdmi_sii9022")) + return 0; + + pinfo.xres = 1280; + pinfo.yres = 720; + MSM_FB_SINGLE_MODE_PANEL(&pinfo); + pinfo.type = HDMI_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 18; + pinfo.fb_num = 2; + pinfo.clk_rate = 74250000; + + pinfo.lcdc.h_back_porch = 124; + pinfo.lcdc.h_front_porch = 110; + pinfo.lcdc.h_pulse_width = 136; + pinfo.lcdc.v_back_porch = 19; + pinfo.lcdc.v_front_porch = 5; + pinfo.lcdc.v_pulse_width = 6; + pinfo.lcdc.border_clr = 0; + pinfo.lcdc.underflow_clr = 0xff; + pinfo.lcdc.hsync_skew = 0; + + ret = lcdc_device_register(&pinfo); + if (ret) { + printk(KERN_ERR "%s: failed to register device\n", __func__); + goto init_exit; + } + + ret = i2c_add_driver(&hdmi_sii_i2c_driver); + if (ret) + printk(KERN_ERR "%s: failed to add i2c driver\n", __func__); + +init_exit: + return ret; +} + +static void __exit hdmi_sii_exit(void) +{ + i2c_del_driver(&hdmi_sii_i2c_driver); +} + +module_init(hdmi_sii_init); +module_exit(hdmi_sii_exit); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("0.1"); +MODULE_AUTHOR("Qualcomm Innovation Center, Inc."); +MODULE_DESCRIPTION("SiI9022 HDMI driver"); +MODULE_ALIAS("platform:hdmi-sii9022"); diff --git a/drivers/video/msm/lcdc.c b/drivers/video/msm/lcdc.c new file mode 100644 index 000000000000..7156e4cdda38 --- /dev/null +++ b/drivers/video/msm/lcdc.c @@ -0,0 +1,289 @@ +/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "msm_fb.h" + +static int lcdc_probe(struct platform_device *pdev); +static int lcdc_remove(struct platform_device *pdev); + +static int lcdc_off(struct platform_device *pdev); +static int lcdc_on(struct platform_device *pdev); + +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; + +static struct clk *pixel_mdp_clk; /* drives the lcdc block in mdp */ +static struct clk *pixel_lcdc_clk; /* drives the lcdc interface */ + +static struct platform_driver lcdc_driver = { + .probe = lcdc_probe, + .remove = lcdc_remove, + .suspend = NULL, + .resume = NULL, + .shutdown = NULL, + .driver = { + .name = "lcdc", + }, +}; + +static struct lcdc_platform_data *lcdc_pdata; + +static int lcdc_off(struct platform_device *pdev) +{ + int ret = 0; + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + ret = panel_next_off(pdev); + + clk_disable_unprepare(pixel_mdp_clk); + clk_disable_unprepare(pixel_lcdc_clk); + + if (lcdc_pdata && lcdc_pdata->lcdc_power_save) + lcdc_pdata->lcdc_power_save(0); + + if (lcdc_pdata && lcdc_pdata->lcdc_gpio_config) + ret = lcdc_pdata->lcdc_gpio_config(0); + +#ifndef CONFIG_MSM_BUS_SCALING + if (mfd->ebi1_clk) { + if (mdp_rev == MDP_REV_303) { + if (clk_set_rate(mfd->ebi1_clk, 0)) + pr_err("%s: ebi1_lcdc_clk set rate failed\n", + __func__); + } + clk_disable_unprepare(mfd->ebi1_clk); + } +#else + mdp_bus_scale_update_request(0); +#endif + + return ret; +} + +static int lcdc_on(struct platform_device *pdev) +{ + int ret = 0; + struct msm_fb_data_type *mfd; + unsigned long panel_pixclock_freq = 0; +#ifndef CONFIG_MSM_BUS_SCALING + unsigned long pm_qos_rate; +#endif + mfd = platform_get_drvdata(pdev); + + if (lcdc_pdata && lcdc_pdata->lcdc_get_clk) + panel_pixclock_freq = lcdc_pdata->lcdc_get_clk(); + + if (!panel_pixclock_freq) + panel_pixclock_freq = mfd->fbi->var.pixclock; +#ifdef CONFIG_MSM_BUS_SCALING + mdp_bus_scale_update_request(2); +#else + if (panel_pixclock_freq > 65000000) + /* pm_qos_rate should be in Khz */ + pm_qos_rate = panel_pixclock_freq / 1000 ; + else + pm_qos_rate = 65000; + + if (mfd->ebi1_clk) { + if (mdp_rev == MDP_REV_303) { + if (clk_set_rate(mfd->ebi1_clk, 65000000)) + pr_err("%s: ebi1_lcdc_clk set rate failed\n", + __func__); + } else { + clk_set_rate(mfd->ebi1_clk, pm_qos_rate * 1000); + } + clk_prepare_enable(mfd->ebi1_clk); + } + +#endif + mfd = platform_get_drvdata(pdev); + + mfd->fbi->var.pixclock = clk_round_rate(pixel_mdp_clk, + mfd->fbi->var.pixclock); + ret = clk_set_rate(pixel_mdp_clk, mfd->fbi->var.pixclock); + if (ret) { + pr_err("%s: Can't set MDP LCDC pixel clock to rate %u\n", + __func__, mfd->fbi->var.pixclock); + goto out; + } + + clk_prepare_enable(pixel_mdp_clk); + clk_prepare_enable(pixel_lcdc_clk); + + if (lcdc_pdata && lcdc_pdata->lcdc_power_save) + lcdc_pdata->lcdc_power_save(1); + if (lcdc_pdata && lcdc_pdata->lcdc_gpio_config) + ret = lcdc_pdata->lcdc_gpio_config(1); + + ret = panel_next_on(pdev); + +out: + return ret; +} + +static int lcdc_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct fb_info *fbi; + struct platform_device *mdp_dev = NULL; + struct msm_fb_panel_data *pdata = NULL; + int rc; + struct clk *ebi1_clk = NULL; + + if (pdev->id == 0) { + lcdc_pdata = pdev->dev.platform_data; + pixel_mdp_clk = clk_get(&pdev->dev, "mdp_clk"); + if (IS_ERR(pixel_mdp_clk)) { + pr_err("Couldnt find pixel_mdp_clk\n"); + return -EINVAL; + } + + pixel_lcdc_clk = clk_get(&pdev->dev, "lcdc_clk"); + if (IS_ERR(pixel_lcdc_clk)) { + pr_err("Couldnt find pixel_lcdc_clk\n"); + return -EINVAL; + } + +#ifndef CONFIG_MSM_BUS_SCALING + ebi1_clk = clk_get(&pdev->dev, "mem_clk"); + if (IS_ERR(ebi1_clk)) + return PTR_ERR(ebi1_clk); +#endif + + return 0; + } + + mfd = platform_get_drvdata(pdev); + mfd->ebi1_clk = ebi1_clk; + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) + return -ENOMEM; + + mdp_dev = platform_device_alloc("mdp", pdev->id); + if (!mdp_dev) + return -ENOMEM; + + /* + * link to the latest pdev + */ + mfd->pdev = mdp_dev; + mfd->dest = DISPLAY_LCDC; + + /* + * alloc panel device data + */ + if (platform_device_add_data + (mdp_dev, pdev->dev.platform_data, + sizeof(struct msm_fb_panel_data))) { + pr_err("lcdc_probe: platform_device_add_data failed!\n"); + platform_device_put(mdp_dev); + return -ENOMEM; + } + /* + * data chain + */ + pdata = (struct msm_fb_panel_data *)mdp_dev->dev.platform_data; + pdata->on = lcdc_on; + pdata->off = lcdc_off; + pdata->next = pdev; + + /* + * get/set panel specific fb info + */ + mfd->panel_info = pdata->panel_info; + + if (mfd->index == 0) + mfd->fb_imgType = MSMFB_DEFAULT_TYPE; + else + mfd->fb_imgType = MDP_RGB_565; + + fbi = mfd->fbi; + fbi->var.pixclock = clk_round_rate(pixel_mdp_clk, + mfd->panel_info.clk_rate); + fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch; + fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch; + fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch; + fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch; + fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width; + fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width; + + /* + * set driver data + */ + platform_set_drvdata(mdp_dev, mfd); + /* + * register in mdp driver + */ + rc = platform_device_add(mdp_dev); + if (rc) + goto lcdc_probe_err; + + pdev_list[pdev_list_cnt++] = pdev; + + return 0; + +lcdc_probe_err: + platform_device_put(mdp_dev); + return rc; +} + +static int lcdc_remove(struct platform_device *pdev) +{ +#ifndef CONFIG_MSM_BUS_SCALING + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + + clk_put(mfd->ebi1_clk); +#endif + return 0; +} + +static int lcdc_register_driver(void) +{ + return platform_driver_register(&lcdc_driver); +} + +static int __init lcdc_driver_init(void) +{ + + return lcdc_register_driver(); +} + +module_init(lcdc_driver_init); diff --git a/drivers/video/msm/lcdc_auo_wvga.c b/drivers/video/msm/lcdc_auo_wvga.c new file mode 100644 index 000000000000..f346c459c3b5 --- /dev/null +++ b/drivers/video/msm/lcdc_auo_wvga.c @@ -0,0 +1,411 @@ +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#ifdef CONFIG_SPI_QUP +#include +#else +#include +#endif +#include "msm_fb.h" + +#define MAX_BACKLIGHT_LEVEL 15 +#define PANEL_CMD_BACKLIGHT_LEVEL 0x6A18 +#define PANEL_CMD_FORMAT 0x3A00 +#define PANEL_CMD_RGBCTRL 0x3B00 +#define PANEL_CMD_BCTRL 0x5300 +#define PANEL_CMD_PWM_EN 0x6A17 + +#define PANEL_CMD_SLEEP_OUT 0x1100 +#define PANEL_CMD_DISP_ON 0x2900 +#define PANEL_CMD_DISP_OFF 0x2800 +#define PANEL_CMD_SLEEP_IN 0x1000 + +#define LCDC_AUO_PANEL_NAME "lcdc_auo_wvga" + +#ifdef CONFIG_SPI_QUP +#define LCDC_AUO_SPI_DEVICE_NAME "lcdc_auo_nt35582" +static struct spi_device *lcdc_spi_client; +#else +static int spi_cs; +static int spi_sclk; +static int spi_mosi; +#endif + +struct auo_state_type { + boolean display_on; + int bl_level; +}; + + +static struct auo_state_type auo_state = { .bl_level = 10 }; +static struct msm_panel_common_pdata *lcdc_auo_pdata; + +#ifndef CONFIG_SPI_QUP +static void auo_spi_write_byte(u8 data) +{ + uint32 bit; + int bnum; + + bnum = 8; /* 8 data bits */ + bit = 0x80; + while (bnum--) { + gpio_set_value(spi_sclk, 0); /* clk low */ + gpio_set_value(spi_mosi, (data & bit) ? 1 : 0); + udelay(1); + gpio_set_value(spi_sclk, 1); /* clk high */ + udelay(1); + bit >>= 1; + } + gpio_set_value(spi_mosi, 0); +} + +static void auo_spi_read_byte(u16 cmd_16, u8 *data) +{ + int bnum; + u8 cmd_hi = (u8)(cmd_16 >> 8); + u8 cmd_low = (u8)(cmd_16); + + /* Chip Select - low */ + gpio_set_value(spi_cs, 0); + udelay(2); + + /* command byte first */ + auo_spi_write_byte(0x20); + udelay(2); + auo_spi_write_byte(cmd_hi); + udelay(2); + auo_spi_write_byte(0x00); + udelay(2); + auo_spi_write_byte(cmd_low); + udelay(2); + auo_spi_write_byte(0xc0); + udelay(2); + + gpio_direction_input(spi_mosi); + + /* followed by data bytes */ + bnum = 1 * 8; /* number of bits */ + *data = 0; + while (bnum) { + gpio_set_value(spi_sclk, 0); /* clk low */ + udelay(1); + *data <<= 1; + *data |= gpio_get_value(spi_mosi) ? 1 : 0; + gpio_set_value(spi_sclk, 1); /* clk high */ + udelay(1); + --bnum; + if ((bnum % 8) == 0) + ++data; + } + + gpio_direction_output(spi_mosi, 0); + + /* Chip Select - high */ + udelay(2); + gpio_set_value(spi_cs, 1); +} +#endif + +static int auo_serigo(u8 *input_data, int input_len) +{ +#ifdef CONFIG_SPI_QUP + int rc; + struct spi_message m; + struct spi_transfer t; + + if (!lcdc_spi_client) { + pr_err("%s lcdc_spi_client is NULL\n", __func__); + return -EINVAL; + } + + memset(&t, 0, sizeof t); + + t.tx_buf = input_data; + t.len = input_len; + t.bits_per_word = 16; + + spi_setup(lcdc_spi_client); + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + rc = spi_sync(lcdc_spi_client, &m); + + return rc; +#else + int i; + + /* Chip Select - low */ + gpio_set_value(spi_cs, 0); + udelay(2); + + for (i = 0; i < input_len; ++i) { + auo_spi_write_byte(input_data[i]); + udelay(2); + } + + /* Chip Select - high */ + gpio_set_value(spi_cs, 1); + + return 0; +#endif +} + +#ifndef CONFIG_SPI_QUP +static void auo_spi_init(void) +{ + spi_sclk = *(lcdc_auo_pdata->gpio_num); + spi_cs = *(lcdc_auo_pdata->gpio_num + 1); + spi_mosi = *(lcdc_auo_pdata->gpio_num + 2); + + /* Set the output so that we don't disturb the slave device */ + gpio_set_value(spi_sclk, 1); + gpio_set_value(spi_mosi, 0); + + /* Set the Chip Select deasserted (active low) */ + gpio_set_value(spi_cs, 1); +} +#endif + +static struct work_struct disp_on_delayed_work; +static void auo_write_cmd(u16 cmd) +{ + u8 local_data[4]; + + local_data[0] = 0x20; + local_data[1] = (u8)(cmd >> 8); + local_data[2] = 0; + local_data[3] = (u8)cmd; + auo_serigo(local_data, 4); +} +static void auo_write_cmd_1param(u16 cmd, u8 para1) +{ + u8 local_data[6]; + + local_data[0] = 0x20; + local_data[1] = (u8)(cmd >> 8); + local_data[2] = 0; + local_data[3] = (u8)cmd; + local_data[4] = 0x40; + local_data[5] = para1; + auo_serigo(local_data, 6); +} +static void lcdc_auo_set_backlight(struct msm_fb_data_type *mfd) +{ + int bl_level; + + bl_level = mfd->bl_level; + if (auo_state.display_on) { + auo_write_cmd_1param(PANEL_CMD_BACKLIGHT_LEVEL, + bl_level * 255 / MAX_BACKLIGHT_LEVEL); + auo_state.bl_level = bl_level; + } + +} +static void auo_disp_on_delayed_work(struct work_struct *work_ptr) +{ + /* 0x1100: Sleep Out */ + auo_write_cmd(PANEL_CMD_SLEEP_OUT); + + msleep(180); + + /* SET_PIXEL_FORMAT: Set how many bits per pixel are used (3A00h)*/ + auo_write_cmd_1param(PANEL_CMD_FORMAT, 0x66); /* 18 bits */ + + /* RGBCTRL: RGB Interface Signal Control (3B00h) */ + auo_write_cmd_1param(PANEL_CMD_RGBCTRL, 0x2B); + + /* Display ON command */ + auo_write_cmd(PANEL_CMD_DISP_ON); + msleep(20); + + /*Backlight on */ + auo_write_cmd_1param(PANEL_CMD_BCTRL, 0x24); /*BCTRL, BL */ + auo_write_cmd_1param(PANEL_CMD_PWM_EN, 0x01); /*Enable PWM Level */ + + msleep(20); +} + +static void auo_disp_on(void) +{ + if (!auo_state.display_on) { + INIT_WORK(&disp_on_delayed_work, auo_disp_on_delayed_work); +#ifdef CONFIG_SPI_QUP + if (lcdc_spi_client) +#endif + schedule_work(&disp_on_delayed_work); + auo_state.display_on = TRUE; + } +} + +static int lcdc_auo_panel_on(struct platform_device *pdev) +{ + pr_info("%s\n", __func__); + if (!auo_state.display_on) { +#ifndef CONFIG_SPI_QUP + lcdc_auo_pdata->panel_config_gpio(1); + auo_spi_init(); +#endif + auo_disp_on(); + } + return 0; +} + +static int lcdc_auo_panel_off(struct platform_device *pdev) +{ + pr_info("%s\n", __func__); + if (auo_state.display_on) { + /* 0x2800: Display Off */ + auo_write_cmd(PANEL_CMD_DISP_OFF); + msleep(120); + /* 0x1000: Sleep In */ + auo_write_cmd(PANEL_CMD_SLEEP_IN); + msleep(120); + + auo_state.display_on = FALSE; + } + return 0; +} + +static int auo_probe(struct platform_device *pdev) +{ + pr_info("%s: id=%d\n", __func__, pdev->id); + if (pdev->id == 0) { + lcdc_auo_pdata = pdev->dev.platform_data; + return 0; + } + + msm_fb_add_device(pdev); + + return 0; +} + +#ifdef CONFIG_SPI_QUP +static int lcdc_auo_spi_probe(struct spi_device *spi) +{ + pr_info("%s\n", __func__); + lcdc_spi_client = spi; + lcdc_spi_client->bits_per_word = 32; + if (auo_state.display_on) + schedule_work(&disp_on_delayed_work); + return 0; +} +static int lcdc_auo_spi_remove(struct spi_device *spi) +{ + lcdc_spi_client = NULL; + return 0; +} +static struct spi_driver lcdc_auo_spi_driver = { + .driver.name = LCDC_AUO_SPI_DEVICE_NAME, + .driver.owner = THIS_MODULE, + .probe = lcdc_auo_spi_probe, + .remove = lcdc_auo_spi_remove, +}; +#endif + +static struct platform_driver this_driver = { + .probe = auo_probe, + .driver.name = LCDC_AUO_PANEL_NAME, +}; + +static struct msm_fb_panel_data auo_panel_data = { + .on = lcdc_auo_panel_on, + .off = lcdc_auo_panel_off, + .set_backlight = lcdc_auo_set_backlight, +}; + +static struct platform_device this_device = { + .name = LCDC_AUO_PANEL_NAME, + .id = 1, + .dev.platform_data = &auo_panel_data, +}; + +static int __init lcdc_auo_panel_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + + if (msm_fb_detect_client(LCDC_AUO_PANEL_NAME)) { + pr_err("%s: detect failed\n", __func__); + return 0; + } + + ret = platform_driver_register(&this_driver); + if (ret) { + pr_err("%s: driver register failed, rc=%d\n", __func__, ret); + return ret; + } + + pinfo = &auo_panel_data.panel_info; + pinfo->xres = 480; + pinfo->yres = 800; + pinfo->type = LCDC_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->wait_cycle = 0; + pinfo->bpp = 18; + pinfo->fb_num = 2; + pinfo->clk_rate = 25600000; + pinfo->bl_max = MAX_BACKLIGHT_LEVEL; + pinfo->bl_min = 1; + + pinfo->lcdc.h_back_porch = 16-2; /* HBP-HLW */ + pinfo->lcdc.h_front_porch = 16; + pinfo->lcdc.h_pulse_width = 2; + + pinfo->lcdc.v_back_porch = 3-2; /* VBP-VLW */ + pinfo->lcdc.v_front_porch = 28; + pinfo->lcdc.v_pulse_width = 2; + + pinfo->lcdc.border_clr = 0; + pinfo->lcdc.underflow_clr = 0xff; + pinfo->lcdc.hsync_skew = 0; + + ret = platform_device_register(&this_device); + if (ret) { + pr_err("%s: device register failed, rc=%d\n", __func__, ret); + goto fail_driver; + } +#ifdef CONFIG_SPI_QUP + ret = spi_register_driver(&lcdc_auo_spi_driver); + + if (ret) { + pr_err("%s: spi register failed: rc=%d\n", __func__, ret); + goto fail_device; + } + pr_info("%s: SUCCESS (SPI)\n", __func__); +#else + pr_info("%s: SUCCESS (BitBang)\n", __func__); +#endif + return ret; + +#ifdef CONFIG_SPI_QUP +fail_device: + platform_device_unregister(&this_device); +#endif +fail_driver: + platform_driver_unregister(&this_driver); + + return ret; +} + +module_init(lcdc_auo_panel_init); +static void __exit lcdc_auo_panel_exit(void) +{ + pr_info("%s\n", __func__); + platform_device_unregister(&this_device); + platform_driver_unregister(&this_driver); +#ifdef CONFIG_SPI_QUP + spi_unregister_driver(&lcdc_auo_spi_driver); +#endif +} +module_exit(lcdc_auo_panel_exit); diff --git a/drivers/video/msm/lcdc_chimei_wxga.c b/drivers/video/msm/lcdc_chimei_wxga.c new file mode 100644 index 000000000000..a29a38bea682 --- /dev/null +++ b/drivers/video/msm/lcdc_chimei_wxga.c @@ -0,0 +1,231 @@ +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#ifdef CONFIG_PMIC8058_PWM +#include +#include +#endif +#include +#include "msm_fb.h" + + + + +static struct pwm_device *bl_pwm; + +#define PWM_FREQ_HZ 210 +#define PWM_PERIOD_USEC (USEC_PER_SEC / PWM_FREQ_HZ) +#define PWM_DUTY_LEVEL (PWM_PERIOD_USEC / PWM_LEVEL) +#define PWM_LEVEL 15 + +static struct msm_panel_common_pdata *cm_pdata; +static struct platform_device *cm_fbpdev; +static int led_pwm; /* pm8058 gpio 24, channel 0 */ +static int led_en; /* pm8058 gpio 1 */ +static int lvds_pwr_down; /* msm gpio 30 */ +static int chimei_bl_level = 1; + + +static void lcdc_chimei_set_backlight(int level) +{ + int ret; + + if (bl_pwm) { + ret = pwm_config(bl_pwm, PWM_DUTY_LEVEL * level, + PWM_PERIOD_USEC); + if (ret) { + pr_err("%s: pwm_config on pwm failed %d\n", + __func__, ret); + return; + } + + ret = pwm_enable(bl_pwm); + if (ret) { + pr_err("%s: pwm_enable on pwm failed %d\n", + __func__, ret); + return; + } + } + + chimei_bl_level = level; +} + +static int lcdc_chimei_panel_on(struct platform_device *pdev) +{ + int ret; + + /* panel powered on here */ + + ret = gpio_request(lvds_pwr_down, "lvds_pwr_down"); + if (ret == 0) { + /* output, pull high to enable */ + gpio_direction_output(lvds_pwr_down, 1); + } else { + pr_err("%s: lvds_pwr_down=%d, gpio_request failed\n", + __func__, lvds_pwr_down); + } + + msleep(200); + /* power on led pwm power >= 200 ms */ + + if (chimei_bl_level == 0) + chimei_bl_level = 1; + lcdc_chimei_set_backlight(chimei_bl_level); + + msleep(10); + + ret = gpio_request(led_en, "led_en"); + if (ret == 0) { + /* output, pull high */ + gpio_direction_output(led_en, 1); + } else { + pr_err("%s: led_en=%d, gpio_request failed\n", + __func__, led_en); + } + return ret; +} + +static int lcdc_chimei_panel_off(struct platform_device *pdev) +{ + /* pull low to disable */ + gpio_set_value_cansleep(led_en, 0); + gpio_free(led_en); + + msleep(10); + + lcdc_chimei_set_backlight(0); + + msleep(200); + /* power off led pwm power >= 200 ms */ + + /* pull low to shut down lvds */ + gpio_set_value_cansleep(lvds_pwr_down, 0); + gpio_free(lvds_pwr_down); + + /* panel power off here */ + + return 0; +} + +static void lcdc_chimei_panel_backlight(struct msm_fb_data_type *mfd) +{ + lcdc_chimei_set_backlight(mfd->bl_level); +} + +static int chimei_probe(struct platform_device *pdev) +{ + int rc = 0; + + if (pdev->id == 0) { + cm_pdata = pdev->dev.platform_data; + if (cm_pdata == NULL) { + pr_err("%s: no PWM gpio specified\n", __func__); + return 0; + } + led_pwm = cm_pdata->gpio_num[0]; + led_en = cm_pdata->gpio_num[1]; + lvds_pwr_down = cm_pdata->gpio_num[2]; + pr_info("%s: led_pwm=%d led_en=%d lvds_pwr_down=%d\n", + __func__, led_pwm, led_en, lvds_pwr_down); + return 0; + } + + if (cm_pdata == NULL) + return -ENODEV; + + bl_pwm = pwm_request(led_pwm, "backlight"); + if (bl_pwm == NULL || IS_ERR(bl_pwm)) { + pr_err("%s pwm_request() failed\n", __func__); + bl_pwm = NULL; + } + + cm_fbpdev = msm_fb_add_device(pdev); + if (!cm_fbpdev) { + dev_err(&pdev->dev, "failed to add msm_fb device\n"); + rc = -ENODEV; + goto probe_exit; + } + +probe_exit: + return rc; +} + +static struct platform_driver this_driver = { + .probe = chimei_probe, + .driver = { + .name = "lcdc_chimei_lvds_wxga", + }, +}; + +static struct msm_fb_panel_data chimei_panel_data = { + .on = lcdc_chimei_panel_on, + .off = lcdc_chimei_panel_off, + .set_backlight = lcdc_chimei_panel_backlight, +}; + +static struct platform_device this_device = { + .name = "lcdc_chimei_lvds_wxga", + .id = 1, + .dev = { + .platform_data = &chimei_panel_data, + } +}; + +static int __init lcdc_chimei_lvds_panel_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + + if (msm_fb_detect_client("lcdc_chimei_wxga")) + return 0; + + ret = platform_driver_register(&this_driver); + if (ret) + return ret; + + pinfo = &chimei_panel_data.panel_info; + pinfo->xres = 1366; + pinfo->yres = 768; + MSM_FB_SINGLE_MODE_PANEL(pinfo); + pinfo->type = LCDC_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->wait_cycle = 0; + pinfo->bpp = 18; + pinfo->fb_num = 2; + pinfo->clk_rate = 69300000; + pinfo->bl_max = PWM_LEVEL; + pinfo->bl_min = 1; + + /* + * this panel is operated by de, + * vsycn and hsync are ignored + */ + pinfo->lcdc.h_back_porch = 108; + pinfo->lcdc.h_front_porch = 0; + pinfo->lcdc.h_pulse_width = 1; + pinfo->lcdc.v_back_porch = 0; + pinfo->lcdc.v_front_porch = 16; + pinfo->lcdc.v_pulse_width = 1; + pinfo->lcdc.border_clr = 0; + pinfo->lcdc.underflow_clr = 0xff; + pinfo->lcdc.hsync_skew = 0; + + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + + return ret; +} + +module_init(lcdc_chimei_lvds_panel_init); diff --git a/drivers/video/msm/lcdc_external.c b/drivers/video/msm/lcdc_external.c new file mode 100644 index 000000000000..b699610f5107 --- /dev/null +++ b/drivers/video/msm/lcdc_external.c @@ -0,0 +1,51 @@ +/* Copyright (c) 2009-2010, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" + +static int __init lcdc_external_init(void) +{ + int ret; + struct msm_panel_info pinfo; + + if (msm_fb_detect_client("lcdc_external")) + return 0; + + pinfo.xres = 1280; + pinfo.yres = 720; + MSM_FB_SINGLE_MODE_PANEL(&pinfo); + pinfo.type = LCDC_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.fb_num = 2; + pinfo.clk_rate = 74250000; + + pinfo.lcdc.h_back_porch = 124; + pinfo.lcdc.h_front_porch = 110; + pinfo.lcdc.h_pulse_width = 136; + pinfo.lcdc.v_back_porch = 19; + pinfo.lcdc.v_front_porch = 5; + pinfo.lcdc.v_pulse_width = 6; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + + ret = lcdc_device_register(&pinfo); + if (ret) + printk(KERN_ERR "%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(lcdc_external_init); diff --git a/drivers/video/msm/lcdc_gordon.c b/drivers/video/msm/lcdc_gordon.c new file mode 100644 index 000000000000..1b6d5f044637 --- /dev/null +++ b/drivers/video/msm/lcdc_gordon.c @@ -0,0 +1,457 @@ +/* Copyright (c) 2009-2010, 2012 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include "msm_fb.h" + +/* registers */ +#define GORDON_REG_NOP 0x00 +#define GORDON_REG_IMGCTL1 0x10 +#define GORDON_REG_IMGCTL2 0x11 +#define GORDON_REG_IMGSET1 0x12 +#define GORDON_REG_IMGSET2 0x13 +#define GORDON_REG_IVBP1 0x14 +#define GORDON_REG_IHBP1 0x15 +#define GORDON_REG_IVNUM1 0x16 +#define GORDON_REG_IHNUM1 0x17 +#define GORDON_REG_IVBP2 0x18 +#define GORDON_REG_IHBP2 0x19 +#define GORDON_REG_IVNUM2 0x1A +#define GORDON_REG_IHNUM2 0x1B +#define GORDON_REG_LCDIFCTL1 0x30 +#define GORDON_REG_VALTRAN 0x31 +#define GORDON_REG_AVCTL 0x33 +#define GORDON_REG_LCDIFCTL2 0x34 +#define GORDON_REG_LCDIFCTL3 0x35 +#define GORDON_REG_LCDIFSET1 0x36 +#define GORDON_REG_PCCTL 0x3C +#define GORDON_REG_TPARAM1 0x40 +#define GORDON_REG_TLCDIF1 0x41 +#define GORDON_REG_TSSPB_ST1 0x42 +#define GORDON_REG_TSSPB_ED1 0x43 +#define GORDON_REG_TSCK_ST1 0x44 +#define GORDON_REG_TSCK_WD1 0x45 +#define GORDON_REG_TGSPB_VST1 0x46 +#define GORDON_REG_TGSPB_VED1 0x47 +#define GORDON_REG_TGSPB_CH1 0x48 +#define GORDON_REG_TGCK_ST1 0x49 +#define GORDON_REG_TGCK_ED1 0x4A +#define GORDON_REG_TPCTL_ST1 0x4B +#define GORDON_REG_TPCTL_ED1 0x4C +#define GORDON_REG_TPCHG_ED1 0x4D +#define GORDON_REG_TCOM_CH1 0x4E +#define GORDON_REG_THBP1 0x4F +#define GORDON_REG_TPHCTL1 0x50 +#define GORDON_REG_EVPH1 0x51 +#define GORDON_REG_EVPL1 0x52 +#define GORDON_REG_EVNH1 0x53 +#define GORDON_REG_EVNL1 0x54 +#define GORDON_REG_TBIAS1 0x55 +#define GORDON_REG_TPARAM2 0x56 +#define GORDON_REG_TLCDIF2 0x57 +#define GORDON_REG_TSSPB_ST2 0x58 +#define GORDON_REG_TSSPB_ED2 0x59 +#define GORDON_REG_TSCK_ST2 0x5A +#define GORDON_REG_TSCK_WD2 0x5B +#define GORDON_REG_TGSPB_VST2 0x5C +#define GORDON_REG_TGSPB_VED2 0x5D +#define GORDON_REG_TGSPB_CH2 0x5E +#define GORDON_REG_TGCK_ST2 0x5F +#define GORDON_REG_TGCK_ED2 0x60 +#define GORDON_REG_TPCTL_ST2 0x61 +#define GORDON_REG_TPCTL_ED2 0x62 +#define GORDON_REG_TPCHG_ED2 0x63 +#define GORDON_REG_TCOM_CH2 0x64 +#define GORDON_REG_THBP2 0x65 +#define GORDON_REG_TPHCTL2 0x66 +#define GORDON_REG_POWCTL 0x80 + +static int lcdc_gordon_panel_off(struct platform_device *pdev); + +static int spi_cs; +static int spi_sclk; +static int spi_sdo; +static int spi_sdi; +static int spi_dac; +static int bl_level; +static unsigned char bit_shift[8] = { (1 << 7), /* MSB */ + (1 << 6), + (1 << 5), + (1 << 4), + (1 << 3), + (1 << 2), + (1 << 1), + (1 << 0) /* LSB */ +}; + +struct gordon_state_type{ + boolean disp_initialized; + boolean display_on; + boolean disp_powered_up; +}; + +static struct gordon_state_type gordon_state = { 0 }; +static struct msm_panel_common_pdata *lcdc_gordon_pdata; + +static void serigo(uint16 reg, uint8 data) +{ + unsigned int tx_val = ((0x00FF & reg) << 8) | data; + unsigned char i, val = 0; + + /* Enable the Chip Select */ + gpio_set_value(spi_cs, 1); + udelay(33); + + /* Transmit it in two parts, Higher Byte first, then Lower Byte */ + val = (unsigned char)((tx_val & 0xFF00) >> 8); + + /* Clock should be Low before entering ! */ + for (i = 0; i < 8; i++) { + /* #1: Drive the Data (High or Low) */ + if (val & bit_shift[i]) + gpio_set_value(spi_sdi, 1); + else + gpio_set_value(spi_sdi, 0); + + /* #2: Drive the Clk High and then Low */ + udelay(33); + gpio_set_value(spi_sclk, 1); + udelay(33); + gpio_set_value(spi_sclk, 0); + } + + /* Idle state of SDO (MOSI) is Low */ + gpio_set_value(spi_sdi, 0); + /* ..then Lower Byte */ + val = (uint8) (tx_val & 0x00FF); + /* Before we enter here the Clock should be Low ! */ + + for (i = 0; i < 8; i++) { + /* #1: Drive the Data (High or Low) */ + if (val & bit_shift[i]) + gpio_set_value(spi_sdi, 1); + else + gpio_set_value(spi_sdi, 0); + + /* #2: Drive the Clk High and then Low */ + udelay(33); + + gpio_set_value(spi_sclk, 1); + udelay(33); + gpio_set_value(spi_sclk, 0); + } + + /* Idle state of SDO (MOSI) is Low */ + gpio_set_value(spi_sdi, 0); + + /* Now Disable the Chip Select */ + udelay(33); + gpio_set_value(spi_cs, 0); +} + +static void spi_init(void) +{ + /* Setting the Default GPIO's */ + spi_sclk = *(lcdc_gordon_pdata->gpio_num); + spi_cs = *(lcdc_gordon_pdata->gpio_num + 1); + spi_sdi = *(lcdc_gordon_pdata->gpio_num + 2); + spi_sdo = *(lcdc_gordon_pdata->gpio_num + 3); + + /* Set the output so that we dont disturb the slave device */ + gpio_set_value(spi_sclk, 0); + gpio_set_value(spi_sdi, 0); + + /* Set the Chip Select De-asserted */ + gpio_set_value(spi_cs, 0); + +} + +static void gordon_disp_powerup(void) +{ + if (!gordon_state.disp_powered_up && !gordon_state.display_on) { + /* Reset the hardware first */ + /* Include DAC power up implementation here */ + gordon_state.disp_powered_up = TRUE; + } +} + +static void gordon_init(void) +{ + /* Image interface settings */ + serigo(GORDON_REG_IMGCTL2, 0x00); + serigo(GORDON_REG_IMGSET1, 0x00); + + /* Exchange the RGB signal for J510(Softbank mobile) */ + serigo(GORDON_REG_IMGSET2, 0x12); + serigo(GORDON_REG_LCDIFSET1, 0x00); + + /* Pre-charge settings */ + serigo(GORDON_REG_PCCTL, 0x09); + serigo(GORDON_REG_LCDIFCTL2, 0x7B); + + mdelay(1); +} + +static void gordon_disp_on(void) +{ + if (gordon_state.disp_powered_up && !gordon_state.display_on) { + gordon_init(); + mdelay(20); + /* gordon_dispmode setting */ + serigo(GORDON_REG_TPARAM1, 0x30); + serigo(GORDON_REG_TLCDIF1, 0x00); + serigo(GORDON_REG_TSSPB_ST1, 0x8B); + serigo(GORDON_REG_TSSPB_ED1, 0x93); + serigo(GORDON_REG_TSCK_ST1, 0x88); + serigo(GORDON_REG_TSCK_WD1, 0x00); + serigo(GORDON_REG_TGSPB_VST1, 0x01); + serigo(GORDON_REG_TGSPB_VED1, 0x02); + serigo(GORDON_REG_TGSPB_CH1, 0x5E); + serigo(GORDON_REG_TGCK_ST1, 0x80); + serigo(GORDON_REG_TGCK_ED1, 0x3C); + serigo(GORDON_REG_TPCTL_ST1, 0x50); + serigo(GORDON_REG_TPCTL_ED1, 0x74); + serigo(GORDON_REG_TPCHG_ED1, 0x78); + serigo(GORDON_REG_TCOM_CH1, 0x50); + serigo(GORDON_REG_THBP1, 0x84); + serigo(GORDON_REG_TPHCTL1, 0x00); + serigo(GORDON_REG_EVPH1, 0x70); + serigo(GORDON_REG_EVPL1, 0x64); + serigo(GORDON_REG_EVNH1, 0x56); + serigo(GORDON_REG_EVNL1, 0x48); + serigo(GORDON_REG_TBIAS1, 0x88); + + /* QVGA settings */ + serigo(GORDON_REG_TPARAM2, 0x28); + serigo(GORDON_REG_TLCDIF2, 0x14); + serigo(GORDON_REG_TSSPB_ST2, 0x49); + serigo(GORDON_REG_TSSPB_ED2, 0x4B); + serigo(GORDON_REG_TSCK_ST2, 0x4A); + serigo(GORDON_REG_TSCK_WD2, 0x02); + serigo(GORDON_REG_TGSPB_VST2, 0x02); + serigo(GORDON_REG_TGSPB_VED2, 0x03); + serigo(GORDON_REG_TGSPB_CH2, 0x2F); + serigo(GORDON_REG_TGCK_ST2, 0x40); + serigo(GORDON_REG_TGCK_ED2, 0x1E); + serigo(GORDON_REG_TPCTL_ST2, 0x2C); + serigo(GORDON_REG_TPCTL_ED2, 0x3A); + serigo(GORDON_REG_TPCHG_ED2, 0x3C); + serigo(GORDON_REG_TCOM_CH2, 0x28); + serigo(GORDON_REG_THBP2, 0x4D); + serigo(GORDON_REG_TPHCTL2, 0x1A); + + /* VGA settings */ + serigo(GORDON_REG_IVBP1, 0x02); + serigo(GORDON_REG_IHBP1, 0x90); + serigo(GORDON_REG_IVNUM1, 0xA0); + serigo(GORDON_REG_IHNUM1, 0x78); + + /* QVGA settings */ + serigo(GORDON_REG_IVBP2, 0x02); + serigo(GORDON_REG_IHBP2, 0x48); + serigo(GORDON_REG_IVNUM2, 0x50); + serigo(GORDON_REG_IHNUM2, 0x3C); + + /* Gordon Charge pump settings and ON */ + serigo(GORDON_REG_POWCTL, 0x03); + mdelay(15); + serigo(GORDON_REG_POWCTL, 0x07); + mdelay(15); + + serigo(GORDON_REG_POWCTL, 0x0F); + mdelay(15); + + serigo(GORDON_REG_AVCTL, 0x03); + mdelay(15); + + serigo(GORDON_REG_POWCTL, 0x1F); + mdelay(15); + + serigo(GORDON_REG_POWCTL, 0x5F); + mdelay(15); + + serigo(GORDON_REG_POWCTL, 0x7F); + mdelay(15); + + serigo(GORDON_REG_LCDIFCTL1, 0x02); + mdelay(15); + + serigo(GORDON_REG_IMGCTL1, 0x00); + mdelay(15); + + serigo(GORDON_REG_LCDIFCTL3, 0x00); + mdelay(15); + + serigo(GORDON_REG_VALTRAN, 0x01); + mdelay(15); + + serigo(GORDON_REG_LCDIFCTL1, 0x03); + mdelay(1); + gordon_state.display_on = TRUE; + } +} + +static int lcdc_gordon_panel_on(struct platform_device *pdev) +{ + if (!gordon_state.disp_initialized) { + /* Configure reset GPIO that drives DAC */ + lcdc_gordon_pdata->panel_config_gpio(1); + spi_dac = *(lcdc_gordon_pdata->gpio_num + 4); + gpio_set_value(spi_dac, 0); + udelay(15); + gpio_set_value(spi_dac, 1); + spi_init(); /* LCD needs SPI */ + gordon_disp_powerup(); + gordon_disp_on(); + if (bl_level <= 1) { + /* keep back light OFF */ + serigo(GORDON_REG_LCDIFCTL2, 0x0B); + udelay(15); + serigo(GORDON_REG_VALTRAN, 0x01); + } else { + /* keep back light ON */ + serigo(GORDON_REG_LCDIFCTL2, 0x7B); + udelay(15); + serigo(GORDON_REG_VALTRAN, 0x01); + } + gordon_state.disp_initialized = TRUE; + } + return 0; +} + +static int lcdc_gordon_panel_off(struct platform_device *pdev) +{ + if (gordon_state.disp_powered_up && gordon_state.display_on) { + serigo(GORDON_REG_LCDIFCTL2, 0x7B); + serigo(GORDON_REG_VALTRAN, 0x01); + serigo(GORDON_REG_LCDIFCTL1, 0x02); + serigo(GORDON_REG_LCDIFCTL3, 0x01); + mdelay(20); + serigo(GORDON_REG_VALTRAN, 0x01); + serigo(GORDON_REG_IMGCTL1, 0x01); + serigo(GORDON_REG_LCDIFCTL1, 0x00); + mdelay(20); + + serigo(GORDON_REG_POWCTL, 0x1F); + mdelay(40); + + serigo(GORDON_REG_POWCTL, 0x07); + mdelay(40); + + serigo(GORDON_REG_POWCTL, 0x03); + mdelay(40); + + serigo(GORDON_REG_POWCTL, 0x00); + mdelay(40); + lcdc_gordon_pdata->panel_config_gpio(0); + gordon_state.display_on = FALSE; + gordon_state.disp_initialized = FALSE; + } + return 0; +} + +static void lcdc_gordon_set_backlight(struct msm_fb_data_type *mfd) +{ + bl_level = mfd->bl_level; + + if (gordon_state.disp_initialized) { + if (bl_level <= 1) { + /* keep back light OFF */ + serigo(GORDON_REG_LCDIFCTL2, 0x0B); + udelay(15); + serigo(GORDON_REG_VALTRAN, 0x01); + } else { + /* keep back light ON */ + serigo(GORDON_REG_LCDIFCTL2, 0x7B); + udelay(15); + serigo(GORDON_REG_VALTRAN, 0x01); + } + } +} + +static int gordon_probe(struct platform_device *pdev) +{ + if (pdev->id == 0) { + lcdc_gordon_pdata = pdev->dev.platform_data; + return 0; + } + msm_fb_add_device(pdev); + return 0; +} + +static struct platform_driver this_driver = { + .probe = gordon_probe, + .driver = { + .name = "lcdc_gordon_vga", + }, +}; + +static struct msm_fb_panel_data gordon_panel_data = { + .on = lcdc_gordon_panel_on, + .off = lcdc_gordon_panel_off, + .set_backlight = lcdc_gordon_set_backlight, +}; + +static struct platform_device this_device = { + .name = "lcdc_gordon_vga", + .id = 1, + .dev = { + .platform_data = &gordon_panel_data, + } +}; + +static int __init lcdc_gordon_panel_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + +#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM + if (msm_fb_detect_client("lcdc_gordon_vga")) + return 0; +#endif + ret = platform_driver_register(&this_driver); + if (ret) + return ret; + + pinfo = &gordon_panel_data.panel_info; + pinfo->xres = 480; + pinfo->yres = 640; + MSM_FB_SINGLE_MODE_PANEL(pinfo); + pinfo->type = LCDC_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->wait_cycle = 0; + pinfo->bpp = 24; + pinfo->fb_num = 2; + pinfo->clk_rate = 24500000; + pinfo->bl_max = 4; + pinfo->bl_min = 1; + + pinfo->lcdc.h_back_porch = 84; + pinfo->lcdc.h_front_porch = 33; + pinfo->lcdc.h_pulse_width = 60; + pinfo->lcdc.v_back_porch = 0; + pinfo->lcdc.v_front_porch = 2; + pinfo->lcdc.v_pulse_width = 2; + pinfo->lcdc.border_clr = 0; /* blk */ + pinfo->lcdc.underflow_clr = 0xff; /* blue */ + pinfo->lcdc.hsync_skew = 0; + + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + + return ret; +} + +module_init(lcdc_gordon_panel_init); diff --git a/drivers/video/msm/lcdc_nt35582_wvga.c b/drivers/video/msm/lcdc_nt35582_wvga.c new file mode 100644 index 000000000000..db7fd34dc1d9 --- /dev/null +++ b/drivers/video/msm/lcdc_nt35582_wvga.c @@ -0,0 +1,472 @@ +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#ifdef CONFIG_SPI_QUP +#include +#endif +#include +#include +#include "msm_fb.h" + +#define LCDC_NT35582_PANEL_NAME "lcdc_nt35582_wvga" + +#define WRITE_FIRST_TRANS 0x20 +#define WRITE_SECOND_TRANS 0x00 +#define WRITE_THIRD_TRANS 0x40 +#define READ_FIRST_TRANS 0x20 +#define READ_SECOND_TRANS 0x00 +#define READ_THIRD_TRANS 0xC0 + +#ifdef CONFIG_SPI_QUP +#define LCDC_NT35582_SPI_DEVICE_NAME "lcdc_nt35582_spi" +static struct spi_device *spi_client; +#endif + +struct nt35582_state_type { + boolean display_on; + int bl_level; +}; + +static struct nt35582_state_type nt35582_state = { 0 }; +static int gpio_backlight_en; +static struct msm_panel_common_pdata *lcdc_nt35582_pdata; + +static int spi_write_2bytes(struct spi_device *spi, + unsigned char reg_high_addr, unsigned char reg_low_addr) +{ + char tx_buf[4]; + int rc; + struct spi_message m; + struct spi_transfer t; + + memset(&t, 0, sizeof t); + t.tx_buf = tx_buf; + + spi_setup(spi); + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + tx_buf[0] = WRITE_FIRST_TRANS; + tx_buf[1] = reg_high_addr; + tx_buf[2] = WRITE_SECOND_TRANS; + tx_buf[3] = reg_low_addr; + t.rx_buf = NULL; + t.len = 4; + t.bits_per_word = 16; + rc = spi_sync(spi, &m); + if (rc) + pr_err("write spi command failed!\n"); + + return rc; +} + +static int spi_write_3bytes(struct spi_device *spi, unsigned char reg_high_addr, + unsigned char reg_low_addr, unsigned char write_data) +{ + char tx_buf[6]; + int rc; + struct spi_message m; + struct spi_transfer t; + + memset(&t, 0, sizeof t); + t.tx_buf = tx_buf; + + spi_setup(spi); + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + tx_buf[0] = WRITE_FIRST_TRANS; + tx_buf[1] = reg_high_addr; + tx_buf[2] = WRITE_SECOND_TRANS; + tx_buf[3] = reg_low_addr; + tx_buf[4] = WRITE_THIRD_TRANS; + tx_buf[5] = write_data; + t.rx_buf = NULL; + t.len = 6; + t.bits_per_word = 16; + rc = spi_sync(spi, &m); + + if (rc) + pr_err("write spi command failed!\n"); + + return rc; +} + +static int spi_read_bytes(struct spi_device *spi, unsigned char reg_high_addr, + unsigned char reg_low_addr, unsigned char *read_value) +{ + char tx_buf[6]; + char rx_buf[6]; + int rc; + struct spi_message m; + struct spi_transfer t; + + memset(&t, 0, sizeof t); + t.tx_buf = tx_buf; + + spi_setup(spi); + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + tx_buf[0] = READ_FIRST_TRANS; + tx_buf[1] = reg_high_addr; + tx_buf[2] = READ_SECOND_TRANS; + tx_buf[3] = reg_low_addr; + tx_buf[4] = READ_THIRD_TRANS; + tx_buf[5] = 0x00; + + t.rx_buf = rx_buf; + t.len = 6; + t.bits_per_word = 16; + rc = spi_sync(spi, &m); + + if (rc) + pr_err("write spi command failed!\n"); + else + *read_value = rx_buf[5]; + + return rc; +} + +static void nt35582_disp_on(void) +{ + uint32 panel_id1 = 0, panel_id2 = 0; + + if (!nt35582_state.display_on) { + + /* GVDD setting */ + spi_write_3bytes(spi_client, 0xC0, 0x00, 0xC0); + spi_write_3bytes(spi_client, 0xC0, 0x01, 0x00); + spi_write_3bytes(spi_client, 0xC0, 0x02, 0xC0); + spi_write_3bytes(spi_client, 0xC0, 0x03, 0x00); + /* Power setting */ + spi_write_3bytes(spi_client, 0xC1, 0x00, 0x40); + spi_write_3bytes(spi_client, 0xC2, 0x00, 0x21); + spi_write_3bytes(spi_client, 0xC2, 0x02, 0x02); + + /* Gamma setting */ + spi_write_3bytes(spi_client, 0xE0, 0x00, 0x0E); + spi_write_3bytes(spi_client, 0xE0, 0x01, 0x54); + spi_write_3bytes(spi_client, 0xE0, 0x02, 0x63); + spi_write_3bytes(spi_client, 0xE0, 0x03, 0x76); + spi_write_3bytes(spi_client, 0xE0, 0x04, 0x1F); + spi_write_3bytes(spi_client, 0xE0, 0x05, 0x31); + spi_write_3bytes(spi_client, 0xE0, 0x06, 0x62); + spi_write_3bytes(spi_client, 0xE0, 0x07, 0x78); + spi_write_3bytes(spi_client, 0xE0, 0x08, 0x1F); + spi_write_3bytes(spi_client, 0xE0, 0x09, 0x25); + spi_write_3bytes(spi_client, 0xE0, 0x0A, 0xB3); + spi_write_3bytes(spi_client, 0xE0, 0x0B, 0x17); + spi_write_3bytes(spi_client, 0xE0, 0x0C, 0x38); + spi_write_3bytes(spi_client, 0xE0, 0x0D, 0x5A); + spi_write_3bytes(spi_client, 0xE0, 0x0E, 0xA2); + spi_write_3bytes(spi_client, 0xE0, 0x0F, 0xA2); + spi_write_3bytes(spi_client, 0xE0, 0x10, 0x24); + spi_write_3bytes(spi_client, 0xE0, 0x11, 0x57); + + spi_write_3bytes(spi_client, 0xE1, 0x00, 0x0E); + spi_write_3bytes(spi_client, 0xE1, 0x01, 0x54); + spi_write_3bytes(spi_client, 0xE1, 0x02, 0x63); + spi_write_3bytes(spi_client, 0xE1, 0x03, 0x76); + spi_write_3bytes(spi_client, 0xE1, 0x04, 0x1F); + spi_write_3bytes(spi_client, 0xE1, 0x05, 0x31); + spi_write_3bytes(spi_client, 0xE1, 0x06, 0X62); + spi_write_3bytes(spi_client, 0xE1, 0x07, 0x78); + spi_write_3bytes(spi_client, 0xE1, 0x08, 0x1F); + spi_write_3bytes(spi_client, 0xE1, 0x09, 0x25); + spi_write_3bytes(spi_client, 0xE1, 0x0A, 0xB3); + spi_write_3bytes(spi_client, 0xE1, 0x0B, 0x17); + spi_write_3bytes(spi_client, 0xE1, 0x0C, 0x38); + spi_write_3bytes(spi_client, 0xE1, 0x0D, 0x5A); + spi_write_3bytes(spi_client, 0xE1, 0x0E, 0xA2); + spi_write_3bytes(spi_client, 0xE1, 0x0F, 0xA2); + spi_write_3bytes(spi_client, 0xE1, 0x10, 0x24); + spi_write_3bytes(spi_client, 0xE1, 0x11, 0x57); + + spi_write_3bytes(spi_client, 0xE2, 0x00, 0x0E); + spi_write_3bytes(spi_client, 0xE2, 0x01, 0x54); + spi_write_3bytes(spi_client, 0xE2, 0x02, 0x63); + spi_write_3bytes(spi_client, 0xE2, 0x03, 0x76); + spi_write_3bytes(spi_client, 0xE2, 0x04, 0x1F); + spi_write_3bytes(spi_client, 0xE2, 0x05, 0x31); + spi_write_3bytes(spi_client, 0xE2, 0x06, 0x62); + spi_write_3bytes(spi_client, 0xE2, 0x07, 0x78); + spi_write_3bytes(spi_client, 0xE2, 0x08, 0x1F); + spi_write_3bytes(spi_client, 0xE2, 0x09, 0x25); + spi_write_3bytes(spi_client, 0xE2, 0x0A, 0xB3); + spi_write_3bytes(spi_client, 0xE2, 0x0B, 0x17); + spi_write_3bytes(spi_client, 0xE2, 0x0C, 0x38); + spi_write_3bytes(spi_client, 0xE2, 0x0D, 0x5A); + spi_write_3bytes(spi_client, 0xE2, 0x0E, 0xA2); + spi_write_3bytes(spi_client, 0xE2, 0x0F, 0xA2); + spi_write_3bytes(spi_client, 0xE2, 0x10, 0x24); + spi_write_3bytes(spi_client, 0xE2, 0x11, 0x57); + + spi_write_3bytes(spi_client, 0xE3, 0x00, 0x0E); + spi_write_3bytes(spi_client, 0xE3, 0x01, 0x54); + spi_write_3bytes(spi_client, 0xE3, 0x02, 0x63); + spi_write_3bytes(spi_client, 0xE3, 0x03, 0x76); + spi_write_3bytes(spi_client, 0xE3, 0x04, 0x1F); + spi_write_3bytes(spi_client, 0xE3, 0x05, 0x31); + spi_write_3bytes(spi_client, 0xE3, 0x06, 0x62); + spi_write_3bytes(spi_client, 0xE3, 0x07, 0x78); + spi_write_3bytes(spi_client, 0xE3, 0x08, 0x1F); + spi_write_3bytes(spi_client, 0xE3, 0x09, 0x25); + spi_write_3bytes(spi_client, 0xE3, 0x0A, 0xB3); + spi_write_3bytes(spi_client, 0xE3, 0x0B, 0x17); + spi_write_3bytes(spi_client, 0xE3, 0x0C, 0x38); + spi_write_3bytes(spi_client, 0xE3, 0x0D, 0x5A); + spi_write_3bytes(spi_client, 0xE3, 0x0E, 0xA2); + spi_write_3bytes(spi_client, 0xE3, 0x0F, 0xA2); + spi_write_3bytes(spi_client, 0xE3, 0x10, 0x24); + spi_write_3bytes(spi_client, 0xE3, 0x11, 0x57); + + spi_write_3bytes(spi_client, 0xE4, 0x00, 0x48); + spi_write_3bytes(spi_client, 0xE4, 0x01, 0x6B); + spi_write_3bytes(spi_client, 0xE4, 0x02, 0x84); + spi_write_3bytes(spi_client, 0xE4, 0x03, 0x9B); + spi_write_3bytes(spi_client, 0xE4, 0x04, 0x1F); + spi_write_3bytes(spi_client, 0xE4, 0x05, 0x31); + spi_write_3bytes(spi_client, 0xE4, 0x06, 0x62); + spi_write_3bytes(spi_client, 0xE4, 0x07, 0x78); + spi_write_3bytes(spi_client, 0xE4, 0x08, 0x1F); + spi_write_3bytes(spi_client, 0xE4, 0x09, 0x25); + spi_write_3bytes(spi_client, 0xE4, 0x0A, 0xB3); + spi_write_3bytes(spi_client, 0xE4, 0x0B, 0x17); + spi_write_3bytes(spi_client, 0xE4, 0x0C, 0x38); + spi_write_3bytes(spi_client, 0xE4, 0x0D, 0x5A); + spi_write_3bytes(spi_client, 0xE4, 0x0E, 0xA2); + spi_write_3bytes(spi_client, 0xE4, 0x0F, 0xA2); + spi_write_3bytes(spi_client, 0xE4, 0x10, 0x24); + spi_write_3bytes(spi_client, 0xE4, 0x11, 0x57); + + spi_write_3bytes(spi_client, 0xE5, 0x00, 0x48); + spi_write_3bytes(spi_client, 0xE5, 0x01, 0x6B); + spi_write_3bytes(spi_client, 0xE5, 0x02, 0x84); + spi_write_3bytes(spi_client, 0xE5, 0x03, 0x9B); + spi_write_3bytes(spi_client, 0xE5, 0x04, 0x1F); + spi_write_3bytes(spi_client, 0xE5, 0x05, 0x31); + spi_write_3bytes(spi_client, 0xE5, 0x06, 0x62); + spi_write_3bytes(spi_client, 0xE5, 0x07, 0x78); + spi_write_3bytes(spi_client, 0xE5, 0x08, 0x1F); + spi_write_3bytes(spi_client, 0xE5, 0x09, 0x25); + spi_write_3bytes(spi_client, 0xE5, 0x0A, 0xB3); + spi_write_3bytes(spi_client, 0xE5, 0x0B, 0x17); + spi_write_3bytes(spi_client, 0xE5, 0x0C, 0x38); + spi_write_3bytes(spi_client, 0xE5, 0x0D, 0x5A); + spi_write_3bytes(spi_client, 0xE5, 0x0E, 0xA2); + spi_write_3bytes(spi_client, 0xE5, 0x0F, 0xA2); + spi_write_3bytes(spi_client, 0xE5, 0x10, 0x24); + spi_write_3bytes(spi_client, 0xE5, 0x11, 0x57); + + /* Data format setting */ + spi_write_3bytes(spi_client, 0x3A, 0x00, 0x70); + + /* Reverse PCLK signal of LCM to meet Qualcomm's platform */ + spi_write_3bytes(spi_client, 0x3B, 0x00, 0x2B); + + /* Scan direstion setting */ + spi_write_3bytes(spi_client, 0x36, 0x00, 0x00); + + /* Sleep out */ + spi_write_2bytes(spi_client, 0x11, 0x00); + + msleep(120); + + /* Display on */ + spi_write_2bytes(spi_client, 0x29, 0x00); + + pr_info("%s: LCM SPI display on CMD finished...\n", __func__); + + msleep(200); + + nt35582_state.display_on = TRUE; + } + + /* Test to read RDDID. It should be 0x0055h and 0x0082h */ + spi_read_bytes(spi_client, 0x10, 0x80, (unsigned char *)&panel_id1); + spi_read_bytes(spi_client, 0x11, 0x80, (unsigned char *)&panel_id2); + + pr_info(KERN_INFO "nt35582_disp_on: LCM_ID=[0x%x, 0x%x]\n", + panel_id1, panel_id2); +} + +static int lcdc_nt35582_panel_on(struct platform_device *pdev) +{ + nt35582_disp_on(); + return 0; +} + +static int lcdc_nt35582_panel_off(struct platform_device *pdev) +{ + nt35582_state.display_on = FALSE; + return 0; +} + +static void lcdc_nt35582_set_backlight(struct msm_fb_data_type *mfd) +{ + int bl_level; + int i = 0, step = 0; + + bl_level = mfd->bl_level; + if (bl_level == nt35582_state.bl_level) + return; + else + nt35582_state.bl_level = bl_level; + + if (bl_level == 0) { + gpio_set_value_cansleep(gpio_backlight_en, 0); + return; + } + + /* Level:0~31 mapping to step 32~1 */ + step = 32 - bl_level; + for (i = 0; i < step; i++) { + gpio_set_value_cansleep(gpio_backlight_en, 0); + ndelay(5); + gpio_set_value_cansleep(gpio_backlight_en, 1); + ndelay(5); + } +} + +static int nt35582_probe(struct platform_device *pdev) +{ + if (pdev->id == 0) { + lcdc_nt35582_pdata = pdev->dev.platform_data; + return 0; + } + + gpio_backlight_en = *(lcdc_nt35582_pdata->gpio_num); + + msm_fb_add_device(pdev); + return 0; +} + +#ifdef CONFIG_SPI_QUP +static int lcdc_nt35582_spi_probe(struct spi_device *spi) +{ + spi_client = spi; + spi_client->bits_per_word = 16; + spi_client->chip_select = 0; + spi_client->max_speed_hz = 1100000; + spi_client->mode = SPI_MODE_0; + spi_setup(spi_client); + + return 0; +} + +static int lcdc_nt35582_spi_remove(struct spi_device *spi) +{ + spi_client = NULL; + return 0; +} + +static struct spi_driver lcdc_nt35582_spi_driver = { + .driver = { + .name = LCDC_NT35582_SPI_DEVICE_NAME, + .owner = THIS_MODULE, + }, + .probe = lcdc_nt35582_spi_probe, + .remove = lcdc_nt35582_spi_remove, +}; +#endif +static struct platform_driver this_driver = { + .probe = nt35582_probe, + .driver = { + .name = LCDC_NT35582_PANEL_NAME, + }, +}; + +static struct msm_fb_panel_data nt35582_panel_data = { + .on = lcdc_nt35582_panel_on, + .off = lcdc_nt35582_panel_off, + .set_backlight = lcdc_nt35582_set_backlight, +}; + +static struct platform_device this_device = { + .name = LCDC_NT35582_PANEL_NAME, + .id = 1, + .dev = { + .platform_data = &nt35582_panel_data, + } +}; + +static int __init lcdc_nt35582_panel_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + +#ifdef CONFIG_FB_MSM_LCDC_AUTO_DETECT + if (msm_fb_detect_client(LCDC_NT35582_PANEL_NAME)) { + pr_err("detect failed\n"); + return 0; + } +#endif + ret = platform_driver_register(&this_driver); + if (ret) { + pr_err("Fails to platform_driver_register...\n"); + return ret; + } + + pinfo = &nt35582_panel_data.panel_info; + pinfo->xres = 480; + pinfo->yres = 800; + MSM_FB_SINGLE_MODE_PANEL(pinfo); + pinfo->type = LCDC_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->wait_cycle = 0; + pinfo->bpp = 24; + pinfo->fb_num = 2; + pinfo->clk_rate = 25600000; + pinfo->bl_max = 31; + pinfo->bl_min = 1; + + pinfo->lcdc.h_back_porch = 10; /* hsw = 8 + hbp=184 */ + pinfo->lcdc.h_front_porch = 10; + pinfo->lcdc.h_pulse_width = 2; + pinfo->lcdc.v_back_porch = 4; /* vsw=1 + vbp = 2 */ + pinfo->lcdc.v_front_porch = 10; + pinfo->lcdc.v_pulse_width = 2; + pinfo->lcdc.border_clr = 0; /* blk */ + pinfo->lcdc.underflow_clr = 0xff; /* blue */ + pinfo->lcdc.hsync_skew = 0; + + ret = platform_device_register(&this_device); + if (ret) { + pr_err("not able to register the device\n"); + goto fail_driver; + } +#ifdef CONFIG_SPI_QUP + ret = spi_register_driver(&lcdc_nt35582_spi_driver); + + if (ret) { + pr_err("not able to register spi\n"); + goto fail_device; + } +#endif + return ret; + +#ifdef CONFIG_SPI_QUP +fail_device: + platform_device_unregister(&this_device); +#endif +fail_driver: + platform_driver_unregister(&this_driver); + return ret; +} + +device_initcall(lcdc_nt35582_panel_init); diff --git a/drivers/video/msm/lcdc_panel.c b/drivers/video/msm/lcdc_panel.c new file mode 100644 index 000000000000..16d6855e1b2f --- /dev/null +++ b/drivers/video/msm/lcdc_panel.c @@ -0,0 +1,84 @@ +/* Copyright (c) 2008-2009, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" + +static int lcdc_panel_on(struct platform_device *pdev) +{ + return 0; +} + +static int lcdc_panel_off(struct platform_device *pdev) +{ + return 0; +} + +static int lcdc_panel_probe(struct platform_device *pdev) +{ + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = lcdc_panel_probe, + .driver = { + .name = "lcdc_panel", + }, +}; + +static struct msm_fb_panel_data lcdc_panel_data = { + .on = lcdc_panel_on, + .off = lcdc_panel_off, +}; + +static int lcdc_dev_id; + +int lcdc_device_register(struct msm_panel_info *pinfo) +{ + struct platform_device *pdev = NULL; + int ret; + + pdev = platform_device_alloc("lcdc_panel", ++lcdc_dev_id); + if (!pdev) + return -ENOMEM; + + lcdc_panel_data.panel_info = *pinfo; + ret = platform_device_add_data(pdev, &lcdc_panel_data, + sizeof(lcdc_panel_data)); + if (ret) { + printk(KERN_ERR + "%s: platform_device_add_data failed!\n", __func__); + goto err_device_put; + } + + ret = platform_device_add(pdev); + if (ret) { + printk(KERN_ERR + "%s: platform_device_register failed!\n", __func__); + goto err_device_put; + } + + return 0; + +err_device_put: + platform_device_put(pdev); + return ret; +} + +static int __init lcdc_panel_init(void) +{ + return platform_driver_register(&this_driver); +} + +module_init(lcdc_panel_init); diff --git a/drivers/video/msm/lcdc_prism.c b/drivers/video/msm/lcdc_prism.c new file mode 100644 index 000000000000..fb040ca76890 --- /dev/null +++ b/drivers/video/msm/lcdc_prism.c @@ -0,0 +1,61 @@ +/* Copyright (c) 2009-2010, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" + +#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM +#include "mddihosti.h" +#endif + +static int __init lcdc_prism_init(void) +{ + int ret; + struct msm_panel_info pinfo; + +#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM + ret = msm_fb_detect_client("lcdc_prism_wvga"); + if (ret == -ENODEV) + return 0; + + if (ret && (mddi_get_client_id() != 0)) + return 0; +#endif + + pinfo.xres = 800; + pinfo.yres = 480; + MSM_FB_SINGLE_MODE_PANEL(&pinfo); + pinfo.type = LCDC_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.fb_num = 2; + pinfo.clk_rate = 30720000; + + pinfo.lcdc.h_back_porch = 21; + pinfo.lcdc.h_front_porch = 81; + pinfo.lcdc.h_pulse_width = 60; + pinfo.lcdc.v_back_porch = 18; + pinfo.lcdc.v_front_porch = 27; + pinfo.lcdc.v_pulse_width = 2; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + + ret = lcdc_device_register(&pinfo); + if (ret) + printk(KERN_ERR "%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(lcdc_prism_init); diff --git a/drivers/video/msm/lcdc_samsung_oled_pt.c b/drivers/video/msm/lcdc_samsung_oled_pt.c new file mode 100644 index 000000000000..00656ebe70c8 --- /dev/null +++ b/drivers/video/msm/lcdc_samsung_oled_pt.c @@ -0,0 +1,588 @@ +/* Copyright (c) 2009-2010, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#ifdef CONFIG_SPI_QUP +#include +#else +#include +#endif +#include "msm_fb.h" + +#define DEBUG +/* #define SYSFS_DEBUG_CMD */ + +#ifdef CONFIG_SPI_QUP +#define LCDC_SAMSUNG_SPI_DEVICE_NAME "lcdc_samsung_ams367pe02" +static struct spi_device *lcdc_spi_client; +#else +static int spi_cs; +static int spi_sclk; +static int spi_mosi; +#endif + +struct samsung_state_type { + boolean disp_initialized; + boolean display_on; + boolean disp_powered_up; + int brightness; +}; + +struct samsung_spi_data { + u8 addr; + u8 len; + u8 data[22]; +}; + +static struct samsung_spi_data panel_sequence[] = { + { .addr = 0xf8, .len = 14, .data = { 0x01, 0x27, 0x27, 0x07, 0x07, + 0x54, 0x9f, 0x63, 0x86, 0x1a, 0x33, 0x0d, 0x00, 0x00 } }, +}; +static struct samsung_spi_data display_sequence[] = { + { .addr = 0xf2, .len = 5, .data = { 0x02, 0x03, 0x1c, 0x10, 0x10 } }, + { .addr = 0xf7, .len = 3, .data = { 0x00, 0x00, 0x30 } }, +}; + +/* lum=300 cd/m2 */ +static struct samsung_spi_data gamma_sequence_300[] = { + { .addr = 0xfa, .len = 22, .data = { 0x02, 0x18, 0x08, 0x24, 0x7d, 0x77, + 0x5b, 0xbe, 0xc1, 0xb1, 0xb3, 0xb7, 0xa6, 0xc3, 0xc5, 0xb9, 0x00, 0xb3, + 0x00, 0xaf, 0x00, 0xe8 } }, + { .addr = 0xFA, .len = 1, .data = { 0x03 } }, +}; +/* lum = 180 cd/m2*/ +static struct samsung_spi_data gamma_sequence_180[] = { + { .addr = 0xfa, .len = 22, .data = { 0x02, 0x18, 0x08, 0x24, 0x83, 0x78, + 0x60, 0xc5, 0xc6, 0xb8, 0xba, 0xbe, 0xad, 0xcb, 0xcd, 0xc2, 0x00, 0x92, + 0x00, 0x8e, 0x00, 0xbc } }, + { .addr = 0xFA, .len = 1, .data = { 0x03 } }, +}; +/* lum = 80 cd/m2*/ +static struct samsung_spi_data gamma_sequence_80[] = { + { .addr = 0xfa, .len = 22, .data = { 0x02, 0x18, 0x08, 0x24, 0x94, 0x73, + 0x6c, 0xcb, 0xca, 0xbe, 0xc4, 0xc7, 0xb8, 0xd3, 0xd5, 0xcb, 0x00, 0x6d, + 0x00, 0x69, 0x00, 0x8b } }, + { .addr = 0xFA, .len = 1, .data = { 0x03 } }, +}; + +static struct samsung_spi_data etc_sequence[] = { + { .addr = 0xF6, .len = 3, .data = { 0x00, 0x8e, 0x07 } }, + { .addr = 0xB3, .len = 1, .data = { 0x0C } }, +}; + +static struct samsung_state_type samsung_state = { .brightness = 180 }; +static struct msm_panel_common_pdata *lcdc_samsung_pdata; + +#ifndef CONFIG_SPI_QUP +static void samsung_spi_write_byte(boolean dc, u8 data) +{ + uint32 bit; + int bnum; + + gpio_set_value(spi_sclk, 0); + gpio_set_value(spi_mosi, dc ? 1 : 0); + udelay(1); /* at least 20 ns */ + gpio_set_value(spi_sclk, 1); /* clk high */ + udelay(1); /* at least 20 ns */ + + bnum = 8; /* 8 data bits */ + bit = 0x80; + while (bnum--) { + gpio_set_value(spi_sclk, 0); /* clk low */ + gpio_set_value(spi_mosi, (data & bit) ? 1 : 0); + udelay(1); + gpio_set_value(spi_sclk, 1); /* clk high */ + udelay(1); + bit >>= 1; + } + gpio_set_value(spi_mosi, 0); + +} + +static void samsung_spi_read_bytes(u8 cmd, u8 *data, int num) +{ + int bnum; + + /* Chip Select - low */ + gpio_set_value(spi_cs, 0); + udelay(2); + + /* command byte first */ + samsung_spi_write_byte(0, cmd); + udelay(2); + + gpio_direction_input(spi_mosi); + + if (num > 1) { + /* extra dummy clock */ + gpio_set_value(spi_sclk, 0); + udelay(1); + gpio_set_value(spi_sclk, 1); + udelay(1); + } + + /* followed by data bytes */ + bnum = num * 8; /* number of bits */ + *data = 0; + while (bnum) { + gpio_set_value(spi_sclk, 0); /* clk low */ + udelay(1); + *data <<= 1; + *data |= gpio_get_value(spi_mosi) ? 1 : 0; + gpio_set_value(spi_sclk, 1); /* clk high */ + udelay(1); + --bnum; + if ((bnum % 8) == 0) + ++data; + } + + gpio_direction_output(spi_mosi, 0); + + /* Chip Select - high */ + udelay(2); + gpio_set_value(spi_cs, 1); +} +#endif + +#ifdef DEBUG +static const char *byte_to_binary(const u8 *buf, int len) +{ + static char b[32*8+1]; + char *p = b; + int i, z; + + for (i = 0; i < len; ++i) { + u8 val = *buf++; + for (z = 1 << 7; z > 0; z >>= 1) + *p++ = (val & z) ? '1' : '0'; + } + *p = 0; + + return b; +} +#endif + +#define BIT_OFFSET (bit_size % 8) +#define ADD_BIT(val) do { \ + tx_buf[bit_size / 8] |= \ + (u8)((val ? 1 : 0) << (7 - BIT_OFFSET)); \ + ++bit_size; \ + } while (0) + +#define ADD_BYTE(data) do { \ + tx_buf[bit_size / 8] |= (u8)(data >> BIT_OFFSET); \ + bit_size += 8; \ + if (BIT_OFFSET != 0) \ + tx_buf[bit_size / 8] |= (u8)(data << (8 - BIT_OFFSET));\ + } while (0) + +static int samsung_serigo(struct samsung_spi_data data) +{ +#ifdef CONFIG_SPI_QUP + char tx_buf[32]; + int bit_size = 0, i, rc; + struct spi_message m; + struct spi_transfer t; + + if (!lcdc_spi_client) { + pr_err("%s lcdc_spi_client is NULL\n", __func__); + return -EINVAL; + } + + memset(&t, 0, sizeof t); + memset(tx_buf, 0, sizeof tx_buf); + t.tx_buf = tx_buf; + spi_setup(lcdc_spi_client); + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + ADD_BIT(FALSE); + ADD_BYTE(data.addr); + for (i = 0; i < data.len; ++i) { + ADD_BIT(TRUE); + ADD_BYTE(data.data[i]); + } + + /* add padding bits so we round to next byte */ + t.len = (bit_size+7) / 8; + if (t.len <= 4) + t.bits_per_word = bit_size; + + rc = spi_sync(lcdc_spi_client, &m); +#ifdef DEBUG + pr_info("%s: addr=0x%02x, #args=%d[%d] [%s], rc=%d\n", + __func__, data.addr, t.len, t.bits_per_word, + byte_to_binary(tx_buf, t.len), rc); +#endif + return rc; +#else + int i; + + /* Chip Select - low */ + gpio_set_value(spi_cs, 0); + udelay(2); + + samsung_spi_write_byte(FALSE, data.addr); + udelay(2); + + for (i = 0; i < data.len; ++i) { + samsung_spi_write_byte(TRUE, data.data[i]); + udelay(2); + } + + /* Chip Select - high */ + gpio_set_value(spi_cs, 1); +#ifdef DEBUG + pr_info("%s: cmd=0x%02x, #args=%d\n", __func__, data.addr, data.len); +#endif + return 0; +#endif +} + +static int samsung_write_cmd(u8 cmd) +{ +#ifdef CONFIG_SPI_QUP + char tx_buf[2]; + int bit_size = 0, rc; + struct spi_message m; + struct spi_transfer t; + + if (!lcdc_spi_client) { + pr_err("%s lcdc_spi_client is NULL\n", __func__); + return -EINVAL; + } + + memset(&t, 0, sizeof t); + memset(tx_buf, 0, sizeof tx_buf); + t.tx_buf = tx_buf; + spi_setup(lcdc_spi_client); + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + ADD_BIT(FALSE); + ADD_BYTE(cmd); + + t.len = 2; + t.bits_per_word = 9; + + rc = spi_sync(lcdc_spi_client, &m); +#ifdef DEBUG + pr_info("%s: addr=0x%02x, #args=%d[%d] [%s], rc=%d\n", + __func__, cmd, t.len, t.bits_per_word, + byte_to_binary(tx_buf, t.len), rc); +#endif + return rc; +#else + /* Chip Select - low */ + gpio_set_value(spi_cs, 0); + udelay(2); + + samsung_spi_write_byte(FALSE, cmd); + + /* Chip Select - high */ + udelay(2); + gpio_set_value(spi_cs, 1); +#ifdef DEBUG + pr_info("%s: cmd=0x%02x\n", __func__, cmd); +#endif + return 0; +#endif +} + +static int samsung_serigo_list(struct samsung_spi_data *data, int count) +{ + int i, rc; + for (i = 0; i < count; ++i, ++data) { + rc = samsung_serigo(*data); + if (rc) + return rc; + msleep(10); + } + return 0; +} + +#ifndef CONFIG_SPI_QUP +static void samsung_spi_init(void) +{ + spi_sclk = *(lcdc_samsung_pdata->gpio_num); + spi_cs = *(lcdc_samsung_pdata->gpio_num + 1); + spi_mosi = *(lcdc_samsung_pdata->gpio_num + 2); + + /* Set the output so that we don't disturb the slave device */ + gpio_set_value(spi_sclk, 1); + gpio_set_value(spi_mosi, 0); + + /* Set the Chip Select deasserted (active low) */ + gpio_set_value(spi_cs, 1); +} +#endif + +static void samsung_disp_powerup(void) +{ + if (!samsung_state.disp_powered_up && !samsung_state.display_on) + samsung_state.disp_powered_up = TRUE; +} + +static struct work_struct disp_on_delayed_work; +static void samsung_disp_on_delayed_work(struct work_struct *work_ptr) +{ + /* 0x01: Software Reset */ + samsung_write_cmd(0x01); + msleep(120); + + msleep(300); + samsung_serigo_list(panel_sequence, + sizeof(panel_sequence)/sizeof(*panel_sequence)); + samsung_serigo_list(display_sequence, + sizeof(display_sequence)/sizeof(*display_sequence)); + + switch (samsung_state.brightness) { + case 300: + samsung_serigo_list(gamma_sequence_300, + sizeof(gamma_sequence_300)/sizeof(*gamma_sequence_300)); + break; + case 180: + default: + samsung_serigo_list(gamma_sequence_180, + sizeof(gamma_sequence_180)/sizeof(*gamma_sequence_180)); + break; + case 80: + samsung_serigo_list(gamma_sequence_80, + sizeof(gamma_sequence_80)/sizeof(*gamma_sequence_80)); + break; + } + + samsung_serigo_list(etc_sequence, + sizeof(etc_sequence)/sizeof(*etc_sequence)); + + /* 0x11: Sleep Out */ + samsung_write_cmd(0x11); + msleep(120); + /* 0x13: Normal Mode On */ + samsung_write_cmd(0x13); + +#ifndef CONFIG_SPI_QUP + { + u8 data; + + msleep(120); + /* 0x0A: Read Display Power Mode */ + samsung_spi_read_bytes(0x0A, &data, 1); + pr_info("%s: power=[%s]\n", __func__, + byte_to_binary(&data, 1)); + + msleep(120); + /* 0x0C: Read Display Pixel Format */ + samsung_spi_read_bytes(0x0C, &data, 1); + pr_info("%s: pixel-format=[%s]\n", __func__, + byte_to_binary(&data, 1)); + } +#endif + msleep(120); + /* 0x29: Display On */ + samsung_write_cmd(0x29); +} + +static void samsung_disp_on(void) +{ + if (samsung_state.disp_powered_up && !samsung_state.display_on) { + INIT_WORK(&disp_on_delayed_work, samsung_disp_on_delayed_work); + schedule_work(&disp_on_delayed_work); + + samsung_state.display_on = TRUE; + } +} + +static int lcdc_samsung_panel_on(struct platform_device *pdev) +{ + pr_info("%s\n", __func__); + if (!samsung_state.disp_initialized) { +#ifndef CONFIG_SPI_QUP + lcdc_samsung_pdata->panel_config_gpio(1); + samsung_spi_init(); +#endif + samsung_disp_powerup(); + samsung_disp_on(); + samsung_state.disp_initialized = TRUE; + } + return 0; +} + +static int lcdc_samsung_panel_off(struct platform_device *pdev) +{ + pr_info("%s\n", __func__); + if (samsung_state.disp_powered_up && samsung_state.display_on) { + /* 0x10: Sleep In */ + samsung_write_cmd(0x10); + msleep(120); + + samsung_state.display_on = FALSE; + samsung_state.disp_initialized = FALSE; + } + return 0; +} + +#ifdef SYSFS_DEBUG_CMD +static ssize_t samsung_rda_cmd(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = snprintf(buf, PAGE_SIZE, "n/a\n"); + pr_info("%s: 'n/a'\n", __func__); + return ret; +} + +static ssize_t samsung_wta_cmd(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + ssize_t ret = strnlen(buf, PAGE_SIZE); + uint32 cmd; + + sscanf(buf, "%x", &cmd); + samsung_write_cmd((u8)cmd); + + return ret; +} + +static DEVICE_ATTR(cmd, S_IRUGO | S_IWUGO, samsung_rda_cmd, samsung_wta_cmd); +static struct attribute *fs_attrs[] = { + &dev_attr_cmd.attr, + NULL, +}; +static struct attribute_group fs_attr_group = { + .attrs = fs_attrs, +}; +#endif + +static struct msm_fb_panel_data samsung_panel_data = { + .on = lcdc_samsung_panel_on, + .off = lcdc_samsung_panel_off, +}; + +static int samsung_probe(struct platform_device *pdev) +{ + struct msm_panel_info *pinfo; +#ifdef SYSFS_DEBUG_CMD + struct platform_device *fb_dev; + struct msm_fb_data_type *mfd; + int rc; +#endif + + pr_info("%s: id=%d\n", __func__, pdev->id); + lcdc_samsung_pdata = pdev->dev.platform_data; + + pinfo = &samsung_panel_data.panel_info; + pinfo->xres = 480; + pinfo->yres = 800; + pinfo->type = LCDC_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->wait_cycle = 0; + pinfo->bpp = 24; + pinfo->fb_num = 2; + pinfo->clk_rate = 25600000; /* Max 27.77MHz */ + pinfo->bl_max = 15; + pinfo->bl_min = 1; + + /* AMS367PE02 Operation Manual, Page 7 */ + pinfo->lcdc.h_back_porch = 16-2; /* HBP-HLW */ + pinfo->lcdc.h_front_porch = 16; + pinfo->lcdc.h_pulse_width = 2; + /* AMS367PE02 Operation Manual, Page 6 */ + pinfo->lcdc.v_back_porch = 3-2; /* VBP-VLW */ + pinfo->lcdc.v_front_porch = 28; + pinfo->lcdc.v_pulse_width = 2; + + pinfo->lcdc.border_clr = 0; + pinfo->lcdc.underflow_clr = 0xff; + pinfo->lcdc.hsync_skew = 0; + pdev->dev.platform_data = &samsung_panel_data; + +#ifndef SYSFS_DEBUG_CMD + msm_fb_add_device(pdev); +#else + fb_dev = msm_fb_add_device(pdev); + mfd = platform_get_drvdata(fb_dev); + rc = sysfs_create_group(&mfd->fbi->dev->kobj, &fs_attr_group); + if (rc) { + pr_err("%s: sysfs group creation failed, rc=%d\n", __func__, + rc); + return rc; + } +#endif + return 0; +} + +#ifdef CONFIG_SPI_QUP +static int lcdc_samsung_spi_probe(struct spi_device *spi) +{ + pr_info("%s\n", __func__); + lcdc_spi_client = spi; + lcdc_spi_client->bits_per_word = 32; + return 0; +} +static int lcdc_samsung_spi_remove(struct spi_device *spi) +{ + lcdc_spi_client = NULL; + return 0; +} +static struct spi_driver lcdc_samsung_spi_driver = { + .driver.name = LCDC_SAMSUNG_SPI_DEVICE_NAME, + .driver.owner = THIS_MODULE, + .probe = lcdc_samsung_spi_probe, + .remove = lcdc_samsung_spi_remove, +}; +#endif + +static struct platform_driver this_driver = { + .probe = samsung_probe, + .driver.name = "lcdc_samsung_oled", +}; + +static int __init lcdc_samsung_panel_init(void) +{ + int ret; + + if (msm_fb_detect_client("lcdc_samsung_oled")) { + pr_err("%s: detect failed\n", __func__); + return 0; + } + + ret = platform_driver_register(&this_driver); + if (ret) { + pr_err("%s: driver register failed, rc=%d\n", __func__, ret); + return ret; + } + +#ifdef CONFIG_SPI_QUP + ret = spi_register_driver(&lcdc_samsung_spi_driver); + + if (ret) { + pr_err("%s: spi register failed: rc=%d\n", __func__, ret); + platform_driver_unregister(&this_driver); + } else + pr_info("%s: SUCCESS (SPI)\n", __func__); +#else + pr_info("%s: SUCCESS (BitBang)\n", __func__); +#endif + return ret; +} + +module_init(lcdc_samsung_panel_init); +static void __exit lcdc_samsung_panel_exit(void) +{ + pr_info("%s\n", __func__); +#ifdef CONFIG_SPI_QUP + spi_unregister_driver(&lcdc_samsung_spi_driver); +#endif + platform_driver_unregister(&this_driver); +} +module_exit(lcdc_samsung_panel_exit); diff --git a/drivers/video/msm/lcdc_samsung_wsvga.c b/drivers/video/msm/lcdc_samsung_wsvga.c new file mode 100644 index 000000000000..e35575084840 --- /dev/null +++ b/drivers/video/msm/lcdc_samsung_wsvga.c @@ -0,0 +1,270 @@ +/* Copyright (c) 2009-2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#ifdef CONFIG_PMIC8058_PWM +#include +#include +#endif +#include +#include "msm_fb.h" + + + +#ifdef CONFIG_PMIC8058_PWM +static struct pwm_device *bl_pwm0; +static struct pwm_device *bl_pwm1; + +/* for samsung panel 300hz was the minimum freq where flickering wasnt + * observed as the screen was dimmed + */ + +#define PWM_FREQ_HZ 300 +#define PWM_PERIOD_USEC (USEC_PER_SEC / PWM_FREQ_HZ) +#define PWM_LEVEL 100 +#define PWM_DUTY_LEVEL (PWM_PERIOD_USEC / PWM_LEVEL) +#endif + +struct lcdc_samsung_data { + struct msm_panel_common_pdata *pdata; +#ifdef CONFIG_FB_MSM_LCDC_DSUB + int vga_enabled; +#endif + struct platform_device *fbpdev; +}; + +static struct lcdc_samsung_data *dd; + + +static void lcdc_samsung_panel_set_backlight(struct msm_fb_data_type *mfd) +{ +#ifdef CONFIG_PMIC8058_PWM + int bl_level; + int ret; + + bl_level = mfd->bl_level; + + if (bl_pwm0) { + ret = pwm_config(bl_pwm0, PWM_DUTY_LEVEL * bl_level, + PWM_PERIOD_USEC); + if (ret) + printk(KERN_ERR "pwm_config on pwm 0 failed %d\n", ret); + } + + if (bl_pwm1) { + ret = pwm_config(bl_pwm1, + PWM_PERIOD_USEC - (PWM_DUTY_LEVEL * bl_level), + PWM_PERIOD_USEC); + if (ret) + printk(KERN_ERR "pwm_config on pwm 1 failed %d\n", ret); + } + + if (bl_pwm0) { + ret = pwm_enable(bl_pwm0); + if (ret) + printk(KERN_ERR "pwm_enable on pwm 0 failed %d\n", ret); + } + + if (bl_pwm1) { + ret = pwm_enable(bl_pwm1); + if (ret) + printk(KERN_ERR "pwm_enable on pwm 1 failed %d\n", ret); + } +#endif + +} + +#ifdef CONFIG_FB_MSM_LCDC_DSUB +static ssize_t show_vga_enable(struct device *device, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", dd->vga_enabled); +} + +static ssize_t store_vga_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long enable; + int rc; + + rc = strict_strtoul(buf, 10, &enable); + if (rc) + return -EINVAL; + + if (dd->pdata && dd->pdata->vga_switch) + rc = dd->pdata->vga_switch(enable); + else + rc = -ENODEV; + if (!rc) { + dd->vga_enabled = enable; + rc = count; + } + return rc; +} + +static DEVICE_ATTR(vga_enable, S_IRUGO|S_IWUSR, show_vga_enable, + store_vga_enable); +static struct attribute *attrs[] = { + &dev_attr_vga_enable.attr, + NULL, +}; +static struct attribute_group attr_group = { + .attrs = attrs, +}; +#endif + +static int samsung_probe(struct platform_device *pdev) +{ + int rc = 0; +#ifdef CONFIG_FB_MSM_LCDC_DSUB + struct msm_fb_data_type *mfd; +#endif + + if (pdev->id == 0) { + dd = kzalloc(sizeof *dd, GFP_KERNEL); + if (!dd) + return -ENOMEM; +#ifdef CONFIG_FB_MSM_LCDC_DSUB + dd->vga_enabled = 0; +#endif + dd->pdata = pdev->dev.platform_data; + return 0; + } else if (!dd) + return -ENODEV; + +#ifdef CONFIG_PMIC8058_PWM + bl_pwm0 = pwm_request(dd->pdata->gpio_num[0], "backlight1"); + if (bl_pwm0 == NULL || IS_ERR(bl_pwm0)) { + pr_err("%s pwm_request() failed\n", __func__); + bl_pwm0 = NULL; + } + + bl_pwm1 = pwm_request(dd->pdata->gpio_num[1], "backlight2"); + if (bl_pwm1 == NULL || IS_ERR(bl_pwm1)) { + pr_err("%s pwm_request() failed\n", __func__); + bl_pwm1 = NULL; + } + + pr_debug("samsung_probe: bl_pwm0=%p LPG_chan0=%d " + "bl_pwm1=%p LPG_chan1=%d\n", + bl_pwm0, (int)dd->pdata->gpio_num[0], + bl_pwm1, (int)dd->pdata->gpio_num[1] + ); +#endif + + + dd->fbpdev = msm_fb_add_device(pdev); + if (!dd->fbpdev) { + dev_err(&pdev->dev, "failed to add msm_fb device\n"); + rc = -ENODEV; + goto probe_exit; + } + +#ifdef CONFIG_FB_MSM_LCDC_DSUB + mfd = platform_get_drvdata(dd->fbpdev); + if (mfd && mfd->fbi && mfd->fbi->dev) { + rc = sysfs_create_group(&mfd->fbi->dev->kobj, &attr_group); + if (rc) + dev_err(&pdev->dev, "failed to create sysfs group\n"); + } else { + dev_err(&pdev->dev, "no dev to create sysfs group\n"); + rc = -ENODEV; + } +#endif + +probe_exit: + return rc; +} + +#ifdef CONFIG_FB_MSM_LCDC_DSUB +static int samsung_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&dd->fbpdev->dev.kobj, &attr_group); + return 0; +} +#endif + +static struct platform_driver this_driver = { + .probe = samsung_probe, +#ifdef CONFIG_FB_MSM_LCDC_DSUB + .remove = samsung_remove, +#endif + .driver = { + .name = "lcdc_samsung_wsvga", + }, +}; + +static struct msm_fb_panel_data samsung_panel_data = { + .set_backlight = lcdc_samsung_panel_set_backlight, +}; + +static struct platform_device this_device = { + .name = "lcdc_samsung_wsvga", + .id = 1, + .dev = { + .platform_data = &samsung_panel_data, + } +}; + +static int __init lcdc_samsung_panel_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + + if (msm_fb_detect_client("lcdc_samsung_wsvga")) + return 0; + + ret = platform_driver_register(&this_driver); + if (ret) + return ret; + + pinfo = &samsung_panel_data.panel_info; + pinfo->xres = 1024; + pinfo->yres = 600; +#ifdef CONFIG_FB_MSM_LCDC_DSUB + /* DSUB (VGA) is on the same bus, this allows us to allocate for the + * max resolution of the DSUB display */ + pinfo->mode2_xres = 1440; + pinfo->mode2_yres = 900; + pinfo->mode2_bpp = 16; +#else + MSM_FB_SINGLE_MODE_PANEL(pinfo); +#endif + pinfo->type = LCDC_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->wait_cycle = 0; + pinfo->bpp = 18; + pinfo->fb_num = 2; + pinfo->clk_rate = 43192000; + pinfo->bl_max = PWM_LEVEL; + pinfo->bl_min = 1; + + pinfo->lcdc.h_back_porch = 80; + pinfo->lcdc.h_front_porch = 48; + pinfo->lcdc.h_pulse_width = 32; + pinfo->lcdc.v_back_porch = 4; + pinfo->lcdc.v_front_porch = 3; + pinfo->lcdc.v_pulse_width = 1; + pinfo->lcdc.border_clr = 0; + pinfo->lcdc.underflow_clr = 0xff; + pinfo->lcdc.hsync_skew = 0; + + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + + return ret; +} + +module_init(lcdc_samsung_panel_init); diff --git a/drivers/video/msm/lcdc_sharp_wvga_pt.c b/drivers/video/msm/lcdc_sharp_wvga_pt.c new file mode 100644 index 000000000000..f380bb41cceb --- /dev/null +++ b/drivers/video/msm/lcdc_sharp_wvga_pt.c @@ -0,0 +1,414 @@ +/* Copyright (c) 2009-2010, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#ifdef CONFIG_PMIC8058_PWM +#include +#include +#endif +#ifdef CONFIG_SPI_QSD +#include +#endif +#include +#include "msm_fb.h" + +#ifdef CONFIG_SPI_QSD +#define LCDC_SHARP_SPI_DEVICE_NAME "lcdc_sharp_ls038y7dx01" +static struct spi_device *lcdc_spi_client; +#endif +static int lcdc_sharp_panel_off(struct platform_device *pdev); + +#define BL_MAX 16 + +#ifdef CONFIG_PMIC8058_PWM +static struct pwm_device *bl_pwm; + +#define PWM_PERIOD 1000 /* us, period of 1Khz */ +#define DUTY_LEVEL (PWM_PERIOD / BL_MAX) +#endif + +#ifndef CONFIG_SPI_QSD +static int spi_cs; +static int spi_sclk; +static int spi_mosi; +static int spi_miso; +static unsigned char bit_shift[8] = { (1 << 7), /* MSB */ + (1 << 6), + (1 << 5), + (1 << 4), + (1 << 3), + (1 << 2), + (1 << 1), + (1 << 0) /* LSB */ +}; +#endif + +struct sharp_state_type { + boolean disp_initialized; + boolean display_on; + boolean disp_powered_up; +}; + +struct sharp_spi_data { + u8 addr; + u8 data; +}; + +static struct sharp_spi_data init_sequence[] = { + { 15, 0x01 }, + { 5, 0x01 }, + { 7, 0x10 }, + { 9, 0x1E }, + { 10, 0x04 }, + { 17, 0xFF }, + { 21, 0x8A }, + { 22, 0x00 }, + { 23, 0x82 }, + { 24, 0x24 }, + { 25, 0x22 }, + { 26, 0x6D }, + { 27, 0xEB }, + { 28, 0xB9 }, + { 29, 0x3A }, + { 49, 0x1A }, + { 50, 0x16 }, + { 51, 0x05 }, + { 55, 0x7F }, + { 56, 0x15 }, + { 57, 0x7B }, + { 60, 0x05 }, + { 61, 0x0C }, + { 62, 0x80 }, + { 63, 0x00 }, + { 92, 0x90 }, + { 97, 0x01 }, + { 98, 0xFF }, + { 113, 0x11 }, + { 114, 0x02 }, + { 115, 0x08 }, + { 123, 0xAB }, + { 124, 0x04 }, + { 6, 0x02 }, + { 133, 0x00 }, + { 134, 0xFE }, + { 135, 0x22 }, + { 136, 0x0B }, + { 137, 0xFF }, + { 138, 0x0F }, + { 139, 0x00 }, + { 140, 0xFE }, + { 141, 0x22 }, + { 142, 0x0B }, + { 143, 0xFF }, + { 144, 0x0F }, + { 145, 0x00 }, + { 146, 0xFE }, + { 147, 0x22 }, + { 148, 0x0B }, + { 149, 0xFF }, + { 150, 0x0F }, + { 202, 0x30 }, + { 30, 0x01 }, + { 4, 0x01 }, + { 31, 0x41 }, +}; + +static struct sharp_state_type sharp_state = { 0 }; +static struct msm_panel_common_pdata *lcdc_sharp_pdata; + +#ifndef CONFIG_SPI_QSD +static void sharp_spi_write_byte(u8 val) +{ + int i; + + /* Clock should be Low before entering */ + for (i = 0; i < 8; i++) { + /* #1: Drive the Data (High or Low) */ + if (val & bit_shift[i]) + gpio_set_value(spi_mosi, 1); + else + gpio_set_value(spi_mosi, 0); + + /* #2: Drive the Clk High and then Low */ + gpio_set_value(spi_sclk, 1); + gpio_set_value(spi_sclk, 0); + } +} +#endif + +static int serigo(u8 reg, u8 data) +{ +#ifdef CONFIG_SPI_QSD + char tx_buf[2]; + int rc; + struct spi_message m; + struct spi_transfer t; + + if (!lcdc_spi_client) { + printk(KERN_ERR "%s lcdc_spi_client is NULL\n", __func__); + return -EINVAL; + } + + memset(&t, 0, sizeof t); + t.tx_buf = tx_buf; + spi_setup(lcdc_spi_client); + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + tx_buf[0] = reg; + tx_buf[1] = data; + t.rx_buf = NULL; + t.len = 2; + rc = spi_sync(lcdc_spi_client, &m); + return rc; +#else + /* Enable the Chip Select - low */ + gpio_set_value(spi_cs, 0); + udelay(1); + + /* Transmit register address first, then data */ + sharp_spi_write_byte(reg); + + /* Idle state of MOSI is Low */ + gpio_set_value(spi_mosi, 0); + udelay(1); + sharp_spi_write_byte(data); + + gpio_set_value(spi_mosi, 0); + gpio_set_value(spi_cs, 1); + return 0; +#endif +} + +#ifndef CONFIG_SPI_QSD +static void sharp_spi_init(void) +{ + spi_sclk = *(lcdc_sharp_pdata->gpio_num); + spi_cs = *(lcdc_sharp_pdata->gpio_num + 1); + spi_mosi = *(lcdc_sharp_pdata->gpio_num + 2); + spi_miso = *(lcdc_sharp_pdata->gpio_num + 3); + + /* Set the output so that we don't disturb the slave device */ + gpio_set_value(spi_sclk, 0); + gpio_set_value(spi_mosi, 0); + + /* Set the Chip Select deasserted (active low) */ + gpio_set_value(spi_cs, 1); +} +#endif + +static void sharp_disp_powerup(void) +{ + if (!sharp_state.disp_powered_up && !sharp_state.display_on) + sharp_state.disp_powered_up = TRUE; +} + +static void sharp_disp_on(void) +{ + int i; + + if (sharp_state.disp_powered_up && !sharp_state.display_on) { + for (i = 0; i < ARRAY_SIZE(init_sequence); i++) { + serigo(init_sequence[i].addr, + init_sequence[i].data); + } + mdelay(10); + serigo(31, 0xC1); + mdelay(10); + serigo(31, 0xD9); + serigo(31, 0xDF); + + sharp_state.display_on = TRUE; + } +} + +static int lcdc_sharp_panel_on(struct platform_device *pdev) +{ + if (!sharp_state.disp_initialized) { +#ifndef CONFIG_SPI_QSD + lcdc_sharp_pdata->panel_config_gpio(1); + sharp_spi_init(); +#endif + sharp_disp_powerup(); + sharp_disp_on(); + sharp_state.disp_initialized = TRUE; + } + return 0; +} + +static int lcdc_sharp_panel_off(struct platform_device *pdev) +{ + if (sharp_state.disp_powered_up && sharp_state.display_on) { + serigo(4, 0x00); + mdelay(40); + serigo(31, 0xC1); + mdelay(40); + serigo(31, 0x00); + msleep(16); + sharp_state.display_on = FALSE; + sharp_state.disp_initialized = FALSE; + } + return 0; +} + +static void lcdc_sharp_panel_set_backlight(struct msm_fb_data_type *mfd) +{ + int bl_level; + + bl_level = mfd->bl_level; + +#ifdef CONFIG_PMIC8058_PWM + if (bl_pwm) { + pwm_config(bl_pwm, DUTY_LEVEL * bl_level, PWM_PERIOD); + pwm_enable(bl_pwm); + } +#endif +} + +static int sharp_probe(struct platform_device *pdev) +{ + if (pdev->id == 0) { + lcdc_sharp_pdata = pdev->dev.platform_data; + return 0; + } + +#ifdef CONFIG_PMIC8058_PWM + bl_pwm = pwm_request(lcdc_sharp_pdata->gpio, "backlight"); + if (bl_pwm == NULL || IS_ERR(bl_pwm)) { + pr_err("%s pwm_request() failed\n", __func__); + bl_pwm = NULL; + } + + printk(KERN_INFO "sharp_probe: bl_pwm=%x LPG_chan=%d\n", + (int) bl_pwm, (int)lcdc_sharp_pdata->gpio); +#endif + + msm_fb_add_device(pdev); + + return 0; +} + +#ifdef CONFIG_SPI_QSD +static int lcdc_sharp_spi_probe(struct spi_device *spi) +{ + lcdc_spi_client = spi; + lcdc_spi_client->bits_per_word = 32; + return 0; +} +static int lcdc_sharp_spi_remove(struct spi_device *spi) +{ + lcdc_spi_client = NULL; + return 0; +} +static struct spi_driver lcdc_sharp_spi_driver = { + .driver = { + .name = LCDC_SHARP_SPI_DEVICE_NAME, + .owner = THIS_MODULE, + }, + .probe = lcdc_sharp_spi_probe, + .remove = lcdc_sharp_spi_remove, +}; +#endif +static struct platform_driver this_driver = { + .probe = sharp_probe, + .driver = { + .name = "lcdc_sharp_wvga", + }, +}; + +static struct msm_fb_panel_data sharp_panel_data = { + .on = lcdc_sharp_panel_on, + .off = lcdc_sharp_panel_off, + .set_backlight = lcdc_sharp_panel_set_backlight, +}; + +static struct platform_device this_device = { + .name = "lcdc_sharp_wvga", + .id = 1, + .dev = { + .platform_data = &sharp_panel_data, + } +}; + +static int __init lcdc_sharp_panel_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + if (msm_fb_detect_client("lcdc_sharp_wvga_pt")) + return 0; +#endif + + ret = platform_driver_register(&this_driver); + if (ret) + return ret; + + pinfo = &sharp_panel_data.panel_info; + pinfo->xres = 480; + pinfo->yres = 800; + MSM_FB_SINGLE_MODE_PANEL(pinfo); + pinfo->type = LCDC_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->wait_cycle = 0; + pinfo->bpp = 18; + pinfo->fb_num = 2; + pinfo->clk_rate = 24500000; + pinfo->bl_max = BL_MAX; + pinfo->bl_min = 1; + + pinfo->lcdc.h_back_porch = 20; + pinfo->lcdc.h_front_porch = 10; + pinfo->lcdc.h_pulse_width = 10; + pinfo->lcdc.v_back_porch = 2; + pinfo->lcdc.v_front_porch = 2; + pinfo->lcdc.v_pulse_width = 2; + pinfo->lcdc.border_clr = 0; + pinfo->lcdc.underflow_clr = 0xff; + pinfo->lcdc.hsync_skew = 0; + + ret = platform_device_register(&this_device); + if (ret) { + printk(KERN_ERR "%s not able to register the device\n", + __func__); + goto fail_driver; + } +#ifdef CONFIG_SPI_QSD + ret = spi_register_driver(&lcdc_sharp_spi_driver); + + if (ret) { + printk(KERN_ERR "%s not able to register spi\n", __func__); + goto fail_device; + } +#endif + return ret; +#ifdef CONFIG_SPI_QSD +fail_device: + platform_device_unregister(&this_device); +#endif +fail_driver: + platform_driver_unregister(&this_driver); + + return ret; +} + +module_init(lcdc_sharp_panel_init); +#ifdef CONFIG_SPI_QSD +static void __exit lcdc_sharp_panel_exit(void) +{ + spi_unregister_driver(&lcdc_sharp_spi_driver); +} +module_exit(lcdc_sharp_panel_exit); +#endif + diff --git a/drivers/video/msm/lcdc_st15.c b/drivers/video/msm/lcdc_st15.c new file mode 100644 index 000000000000..597a08f8cf2d --- /dev/null +++ b/drivers/video/msm/lcdc_st15.c @@ -0,0 +1,413 @@ +/* Copyright (c) 2010, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include "msm_fb.h" + +#define DEVICE_NAME "sii9022" +#define SII9022_DEVICE_ID 0xB0 +#define SII9022_ISR 0x3D +#define SII9022_ISR_RXS_STATUS 0x08 + +static int lcdc_sii9022_panel_on(struct platform_device *pdev); +static int lcdc_sii9022_panel_off(struct platform_device *pdev); + +static struct i2c_client *sii9022_i2c_client; + +struct sii9022_data { + struct msm_hdmi_platform_data *pd; + struct platform_device *pdev; + struct work_struct work; + int x_res; + int y_res; + int sysfs_entry_created; + int hdmi_attached; +}; +static struct sii9022_data *dd; + +struct sii9022_i2c_addr_data{ + u8 addr; + u8 data; +}; + +/* video mode data */ +static u8 video_mode_data[] = { + 0x00, + 0xF9, 0x1C, 0x70, 0x17, 0x72, 0x06, 0xEE, 0x02, +}; + +static u8 avi_io_format[] = { + 0x09, + 0x00, 0x00, +}; + +/* power state */ +static struct sii9022_i2c_addr_data regset0[] = { + { 0x60, 0x04 }, + { 0x63, 0x00 }, + { 0x1E, 0x00 }, +}; + +static u8 video_infoframe[] = { + 0x0C, + 0xF0, 0x00, 0x68, 0x00, 0x04, 0x00, 0x19, 0x00, + 0xE9, 0x02, 0x04, 0x01, 0x04, 0x06, +}; + +/* configure audio */ +static struct sii9022_i2c_addr_data regset1[] = { + { 0x26, 0x90 }, + { 0x20, 0x90 }, + { 0x1F, 0x80 }, + { 0x26, 0x80 }, + { 0x24, 0x02 }, + { 0x25, 0x0B }, + { 0xBC, 0x02 }, + { 0xBD, 0x24 }, + { 0xBE, 0x02 }, +}; + +/* enable audio */ +static u8 misc_infoframe[] = { + 0xBF, + 0xC2, 0x84, 0x01, 0x0A, 0x6F, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +/* set HDMI, active */ +static struct sii9022_i2c_addr_data regset2[] = { + { 0x1A, 0x01 }, + { 0x3D, 0x00 }, + { 0x3C, 0x02 }, +}; + +static struct msm_fb_panel_data sii9022_panel_data = { + .on = lcdc_sii9022_panel_on, + .off = lcdc_sii9022_panel_off, +}; + +static struct platform_device sii9022_device = { + .name = DEVICE_NAME, + .id = 1, + .dev = { + .platform_data = &sii9022_panel_data, + } +}; + +static int send_i2c_data(struct i2c_client *client, + struct sii9022_i2c_addr_data *regset, + int size) +{ + int i; + int rc = 0; + + for (i = 0; i < size; i++) { + rc = i2c_smbus_write_byte_data( + client, + regset[i].addr, regset[i].data); + if (rc) + break; + } + return rc; +} + +static void sii9022_work_f(struct work_struct *work) +{ + int isr; + + isr = i2c_smbus_read_byte_data(sii9022_i2c_client, SII9022_ISR); + if (isr < 0) { + dev_err(&sii9022_i2c_client->dev, + "i2c read of isr failed rc = 0x%x\n", isr); + return; + } + if (isr == 0) + return; + + /* reset any set bits */ + i2c_smbus_write_byte_data(sii9022_i2c_client, SII9022_ISR, isr); + dd->hdmi_attached = isr & SII9022_ISR_RXS_STATUS; + if (dd->pd->cable_detect) + dd->pd->cable_detect(dd->hdmi_attached); + if (dd->hdmi_attached) { + dd->x_res = 1280; + dd->y_res = 720; + } else { + dd->x_res = sii9022_panel_data.panel_info.xres; + dd->y_res = sii9022_panel_data.panel_info.yres; + } +} + +static irqreturn_t sii9022_interrupt(int irq, void *dev_id) +{ + struct sii9022_data *dd = dev_id; + + schedule_work(&dd->work); + return IRQ_HANDLED; +} + +static int hdmi_sii_enable(struct i2c_client *client) +{ + int rc; + int retries = 10; + int count; + + rc = i2c_smbus_write_byte_data(client, 0xC7, 0x00); + if (rc) + goto enable_exit; + + do { + msleep(1); + rc = i2c_smbus_read_byte_data(client, 0x1B); + } while ((rc != SII9022_DEVICE_ID) && retries--); + + if (rc != SII9022_DEVICE_ID) + return -ENODEV; + + rc = i2c_smbus_write_byte_data(client, 0x1A, 0x11); + if (rc) + goto enable_exit; + + count = ARRAY_SIZE(video_mode_data); + rc = i2c_master_send(client, video_mode_data, count); + if (rc != count) { + rc = -EIO; + goto enable_exit; + } + + rc = i2c_smbus_write_byte_data(client, 0x08, 0x20); + if (rc) + goto enable_exit; + count = ARRAY_SIZE(avi_io_format); + rc = i2c_master_send(client, avi_io_format, count); + if (rc != count) { + rc = -EIO; + goto enable_exit; + } + + rc = send_i2c_data(client, regset0, ARRAY_SIZE(regset0)); + if (rc) + goto enable_exit; + + count = ARRAY_SIZE(video_infoframe); + rc = i2c_master_send(client, video_infoframe, count); + if (rc != count) { + rc = -EIO; + goto enable_exit; + } + + rc = send_i2c_data(client, regset1, ARRAY_SIZE(regset1)); + if (rc) + goto enable_exit; + + count = ARRAY_SIZE(misc_infoframe); + rc = i2c_master_send(client, misc_infoframe, count); + if (rc != count) { + rc = -EIO; + goto enable_exit; + } + + rc = send_i2c_data(client, regset2, ARRAY_SIZE(regset2)); + if (rc) + goto enable_exit; + + return 0; +enable_exit: + printk(KERN_ERR "%s: exited rc=%d\n", __func__, rc); + return rc; +} + +static ssize_t show_res(struct device *device, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%dx%d\n", dd->x_res, dd->y_res); +} + +static struct device_attribute device_attrs[] = { + __ATTR(screen_resolution, S_IRUGO|S_IWUSR, show_res, NULL), +}; + +static int lcdc_sii9022_panel_on(struct platform_device *pdev) +{ + int rc; + if (!dd->sysfs_entry_created) { + dd->pdev = pdev; + rc = device_create_file(&pdev->dev, &device_attrs[0]); + if (!rc) + dd->sysfs_entry_created = 1; + } + + rc = hdmi_sii_enable(sii9022_i2c_client); + if (rc) { + dd->hdmi_attached = 0; + dd->x_res = sii9022_panel_data.panel_info.xres; + dd->y_res = sii9022_panel_data.panel_info.yres; + } + if (dd->pd->irq) + enable_irq(dd->pd->irq); + /* Don't return the value from hdmi_sii_enable(). + * It may fail on some ST1.5s, but we must return 0 from this + * function in order for the on-board display to turn on. + */ + return 0; +} + +static int lcdc_sii9022_panel_off(struct platform_device *pdev) +{ + if (dd->pd->irq) + disable_irq(dd->pd->irq); + return 0; +} + +static const struct i2c_device_id hmdi_sii_id[] = { + { DEVICE_NAME, 0 }, + { } +}; + +static int hdmi_sii_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C)) + return -ENODEV; + + dd = kzalloc(sizeof *dd, GFP_KERNEL); + if (!dd) { + rc = -ENOMEM; + goto probe_exit; + } + sii9022_i2c_client = client; + i2c_set_clientdata(client, dd); + dd->pd = client->dev.platform_data; + if (!dd->pd) { + rc = -ENODEV; + goto probe_free; + } + if (dd->pd->irq) { + INIT_WORK(&dd->work, sii9022_work_f); + rc = request_irq(dd->pd->irq, + &sii9022_interrupt, + IRQF_TRIGGER_FALLING, + "sii9022_cable", dd); + if (rc) + goto probe_free; + disable_irq(dd->pd->irq); + } + msm_fb_add_device(&sii9022_device); + dd->x_res = sii9022_panel_data.panel_info.xres; + dd->y_res = sii9022_panel_data.panel_info.yres; + + return 0; + +probe_free: + i2c_set_clientdata(client, NULL); + kfree(dd); +probe_exit: + return rc; +} + +static int hdmi_sii_remove(struct i2c_client *client) +{ + int err = 0 ; + struct msm_hdmi_platform_data *pd; + + if (dd->sysfs_entry_created) + device_remove_file(&dd->pdev->dev, &device_attrs[0]); + pd = client->dev.platform_data; + if (pd && pd->irq) + free_irq(pd->irq, dd); + i2c_set_clientdata(client, NULL); + kfree(dd); + + return err ; +} + +#ifdef CONFIG_PM +static int sii9022_suspend(struct device *dev) +{ + if (dd && dd->pd && dd->pd->irq) + disable_irq(dd->pd->irq); + return 0; +} + +static int sii9022_resume(struct device *dev) +{ + if (dd && dd->pd && dd->pd->irq) + enable_irq(dd->pd->irq); + return 0; +} + +static struct dev_pm_ops sii9022_pm_ops = { + .suspend = sii9022_suspend, + .resume = sii9022_resume, +}; +#endif + +static struct i2c_driver hdmi_sii_i2c_driver = { + .driver = { + .name = DEVICE_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &sii9022_pm_ops, +#endif + }, + .probe = hdmi_sii_probe, + .remove = __exit_p(hdmi_sii_remove), + .id_table = hmdi_sii_id, +}; + +static int __init lcdc_st15_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + + if (msm_fb_detect_client("lcdc_st15")) + return 0; + + pinfo = &sii9022_panel_data.panel_info; + pinfo->xres = 1366; + pinfo->yres = 768; + MSM_FB_SINGLE_MODE_PANEL(pinfo); + pinfo->type = LCDC_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->wait_cycle = 0; + pinfo->bpp = 24; + pinfo->fb_num = 2; + pinfo->clk_rate = 74250000; + + pinfo->lcdc.h_back_porch = 120; + pinfo->lcdc.h_front_porch = 20; + pinfo->lcdc.h_pulse_width = 40; + pinfo->lcdc.v_back_porch = 25; + pinfo->lcdc.v_front_porch = 1; + pinfo->lcdc.v_pulse_width = 7; + pinfo->lcdc.border_clr = 0; /* blk */ + pinfo->lcdc.underflow_clr = 0xff; /* blue */ + pinfo->lcdc.hsync_skew = 0; + + ret = i2c_add_driver(&hdmi_sii_i2c_driver); + if (ret) + printk(KERN_ERR "%s: failed to add i2c driver\n", __func__); + + return ret; +} + +static void __exit hdmi_sii_exit(void) +{ + i2c_del_driver(&hdmi_sii_i2c_driver); +} + +module_init(lcdc_st15_init); +module_exit(hdmi_sii_exit); diff --git a/drivers/video/msm/lcdc_toshiba_fwvga_pt.c b/drivers/video/msm/lcdc_toshiba_fwvga_pt.c new file mode 100644 index 000000000000..db13c73d0410 --- /dev/null +++ b/drivers/video/msm/lcdc_toshiba_fwvga_pt.c @@ -0,0 +1,471 @@ +/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include "msm_fb.h" + +static int spi_cs0_N; +static int spi_sclk; +static int spi_mosi; +static int spi_miso; + +struct toshiba_state_type { + boolean disp_initialized; + boolean display_on; + boolean disp_powered_up; +}; + +static struct toshiba_state_type toshiba_state = { 0 }; +static struct msm_panel_common_pdata *lcdc_toshiba_pdata; + +static int toshiba_spi_write(char data1, char data2, int rs) +{ + uint32 bitdata = 0, bnum = 24, bmask = 0x800000; + + gpio_set_value_cansleep(spi_cs0_N, 0); /* cs* low */ + udelay(1); + + if (rs) + bitdata = (0x72 << 16); + else + bitdata = (0x70 << 16); + + bitdata |= ((data1 << 8) | data2); + + while (bnum) { + gpio_set_value_cansleep(spi_sclk, 0); /* clk low */ + udelay(1); + + if (bitdata & bmask) + gpio_set_value_cansleep(spi_mosi, 1); + else + gpio_set_value_cansleep(spi_mosi, 0); + + udelay(1); + gpio_set_value_cansleep(spi_sclk, 1); /* clk high */ + udelay(1); + bmask >>= 1; + bnum--; + } + + gpio_set_value_cansleep(spi_cs0_N, 1); /* cs* high */ + udelay(1); + return 0; +} + +static void spi_pin_assign(void) +{ + /* Setting the Default GPIO's */ + spi_mosi = *(lcdc_toshiba_pdata->gpio_num); + spi_miso = *(lcdc_toshiba_pdata->gpio_num + 1); + spi_sclk = *(lcdc_toshiba_pdata->gpio_num + 2); + spi_cs0_N = *(lcdc_toshiba_pdata->gpio_num + 3); +} + +static void toshiba_disp_powerup(void) +{ + if (!toshiba_state.disp_powered_up && !toshiba_state.display_on) { + /* Reset the hardware first */ + /* Include DAC power up implementation here */ + toshiba_state.disp_powered_up = TRUE; + } +} + +static void toshiba_disp_on(void) +{ + if (toshiba_state.disp_powered_up && !toshiba_state.display_on) { + toshiba_spi_write(0x01, 0x00, 0); + toshiba_spi_write(0x30, 0x00, 1); + + udelay(500); + toshiba_spi_write(0x01, 0x01, 0); + toshiba_spi_write(0x40, 0x10, 1); + +#ifdef TOSHIBA_FWVGA_FULL_INIT + udelay(500); + toshiba_spi_write(0x01, 0x06, 0); + toshiba_spi_write(0x00, 0x00, 1); + msleep(20); + + toshiba_spi_write(0x00, 0x01, 0); + toshiba_spi_write(0x03, 0x10, 1); + + udelay(500); + toshiba_spi_write(0x00, 0x02, 0); + toshiba_spi_write(0x01, 0x00, 1); + + udelay(500); + toshiba_spi_write(0x00, 0x03, 0); + toshiba_spi_write(0x00, 0x00, 1); + + udelay(500); + toshiba_spi_write(0x00, 0x07, 0); + toshiba_spi_write(0x00, 0x00, 1); + + udelay(500); + toshiba_spi_write(0x00, 0x08, 0); + toshiba_spi_write(0x00, 0x04, 1); + + udelay(500); + toshiba_spi_write(0x00, 0x09, 0); + toshiba_spi_write(0x00, 0x0c, 1); +#endif + udelay(500); + toshiba_spi_write(0x00, 0x0c, 0); + toshiba_spi_write(0x40, 0x10, 1); + + udelay(500); + toshiba_spi_write(0x00, 0x0e, 0); + toshiba_spi_write(0x00, 0x00, 1); + + udelay(500); + toshiba_spi_write(0x00, 0x20, 0); + toshiba_spi_write(0x01, 0x3f, 1); + + udelay(500); + toshiba_spi_write(0x00, 0x22, 0); + toshiba_spi_write(0x76, 0x00, 1); + + udelay(500); + toshiba_spi_write(0x00, 0x23, 0); + toshiba_spi_write(0x1c, 0x0a, 1); + + udelay(500); + toshiba_spi_write(0x00, 0x24, 0); + toshiba_spi_write(0x1c, 0x2c, 1); + + udelay(500); + toshiba_spi_write(0x00, 0x25, 0); + toshiba_spi_write(0x1c, 0x4e, 1); + + udelay(500); + toshiba_spi_write(0x00, 0x27, 0); + toshiba_spi_write(0x00, 0x00, 1); + + udelay(500); + toshiba_spi_write(0x00, 0x28, 0); + toshiba_spi_write(0x76, 0x0c, 1); + +#ifdef TOSHIBA_FWVGA_FULL_INIT + udelay(500); + toshiba_spi_write(0x03, 0x00, 0); + toshiba_spi_write(0x00, 0x00, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x01, 0); + toshiba_spi_write(0x05, 0x02, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x02, 0); + toshiba_spi_write(0x07, 0x05, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x03, 0); + toshiba_spi_write(0x00, 0x00, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x04, 0); + toshiba_spi_write(0x02, 0x00, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x05, 0); + toshiba_spi_write(0x07, 0x07, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x06, 0); + toshiba_spi_write(0x10, 0x10, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x07, 0); + toshiba_spi_write(0x02, 0x02, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x08, 0); + toshiba_spi_write(0x07, 0x04, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x09, 0); + toshiba_spi_write(0x07, 0x07, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x0a, 0); + toshiba_spi_write(0x00, 0x00, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x0b, 0); + toshiba_spi_write(0x00, 0x00, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x0c, 0); + toshiba_spi_write(0x07, 0x07, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x0d, 0); + toshiba_spi_write(0x10, 0x10, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x10, 0); + toshiba_spi_write(0x01, 0x04, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x11, 0); + toshiba_spi_write(0x05, 0x03, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x12, 0); + toshiba_spi_write(0x03, 0x04, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x15, 0); + toshiba_spi_write(0x03, 0x04, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x16, 0); + toshiba_spi_write(0x03, 0x1c, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x17, 0); + toshiba_spi_write(0x02, 0x04, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x18, 0); + toshiba_spi_write(0x04, 0x02, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x19, 0); + toshiba_spi_write(0x03, 0x05, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x1c, 0); + toshiba_spi_write(0x07, 0x07, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x1d, 0); + toshiba_spi_write(0x02, 0x1f, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x20, 0); + toshiba_spi_write(0x05, 0x07, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x21, 0); + toshiba_spi_write(0x06, 0x04, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x22, 0); + toshiba_spi_write(0x04, 0x05, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x27, 0); + toshiba_spi_write(0x02, 0x03, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x28, 0); + toshiba_spi_write(0x03, 0x00, 1); + + udelay(500); + toshiba_spi_write(0x03, 0x29, 0); + toshiba_spi_write(0x00, 0x02, 1); + +#endif + udelay(500); + toshiba_spi_write(0x01, 0x00, 0); + toshiba_spi_write(0x36, 0x3c, 1); + udelay(500); + + toshiba_spi_write(0x01, 0x01, 0); + toshiba_spi_write(0x40, 0x03, 1); + + udelay(500); + toshiba_spi_write(0x01, 0x02, 0); + toshiba_spi_write(0x00, 0x01, 1); + + udelay(500); + toshiba_spi_write(0x01, 0x03, 0); + toshiba_spi_write(0x3c, 0x58, 1); + + udelay(500); + toshiba_spi_write(0x01, 0x0c, 0); + toshiba_spi_write(0x01, 0x35, 1); + + udelay(500); + toshiba_spi_write(0x01, 0x06, 0); + toshiba_spi_write(0x00, 0x02, 1); + + udelay(500); + toshiba_spi_write(0x00, 0x29, 0); + toshiba_spi_write(0x03, 0xbf, 1); + + udelay(500); + toshiba_spi_write(0x01, 0x06, 0); + toshiba_spi_write(0x00, 0x03, 1); + msleep(32); + + toshiba_spi_write(0x01, 0x01, 0); + toshiba_spi_write(0x40, 0x10, 1); + msleep(80); + + toshiba_state.display_on = TRUE; + } +} + +static int lcdc_toshiba_panel_on(struct platform_device *pdev) +{ + if (!toshiba_state.disp_initialized) { + /* Configure reset GPIO that drives DAC */ + if (lcdc_toshiba_pdata->panel_config_gpio) + lcdc_toshiba_pdata->panel_config_gpio(1); + toshiba_disp_powerup(); + toshiba_disp_on(); + toshiba_state.disp_initialized = TRUE; + } + return 0; +} + +static int lcdc_toshiba_panel_off(struct platform_device *pdev) +{ + if (toshiba_state.disp_powered_up && toshiba_state.display_on) { + toshiba_spi_write(0x01, 0x06, 1); + toshiba_spi_write(0x00, 0x02, 1); + msleep(80); + + toshiba_spi_write(0x01, 0x06, 1); + toshiba_spi_write(0x00, 0x00, 1); + + toshiba_spi_write(0x00, 0x29, 1); + toshiba_spi_write(0x00, 0x02, 1); + + toshiba_spi_write(0x01, 0x00, 1); + toshiba_spi_write(0x30, 0x00, 1); + + if (lcdc_toshiba_pdata->panel_config_gpio) + lcdc_toshiba_pdata->panel_config_gpio(0); + toshiba_state.display_on = FALSE; + toshiba_state.disp_initialized = FALSE; + } + + return 0; +} + +static void lcdc_toshiba_set_backlight(struct msm_fb_data_type *mfd) +{ + int ret; + int bl_level; + + bl_level = mfd->bl_level; + + if (lcdc_toshiba_pdata && lcdc_toshiba_pdata->pmic_backlight) + ret = lcdc_toshiba_pdata->pmic_backlight(bl_level); + else + pr_err("%s(): Backlight level set failed", __func__); + + return; +} + +static int toshiba_probe(struct platform_device *pdev) +{ + if (pdev->id == 0) { + lcdc_toshiba_pdata = pdev->dev.platform_data; + spi_pin_assign(); + return 0; + } + msm_fb_add_device(pdev); + return 0; +} + +static struct platform_driver this_driver = { + .probe = toshiba_probe, + .driver = { + .name = "lcdc_toshiba_fwvga_pt", + }, +}; + +static struct msm_fb_panel_data toshiba_panel_data = { + .on = lcdc_toshiba_panel_on, + .off = lcdc_toshiba_panel_off, + .set_backlight = lcdc_toshiba_set_backlight, +}; + +static struct platform_device this_device = { + .name = "lcdc_toshiba_fwvga_pt", + .id = 1, + .dev = { + .platform_data = &toshiba_panel_data, + } +}; + +static int __init lcdc_toshiba_panel_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + + ret = msm_fb_detect_client("lcdc_toshiba_fwvga_pt"); + if (ret) + return 0; + + + ret = platform_driver_register(&this_driver); + if (ret) + return ret; + + pinfo = &toshiba_panel_data.panel_info; + pinfo->xres = 480; + pinfo->yres = 864; + MSM_FB_SINGLE_MODE_PANEL(pinfo); + pinfo->type = LCDC_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->wait_cycle = 0; + pinfo->bpp = 18; + pinfo->fb_num = 2; + /* 30Mhz mdp_lcdc_pclk and mdp_lcdc_pad_pcl */ + pinfo->clk_rate = 30720000; + pinfo->bl_max = 100; + pinfo->bl_min = 1; + + if (cpu_is_msm7x25a() || cpu_is_msm7x25aa() || cpu_is_msm7x25ab()) { + pinfo->yres = 320; + pinfo->lcdc.h_back_porch = 10; + pinfo->lcdc.h_front_porch = 21; + pinfo->lcdc.h_pulse_width = 5; + pinfo->lcdc.v_back_porch = 8; + pinfo->lcdc.v_front_porch = 540; + pinfo->lcdc.v_pulse_width = 42; + pinfo->lcdc.border_clr = 0; /* blk */ + pinfo->lcdc.underflow_clr = 0xff; /* blue */ + pinfo->lcdc.hsync_skew = 0; + } else { + pinfo->lcdc.h_back_porch = 8; + pinfo->lcdc.h_front_porch = 16; + pinfo->lcdc.h_pulse_width = 8; + pinfo->lcdc.v_back_porch = 2; + pinfo->lcdc.v_front_porch = 2; + pinfo->lcdc.v_pulse_width = 2; + pinfo->lcdc.border_clr = 0; /* blk */ + pinfo->lcdc.underflow_clr = 0xff; /* blue */ + pinfo->lcdc.hsync_skew = 0; + } + + ret = platform_device_register(&this_device); + if (ret) { + printk(KERN_ERR "%s not able to register the device\n", + __func__); + platform_driver_unregister(&this_driver); + } + return ret; +} + +device_initcall(lcdc_toshiba_panel_init); diff --git a/drivers/video/msm/lcdc_toshiba_wvga_pt.c b/drivers/video/msm/lcdc_toshiba_wvga_pt.c new file mode 100644 index 000000000000..f9f4f5c27bd4 --- /dev/null +++ b/drivers/video/msm/lcdc_toshiba_wvga_pt.c @@ -0,0 +1,519 @@ +/* Copyright (c) 2009-2010, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#ifdef CONFIG_SPI_QSD +#include +#endif +#include +#include +#include "msm_fb.h" + +#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM +#include "mddihosti.h" +#endif + +#ifdef CONFIG_SPI_QSD +#define LCDC_TOSHIBA_SPI_DEVICE_NAME "lcdc_toshiba_ltm030dd40" +static struct spi_device *lcdc_toshiba_spi_client; +#else +static int spi_cs; +static int spi_sclk; +static int spi_mosi; +static int spi_miso; +#endif +struct toshiba_state_type{ + boolean disp_initialized; + boolean display_on; + boolean disp_powered_up; +}; + +static struct toshiba_state_type toshiba_state = { 0 }; +static struct msm_panel_common_pdata *lcdc_toshiba_pdata; + +#ifndef CONFIG_SPI_QSD +static void toshiba_spi_write_byte(char dc, uint8 data) +{ + uint32 bit; + int bnum; + + gpio_set_value(spi_sclk, 0); /* clk low */ + /* dc: 0 for command, 1 for parameter */ + gpio_set_value(spi_mosi, dc); + udelay(1); /* at least 20 ns */ + gpio_set_value(spi_sclk, 1); /* clk high */ + udelay(1); /* at least 20 ns */ + bnum = 8; /* 8 data bits */ + bit = 0x80; + while (bnum) { + gpio_set_value(spi_sclk, 0); /* clk low */ + if (data & bit) + gpio_set_value(spi_mosi, 1); + else + gpio_set_value(spi_mosi, 0); + udelay(1); + gpio_set_value(spi_sclk, 1); /* clk high */ + udelay(1); + bit >>= 1; + bnum--; + } +} +#endif + +static int toshiba_spi_write(char cmd, uint32 data, int num) +{ + char *bp; +#ifdef CONFIG_SPI_QSD + char tx_buf[4]; + int rc, i; + struct spi_message m; + struct spi_transfer t; + uint32 final_data = 0; + + if (!lcdc_toshiba_spi_client) { + printk(KERN_ERR "%s lcdc_toshiba_spi_client is NULL\n", + __func__); + return -EINVAL; + } + + memset(&t, 0, sizeof t); + t.tx_buf = tx_buf; + spi_setup(lcdc_toshiba_spi_client); + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + /* command byte first */ + final_data |= cmd << 23; + t.len = num + 2; + if (t.len < 4) + t.bits_per_word = 8 * t.len; + /* followed by parameter bytes */ + if (num) { + bp = (char *)&data;; + bp += (num - 1); + i = 1; + while (num) { + final_data |= 1 << (((4 - i) << 3) - i - 1); + final_data |= *bp << (((4 - i - 1) << 3) - i - 1); + num--; + bp--; + i++; + } + } + + bp = (char *)&final_data; + for (i = 0; i < t.len; i++) + tx_buf[i] = bp[3 - i]; + t.rx_buf = NULL; + rc = spi_sync(lcdc_toshiba_spi_client, &m); + if (rc) + printk(KERN_ERR "spi_sync _write failed %d\n", rc); + return rc; +#else + gpio_set_value(spi_cs, 1); /* cs high */ + + /* command byte first */ + toshiba_spi_write_byte(0, cmd); + + /* followed by parameter bytes */ + if (num) { + bp = (char *)&data;; + bp += (num - 1); + while (num) { + toshiba_spi_write_byte(1, *bp); + num--; + bp--; + } + } + + gpio_set_value(spi_cs, 0); /* cs low */ + udelay(1); + return 0; +#endif +} + +static int toshiba_spi_read_bytes(char cmd, uint32 *data, int num) +{ +#ifdef CONFIG_SPI_QSD + char tx_buf[5]; + char rx_buf[5]; + int rc; + struct spi_message m; + struct spi_transfer t; + + if (!lcdc_toshiba_spi_client) { + printk(KERN_ERR "%s lcdc_toshiba_spi_client is NULL\n", + __func__); + return -EINVAL; + } + + memset(&t, 0, sizeof t); + t.tx_buf = tx_buf; + t.rx_buf = rx_buf; + spi_setup(lcdc_toshiba_spi_client); + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + /* command byte first */ + tx_buf[0] = 0 | ((cmd >> 1) & 0x7f); + tx_buf[1] = (cmd & 0x01) << 7; + tx_buf[2] = 0; + tx_buf[3] = 0; + tx_buf[4] = 0; + + t.len = 5; + + rc = spi_sync(lcdc_toshiba_spi_client, &m); + *data = 0; + *data = ((rx_buf[1] & 0x1f) << 19) | (rx_buf[2] << 11) | + (rx_buf[3] << 3) | ((rx_buf[4] & 0xe0) >> 5); + if (rc) + printk(KERN_ERR "spi_sync _read failed %d\n", rc); + return rc; +#else + uint32 dbit, bits; + int bnum; + + gpio_set_value(spi_cs, 1); /* cs high */ + + /* command byte first */ + toshiba_spi_write_byte(0, cmd); + + if (num > 1) { + /* extra dc bit */ + gpio_set_value(spi_sclk, 0); /* clk low */ + udelay(1); + dbit = gpio_get_value(spi_miso);/* dc bit */ + udelay(1); + gpio_set_value(spi_sclk, 1); /* clk high */ + } + + /* followed by data bytes */ + bnum = num * 8; /* number of bits */ + bits = 0; + while (bnum) { + bits <<= 1; + gpio_set_value(spi_sclk, 0); /* clk low */ + udelay(1); + dbit = gpio_get_value(spi_miso); + udelay(1); + gpio_set_value(spi_sclk, 1); /* clk high */ + bits |= dbit; + bnum--; + } + + *data = bits; + + udelay(1); + gpio_set_value(spi_cs, 0); /* cs low */ + udelay(1); + return 0; +#endif +} + +#ifndef CONFIG_SPI_QSD +static void spi_pin_assign(void) +{ + /* Setting the Default GPIO's */ + spi_sclk = *(lcdc_toshiba_pdata->gpio_num); + spi_cs = *(lcdc_toshiba_pdata->gpio_num + 1); + spi_mosi = *(lcdc_toshiba_pdata->gpio_num + 2); + spi_miso = *(lcdc_toshiba_pdata->gpio_num + 3); +} +#endif + +static void toshiba_disp_powerup(void) +{ + if (!toshiba_state.disp_powered_up && !toshiba_state.display_on) { + /* Reset the hardware first */ + /* Include DAC power up implementation here */ + toshiba_state.disp_powered_up = TRUE; + } +} + +static void toshiba_disp_on(void) +{ + uint32 data; + +#ifndef CONFIG_SPI_QSD + gpio_set_value(spi_cs, 0); /* low */ + gpio_set_value(spi_sclk, 1); /* high */ + gpio_set_value(spi_mosi, 0); + gpio_set_value(spi_miso, 0); +#endif + + if (toshiba_state.disp_powered_up && !toshiba_state.display_on) { + toshiba_spi_write(0, 0, 0); + mdelay(7); + toshiba_spi_write(0, 0, 0); + mdelay(7); + toshiba_spi_write(0, 0, 0); + mdelay(7); + toshiba_spi_write(0xba, 0x11, 1); + toshiba_spi_write(0x36, 0x00, 1); + mdelay(1); + toshiba_spi_write(0x3a, 0x60, 1); + toshiba_spi_write(0xb1, 0x5d, 1); + mdelay(1); + toshiba_spi_write(0xb2, 0x33, 1); + toshiba_spi_write(0xb3, 0x22, 1); + mdelay(1); + toshiba_spi_write(0xb4, 0x02, 1); + toshiba_spi_write(0xb5, 0x1e, 1); /* vcs -- adjust brightness */ + mdelay(1); + toshiba_spi_write(0xb6, 0x27, 1); + toshiba_spi_write(0xb7, 0x03, 1); + mdelay(1); + toshiba_spi_write(0xb9, 0x24, 1); + toshiba_spi_write(0xbd, 0xa1, 1); + mdelay(1); + toshiba_spi_write(0xbb, 0x00, 1); + toshiba_spi_write(0xbf, 0x01, 1); + mdelay(1); + toshiba_spi_write(0xbe, 0x00, 1); + toshiba_spi_write(0xc0, 0x11, 1); + mdelay(1); + toshiba_spi_write(0xc1, 0x11, 1); + toshiba_spi_write(0xc2, 0x11, 1); + mdelay(1); + toshiba_spi_write(0xc3, 0x3232, 2); + mdelay(1); + toshiba_spi_write(0xc4, 0x3232, 2); + mdelay(1); + toshiba_spi_write(0xc5, 0x3232, 2); + mdelay(1); + toshiba_spi_write(0xc6, 0x3232, 2); + mdelay(1); + toshiba_spi_write(0xc7, 0x6445, 2); + mdelay(1); + toshiba_spi_write(0xc8, 0x44, 1); + toshiba_spi_write(0xc9, 0x52, 1); + mdelay(1); + toshiba_spi_write(0xca, 0x00, 1); + mdelay(1); + toshiba_spi_write(0xec, 0x02a4, 2); /* 0x02a4 */ + mdelay(1); + toshiba_spi_write(0xcf, 0x01, 1); + mdelay(1); + toshiba_spi_write(0xd0, 0xc003, 2); /* c003 */ + mdelay(1); + toshiba_spi_write(0xd1, 0x01, 1); + mdelay(1); + toshiba_spi_write(0xd2, 0x0028, 2); + mdelay(1); + toshiba_spi_write(0xd3, 0x0028, 2); + mdelay(1); + toshiba_spi_write(0xd4, 0x26a4, 2); + mdelay(1); + toshiba_spi_write(0xd5, 0x20, 1); + mdelay(1); + toshiba_spi_write(0xef, 0x3200, 2); + mdelay(32); + toshiba_spi_write(0xbc, 0x80, 1); /* wvga pass through */ + toshiba_spi_write(0x3b, 0x00, 1); + mdelay(1); + toshiba_spi_write(0xb0, 0x16, 1); + mdelay(1); + toshiba_spi_write(0xb8, 0xfff5, 2); + mdelay(1); + toshiba_spi_write(0x11, 0, 0); + mdelay(5); + toshiba_spi_write(0x29, 0, 0); + mdelay(5); + toshiba_state.display_on = TRUE; + } + + data = 0; + toshiba_spi_read_bytes(0x04, &data, 3); + printk(KERN_INFO "toshiba_disp_on: id=%x\n", data); + +} + +static int lcdc_toshiba_panel_on(struct platform_device *pdev) +{ + if (!toshiba_state.disp_initialized) { + /* Configure reset GPIO that drives DAC */ + if (lcdc_toshiba_pdata->panel_config_gpio) + lcdc_toshiba_pdata->panel_config_gpio(1); + toshiba_disp_powerup(); + toshiba_disp_on(); + toshiba_state.disp_initialized = TRUE; + } + return 0; +} + +static int lcdc_toshiba_panel_off(struct platform_device *pdev) +{ + if (toshiba_state.disp_powered_up && toshiba_state.display_on) { + /* Main panel power off (Deep standby in) */ + + toshiba_spi_write(0x28, 0, 0); /* display off */ + mdelay(1); + toshiba_spi_write(0xb8, 0x8002, 2); /* output control */ + mdelay(1); + toshiba_spi_write(0x10, 0x00, 1); /* sleep mode in */ + mdelay(85); /* wait 85 msec */ + toshiba_spi_write(0xb0, 0x00, 1); /* deep standby in */ + mdelay(1); + if (lcdc_toshiba_pdata->panel_config_gpio) + lcdc_toshiba_pdata->panel_config_gpio(0); + toshiba_state.display_on = FALSE; + toshiba_state.disp_initialized = FALSE; + } + return 0; +} + +static void lcdc_toshiba_set_backlight(struct msm_fb_data_type *mfd) +{ + int bl_level; + int ret = -EPERM; + int i = 0; + + bl_level = mfd->bl_level; + + while (i++ < 3) { + ret = pmic_set_led_intensity(LED_LCD, bl_level); + if (ret == 0) + return; + msleep(10); + } + + printk(KERN_WARNING "%s: can't set lcd backlight!\n", + __func__); +} + +static int toshiba_probe(struct platform_device *pdev) +{ + if (pdev->id == 0) { + lcdc_toshiba_pdata = pdev->dev.platform_data; +#ifndef CONFIG_SPI_QSD + spi_pin_assign(); +#endif + return 0; + } + msm_fb_add_device(pdev); + return 0; +} + +#ifdef CONFIG_SPI_QSD +static int lcdc_toshiba_spi_probe(struct spi_device *spi) +{ + lcdc_toshiba_spi_client = spi; + lcdc_toshiba_spi_client->bits_per_word = 32; + return 0; +} +static int lcdc_toshiba_spi_remove(struct spi_device *spi) +{ + lcdc_toshiba_spi_client = NULL; + return 0; +} + +static struct spi_driver lcdc_toshiba_spi_driver = { + .driver = { + .name = LCDC_TOSHIBA_SPI_DEVICE_NAME, + .owner = THIS_MODULE, + }, + .probe = lcdc_toshiba_spi_probe, + .remove = lcdc_toshiba_spi_remove, +}; +#endif +static struct platform_driver this_driver = { + .probe = toshiba_probe, + .driver = { + .name = "lcdc_toshiba_wvga", + }, +}; + +static struct msm_fb_panel_data toshiba_panel_data = { + .on = lcdc_toshiba_panel_on, + .off = lcdc_toshiba_panel_off, + .set_backlight = lcdc_toshiba_set_backlight, +}; + +static struct platform_device this_device = { + .name = "lcdc_toshiba_wvga", + .id = 1, + .dev = { + .platform_data = &toshiba_panel_data, + } +}; + +static int __init lcdc_toshiba_panel_init(void) +{ + int ret; + struct msm_panel_info *pinfo; +#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM + if (mddi_get_client_id() != 0) + return 0; + + ret = msm_fb_detect_client("lcdc_toshiba_wvga_pt"); + if (ret) + return 0; + +#endif + + ret = platform_driver_register(&this_driver); + if (ret) + return ret; + + pinfo = &toshiba_panel_data.panel_info; + pinfo->xres = 480; + pinfo->yres = 800; + MSM_FB_SINGLE_MODE_PANEL(pinfo); + pinfo->type = LCDC_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->wait_cycle = 0; + pinfo->bpp = 18; + pinfo->fb_num = 2; + /* 30Mhz mdp_lcdc_pclk and mdp_lcdc_pad_pcl */ + pinfo->clk_rate = 30720000; + pinfo->bl_max = 15; + pinfo->bl_min = 1; + + pinfo->lcdc.h_back_porch = 184; /* hsw = 8 + hbp=184 */ + pinfo->lcdc.h_front_porch = 4; + pinfo->lcdc.h_pulse_width = 8; + pinfo->lcdc.v_back_porch = 2; /* vsw=1 + vbp = 2 */ + pinfo->lcdc.v_front_porch = 3; + pinfo->lcdc.v_pulse_width = 1; + pinfo->lcdc.border_clr = 0; /* blk */ + pinfo->lcdc.underflow_clr = 0xff; /* blue */ + pinfo->lcdc.hsync_skew = 0; + + ret = platform_device_register(&this_device); + if (ret) { + printk(KERN_ERR "%s not able to register the device\n", + __func__); + goto fail_driver; + } +#ifdef CONFIG_SPI_QSD + ret = spi_register_driver(&lcdc_toshiba_spi_driver); + + if (ret) { + printk(KERN_ERR "%s not able to register spi\n", __func__); + goto fail_device; + } +#endif + return ret; + +#ifdef CONFIG_SPI_QSD +fail_device: + platform_device_unregister(&this_device); +#endif +fail_driver: + platform_driver_unregister(&this_driver); + return ret; +} + +device_initcall(lcdc_toshiba_panel_init); diff --git a/drivers/video/msm/lcdc_truly_ips3p2335.c b/drivers/video/msm/lcdc_truly_ips3p2335.c new file mode 100644 index 000000000000..abb4756365fe --- /dev/null +++ b/drivers/video/msm/lcdc_truly_ips3p2335.c @@ -0,0 +1,305 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include "msm_fb.h" + +static int prev_bl = 17; + +static int spi_cs; +static int spi_sclk; +static int spi_mosi; +static int gpio_backlight_en; +static int gpio_display_reset; + +struct truly_state_type { + boolean disp_initialized; + boolean display_on; + boolean disp_powered_up; +}; + +static struct truly_state_type truly_state = { 0 }; +static struct msm_panel_common_pdata *lcdc_truly_pdata; + +static char init_item_v1[] = { 0xff, 0x83, 0x57, }; +static char init_item_v2[] = { 0x03, }; +static char init_item_v3[] = { 0x00, 0x13, 0x1C, 0x1C, 0x83, 0x48, }; +static char init_item_v4[] = { 0x43, 0x06, 0x06, 0x06, }; +static char init_item_v5[] = { 0x53, }; +static char init_item_v6[] = { 0x02, 0x40, 0x00, 0x2a, 0x2a, 0x0d, 0x3f, }; +static char init_item_v7[] = { 0x70, 0x50, 0x01, 0x3c, 0xe8, 0x08, }; +static char init_item_v8[] = { 0x17, 0x0f, }; +static char init_item_v9[] = { 0x60}; +static char init_item_v10[] = { 0x00, 0x13, 0x1a, 0x29, 0x2d, 0x41, 0x49, + 0x52, 0x48, 0x41, 0x3c, 0x33, 0x30, 0x1c, + 0x19, 0x03, 0x00, 0x13, 0x1a, 0x29, 0x2d, + 0x41, 0x49, 0x52, 0x48, 0x41, 0x3c, 0x33, + 0x31, 0x1c, 0x19, 0x03, 0x00, 0x01, + }; +static char init_item_v11[] = { 0x40, }; + +static inline void truly_spi_write_byte(char dc, uint8 data) +{ + uint32 bit; + int bnum; + + gpio_set_value_cansleep(spi_sclk, 0); /* clk low */ + /* dc: 0 for command, 1 for parameter */ + gpio_set_value_cansleep(spi_mosi, dc); + udelay(1); /* at least 20 ns */ + gpio_set_value_cansleep(spi_sclk, 1); /* clk high */ + udelay(1); /* at least 20 ns */ + bnum = 8; /* 8 data bits */ + bit = 0x80; + while (bnum) { + gpio_set_value_cansleep(spi_sclk, 0); /* clk low */ + if (data & bit) + gpio_set_value_cansleep(spi_mosi, 1); + else + gpio_set_value_cansleep(spi_mosi, 0); + udelay(1); + gpio_set_value_cansleep(spi_sclk, 1); /* clk high */ + udelay(1); + bit >>= 1; + bnum--; + } +} + +static inline int truly_spi_write(char cmd, char *data, int num) +{ + int i; + + gpio_set_value_cansleep(spi_cs, 0); /* cs low */ + /* command byte first */ + truly_spi_write_byte(0, cmd); + /* followed by parameter bytes */ + for (i = 0; i < num; i++) { + if (data) + truly_spi_write_byte(1, data[i]); + } + gpio_set_value_cansleep(spi_mosi, 1); /* mosi high */ + gpio_set_value_cansleep(spi_cs, 1); /* cs high */ + udelay(10); + return 0; +} + +static void spi_pin_assign(void) +{ + /* Setting the Default GPIO's */ + spi_mosi = *(lcdc_truly_pdata->gpio_num); + spi_sclk = *(lcdc_truly_pdata->gpio_num + 1); + spi_cs = *(lcdc_truly_pdata->gpio_num + 2); + gpio_backlight_en = *(lcdc_truly_pdata->gpio_num + 3); + gpio_display_reset = *(lcdc_truly_pdata->gpio_num + 4); + pr_debug("spi_mosi:%d spi_sclk:%d spi_cs:%d backlight:%d reset:%d\n", + spi_mosi, spi_sclk, spi_cs, gpio_backlight_en, + gpio_display_reset); + +} + +static void truly_disp_powerup(void) +{ + /* Reset the hardware first */ + /* Include DAC power up implementation here */ + if (!truly_state.disp_powered_up && !truly_state.display_on) + truly_state.disp_powered_up = TRUE; +} + +static void truly_disp_reginit(void) +{ + pr_debug("%s disp_powered_up:%d display_on:%d\n", __func__, + truly_state.disp_powered_up, truly_state.display_on); + if (truly_state.disp_powered_up && !truly_state.display_on) { + gpio_set_value_cansleep(spi_cs, 1); /* cs high */ + + truly_spi_write(0xb9, init_item_v1, sizeof(init_item_v1)); + msleep(20); + truly_spi_write(0xcc, init_item_v2, sizeof(init_item_v2)); + truly_spi_write(0xb1, init_item_v3, sizeof(init_item_v3)); + truly_spi_write(0xb3, init_item_v4, sizeof(init_item_v4)); + truly_spi_write(0xb6, init_item_v5, sizeof(init_item_v5)); + truly_spi_write(0xb4, init_item_v6, sizeof(init_item_v6)); + truly_spi_write(0xc0, init_item_v7, sizeof(init_item_v7)); + truly_spi_write(0xe3, init_item_v8, sizeof(init_item_v8)); + truly_spi_write(0x3a, init_item_v9, sizeof(init_item_v9)); + truly_spi_write(0xe0, init_item_v10, sizeof(init_item_v10)); + truly_spi_write(0x36, init_item_v11, sizeof(init_item_v11)); + truly_spi_write(0x11, NULL, 0); + msleep(150); + truly_spi_write(0x29, NULL, 0); + msleep(25); + + truly_state.display_on = TRUE; + } +} + +static int lcdc_truly_panel_on(struct platform_device *pdev) +{ + /* Configure reset GPIO that drives DAC */ + if (lcdc_truly_pdata->panel_config_gpio) + lcdc_truly_pdata->panel_config_gpio(1); + gpio_set_value_cansleep(gpio_display_reset, 1); + truly_disp_powerup(); + truly_disp_reginit(); + truly_state.disp_initialized = TRUE; + return 0; +} + +static int lcdc_truly_panel_off(struct platform_device *pdev) +{ + if (truly_state.disp_powered_up && truly_state.display_on) { + /* Main panel power off (Pull down reset) */ + gpio_set_value_cansleep(gpio_display_reset, 0); + truly_state.display_on = FALSE; + truly_state.disp_initialized = FALSE; + } + return 0; +} + +static void lcdc_truly_set_backlight(struct msm_fb_data_type *mfd) +{ + int step = 0, i = 0; + unsigned long flags; + int bl_level = mfd->bl_level; + + /* real backlight level, 1 - max, 16 - min, 17 - off */ + bl_level = 17 - bl_level; + + if (bl_level > prev_bl) { + step = bl_level - prev_bl; + if (bl_level == 17) + step--; + } else if (bl_level < prev_bl) { + step = bl_level + 16 - prev_bl; + } else { + pr_info("%s: no change\n", __func__); + return; + } + + if (bl_level == 17) { + /* turn off backlight */ + gpio_set_value(gpio_backlight_en, 0); + } else { + local_irq_save(flags); + + if (prev_bl == 17) { + /* turn on backlight */ + gpio_set_value(gpio_backlight_en, 1); + udelay(30); + } + + /* adjust backlight level */ + for (i = 0; i < step; i++) { + gpio_set_value(gpio_backlight_en, 0); + udelay(1); + gpio_set_value(gpio_backlight_en, 1); + udelay(1); + } + + local_irq_restore(flags); + } + msleep(20); + prev_bl = bl_level; + + return; +} + +static int truly_probe(struct platform_device *pdev) +{ + + if (pdev->id == 0) { + lcdc_truly_pdata = pdev->dev.platform_data; + + if (!lcdc_truly_pdata) + pr_err("%s pdata is null\n", __func__); + + spi_pin_assign(); + return 0; + } + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = truly_probe, + .driver = { + .name = "lcdc_truly_hvga_ips3p2335_pt", + }, +}; + +static struct msm_fb_panel_data truly_panel_data = { + .on = lcdc_truly_panel_on, + .off = lcdc_truly_panel_off, + .set_backlight = lcdc_truly_set_backlight, +}; + +static struct platform_device this_device = { + .name = "lcdc_truly_hvga_ips3p2335_pt", + .id = 1, + .dev = { + .platform_data = &truly_panel_data, + } +}; + +static int __init lcdc_truly_panel_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + + ret = msm_fb_detect_client("lcdc_truly_hvga_ips3p2335_pt"); + if (ret) + return 0; + + ret = platform_driver_register(&this_driver); + if (ret) { + pr_err("%s() driver registration failed", __func__); + return ret; + } + + pinfo = &truly_panel_data.panel_info; + pinfo->xres = 320; + pinfo->yres = 480; + MSM_FB_SINGLE_MODE_PANEL(pinfo); + pinfo->type = LCDC_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->wait_cycle = 0; + pinfo->bpp = 18; + pinfo->fb_num = 2; + /* 10Mhz mdp_lcdc_pclk and mdp_lcdc_pad_pcl */ + pinfo->clk_rate = 10240000; + pinfo->bl_max = 16; + pinfo->bl_min = 1; + + pinfo->lcdc.h_back_porch = 16; /* hsw = 8 + hbp=16 */ + pinfo->lcdc.h_front_porch = 4; + pinfo->lcdc.h_pulse_width = 8; + pinfo->lcdc.v_back_porch = 7; /* vsw=1 + vbp = 7 */ + pinfo->lcdc.v_front_porch = 3; + pinfo->lcdc.v_pulse_width = 1; + pinfo->lcdc.border_clr = 0; /* blk */ + pinfo->lcdc.underflow_clr = 0xff; /* blue */ + pinfo->lcdc.hsync_skew = 0; + + ret = platform_device_register(&this_device); + if (ret) { + pr_err("%s not able to register the device\n", __func__); + platform_driver_unregister(&this_driver); + } + return ret; +} + +device_initcall(lcdc_truly_panel_init); diff --git a/drivers/video/msm/lcdc_wxga.c b/drivers/video/msm/lcdc_wxga.c new file mode 100644 index 000000000000..dca57dee34d1 --- /dev/null +++ b/drivers/video/msm/lcdc_wxga.c @@ -0,0 +1,53 @@ +/* Copyright (c) 2009-2010, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" + +static int __init lcdc_wxga_init(void) +{ + int ret; + struct msm_panel_info pinfo; + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + if (msm_fb_detect_client("lcdc_wxga")) + return 0; +#endif + + pinfo.xres = 1280; + pinfo.yres = 720; + MSM_FB_SINGLE_MODE_PANEL(&pinfo); + pinfo.type = LCDC_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.fb_num = 2; + pinfo.clk_rate = 74250000; + + pinfo.lcdc.h_back_porch = 124; + pinfo.lcdc.h_front_porch = 110; + pinfo.lcdc.h_pulse_width = 136; + pinfo.lcdc.v_back_porch = 19; + pinfo.lcdc.v_front_porch = 5; + pinfo.lcdc.v_pulse_width = 6; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + + ret = lcdc_device_register(&pinfo); + if (ret) + printk(KERN_ERR "%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(lcdc_wxga_init); diff --git a/drivers/video/msm/logo.c b/drivers/video/msm/logo.c new file mode 100644 index 000000000000..57d754e4d81a --- /dev/null +++ b/drivers/video/msm/logo.c @@ -0,0 +1,103 @@ +/* drivers/video/msm/logo.c + * + * Show Logo in RLE 565 format + * + * Copyright (C) 2008 Google Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +#define fb_width(fb) ((fb)->var.xres) +#define fb_height(fb) ((fb)->var.yres) +#define fb_size(fb) ((fb)->var.xres * (fb)->var.yres * 2) + +static void memset16(void *_ptr, unsigned short val, unsigned count) +{ + unsigned short *ptr = _ptr; + count >>= 1; + while (count--) + *ptr++ = val; +} + +/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */ +int load_565rle_image(char *filename, bool bf_supported) +{ + struct fb_info *info; + int fd, count, err = 0; + unsigned max; + unsigned short *data, *bits, *ptr; + + info = registered_fb[0]; + if (!info) { + printk(KERN_WARNING "%s: Can not access framebuffer\n", + __func__); + return -ENODEV; + } + + fd = sys_open(filename, O_RDONLY, 0); + if (fd < 0) { + printk(KERN_WARNING "%s: Can not open %s\n", + __func__, filename); + return -ENOENT; + } + count = sys_lseek(fd, (off_t)0, 2); + if (count <= 0) { + err = -EIO; + goto err_logo_close_file; + } + sys_lseek(fd, (off_t)0, 0); + data = kmalloc(count, GFP_KERNEL); + if (!data) { + printk(KERN_WARNING "%s: Can not alloc data\n", __func__); + err = -ENOMEM; + goto err_logo_close_file; + } + if (sys_read(fd, (char *)data, count) != count) { + err = -EIO; + goto err_logo_free_data; + } + + max = fb_width(info) * fb_height(info); + ptr = data; + if (bf_supported && (info->node == 1 || info->node == 2)) { + err = -EPERM; + pr_err("%s:%d no info->creen_base on fb%d!\n", + __func__, __LINE__, info->node); + goto err_logo_free_data; + } + bits = (unsigned short *)(info->screen_base); + while (count > 3) { + unsigned n = ptr[0]; + if (n > max) + break; + memset16(bits, ptr[1], n << 1); + bits += n; + max -= n; + ptr += 2; + count -= 4; + } + +err_logo_free_data: + kfree(data); +err_logo_close_file: + sys_close(fd); + return err; +} +EXPORT_SYMBOL(load_565rle_image); diff --git a/drivers/video/msm/lvds.c b/drivers/video/msm/lvds.c new file mode 100644 index 000000000000..18426c55f022 --- /dev/null +++ b/drivers/video/msm/lvds.c @@ -0,0 +1,373 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_fb.h" +#include "mdp4.h" +static int lvds_probe(struct platform_device *pdev); +static int lvds_remove(struct platform_device *pdev); + +static int lvds_off(struct platform_device *pdev); +static int lvds_on(struct platform_device *pdev); + +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; + +static struct clk *lvds_clk; + +static struct platform_driver lvds_driver = { + .probe = lvds_probe, + .remove = lvds_remove, + .suspend = NULL, + .resume = NULL, + .shutdown = NULL, + .driver = { + .name = "lvds", + }, +}; + +static struct lcdc_platform_data *lvds_pdata; + +static void lvds_init(struct msm_fb_data_type *mfd) +{ + unsigned int lvds_intf = 0, lvds_phy_cfg0 = 0; + + MDP_OUTP(MDP_BASE + 0xc2034, 0x33); + usleep(1000); + + /* LVDS PHY PLL configuration */ + MDP_OUTP(MDP_BASE + 0xc3004, 0x62); + MDP_OUTP(MDP_BASE + 0xc3008, 0x30); + MDP_OUTP(MDP_BASE + 0xc300c, 0xc4); + MDP_OUTP(MDP_BASE + 0xc3014, 0x10); + MDP_OUTP(MDP_BASE + 0xc3018, 0x05); + MDP_OUTP(MDP_BASE + 0xc301c, 0x62); + MDP_OUTP(MDP_BASE + 0xc3020, 0x41); + MDP_OUTP(MDP_BASE + 0xc3024, 0x0d); + + MDP_OUTP(MDP_BASE + 0xc3000, 0x01); + /* Wait until LVDS PLL is locked and ready */ + while (!readl_relaxed(MDP_BASE + 0xc3080)) + cpu_relax(); + + writel_relaxed(0x00, mmss_cc_base + 0x0264); + writel_relaxed(0x00, mmss_cc_base + 0x0094); + + writel_relaxed(0x02, mmss_cc_base + 0x00E4); + + writel_relaxed((0x80 | readl_relaxed(mmss_cc_base + 0x00E4)), + mmss_cc_base + 0x00E4); + usleep(1000); + writel_relaxed((~0x80 & readl_relaxed(mmss_cc_base + 0x00E4)), + mmss_cc_base + 0x00E4); + + writel_relaxed(0x05, mmss_cc_base + 0x0094); + writel_relaxed(0x02, mmss_cc_base + 0x0264); + /* Wait until LVDS pixel clock output is enabled */ + mb(); + + if (mfd->panel_info.bpp == 24) { + if (lvds_pdata && + lvds_pdata->lvds_pixel_remap && + lvds_pdata->lvds_pixel_remap()) { + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */ + MDP_OUTP(MDP_BASE + 0xc2014, 0x05080001); + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */ + MDP_OUTP(MDP_BASE + 0xc2018, 0x00020304); + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */ + MDP_OUTP(MDP_BASE + 0xc201c, 0x1011090a); + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */ + MDP_OUTP(MDP_BASE + 0xc2020, 0x000b0c0d); + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */ + MDP_OUTP(MDP_BASE + 0xc2024, 0x191a1213); + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */ + MDP_OUTP(MDP_BASE + 0xc2028, 0x00141518); + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */ + MDP_OUTP(MDP_BASE + 0xc202c, 0x171b0607); + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_6_TO_4 */ + MDP_OUTP(MDP_BASE + 0xc2030, 0x000e0f16); + } else { + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */ + MDP_OUTP(MDP_BASE + 0xc2014, 0x03040508); + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */ + MDP_OUTP(MDP_BASE + 0xc2018, 0x00000102); + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */ + MDP_OUTP(MDP_BASE + 0xc201c, 0x0c0d1011); + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */ + MDP_OUTP(MDP_BASE + 0xc2020, 0x00090a0b); + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */ + MDP_OUTP(MDP_BASE + 0xc2024, 0x151a191a); + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */ + MDP_OUTP(MDP_BASE + 0xc2028, 0x00121314); + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */ + MDP_OUTP(MDP_BASE + 0xc202c, 0x0f16171b); + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_6_TO_4 */ + MDP_OUTP(MDP_BASE + 0xc2030, 0x0006070e); + } + if (mfd->panel_info.lvds.channel_mode == + LVDS_DUAL_CHANNEL_MODE) { + lvds_intf = 0x0001ff80; + lvds_phy_cfg0 = BIT(6) | BIT(7); + if (mfd->panel_info.lvds.channel_swap) + lvds_intf |= BIT(4); + } else { + lvds_intf = 0x00010f84; + lvds_phy_cfg0 = BIT(6); + } + } else if (mfd->panel_info.bpp == 18) { + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */ + MDP_OUTP(MDP_BASE + 0xc2014, 0x03040508); + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */ + MDP_OUTP(MDP_BASE + 0xc2018, 0x00000102); + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */ + MDP_OUTP(MDP_BASE + 0xc201c, 0x0c0d1011); + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */ + MDP_OUTP(MDP_BASE + 0xc2020, 0x00090a0b); + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */ + MDP_OUTP(MDP_BASE + 0xc2024, 0x1518191a); + /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */ + MDP_OUTP(MDP_BASE + 0xc2028, 0x00121314); + + if (mfd->panel_info.lvds.channel_mode == + LVDS_DUAL_CHANNEL_MODE) { + lvds_intf = 0x00017788; + lvds_phy_cfg0 = BIT(6) | BIT(7); + if (mfd->panel_info.lvds.channel_swap) + lvds_intf |= BIT(4); + } else { + lvds_intf = 0x0001078c; + lvds_phy_cfg0 = BIT(6); + } + } else { + BUG(); + } + + /* MDP_LVDSPHY_CFG0 */ + MDP_OUTP(MDP_BASE + 0xc3100, lvds_phy_cfg0); + /* MDP_LCDC_LVDS_INTF_CTL */ + MDP_OUTP(MDP_BASE + 0xc2000, lvds_intf); + MDP_OUTP(MDP_BASE + 0xc3108, 0x30); + lvds_phy_cfg0 |= BIT(4); + + /* Wait until LVDS PHY registers are configured */ + mb(); + usleep(1); + /* MDP_LVDSPHY_CFG0, enable serialization */ + MDP_OUTP(MDP_BASE + 0xc3100, lvds_phy_cfg0); +} + +static int lvds_off(struct platform_device *pdev) +{ + int ret = 0; + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + ret = panel_next_off(pdev); + + if (lvds_clk) + clk_disable_unprepare(lvds_clk); + + MDP_OUTP(MDP_BASE + 0xc3100, 0x0); + MDP_OUTP(MDP_BASE + 0xc3000, 0x0); + usleep(10); + + if (lvds_pdata && lvds_pdata->lcdc_power_save) + lvds_pdata->lcdc_power_save(0); + + if (lvds_pdata && lvds_pdata->lcdc_gpio_config) + ret = lvds_pdata->lcdc_gpio_config(0); + +#ifdef CONFIG_MSM_BUS_SCALING + mdp_bus_scale_update_request(0); +#endif + + return ret; +} + +static int lvds_on(struct platform_device *pdev) +{ + int ret = 0; + struct msm_fb_data_type *mfd; + unsigned long panel_pixclock_freq = 0; + mfd = platform_get_drvdata(pdev); + + if (lvds_pdata && lvds_pdata->lcdc_get_clk) + panel_pixclock_freq = lvds_pdata->lcdc_get_clk(); + + if (!panel_pixclock_freq) + panel_pixclock_freq = mfd->fbi->var.pixclock; +#ifdef CONFIG_MSM_BUS_SCALING + mdp_bus_scale_update_request(2); +#endif + mfd = platform_get_drvdata(pdev); + + if (lvds_clk) { + mfd->fbi->var.pixclock = clk_round_rate(lvds_clk, + mfd->fbi->var.pixclock); + ret = clk_set_rate(lvds_clk, mfd->fbi->var.pixclock); + if (ret) { + pr_err("%s: Can't set lvds clock to rate %u\n", + __func__, mfd->fbi->var.pixclock); + goto out; + } + clk_prepare_enable(lvds_clk); + } + + if (lvds_pdata && lvds_pdata->lcdc_power_save) + lvds_pdata->lcdc_power_save(1); + if (lvds_pdata && lvds_pdata->lcdc_gpio_config) + ret = lvds_pdata->lcdc_gpio_config(1); + + lvds_init(mfd); + ret = panel_next_on(pdev); + +out: + return ret; +} + +static int lvds_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct fb_info *fbi; + struct platform_device *mdp_dev = NULL; + struct msm_fb_panel_data *pdata = NULL; + int rc; + + if (pdev->id == 0) { + lvds_pdata = pdev->dev.platform_data; + + lvds_clk = clk_get(&pdev->dev, "lvds_clk"); + if (IS_ERR_OR_NULL(lvds_clk)) { + pr_err("Couldnt find lvds_clk\n"); + lvds_clk = NULL; + } + return 0; + } + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) + return -ENOMEM; + + mdp_dev = platform_device_alloc("mdp", pdev->id); + if (!mdp_dev) + return -ENOMEM; + + /* + * link to the latest pdev + */ + mfd->pdev = mdp_dev; + mfd->dest = DISPLAY_LCDC; + + /* + * alloc panel device data + */ + if (platform_device_add_data + (mdp_dev, pdev->dev.platform_data, + sizeof(struct msm_fb_panel_data))) { + pr_err("lvds_probe: platform_device_add_data failed!\n"); + platform_device_put(mdp_dev); + return -ENOMEM; + } + /* + * data chain + */ + pdata = (struct msm_fb_panel_data *)mdp_dev->dev.platform_data; + pdata->on = lvds_on; + pdata->off = lvds_off; + pdata->next = pdev; + + /* + * get/set panel specific fb info + */ + mfd->panel_info = pdata->panel_info; + + if (mfd->index == 0) + mfd->fb_imgType = MSMFB_DEFAULT_TYPE; + else + mfd->fb_imgType = MDP_RGB_565; + + fbi = mfd->fbi; + if (lvds_clk) { + fbi->var.pixclock = clk_round_rate(lvds_clk, + mfd->panel_info.clk_rate); + } + + fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch; + fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch; + fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch; + fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch; + fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width; + fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width; + + /* + * set driver data + */ + platform_set_drvdata(mdp_dev, mfd); + /* + * register in mdp driver + */ + rc = platform_device_add(mdp_dev); + if (rc) + goto lvds_probe_err; + + pdev_list[pdev_list_cnt++] = pdev; + + return 0; + +lvds_probe_err: + platform_device_put(mdp_dev); + return rc; +} + +static int lvds_remove(struct platform_device *pdev) +{ + return 0; +} + +static int lvds_register_driver(void) +{ + return platform_driver_register(&lvds_driver); +} + +static int __init lvds_driver_init(void) +{ + return lvds_register_driver(); +} + +module_init(lvds_driver_init); diff --git a/drivers/video/msm/lvds_chimei_wxga.c b/drivers/video/msm/lvds_chimei_wxga.c new file mode 100644 index 000000000000..6074cd82958b --- /dev/null +++ b/drivers/video/msm/lvds_chimei_wxga.c @@ -0,0 +1,167 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "msm_fb.h" +#include +#include + +#define LVDS_CHIMEI_PWM_FREQ_HZ 300 +#define LVDS_CHIMEI_PWM_PERIOD_USEC (USEC_PER_SEC / LVDS_CHIMEI_PWM_FREQ_HZ) +#define LVDS_CHIMEI_PWM_LEVEL 255 +#define LVDS_CHIMEI_PWM_DUTY_LEVEL \ + (LVDS_CHIMEI_PWM_PERIOD_USEC / LVDS_CHIMEI_PWM_LEVEL) + + +static struct lvds_panel_platform_data *cm_pdata; +static struct platform_device *cm_fbpdev; +static struct pwm_device *bl_lpm; + +static int lvds_chimei_panel_on(struct platform_device *pdev) +{ + return 0; +} + +static int lvds_chimei_panel_off(struct platform_device *pdev) +{ + return 0; +} + +static void lvds_chimei_set_backlight(struct msm_fb_data_type *mfd) +{ + int ret; + + pr_debug("%s: back light level %d\n", __func__, mfd->bl_level); + + if (bl_lpm) { + ret = pwm_config(bl_lpm, LVDS_CHIMEI_PWM_DUTY_LEVEL * + mfd->bl_level, LVDS_CHIMEI_PWM_PERIOD_USEC); + if (ret) { + pr_err("pwm_config on lpm failed %d\n", ret); + return; + } + if (mfd->bl_level) { + ret = pwm_enable(bl_lpm); + if (ret) + pr_err("pwm enable/disable on lpm failed" + "for bl %d\n", mfd->bl_level); + } else { + pwm_disable(bl_lpm); + } + } +} + +static int lvds_chimei_probe(struct platform_device *pdev) +{ + int rc = 0; + + if (pdev->id == 0) { + cm_pdata = pdev->dev.platform_data; + if (cm_pdata == NULL) + pr_err("%s: no PWM gpio specified\n", __func__); + return 0; + } + + if (cm_pdata != NULL) + bl_lpm = pwm_request(cm_pdata->gpio[0], + "backlight"); + + if (bl_lpm == NULL || IS_ERR(bl_lpm)) { + pr_err("%s pwm_request() failed\n", __func__); + bl_lpm = NULL; + } + pr_debug("bl_lpm = %p lpm = %d\n", bl_lpm, + cm_pdata->gpio[0]); + + cm_fbpdev = msm_fb_add_device(pdev); + if (!cm_fbpdev) { + dev_err(&pdev->dev, "failed to add msm_fb device\n"); + rc = -ENODEV; + goto probe_exit; + } + +probe_exit: + return rc; +} + +static struct platform_driver this_driver = { + .probe = lvds_chimei_probe, + .driver = { + .name = "lvds_chimei_wxga", + }, +}; + +static struct msm_fb_panel_data lvds_chimei_panel_data = { + .on = lvds_chimei_panel_on, + .off = lvds_chimei_panel_off, + .set_backlight = lvds_chimei_set_backlight, +}; + +static struct platform_device this_device = { + .name = "lvds_chimei_wxga", + .id = 1, + .dev = { + .platform_data = &lvds_chimei_panel_data, + } +}; + +static int __init lvds_chimei_wxga_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + + if (msm_fb_detect_client("lvds_chimei_wxga")) + return 0; + + ret = platform_driver_register(&this_driver); + if (ret) + return ret; + + pinfo = &lvds_chimei_panel_data.panel_info; + pinfo->xres = 1366; + pinfo->yres = 768; + MSM_FB_SINGLE_MODE_PANEL(pinfo); + pinfo->type = LVDS_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->wait_cycle = 0; + pinfo->bpp = 24; + pinfo->fb_num = 2; + pinfo->clk_rate = 75000000; + pinfo->bl_max = 255; + pinfo->bl_min = 1; + + /* + * this panel is operated by de, + * vsycn and hsync are ignored + */ + pinfo->lcdc.h_back_porch = 0; + pinfo->lcdc.h_front_porch = 194; + pinfo->lcdc.h_pulse_width = 40; + pinfo->lcdc.v_back_porch = 0; + pinfo->lcdc.v_front_porch = 38; + pinfo->lcdc.v_pulse_width = 20; + pinfo->lcdc.underflow_clr = 0xff; + pinfo->lcdc.hsync_skew = 0; + pinfo->lvds.channel_mode = LVDS_SINGLE_CHANNEL_MODE; + + /* Set border color, padding only for reducing active display region */ + pinfo->lcdc.border_clr = 0x0; + pinfo->lcdc.xres_pad = 0; + pinfo->lcdc.yres_pad = 0; + + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + + return ret; +} + +module_init(lvds_chimei_wxga_init); diff --git a/drivers/video/msm/mddi.c b/drivers/video/msm/mddi.c new file mode 100644 index 000000000000..6081995dc1a6 --- /dev/null +++ b/drivers/video/msm/mddi.c @@ -0,0 +1,590 @@ +/* + * MSM MDDI Transport + * + * Copyright (C) 2007 Google Incorporated + * Copyright (c) 2007-2012, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "msm_fb.h" +#include "mddihosti.h" +#include "mddihost.h" +#include +#include + +static int mddi_probe(struct platform_device *pdev); +static int mddi_remove(struct platform_device *pdev); + +static int mddi_off(struct platform_device *pdev); +static int mddi_on(struct platform_device *pdev); + +#ifdef CONFIG_PM +static int mddi_suspend(struct platform_device *pdev, pm_message_t state); +static int mddi_resume(struct platform_device *pdev); +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mddi_early_suspend(struct early_suspend *h); +static void mddi_early_resume(struct early_suspend *h); +#endif + +static void pmdh_clk_disable(void); +static void pmdh_clk_enable(void); +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; +static struct clk *mddi_clk; +static struct clk *mddi_pclk; +static struct mddi_platform_data *mddi_pdata; + +DEFINE_MUTEX(mddi_timer_lock); + +static int mddi_runtime_suspend(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: suspending...\n"); + return 0; +} + +static int mddi_runtime_resume(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: resuming...\n"); + return 0; +} + +static int mddi_runtime_idle(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: idling...\n"); + return 0; +} + +static struct dev_pm_ops mddi_dev_pm_ops = { + .runtime_suspend = mddi_runtime_suspend, + .runtime_resume = mddi_runtime_resume, + .runtime_idle = mddi_runtime_idle, +}; + +static int pmdh_clk_status; +int irq_enabled; +unsigned char mddi_timer_shutdown_flag; + +static struct platform_driver mddi_driver = { + .probe = mddi_probe, + .remove = mddi_remove, +#ifndef CONFIG_HAS_EARLYSUSPEND +#ifdef CONFIG_PM + .suspend = mddi_suspend, + .resume = mddi_resume, +#endif +#endif + .shutdown = NULL, + .driver = { + .name = "mddi", + .pm = &mddi_dev_pm_ops, + }, +}; + +extern int int_mddi_pri_flag; +DEFINE_MUTEX(pmdh_clk_lock); + +int pmdh_clk_func(int value) +{ + int ret = 0; + + switch (value) { + case 0: + pmdh_clk_disable(); + break; + case 1: + pmdh_clk_enable(); + break; + case 2: + default: + mutex_lock(&pmdh_clk_lock); + ret = pmdh_clk_status; + mutex_unlock(&pmdh_clk_lock); + break; + } + return ret; +} + +static void pmdh_clk_disable() +{ + mutex_lock(&pmdh_clk_lock); + if (pmdh_clk_status == 0) { + mutex_unlock(&pmdh_clk_lock); + return; + } + + if (mddi_host_timer.function) { + mutex_lock(&mddi_timer_lock); + mddi_timer_shutdown_flag = 1; + mutex_unlock(&mddi_timer_lock); + del_timer_sync(&mddi_host_timer); + mutex_lock(&mddi_timer_lock); + mddi_timer_shutdown_flag = 0; + mutex_unlock(&mddi_timer_lock); + } + if (int_mddi_pri_flag && irq_enabled) { + disable_irq(INT_MDDI_PRI); + irq_enabled = 0; + } + + if (mddi_clk) { + clk_disable_unprepare(mddi_clk); + pmdh_clk_status = 0; + } + if (mddi_pclk) + clk_disable_unprepare(mddi_pclk); + mutex_unlock(&pmdh_clk_lock); +} + +static void pmdh_clk_enable() +{ + mutex_lock(&pmdh_clk_lock); + if (pmdh_clk_status == 1) { + mutex_unlock(&pmdh_clk_lock); + return; + } + + if (mddi_clk) { + clk_prepare_enable(mddi_clk); + pmdh_clk_status = 1; + } + if (mddi_pclk) + clk_prepare_enable(mddi_pclk); + + if (int_mddi_pri_flag && !irq_enabled) { + enable_irq(INT_MDDI_PRI); + irq_enabled = 1; + } + + if (mddi_host_timer.function) + mddi_host_timer_service(0); + + mutex_unlock(&pmdh_clk_lock); +} + +static int mddi_off(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + boolean dma_pending, dma_update_flag; + int ret, i; + + mfd = platform_get_drvdata(pdev); + + for (i = 0; i < 6; i++) { + dma_update_flag = mfd->dma_update_flag; + dma_pending = mfd->dma->busy; + if (dma_update_flag && !dma_pending) + break; + msleep(5); + } + + pmdh_clk_enable(); + ret = panel_next_off(pdev); + pmdh_clk_disable(); + + if (mddi_pdata && mddi_pdata->mddi_power_save) + mddi_pdata->mddi_power_save(0); +#ifdef CONFIG_MSM_BUS_SCALING + mdp_bus_scale_update_request(0); +#else + if (mfd->ebi1_clk) + clk_disable_unprepare(mfd->ebi1_clk); +#endif + pm_runtime_put(&pdev->dev); + return ret; +} + +static int mddi_on(struct platform_device *pdev) +{ + int ret = 0; + u32 clk_rate; + struct msm_fb_data_type *mfd; +#ifdef ENABLE_FWD_LINK_SKEW_CALIBRATION + mddi_host_type host_idx = MDDI_HOST_PRIM; + u32 stat_reg; +#endif + + mfd = platform_get_drvdata(pdev); + pm_runtime_get(&pdev->dev); + if (mddi_pdata && mddi_pdata->mddi_power_save) + mddi_pdata->mddi_power_save(1); + + pmdh_clk_enable(); +#ifdef ENABLE_FWD_LINK_SKEW_CALIBRATION + if (mddi_client_type < 2) { + /* For skew calibration, clock should be less than 50MHz */ + clk_rate = clk_round_rate(mddi_clk, 49000000); + if (!clk_set_rate(mddi_clk, clk_rate)) { + stat_reg = mddi_host_reg_in(STAT); + printk(KERN_DEBUG "\n stat_reg = 0x%x", stat_reg); + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE); + if (stat_reg & (0x1 << 4)) + mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE); + + mddi_host_reg_out(CMD, MDDI_CMD_SEND_RTD); + mddi_send_fw_link_skew_cal(host_idx); + mddi_host_reg_out(CMD, MDDI_CMD_SEND_RTD); + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE | 1); + } else { + printk(KERN_ERR "%s: clk_set_rate failed\n", + __func__); + } + } +#endif + + clk_rate = mfd->fbi->var.pixclock; + clk_rate = min(clk_rate, mfd->panel_info.clk_max); + + if (mddi_pdata && + mddi_pdata->mddi_sel_clk && + mddi_pdata->mddi_sel_clk(&clk_rate)) + printk(KERN_ERR + "%s: can't select mddi io clk targate rate = %d\n", + __func__, clk_rate); + + clk_rate = clk_round_rate(mddi_clk, clk_rate); + if (clk_set_rate(mddi_clk, clk_rate) < 0) + printk(KERN_ERR "%s: clk_set_rate failed\n", + __func__); + +#ifdef CONFIG_MSM_BUS_SCALING + mdp_bus_scale_update_request(2); +#else + if (mfd->ebi1_clk) + clk_prepare_enable(mfd->ebi1_clk); +#endif + ret = panel_next_on(pdev); + + return ret; +} + +static int mddi_resource_initialized; + +static int mddi_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct platform_device *mdp_dev = NULL; + struct msm_fb_panel_data *pdata = NULL; + int rc; + resource_size_t size ; + u32 clk_rate; + unsigned long rate; + int ret; + struct clk *ebi1_clk = NULL; + + if ((pdev->id == 0) && (pdev->num_resources >= 0)) { + mddi_pdata = pdev->dev.platform_data; + pmdh_clk_status = 0; + + mddi_clk = clk_get(&pdev->dev, "core_clk"); + if (IS_ERR(mddi_clk)) { + pr_err("can't find mddi_clk\n"); + return PTR_ERR(mddi_clk); + } + rate = clk_round_rate(mddi_clk, 49000000); + ret = clk_set_rate(mddi_clk, rate); + if (ret) + pr_err("Can't set mddi_clk min rate to %lu\n", + rate); + + pr_info("mddi_clk init rate is %lu\n", + clk_get_rate(mddi_clk)); + mddi_pclk = clk_get(&pdev->dev, "iface_clk"); + if (IS_ERR(mddi_pclk)) + mddi_pclk = NULL; + pmdh_clk_enable(); + +#ifndef CONFIG_MSM_BUS_SCALING + ebi1_clk = clk_get(&pdev->dev, "mem_clk"); + if (IS_ERR(ebi1_clk)) + return PTR_ERR(ebi1_clk); + clk_set_rate(ebi1_clk, 65000000); +#endif + + size = resource_size(&pdev->resource[0]); + msm_pmdh_base = ioremap(pdev->resource[0].start, size); + + MSM_FB_INFO("primary mddi base phy_addr = 0x%x virt = 0x%x\n", + pdev->resource[0].start, (int) msm_pmdh_base); + + if (unlikely(!msm_pmdh_base)) + return -ENOMEM; + + if (mddi_pdata && mddi_pdata->mddi_power_save) + mddi_pdata->mddi_power_save(1); + + mddi_resource_initialized = 1; + return 0; + } + + if (!mddi_resource_initialized) + return -EPERM; + + mfd = platform_get_drvdata(pdev); + mfd->ebi1_clk = ebi1_clk; + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) + return -ENOMEM; + + mdp_dev = platform_device_alloc("mdp", pdev->id); + if (!mdp_dev) + return -ENOMEM; + + /* + * link to the latest pdev + */ + mfd->pdev = mdp_dev; + mfd->dest = DISPLAY_LCD; + + /* + * alloc panel device data + */ + if (platform_device_add_data + (mdp_dev, pdev->dev.platform_data, + sizeof(struct msm_fb_panel_data))) { + printk(KERN_ERR "mddi_probe: platform_device_add_data failed!\n"); + platform_device_put(mdp_dev); + return -ENOMEM; + } + /* + * data chain + */ + pdata = mdp_dev->dev.platform_data; + pdata->on = mddi_on; + pdata->off = mddi_off; + pdata->next = pdev; + pdata->clk_func = pmdh_clk_func; + /* + * get/set panel specific fb info + */ + mfd->panel_info = pdata->panel_info; + + if (mfd->index == 0) + mfd->fb_imgType = MSMFB_DEFAULT_TYPE; + else + mfd->fb_imgType = MDP_RGB_565; + + clk_rate = mfd->panel_info.clk_max; + if (mddi_pdata && + mddi_pdata->mddi_sel_clk && + mddi_pdata->mddi_sel_clk(&clk_rate)) + printk(KERN_ERR + "%s: can't select mddi io clk targate rate = %d\n", + __func__, clk_rate); + + if (clk_set_max_rate(mddi_clk, clk_rate) < 0) + printk(KERN_ERR "%s: clk_set_max_rate failed\n", __func__); + mfd->panel_info.clk_rate = mfd->panel_info.clk_min; + + if (!mddi_client_type) + mddi_client_type = mfd->panel_info.lcd.rev; + else if (!mfd->panel_info.lcd.rev) + printk(KERN_ERR + "%s: mddi client is trying to revert back to type 1 !!!\n", + __func__); + + /* + * set driver data + */ + platform_set_drvdata(mdp_dev, mfd); + rc = pm_runtime_set_active(&pdev->dev); + if (rc < 0) + printk(KERN_ERR "pm_runtime: fail to set active\n"); + + rc = 0; + pm_runtime_enable(&pdev->dev); + /* + * register in mdp driver + */ + rc = platform_device_add(mdp_dev); + if (rc) + goto mddi_probe_err; + + pdev_list[pdev_list_cnt++] = pdev; + +#ifdef CONFIG_HAS_EARLYSUSPEND + mfd->mddi_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; + mfd->mddi_early_suspend.suspend = mddi_early_suspend; + mfd->mddi_early_suspend.resume = mddi_early_resume; + register_early_suspend(&mfd->mddi_early_suspend); +#endif + + return 0; + +mddi_probe_err: + platform_device_put(mdp_dev); + return rc; +} + +static int mddi_pad_ctrl; +static int mddi_power_locked; + +int mddi_client_power(unsigned int client_id) +{ + int ret = 0; + if (mddi_pdata && mddi_pdata->mddi_client_power) + ret = mddi_pdata->mddi_client_power(client_id); + return ret; +} + +void mddi_disable(int lock) +{ + mddi_host_type host_idx = MDDI_HOST_PRIM; + + if (mddi_power_locked) + return; + + if (lock) + mddi_power_locked = 1; + pmdh_clk_enable(); + + mddi_pad_ctrl = mddi_host_reg_in(PAD_CTL); + mddi_host_reg_out(PAD_CTL, 0x0); + + pmdh_clk_disable(); + + if (mddi_pdata && mddi_pdata->mddi_power_save) + mddi_pdata->mddi_power_save(0); +} + +#ifdef CONFIG_PM +static int mddi_is_in_suspend; + +static int mddi_suspend(struct platform_device *pdev, pm_message_t state) +{ + mddi_host_type host_idx = MDDI_HOST_PRIM; + if (mddi_is_in_suspend) + return 0; + + mddi_is_in_suspend = 1; + + if (mddi_power_locked) + return 0; + + pmdh_clk_enable(); + + mddi_pad_ctrl = mddi_host_reg_in(PAD_CTL); + mddi_host_reg_out(PAD_CTL, 0x0); + + pmdh_clk_disable(); + + return 0; +} + +static int mddi_resume(struct platform_device *pdev) +{ + mddi_host_type host_idx = MDDI_HOST_PRIM; + + if (!mddi_is_in_suspend) + return 0; + + mddi_is_in_suspend = 0; + + if (mddi_power_locked) + return 0; + + pmdh_clk_enable(); + + mddi_host_reg_out(PAD_CTL, mddi_pad_ctrl); + + + return 0; +} +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mddi_early_suspend(struct early_suspend *h) +{ + pm_message_t state; + struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type, + mddi_early_suspend); + + state.event = PM_EVENT_SUSPEND; + mddi_suspend(mfd->pdev, state); +} + +static void mddi_early_resume(struct early_suspend *h) +{ + struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type, + mddi_early_suspend); + mddi_resume(mfd->pdev); +} +#endif + +static int mddi_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + if (mddi_host_timer.function) { + mutex_lock(&mddi_timer_lock); + mddi_timer_shutdown_flag = 1; + mutex_unlock(&mddi_timer_lock); + del_timer_sync(&mddi_host_timer); + mutex_lock(&mddi_timer_lock); + mddi_timer_shutdown_flag = 0; + mutex_unlock(&mddi_timer_lock); + } + + iounmap(msm_pmdh_base); + + return 0; +} + +static int mddi_register_driver(void) +{ + return platform_driver_register(&mddi_driver); +} + +static int __init mddi_driver_init(void) +{ + int ret; + + ret = mddi_register_driver(); + if (ret) { + pmdh_clk_disable(); + clk_put(mddi_clk); + if (mddi_pclk) + clk_put(mddi_pclk); + printk(KERN_ERR "mddi_register_driver() failed!\n"); + return ret; + } + + mddi_init(); + + return ret; +} + +module_init(mddi_driver_init); diff --git a/drivers/video/msm/mddi_client_dummy.c b/drivers/video/msm/mddi_client_dummy.c new file mode 100644 index 000000000000..ebbae87885b6 --- /dev/null +++ b/drivers/video/msm/mddi_client_dummy.c @@ -0,0 +1,97 @@ +/* drivers/video/msm_fb/mddi_client_dummy.c + * + * Support for "dummy" mddi client devices which require no + * special initialization code. + * + * Copyright (C) 2007 Google Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + +#include + +struct panel_info { + struct platform_device pdev; + struct msm_panel_data panel_data; +}; + +static int mddi_dummy_suspend(struct msm_panel_data *panel_data) +{ + return 0; +} + +static int mddi_dummy_resume(struct msm_panel_data *panel_data) +{ + return 0; +} + +static int mddi_dummy_blank(struct msm_panel_data *panel_data) +{ + return 0; +} + +static int mddi_dummy_unblank(struct msm_panel_data *panel_data) +{ + return 0; +} + +static int mddi_dummy_probe(struct platform_device *pdev) +{ + struct msm_mddi_client_data *client_data = pdev->dev.platform_data; + struct panel_info *panel = + kzalloc(sizeof(struct panel_info), GFP_KERNEL); + int ret; + if (!panel) + return -ENOMEM; + platform_set_drvdata(pdev, panel); + panel->panel_data.suspend = mddi_dummy_suspend; + panel->panel_data.resume = mddi_dummy_resume; + panel->panel_data.blank = mddi_dummy_blank; + panel->panel_data.unblank = mddi_dummy_unblank; + panel->panel_data.caps = MSMFB_CAP_PARTIAL_UPDATES; + panel->pdev.name = "msm_panel"; + panel->pdev.id = pdev->id; + platform_device_add_resources(&panel->pdev, + client_data->fb_resource, 1); + panel->panel_data.fb_data = client_data->private_client_data; + panel->pdev.dev.platform_data = &panel->panel_data; + ret = platform_device_register(&panel->pdev); + if (ret) { + kfree(panel); + return ret; + } + return 0; +} + +static int mddi_dummy_remove(struct platform_device *pdev) +{ + struct panel_info *panel = platform_get_drvdata(pdev); + kfree(panel); + return 0; +} + +static struct platform_driver mddi_client_dummy = { + .probe = mddi_dummy_probe, + .remove = mddi_dummy_remove, + .driver = { .name = "mddi_c_dummy" }, +}; + +static int __init mddi_client_dummy_init(void) +{ + platform_driver_register(&mddi_client_dummy); + return 0; +} + +module_init(mddi_client_dummy_init); + diff --git a/drivers/video/msm/mddi_client_nt35399.c b/drivers/video/msm/mddi_client_nt35399.c new file mode 100644 index 000000000000..eb8c701fed68 --- /dev/null +++ b/drivers/video/msm/mddi_client_nt35399.c @@ -0,0 +1,251 @@ +/* drivers/video/msm_fb/mddi_client_nt35399.c + * + * Support for Novatek NT35399 MDDI client of Sapphire + * + * Copyright (C) 2008 HTC Incorporated + * Author: Solomon Chiu (solomon_chiu@htc.com) + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +static DECLARE_WAIT_QUEUE_HEAD(nt35399_vsync_wait); + +struct panel_info { + struct msm_mddi_client_data *client_data; + struct platform_device pdev; + struct msm_panel_data panel_data; + struct msmfb_callback *fb_callback; + struct work_struct panel_work; + struct workqueue_struct *fb_wq; + int nt35399_got_int; +}; + +static void +nt35399_request_vsync(struct msm_panel_data *panel_data, + struct msmfb_callback *callback) +{ + struct panel_info *panel = container_of(panel_data, struct panel_info, + panel_data); + struct msm_mddi_client_data *client_data = panel->client_data; + + panel->fb_callback = callback; + if (panel->nt35399_got_int) { + panel->nt35399_got_int = 0; + client_data->activate_link(client_data); /* clears interrupt */ + } +} + +static void nt35399_wait_vsync(struct msm_panel_data *panel_data) +{ + struct panel_info *panel = container_of(panel_data, struct panel_info, + panel_data); + struct msm_mddi_client_data *client_data = panel->client_data; + + if (panel->nt35399_got_int) { + panel->nt35399_got_int = 0; + client_data->activate_link(client_data); /* clears interrupt */ + } + + if (wait_event_timeout(nt35399_vsync_wait, panel->nt35399_got_int, + HZ/2) == 0) + printk(KERN_ERR "timeout waiting for VSYNC\n"); + + panel->nt35399_got_int = 0; + /* interrupt clears when screen dma starts */ +} + +static int nt35399_suspend(struct msm_panel_data *panel_data) +{ + struct panel_info *panel = container_of(panel_data, struct panel_info, + panel_data); + struct msm_mddi_client_data *client_data = panel->client_data; + + struct msm_mddi_bridge_platform_data *bridge_data = + client_data->private_client_data; + int ret; + + ret = bridge_data->uninit(bridge_data, client_data); + if (ret) { + printk(KERN_INFO "mddi nt35399 client: non zero return from " + "uninit\n"); + return ret; + } + client_data->suspend(client_data); + return 0; +} + +static int nt35399_resume(struct msm_panel_data *panel_data) +{ + struct panel_info *panel = container_of(panel_data, struct panel_info, + panel_data); + struct msm_mddi_client_data *client_data = panel->client_data; + + struct msm_mddi_bridge_platform_data *bridge_data = + client_data->private_client_data; + int ret; + + client_data->resume(client_data); + ret = bridge_data->init(bridge_data, client_data); + if (ret) + return ret; + return 0; +} + +static int nt35399_blank(struct msm_panel_data *panel_data) +{ + struct panel_info *panel = container_of(panel_data, struct panel_info, + panel_data); + struct msm_mddi_client_data *client_data = panel->client_data; + struct msm_mddi_bridge_platform_data *bridge_data = + client_data->private_client_data; + + return bridge_data->blank(bridge_data, client_data); +} + +static int nt35399_unblank(struct msm_panel_data *panel_data) +{ + struct panel_info *panel = container_of(panel_data, struct panel_info, + panel_data); + struct msm_mddi_client_data *client_data = panel->client_data; + struct msm_mddi_bridge_platform_data *bridge_data = + client_data->private_client_data; + + return bridge_data->unblank(bridge_data, client_data); +} + +irqreturn_t nt35399_vsync_interrupt(int irq, void *data) +{ + struct panel_info *panel = data; + + panel->nt35399_got_int = 1; + + if (panel->fb_callback) { + panel->fb_callback->func(panel->fb_callback); + panel->fb_callback = NULL; + } + + wake_up(&nt35399_vsync_wait); + + return IRQ_HANDLED; +} + +static int setup_vsync(struct panel_info *panel, int init) +{ + int ret; + int gpio = 97; + unsigned int irq; + + if (!init) { + ret = 0; + goto uninit; + } + ret = gpio_request_one(gpio, GPIOF_IN, "vsync"); + if (ret) + goto err_request_gpio_failed; + + ret = irq = gpio_to_irq(gpio); + if (ret < 0) + goto err_get_irq_num_failed; + + ret = request_irq(irq, nt35399_vsync_interrupt, IRQF_TRIGGER_RISING, + "vsync", panel); + if (ret) + goto err_request_irq_failed; + + printk(KERN_INFO "vsync on gpio %d now %d\n", + gpio, gpio_get_value(gpio)); + return 0; + +uninit: + free_irq(gpio_to_irq(gpio), panel->client_data); +err_request_irq_failed: +err_get_irq_num_failed: + gpio_free(gpio); +err_request_gpio_failed: + return ret; +} + +static int mddi_nt35399_probe(struct platform_device *pdev) +{ + struct msm_mddi_client_data *client_data = pdev->dev.platform_data; + struct msm_mddi_bridge_platform_data *bridge_data = + client_data->private_client_data; + + int ret; + + struct panel_info *panel = kzalloc(sizeof(struct panel_info), + GFP_KERNEL); + + printk(KERN_DEBUG "%s: enter.\n", __func__); + + if (!panel) + return -ENOMEM; + platform_set_drvdata(pdev, panel); + + ret = setup_vsync(panel, 1); + if (ret) { + dev_err(&pdev->dev, "mddi_nt35399_setup_vsync failed\n"); + return ret; + } + + panel->client_data = client_data; + panel->panel_data.suspend = nt35399_suspend; + panel->panel_data.resume = nt35399_resume; + panel->panel_data.wait_vsync = nt35399_wait_vsync; + panel->panel_data.request_vsync = nt35399_request_vsync; + panel->panel_data.blank = nt35399_blank; + panel->panel_data.unblank = nt35399_unblank; + panel->panel_data.fb_data = &bridge_data->fb_data; + panel->panel_data.caps = 0; + + panel->pdev.name = "msm_panel"; + panel->pdev.id = pdev->id; + panel->pdev.resource = client_data->fb_resource; + panel->pdev.num_resources = 1; + panel->pdev.dev.platform_data = &panel->panel_data; + + if (bridge_data->init) + bridge_data->init(bridge_data, client_data); + + platform_device_register(&panel->pdev); + + return 0; +} + +static int mddi_nt35399_remove(struct platform_device *pdev) +{ + struct panel_info *panel = platform_get_drvdata(pdev); + + setup_vsync(panel, 0); + kfree(panel); + return 0; +} + +static struct platform_driver mddi_client_0bda_8a47 = { + .probe = mddi_nt35399_probe, + .remove = mddi_nt35399_remove, + .driver = { .name = "mddi_c_0bda_8a47" }, +}; + +static int __init mddi_client_nt35399_init(void) +{ + return platform_driver_register(&mddi_client_0bda_8a47); +} + +module_init(mddi_client_nt35399_init); + diff --git a/drivers/video/msm/mddi_client_toshiba.c b/drivers/video/msm/mddi_client_toshiba.c new file mode 100644 index 000000000000..886878109098 --- /dev/null +++ b/drivers/video/msm/mddi_client_toshiba.c @@ -0,0 +1,256 @@ +/* drivers/video/msm_fb/mddi_client_toshiba.c + * + * Support for Toshiba TC358720XBG mddi client devices which require no + * special initialization code. + * + * Copyright (C) 2007 Google Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + + +#define LCD_CONTROL_BLOCK_BASE 0x110000 +#define CMN (LCD_CONTROL_BLOCK_BASE|0x10) +#define INTFLG (LCD_CONTROL_BLOCK_BASE|0x18) +#define HCYCLE (LCD_CONTROL_BLOCK_BASE|0x34) +#define HDE_START (LCD_CONTROL_BLOCK_BASE|0x3C) +#define VPOS (LCD_CONTROL_BLOCK_BASE|0xC0) +#define MPLFBUF (LCD_CONTROL_BLOCK_BASE|0x20) +#define WAKEUP (LCD_CONTROL_BLOCK_BASE|0x54) +#define WSYN_DLY (LCD_CONTROL_BLOCK_BASE|0x58) +#define REGENB (LCD_CONTROL_BLOCK_BASE|0x5C) + +#define BASE5 0x150000 +#define BASE6 0x160000 +#define BASE7 0x170000 + +#define GPIOIEV (BASE5 + 0x10) +#define GPIOIE (BASE5 + 0x14) +#define GPIORIS (BASE5 + 0x18) +#define GPIOMIS (BASE5 + 0x1C) +#define GPIOIC (BASE5 + 0x20) + +#define INTMASK (BASE6 + 0x0C) +#define INTMASK_VWAKEOUT (1U << 0) +#define INTMASK_VWAKEOUT_ACTIVE_LOW (1U << 8) +#define GPIOSEL (BASE7 + 0x00) +#define GPIOSEL_VWAKEINT (1U << 0) + +static DECLARE_WAIT_QUEUE_HEAD(toshiba_vsync_wait); + +struct panel_info { + struct msm_mddi_client_data *client_data; + struct platform_device pdev; + struct msm_panel_data panel_data; + struct msmfb_callback *toshiba_callback; + int toshiba_got_int; + int irq; +}; + + +static void toshiba_request_vsync(struct msm_panel_data *panel_data, + struct msmfb_callback *callback) +{ + struct panel_info *panel = container_of(panel_data, struct panel_info, + panel_data); + struct msm_mddi_client_data *client_data = panel->client_data; + + panel->toshiba_callback = callback; + if (panel->toshiba_got_int) { + panel->toshiba_got_int = 0; + client_data->activate_link(client_data); + } +} + +static void toshiba_clear_vsync(struct msm_panel_data *panel_data) +{ + struct panel_info *panel = container_of(panel_data, struct panel_info, + panel_data); + struct msm_mddi_client_data *client_data = panel->client_data; + + client_data->activate_link(client_data); +} + +static void toshiba_wait_vsync(struct msm_panel_data *panel_data) +{ + struct panel_info *panel = container_of(panel_data, struct panel_info, + panel_data); + struct msm_mddi_client_data *client_data = panel->client_data; + + if (panel->toshiba_got_int) { + panel->toshiba_got_int = 0; + client_data->activate_link(client_data); /* clears interrupt */ + } + if (wait_event_timeout(toshiba_vsync_wait, panel->toshiba_got_int, + HZ/2) == 0) + printk(KERN_ERR "timeout waiting for VSYNC\n"); + panel->toshiba_got_int = 0; + /* interrupt clears when screen dma starts */ +} + +static int toshiba_suspend(struct msm_panel_data *panel_data) +{ + struct panel_info *panel = container_of(panel_data, struct panel_info, + panel_data); + struct msm_mddi_client_data *client_data = panel->client_data; + + struct msm_mddi_bridge_platform_data *bridge_data = + client_data->private_client_data; + int ret; + + ret = bridge_data->uninit(bridge_data, client_data); + if (ret) { + printk(KERN_INFO "mddi toshiba client: non zero return from " + "uninit\n"); + return ret; + } + client_data->suspend(client_data); + return 0; +} + +static int toshiba_resume(struct msm_panel_data *panel_data) +{ + struct panel_info *panel = container_of(panel_data, struct panel_info, + panel_data); + struct msm_mddi_client_data *client_data = panel->client_data; + + struct msm_mddi_bridge_platform_data *bridge_data = + client_data->private_client_data; + int ret; + + client_data->resume(client_data); + ret = bridge_data->init(bridge_data, client_data); + if (ret) + return ret; + return 0; +} + +static int toshiba_blank(struct msm_panel_data *panel_data) +{ + struct panel_info *panel = container_of(panel_data, struct panel_info, + panel_data); + struct msm_mddi_client_data *client_data = panel->client_data; + struct msm_mddi_bridge_platform_data *bridge_data = + client_data->private_client_data; + + return bridge_data->blank(bridge_data, client_data); +} + +static int toshiba_unblank(struct msm_panel_data *panel_data) +{ + struct panel_info *panel = container_of(panel_data, struct panel_info, + panel_data); + struct msm_mddi_client_data *client_data = panel->client_data; + struct msm_mddi_bridge_platform_data *bridge_data = + client_data->private_client_data; + + return bridge_data->unblank(bridge_data, client_data); +} + +irqreturn_t toshiba_vsync_interrupt(int irq, void *data) +{ + struct panel_info *panel = data; + + panel->toshiba_got_int = 1; + if (panel->toshiba_callback) { + panel->toshiba_callback->func(panel->toshiba_callback); + panel->toshiba_callback = 0; + } + wake_up(&toshiba_vsync_wait); + return IRQ_HANDLED; +} + +static int mddi_toshiba_probe(struct platform_device *pdev) +{ + int ret; + struct msm_mddi_client_data *client_data = pdev->dev.platform_data; + struct msm_mddi_bridge_platform_data *bridge_data = + client_data->private_client_data; + struct panel_info *panel = + kzalloc(sizeof(struct panel_info), GFP_KERNEL); + if (!panel) + return -ENOMEM; + platform_set_drvdata(pdev, panel); + + /* mddi_remote_write(mddi, 0, WAKEUP); */ + client_data->remote_write(client_data, GPIOSEL_VWAKEINT, GPIOSEL); + client_data->remote_write(client_data, INTMASK_VWAKEOUT, INTMASK); + + ret = platform_get_irq_byname(pdev, "vsync"); + if (ret < 0) + goto err_plat_get_irq; + + panel->irq = ret; + ret = request_irq(panel->irq, toshiba_vsync_interrupt, + IRQF_TRIGGER_RISING, "vsync", panel); + if (ret) { + dev_err(&pdev->dev, "mddi_bridge_setup_vsync failed\n"); + goto err_req_irq; + } + + panel->client_data = client_data; + panel->panel_data.suspend = toshiba_suspend; + panel->panel_data.resume = toshiba_resume; + panel->panel_data.wait_vsync = toshiba_wait_vsync; + panel->panel_data.request_vsync = toshiba_request_vsync; + panel->panel_data.clear_vsync = toshiba_clear_vsync; + panel->panel_data.blank = toshiba_blank; + panel->panel_data.unblank = toshiba_unblank; + panel->panel_data.fb_data = &bridge_data->fb_data; + panel->panel_data.caps = MSMFB_CAP_PARTIAL_UPDATES; + + panel->pdev.name = "msm_panel"; + panel->pdev.id = pdev->id; + panel->pdev.resource = client_data->fb_resource; + panel->pdev.num_resources = 1; + panel->pdev.dev.platform_data = &panel->panel_data; + bridge_data->init(bridge_data, client_data); + platform_device_register(&panel->pdev); + + return 0; + +err_req_irq: +err_plat_get_irq: + kfree(panel); + return ret; +} + +static int mddi_toshiba_remove(struct platform_device *pdev) +{ + struct panel_info *panel = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + free_irq(panel->irq, panel); + kfree(panel); + return 0; +} + +static struct platform_driver mddi_client_d263_0000 = { + .probe = mddi_toshiba_probe, + .remove = mddi_toshiba_remove, + .driver = { .name = "mddi_c_d263_0000" }, +}; + +static int __init mddi_client_toshiba_init(void) +{ + platform_driver_register(&mddi_client_d263_0000); + return 0; +} + +module_init(mddi_client_toshiba_init); + diff --git a/drivers/video/msm/mddi_ext.c b/drivers/video/msm/mddi_ext.c new file mode 100644 index 000000000000..83831b0620ed --- /dev/null +++ b/drivers/video/msm/mddi_ext.c @@ -0,0 +1,354 @@ +/* Copyright (c) 2008-2009, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_fb.h" +#include "mddihosti.h" + +static int mddi_ext_probe(struct platform_device *pdev); +static int mddi_ext_remove(struct platform_device *pdev); + +static int mddi_ext_off(struct platform_device *pdev); +static int mddi_ext_on(struct platform_device *pdev); + +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; + +static int mddi_ext_suspend(struct platform_device *pdev, pm_message_t state); +static int mddi_ext_resume(struct platform_device *pdev); + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mddi_ext_early_suspend(struct early_suspend *h); +static void mddi_ext_early_resume(struct early_suspend *h); +#endif + +static int mddi_ext_runtime_suspend(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: suspending...\n"); + return 0; +} + +static int mddi_ext_runtime_resume(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: resuming...\n"); + return 0; +} + +static int mddi_ext_runtime_idle(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: idling...\n"); + return 0; +} +static struct dev_pm_ops mddi_ext_dev_pm_ops = { + .runtime_suspend = mddi_ext_runtime_suspend, + .runtime_resume = mddi_ext_runtime_resume, + .runtime_idle = mddi_ext_runtime_idle, +}; + +static struct platform_driver mddi_ext_driver = { + .probe = mddi_ext_probe, + .remove = mddi_ext_remove, +#ifndef CONFIG_HAS_EARLYSUSPEND +#ifdef CONFIG_PM + .suspend = mddi_ext_suspend, + .resume = mddi_ext_resume, +#endif +#endif + .resume_early = NULL, + .resume = NULL, + .shutdown = NULL, + .driver = { + .name = "mddi_ext", + .pm = &mddi_ext_dev_pm_ops, + }, +}; + +static struct clk *mddi_ext_clk; +static struct clk *mddi_ext_pclk; +static struct mddi_platform_data *mddi_ext_pdata; + +extern int int_mddi_ext_flag; + +static int mddi_ext_off(struct platform_device *pdev) +{ + int ret = 0; + + ret = panel_next_off(pdev); + mddi_host_stop_ext_display(); + pm_runtime_put(&pdev->dev); + return ret; +} + +static int mddi_ext_on(struct platform_device *pdev) +{ + int ret = 0; + u32 clk_rate; + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + pm_runtime_get(&pdev->dev); + clk_rate = mfd->fbi->var.pixclock; + clk_rate = min(clk_rate, mfd->panel_info.clk_max); + + if (mddi_ext_pdata && + mddi_ext_pdata->mddi_sel_clk && + mddi_ext_pdata->mddi_sel_clk(&clk_rate)) + printk(KERN_ERR + "%s: can't select mddi io clk targate rate = %d\n", + __func__, clk_rate); + + clk_rate = clk_round_rate(mddi_ext_clk, clk_rate); + if (clk_set_rate(mddi_ext_clk, clk_rate) < 0) + printk(KERN_ERR "%s: clk_set_rate failed\n", + __func__); + + mddi_host_start_ext_display(); + ret = panel_next_on(pdev); + + return ret; +} + +static int mddi_ext_resource_initialized; + +static int mddi_ext_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct platform_device *mdp_dev = NULL; + struct msm_fb_panel_data *pdata = NULL; + int rc; + resource_size_t size ; + u32 clk_rate; + + if ((pdev->id == 0) && (pdev->num_resources >= 0)) { + mddi_ext_pdata = pdev->dev.platform_data; + mddi_ext_clk = clk_get(&pdev->dev, "core_clk"); + if (IS_ERR(mddi_ext_clk)) { + pr_err("can't find emdh_clk\n"); + return PTR_ERR(mddi_ext_clk); + } + clk_prepare_enable(mddi_ext_clk); + + mddi_ext_pclk = clk_get(&pdev->dev, "iface_clk"); + if (IS_ERR(mddi_ext_pclk)) + mddi_ext_pclk = NULL; + else + clk_prepare_enable(mddi_ext_pclk); + + size = resource_size(&pdev->resource[0]); + msm_emdh_base = ioremap(pdev->resource[0].start, size); + + MSM_FB_INFO("external mddi base address = 0x%x\n", + pdev->resource[0].start); + + if (unlikely(!msm_emdh_base)) + return -ENOMEM; + + mddi_ext_resource_initialized = 1; + return 0; + } + + if (!mddi_ext_resource_initialized) + return -EPERM; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) + return -ENOMEM; + + mdp_dev = platform_device_alloc("mdp", pdev->id); + if (!mdp_dev) + return -ENOMEM; + + /* + * link to the latest pdev + */ + mfd->pdev = mdp_dev; + mfd->dest = DISPLAY_EXT_MDDI; + + /* + * alloc panel device data + */ + if (platform_device_add_data + (mdp_dev, pdev->dev.platform_data, + sizeof(struct msm_fb_panel_data))) { + printk(KERN_ERR "mddi_ext_probe: platform_device_add_data failed!\n"); + platform_device_put(mdp_dev); + return -ENOMEM; + } + /* + * data chain + */ + pdata = mdp_dev->dev.platform_data; + pdata->on = mddi_ext_on; + pdata->off = mddi_ext_off; + pdata->next = pdev; + + /* + * get/set panel specific fb info + */ + mfd->panel_info = pdata->panel_info; + mfd->fb_imgType = MDP_RGB_565; + + clk_rate = mfd->panel_info.clk_max; + if (mddi_ext_pdata && + mddi_ext_pdata->mddi_sel_clk && + mddi_ext_pdata->mddi_sel_clk(&clk_rate)) + printk(KERN_ERR + "%s: can't select mddi io clk targate rate = %d\n", + __func__, clk_rate); + + if (clk_set_max_rate(mddi_ext_clk, clk_rate) < 0) + printk(KERN_ERR "%s: clk_set_max_rate failed\n", __func__); + mfd->panel_info.clk_rate = mfd->panel_info.clk_min; + + /* + * set driver data + */ + platform_set_drvdata(mdp_dev, mfd); + rc = pm_runtime_set_active(&pdev->dev); + if (rc < 0) + printk(KERN_ERR "pm_runtime: fail to set active\n"); + + rc = 0; + pm_runtime_enable(&pdev->dev); + /* + * register in mdp driver + */ + rc = platform_device_add(mdp_dev); + if (rc) + goto mddi_ext_probe_err; + + pdev_list[pdev_list_cnt++] = pdev; + +#ifdef CONFIG_HAS_EARLYSUSPEND + mfd->mddi_ext_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB; + mfd->mddi_ext_early_suspend.suspend = mddi_ext_early_suspend; + mfd->mddi_ext_early_suspend.resume = mddi_ext_early_resume; + register_early_suspend(&mfd->mddi_ext_early_suspend); +#endif + + return 0; + +mddi_ext_probe_err: + platform_device_put(mdp_dev); + return rc; +} + +static int mddi_ext_is_in_suspend; + +static int mddi_ext_suspend(struct platform_device *pdev, pm_message_t state) +{ + if (mddi_ext_is_in_suspend) + return 0; + + mddi_ext_is_in_suspend = 1; + + clk_disable_unprepare(mddi_ext_clk); + if (mddi_ext_pclk) + clk_disable_unprepare(mddi_ext_pclk); + + disable_irq(INT_MDDI_EXT); + + return 0; +} + +static int mddi_ext_resume(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + + if (!mddi_ext_is_in_suspend) + return 0; + + mddi_ext_is_in_suspend = 0; + enable_irq(INT_MDDI_EXT); + + clk_prepare_enable(mddi_ext_clk); + if (mddi_ext_pclk) + clk_prepare_enable(mddi_ext_pclk); + + return 0; +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mddi_ext_early_suspend(struct early_suspend *h) +{ + pm_message_t state; + struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type, + mddi_ext_early_suspend); + + state.event = PM_EVENT_SUSPEND; + mddi_ext_suspend(mfd->pdev, state); +} + +static void mddi_ext_early_resume(struct early_suspend *h) +{ + struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type, + mddi_ext_early_suspend); + mddi_ext_resume(mfd->pdev); +} +#endif + +static int mddi_ext_remove(struct platform_device *pdev) +{ + pm_runtim_disable(&pdev->dev); + iounmap(msm_emdh_base); + return 0; +} + +static int mddi_ext_register_driver(void) +{ + return platform_driver_register(&mddi_ext_driver); +} + +static int __init mddi_ext_driver_init(void) +{ + int ret; + + ret = mddi_ext_register_driver(); + if (ret) { + printk(KERN_ERR "mddi_ext_register_driver() failed!\n"); + return ret; + } + mddi_init(); + + return ret; +} + +module_init(mddi_ext_driver_init); diff --git a/drivers/video/msm/mddi_ext_lcd.c b/drivers/video/msm/mddi_ext_lcd.c new file mode 100644 index 000000000000..aa4d48425995 --- /dev/null +++ b/drivers/video/msm/mddi_ext_lcd.c @@ -0,0 +1,90 @@ +/* Copyright (c) 2008-2010, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mddihost.h" +#include "mddihosti.h" + +static int mddi_ext_lcd_on(struct platform_device *pdev); +static int mddi_ext_lcd_off(struct platform_device *pdev); + +static int mddi_ext_lcd_on(struct platform_device *pdev) +{ + return 0; +} + +static int mddi_ext_lcd_off(struct platform_device *pdev) +{ + return 0; +} + +static int __init mddi_ext_lcd_probe(struct platform_device *pdev) +{ + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = mddi_ext_lcd_probe, + .driver = { + .name = "extmddi_svga", + }, +}; + +static struct msm_fb_panel_data mddi_ext_lcd_panel_data = { + .panel_info.xres = 800, + .panel_info.yres = 600, + .panel_info.mode2_xres = 0; + .panel_info.mode2_yres = 0; + .panel_info.mode2_bpp = 0; + .panel_info.type = EXT_MDDI_PANEL, + .panel_info.pdest = DISPLAY_1, + .panel_info.wait_cycle = 0, + .panel_info.bpp = 18, + .panel_info.fb_num = 2, + .panel_info.clk_rate = 122880000, + .panel_info.clk_min = 120000000, + .panel_info.clk_max = 125000000, + .on = mddi_ext_lcd_on, + .off = mddi_ext_lcd_off, +}; + +static struct platform_device this_device = { + .name = "extmddi_svga", + .id = 0, + .dev = { + .platform_data = &mddi_ext_lcd_panel_data, + } +}; + +static int __init mddi_ext_lcd_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + + ret = platform_driver_register(&this_driver); + if (!ret) { + pinfo = &mddi_ext_lcd_panel_data.panel_info; + pinfo->lcd.vsync_enable = FALSE; + pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR; + + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + } + + return ret; +} + +module_init(mddi_ext_lcd_init); diff --git a/drivers/video/msm/mddi_hw.h b/drivers/video/msm/mddi_hw.h new file mode 100644 index 000000000000..47bb4494c5f7 --- /dev/null +++ b/drivers/video/msm/mddi_hw.h @@ -0,0 +1,314 @@ +/* drivers/video/msm_fb/mddi_hw.h + * + * MSM MDDI Hardware Registers and Structures + * + * Copyright (C) 2007 QUALCOMM Incorporated + * Copyright (C) 2007 Google Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MDDI_HW_H_ +#define _MDDI_HW_H_ + +#include + +#define MDDI_CMD 0x0000 +#define MDDI_VERSION 0x0004 +#define MDDI_PRI_PTR 0x0008 +#define MDDI_SEC_PTR 0x000c +#define MDDI_BPS 0x0010 +#define MDDI_SPM 0x0014 +#define MDDI_INT 0x0018 +#define MDDI_INTEN 0x001c +#define MDDI_REV_PTR 0x0020 +#define MDDI_REV_SIZE 0x0024 +#define MDDI_STAT 0x0028 +#define MDDI_REV_RATE_DIV 0x002c +#define MDDI_REV_CRC_ERR 0x0030 +#define MDDI_TA1_LEN 0x0034 +#define MDDI_TA2_LEN 0x0038 +#define MDDI_TEST_BUS 0x003c +#define MDDI_TEST 0x0040 +#define MDDI_REV_PKT_CNT 0x0044 +#define MDDI_DRIVE_HI 0x0048 +#define MDDI_DRIVE_LO 0x004c +#define MDDI_DISP_WAKE 0x0050 +#define MDDI_REV_ENCAP_SZ 0x0054 +#define MDDI_RTD_VAL 0x0058 +#define MDDI_PAD_CTL 0x0068 +#define MDDI_DRIVER_START_CNT 0x006c +#define MDDI_NEXT_PRI_PTR 0x0070 +#define MDDI_NEXT_SEC_PTR 0x0074 +#define MDDI_MISR_CTL 0x0078 +#define MDDI_MISR_DATA 0x007c +#define MDDI_SF_CNT 0x0080 +#define MDDI_MF_CNT 0x0084 +#define MDDI_CURR_REV_PTR 0x0088 +#define MDDI_CORE_VER 0x008c +#define MDDI_FIFO_ALLOC 0x0090 +#define MDDI_PAD_IO_CTL 0x00a0 +#define MDDI_PAD_CAL 0x00a4 + +#define MDDI_INT_PRI_PTR_READ 0x0001 +#define MDDI_INT_SEC_PTR_READ 0x0002 +#define MDDI_INT_REV_DATA_AVAIL 0x0004 +#define MDDI_INT_DISP_REQ 0x0008 +#define MDDI_INT_PRI_UNDERFLOW 0x0010 +#define MDDI_INT_SEC_UNDERFLOW 0x0020 +#define MDDI_INT_REV_OVERFLOW 0x0040 +#define MDDI_INT_CRC_ERROR 0x0080 +#define MDDI_INT_MDDI_IN 0x0100 +#define MDDI_INT_PRI_OVERWRITE 0x0200 +#define MDDI_INT_SEC_OVERWRITE 0x0400 +#define MDDI_INT_REV_OVERWRITE 0x0800 +#define MDDI_INT_DMA_FAILURE 0x1000 +#define MDDI_INT_LINK_ACTIVE 0x2000 +#define MDDI_INT_IN_HIBERNATION 0x4000 +#define MDDI_INT_PRI_LINK_LIST_DONE 0x8000 +#define MDDI_INT_SEC_LINK_LIST_DONE 0x10000 +#define MDDI_INT_NO_CMD_PKTS_PEND 0x20000 +#define MDDI_INT_RTD_FAILURE 0x40000 +#define MDDI_INT_REV_PKT_RECEIVED 0x80000 +#define MDDI_INT_REV_PKTS_AVAIL 0x100000 + +#define MDDI_INT_NEED_CLEAR ( \ + MDDI_INT_REV_DATA_AVAIL | \ + MDDI_INT_PRI_UNDERFLOW | \ + MDDI_INT_SEC_UNDERFLOW | \ + MDDI_INT_REV_OVERFLOW | \ + MDDI_INT_CRC_ERROR | \ + MDDI_INT_REV_PKT_RECEIVED) + + +#define MDDI_STAT_LINK_ACTIVE 0x0001 +#define MDDI_STAT_NEW_REV_PTR 0x0002 +#define MDDI_STAT_NEW_PRI_PTR 0x0004 +#define MDDI_STAT_NEW_SEC_PTR 0x0008 +#define MDDI_STAT_IN_HIBERNATION 0x0010 +#define MDDI_STAT_PRI_LINK_LIST_DONE 0x0020 +#define MDDI_STAT_SEC_LINK_LIST_DONE 0x0040 +#define MDDI_STAT_PENDING_TIMING_PKT 0x0080 +#define MDDI_STAT_PENDING_REV_ENCAP 0x0100 +#define MDDI_STAT_PENDING_POWERDOWN 0x0200 +#define MDDI_STAT_RTD_MEAS_FAIL 0x0800 +#define MDDI_STAT_CLIENT_WAKEUP_REQ 0x1000 + + +#define MDDI_CMD_POWERDOWN 0x0100 +#define MDDI_CMD_POWERUP 0x0200 +#define MDDI_CMD_HIBERNATE 0x0300 +#define MDDI_CMD_RESET 0x0400 +#define MDDI_CMD_DISP_IGNORE 0x0501 +#define MDDI_CMD_DISP_LISTEN 0x0500 +#define MDDI_CMD_SEND_REV_ENCAP 0x0600 +#define MDDI_CMD_GET_CLIENT_CAP 0x0601 +#define MDDI_CMD_GET_CLIENT_STATUS 0x0602 +#define MDDI_CMD_SEND_RTD 0x0700 +#define MDDI_CMD_LINK_ACTIVE 0x0900 +#define MDDI_CMD_PERIODIC_REV_ENCAP 0x0A00 +#define MDDI_CMD_FORCE_NEW_REV_PTR 0x0C00 + + + +#define MDDI_VIDEO_REV_PKT_SIZE 0x40 +#define MDDI_CLIENT_CAPABILITY_REV_PKT_SIZE 0x60 +#define MDDI_MAX_REV_PKT_SIZE 0x60 + +/* #define MDDI_REV_BUFFER_SIZE 128 */ +#define MDDI_REV_BUFFER_SIZE (MDDI_MAX_REV_PKT_SIZE * 4) + +/* MDP sends 256 pixel packets, so lower value hibernates more without + * significantly increasing latency of waiting for next subframe */ +#define MDDI_HOST_BYTES_PER_SUBFRAME 0x3C00 + +#if defined(CONFIG_MSM_MDP31) || defined(CONFIG_MSM_MDP40) +#define MDDI_HOST_TA2_LEN 0x001a +#define MDDI_HOST_REV_RATE_DIV 0x0004 +#else +#define MDDI_HOST_TA2_LEN 0x000c +#define MDDI_HOST_REV_RATE_DIV 0x0002 +#endif + + +struct __attribute__((packed)) mddi_rev_packet { + uint16_t length; + uint16_t type; + uint16_t client_id; +}; + +struct __attribute__((packed)) mddi_client_status { + uint16_t length; + uint16_t type; + uint16_t client_id; + uint16_t reverse_link_request; /* bytes needed in rev encap message */ + uint8_t crc_error_count; + uint8_t capability_change; + uint16_t graphics_busy_flags; + uint16_t crc16; +}; + +struct __attribute__((packed)) mddi_client_caps { + uint16_t length; /* length, exclusive of this field */ + uint16_t type; /* 66 */ + uint16_t client_id; + + uint16_t Protocol_Version; + uint16_t Minimum_Protocol_Version; + uint16_t Data_Rate_Capability; + uint8_t Interface_Type_Capability; + uint8_t Number_of_Alt_Displays; + uint16_t PostCal_Data_Rate; + uint16_t Bitmap_Width; + uint16_t Bitmap_Height; + uint16_t Display_Window_Width; + uint16_t Display_Window_Height; + uint32_t Color_Map_Size; + uint16_t Color_Map_RGB_Width; + uint16_t RGB_Capability; + uint8_t Monochrome_Capability; + uint8_t Reserved_1; + uint16_t Y_Cb_Cr_Capability; + uint16_t Bayer_Capability; + uint16_t Alpha_Cursor_Image_Planes; + uint32_t Client_Feature_Capability_Indicators; + uint8_t Maximum_Video_Frame_Rate_Capability; + uint8_t Minimum_Video_Frame_Rate_Capability; + uint16_t Minimum_Sub_frame_Rate; + uint16_t Audio_Buffer_Depth; + uint16_t Audio_Channel_Capability; + uint16_t Audio_Sample_Rate_Capability; + uint8_t Audio_Sample_Resolution; + uint8_t Mic_Audio_Sample_Resolution; + uint16_t Mic_Sample_Rate_Capability; + uint8_t Keyboard_Data_Format; + uint8_t pointing_device_data_format; + uint16_t content_protection_type; + uint16_t Mfr_Name; + uint16_t Product_Code; + uint16_t Reserved_3; + uint32_t Serial_Number; + uint8_t Week_of_Manufacture; + uint8_t Year_of_Manufacture; + + uint16_t crc16; +} mddi_client_capability_type; + + +struct __attribute__((packed)) mddi_video_stream { + uint16_t length; + uint16_t type; /* 16 */ + uint16_t client_id; /* 0 */ + + uint16_t video_data_format_descriptor; +/* format of each pixel in the Pixel Data in the present stream in the + * present packet. + * If bits [15:13] = 000 monochrome + * If bits [15:13] = 001 color pixels (palette). + * If bits [15:13] = 010 color pixels in raw RGB + * If bits [15:13] = 011 data in 4:2:2 Y Cb Cr format + * If bits [15:13] = 100 Bayer pixels + */ + + uint16_t pixel_data_attributes; +/* interpreted as follows: + * Bits [1:0] = 11 pixel data is displayed to both eyes + * Bits [1:0] = 10 pixel data is routed to the left eye only. + * Bits [1:0] = 01 pixel data is routed to the right eye only. + * Bits [1:0] = 00 pixel data is routed to the alternate display. + * Bit 2 is 0 Pixel Data is in the standard progressive format. + * Bit 2 is 1 Pixel Data is in interlace format. + * Bit 3 is 0 Pixel Data is in the standard progressive format. + * Bit 3 is 1 Pixel Data is in alternate pixel format. + * Bit 4 is 0 Pixel Data is to or from the display frame buffer. + * Bit 4 is 1 Pixel Data is to or from the camera. + * Bit 5 is 0 pixel data contains the next consecutive row of pixels. + * Bit 5 is 1 X Left Edge, Y Top Edge, X Right Edge, Y Bottom Edge, + * X Start, and Y Start parameters are not defined and + * shall be ignored by the client. + * Bits [7:6] = 01 Pixel data is written to the offline image buffer. + * Bits [7:6] = 00 Pixel data is written to the buffer to refresh display. + * Bits [7:6] = 11 Pixel data is written to all image buffers. + * Bits [7:6] = 10 Invalid. Reserved for future use. + * Bits 8 through 11 alternate display number. + * Bits 12 through 14 are reserved for future use and shall be set to zero. + * Bit 15 is 1 the row of pixels is the last row of pixels in a frame. + */ + + uint16_t x_left_edge; + uint16_t y_top_edge; + /* X,Y coordinate of the top left edge of the screen window */ + + uint16_t x_right_edge; + uint16_t y_bottom_edge; + /* X,Y coordinate of the bottom right edge of the window being + * updated. */ + + uint16_t x_start; + uint16_t y_start; + /* (X Start, Y Start) is the first pixel in the Pixel Data field + * below. */ + + uint16_t pixel_count; + /* number of pixels in the Pixel Data field below. */ + + uint16_t parameter_CRC; + /* 16-bit CRC of all bytes from the Packet Length to the Pixel Count. */ + + uint16_t reserved; + /* 16-bit variable to make structure align on 4 byte boundary */ +}; + +#define TYPE_VIDEO_STREAM 16 +#define TYPE_CLIENT_CAPS 66 +#define TYPE_REGISTER_ACCESS 146 +#define TYPE_CLIENT_STATUS 70 + +struct __attribute__((packed)) mddi_register_access { + uint16_t length; + uint16_t type; /* 146 */ + uint16_t client_id; + + uint16_t read_write_info; + /* Bits 13:0 a 14-bit unsigned integer that specifies the number of + * 32-bit Register Data List items to be transferred in the + * Register Data List field. + * Bits[15:14] = 00 Write to register(s); + * Bits[15:14] = 10 Read from register(s); + * Bits[15:14] = 11 Response to a Read. + * Bits[15:14] = 01 this value is reserved for future use. */ +#define MDDI_WRITE (0 << 14) +#define MDDI_READ (2 << 14) +#define MDDI_READ_RESP (3 << 14) + + uint32_t register_address; + /* the register address that is to be written to or read from. */ + + uint16_t crc16; + + uint32_t register_data_list; + /* list of 4-byte register data values for/from client registers */ +}; + +struct __attribute__((packed)) mddi_llentry { + uint16_t flags; + uint16_t header_count; + uint16_t data_count; + dma_addr_t data; /* 32 bit */ + struct mddi_llentry *next; + uint16_t reserved; + union { + struct mddi_video_stream v; + struct mddi_register_access r; + uint32_t _[12]; + } u; +}; + +#endif diff --git a/drivers/video/msm/mddi_orise.c b/drivers/video/msm/mddi_orise.c new file mode 100644 index 000000000000..bf9f1fa10e98 --- /dev/null +++ b/drivers/video/msm/mddi_orise.c @@ -0,0 +1,128 @@ +/* Copyright (c) 2010, 2012 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mddihost.h" +#include "mddihosti.h" + +#define MDDI_ORISE_1_2 1 +#define write_client_reg(__X, __Y, __Z) {\ + mddi_queue_register_write(__X, __Y, TRUE, 0);\ +} + +static int mddi_orise_lcd_on(struct platform_device *pdev); +static int mddi_orise_lcd_off(struct platform_device *pdev); +static int __init mddi_orise_probe(struct platform_device *pdev); +static int __init mddi_orise_init(void); + +/* function used to turn on the display */ +static void mddi_orise_prim_lcd_init(void) +{ + write_client_reg(0x00110000, 0, TRUE); + mddi_wait(150); + write_client_reg(0x00290000, 0, TRUE); +} + +static struct platform_driver this_driver = { + .driver = { + .name = "mddi_orise", + }, +}; + +static struct msm_fb_panel_data mddi_orise_panel_data = { + .on = mddi_orise_lcd_on, + .off = mddi_orise_lcd_off, +}; + +static struct platform_device this_device = { + .name = "mddi_orise", + .id = MDDI_ORISE_1_2, + .dev = { + .platform_data = &mddi_orise_panel_data, + } +}; + +static int mddi_orise_lcd_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + mfd = platform_get_drvdata(pdev); + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + mddi_orise_prim_lcd_init(); + + return 0; +} + +static int mddi_orise_lcd_off(struct platform_device *pdev) +{ + return 0; +} + +static int __init mddi_orise_probe(struct platform_device *pdev) +{ + msm_fb_add_device(pdev); + return 0; +} + +static int __init mddi_orise_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + u32 id; + ret = msm_fb_detect_client("mddi_orise"); + if (ret == -ENODEV) + return 0; + + if (ret) { + id = mddi_get_client_id(); + if (((id >> 16) != 0xbe8d) || ((id & 0xffff) != 0x8031)) + return 0; + } +#endif + ret = platform_driver_probe(&this_driver, mddi_orise_probe); + if (!ret) { + pinfo = &mddi_orise_panel_data.panel_info; + pinfo->xres = 480; + pinfo->yres = 800; + MSM_FB_SINGLE_MODE_PANEL(pinfo); + pinfo->type = MDDI_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->mddi.is_type1 = TRUE; + pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR; + pinfo->wait_cycle = 0; + pinfo->bpp = 18; + pinfo->fb_num = 2; + pinfo->clk_rate = 192000000; + pinfo->clk_min = 192000000; + pinfo->clk_max = 192000000; + pinfo->lcd.rev = 2; + pinfo->lcd.vsync_enable = FALSE; + pinfo->lcd.refx100 = 6050; + pinfo->lcd.v_back_porch = 2; + pinfo->lcd.v_front_porch = 2; + pinfo->lcd.v_pulse_width = 105; + pinfo->lcd.hw_vsync_mode = TRUE; + pinfo->lcd.vsync_notifier_period = 0; + + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + } + return ret; +} +module_init(mddi_orise_init); diff --git a/drivers/video/msm/mddi_prism.c b/drivers/video/msm/mddi_prism.c new file mode 100644 index 000000000000..c85b800a1846 --- /dev/null +++ b/drivers/video/msm/mddi_prism.c @@ -0,0 +1,112 @@ +/* Copyright (c) 2008-2010, 2012 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mddihost.h" +#include "mddihosti.h" + +static int prism_lcd_on(struct platform_device *pdev); +static int prism_lcd_off(struct platform_device *pdev); + +static int prism_lcd_on(struct platform_device *pdev) +{ + /* Set the MDP pixel data attributes for Primary Display */ + mddi_host_write_pix_attr_reg(0x00C3); + + return 0; +} + +static int prism_lcd_off(struct platform_device *pdev) +{ + return 0; +} + +static int prism_probe(struct platform_device *pdev) +{ + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = prism_probe, + .driver = { + .name = "mddi_prism_wvga", + }, +}; + +static struct msm_fb_panel_data prism_panel_data = { + .on = prism_lcd_on, + .off = prism_lcd_off, +}; + +static struct platform_device this_device = { + .name = "mddi_prism_wvga", + .id = 0, + .dev = { + .platform_data = &prism_panel_data, + } +}; + +static int __init prism_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + u32 id; + + ret = msm_fb_detect_client("mddi_prism_wvga"); + if (ret == -ENODEV) + return 0; + + if (ret) { + id = mddi_get_client_id(); + + if (((id >> 16) != 0x4474) || ((id & 0xffff) == 0x8960)) + return 0; + } +#endif + ret = platform_driver_register(&this_driver); + if (!ret) { + pinfo = &prism_panel_data.panel_info; + pinfo->xres = 800; + pinfo->yres = 480; + MSM_FB_SINGLE_MODE_PANEL(pinfo); + pinfo->type = MDDI_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR; + pinfo->wait_cycle = 0; + pinfo->mddi.is_type1 = TRUE; + pinfo->bpp = 18; + pinfo->fb_num = 2; + pinfo->clk_rate = 153600000; + pinfo->clk_min = 140000000; + pinfo->clk_max = 160000000; + pinfo->lcd.vsync_enable = TRUE; + pinfo->lcd.refx100 = 6050; + pinfo->lcd.v_back_porch = 23; + pinfo->lcd.v_front_porch = 20; + pinfo->lcd.v_pulse_width = 105; + pinfo->lcd.hw_vsync_mode = TRUE; + pinfo->lcd.vsync_notifier_period = 0; + + ret = platform_device_register(&this_device); + if (ret) + platform_driver_unregister(&this_driver); + } + + return ret; +} + +module_init(prism_init); diff --git a/drivers/video/msm/mddi_quickvx.c b/drivers/video/msm/mddi_quickvx.c new file mode 100644 index 000000000000..f89f0baf895b --- /dev/null +++ b/drivers/video/msm/mddi_quickvx.c @@ -0,0 +1,719 @@ +/* Copyright (c) 2010, 2012 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include "msm_fb.h" +#include "mddihost.h" +#include "mddihosti.h" + +/* WVGA Primary Display */ +#define MDDI_QUICKVX_1_2 1 +/* MDDI Manufacturer Code */ +#define QUICKVX_MDDI_MFR_CODE 0xc583 +/* MDDI Product Code */ +#define QUICKVX_MDDI_PRD_CODE 0x5800 + +/* Register Address Maps */ +/* MDDI Address Anti-fuse values for bits [31:22] */ +#define QUICKVX_ADDR_31_22_AF (0X000 << 22) + +/* MDDI Address Maps */ +/* VEE Block Address Base */ +#define QUICKVX_VEE_BASE (QUICKVX_ADDR_31_22_AF | 0x00000000) +/* SPI Block Address Base */ +#define QUICKVX_SPI_BASE (QUICKVX_ADDR_31_22_AF | 0x00010000) +/* Clock and Reset (CAR) Address Base */ +#define QUICKVX_CAR_BASE (QUICKVX_ADDR_31_22_AF | 0x00020000) +/* Register Control Block (RCB) Address Base */ +#define QUICKVX_RCB_BASE (QUICKVX_ADDR_31_22_AF | 0x00030000) +/* Cellular RAM Address Base */ +#define QUICKVX_CELLRAM_BASE (QUICKVX_ADDR_31_22_AF | 0x00100000) +/* FB through A2F Address Base */ +#define QUICKVX_FB_A2F_BASE (QUICKVX_ADDR_31_22_AF | 0x00200000) + + +/*************************************************** + * Common Registers in Register Control Block (RCB) Registers + ***************************************************/ + /* CellRAM Configuration RCR Register */ +#define QUICKVX_RCB_RCR_REG (QUICKVX_RCB_BASE | 0x00000000) +/* Image Effect Register */ +#define QUICKVX_RCB_IER_REG (QUICKVX_RCB_BASE | 0x00000004) +/* Row Number Register */ +#define QUICKVX_RCB_ROWNUM_REG (QUICKVX_RCB_BASE | 0x00000008) +/* TCON Timing0 Register */ +#define QUICKVX_RCB_TCON0_REG (QUICKVX_RCB_BASE | 0x0000000C) +/* TCON Timing1 Register */ +#define QUICKVX_RCB_TCON1_REG (QUICKVX_RCB_BASE | 0x00000010) +/* TCON Timing2 Register */ +#define QUICKVX_RCB_TCON2_REG (QUICKVX_RCB_BASE | 0x00000014) +/* PWM Control Register */ +#define QUICKVX_RCB_PWMC_REG (QUICKVX_RCB_BASE | 0x00000018) +/* PWM Width Register */ +#define QUICKVX_RCB_PWMW_REG (QUICKVX_RCB_BASE | 0x0000001C) +/* VEE Configuration Register */ +#define QUICKVX_RCB_VEECONF_REG (QUICKVX_RCB_BASE | 0x00000020) +/* CellRAM Configuration BCR Register */ +#define QUICKVX_RCB_CELLBCR_REG (QUICKVX_RCB_BASE | 0x00000024) +/* CellRAM Configuration Control Register */ +#define QUICKVX_RCB_CELLCC_REG (QUICKVX_RCB_BASE | 0x00000028) +/* Use Case Register */ +#define QUICKVX_RCB_USECASE_REG (QUICKVX_RCB_BASE | 0x00000100) +/* Video Parameter Register */ +#define QUICKVX_RCB_VPARM_REG (QUICKVX_RCB_BASE | 0x00000104) +/* MDDI Client Wake-up Register */ +#define QUICKVX_RCB_MCW_REG (QUICKVX_RCB_BASE | 0x00000108) +/* Burst Length Register */ +#define QUICKVX_RCB_BURSTLN_REG (QUICKVX_RCB_BASE | 0x0000010C) +/* Display Attributes Register */ +#define QUICKVX_RCB_DISPATTR_REG (QUICKVX_RCB_BASE | 0x00000110) +/* Error Status Register */ +#define QUICKVX_RCB_ERRSTAT_REG (QUICKVX_RCB_BASE | 0x00000114) +/* Error Mask Register */ +#define QUICKVX_RCB_ERRMSK_REG (QUICKVX_RCB_BASE | 0x00000118) +/* MDDI ASSP FIFO Overflow Address Register */ +#define QUICKVX_RCB_ASSPFOA_REG (QUICKVX_RCB_BASE | 0x0000011C) +/* MDDI Fabric FIFO Overflow Address Register */ +#define QUICKVX_RCB_FABFOA_REG (QUICKVX_RCB_BASE | 0x00000120) +/* Incoming RGB FIFO Overflow Address Register */ +#define QUICKVX_RCB_IRFOA_REG (QUICKVX_RCB_BASE | 0x00000124) +/* SPI Overflow Address Register */ +#define QUICKVX_RCB_SPIOA_REG (QUICKVX_RCB_BASE | 0x00000128) +/* Ping Buffer Address Register */ +#define QUICKVX_RCB_PINGBA_REG (QUICKVX_RCB_BASE | 0x0000012C) +/* Pong Buffer Address Register */ +#define QUICKVX_RCB_PONGBA_REG (QUICKVX_RCB_BASE | 0x00000130) +/* Configuration Done Register */ +#define QUICKVX_RCB_CONFDONE_REG (QUICKVX_RCB_BASE | 0x00000134) +/* FIFO Flush Register */ +#define QUICKVX_RCB_FFLUSH_REG (QUICKVX_RCB_BASE | 0x00000138) + + +/*************************************************** + * SPI Block Registers + ***************************************************/ +/* SPI Rx0 Register */ +#define QUICKVX_SPI_RX0_REG (QUICKVX_SPI_BASE | 0x00000000) +/* SPI Rx1 Register */ +#define QUICKVX_SPI_RX1_REG (QUICKVX_SPI_BASE | 0x00000004) +/* SPI Rx2 Register */ +#define QUICKVX_SPI_RX2_REG (QUICKVX_SPI_BASE | 0x00000008) +/* SPI Rx3 Register */ +#define QUICKVX_SPI_RX3_REG (QUICKVX_SPI_BASE | 0x0000000C) +/* SPI Rx4 Register */ +#define QUICKVX_SPI_RX4_REG (QUICKVX_SPI_BASE | 0x00000010) +/* SPI Rx5 Register */ +#define QUICKVX_SPI_RX5_REG (QUICKVX_SPI_BASE | 0x00000014) +/* SPI Rx6 Register */ +#define QUICKVX_SPI_RX6_REG (QUICKVX_SPI_BASE | 0x00000018) +/* SPI Rx7 Register */ +#define QUICKVX_SPI_RX7_REG (QUICKVX_SPI_BASE | 0x0000001C) +/* SPI Tx0 Register */ +#define QUICKVX_SPI_TX0_REG (QUICKVX_SPI_BASE | 0x00000020) +/* SPI Tx1 Register */ +#define QUICKVX_SPI_TX1_REG (QUICKVX_SPI_BASE | 0x00000024) +/* SPI Tx2 Register */ +#define QUICKVX_SPI_TX2_REG (QUICKVX_SPI_BASE | 0x00000028) +/* SPI Tx3 Register */ +#define QUICKVX_SPI_TX3_REG (QUICKVX_SPI_BASE | 0x0000002C) +/* SPI Tx4 Register */ +#define QUICKVX_SPI_TX4_REG (QUICKVX_SPI_BASE | 0x00000030) +/* SPI Tx5 Register */ +#define QUICKVX_SPI_TX5_REG (QUICKVX_SPI_BASE | 0x00000034) +/* SPI Tx6 Register */ +#define QUICKVX_SPI_TX6_REG (QUICKVX_SPI_BASE | 0x00000038) +/* SPI Tx7 Register */ +#define QUICKVX_SPI_TX7_REG (QUICKVX_SPI_BASE | 0x0000003C) +/* SPI Control Register */ +#define QUICKVX_SPI_CTRL_REG (QUICKVX_SPI_BASE | 0x00000040) +/* SPI Transfer Length Register */ +#define QUICKVX_SPI_TLEN_REG (QUICKVX_SPI_BASE | 0x00000044) + + +/*************************************************** + * Clock and Reset (CAR) Block Registers + ***************************************************/ +/* ASSP Global Clock Enable Register */ +#define QUICKVX_CAR_ASSP_GCE_REG (QUICKVX_CAR_BASE | 0x00000000) +/* VLP Control1 Register */ +#define QUICKVX_CAR_VLPCTRL1_REG (QUICKVX_CAR_BASE | 0x00000004) +/* VLP Control2 Register */ +#define QUICKVX_CAR_VLPCTRL2_REG (QUICKVX_CAR_BASE | 0x00000008) +/* Clock Selection Register */ +#define QUICKVX_CAR_CLKSEL_REG (QUICKVX_CAR_BASE | 0x0000000C) +/* PLL Control Register */ +#define QUICKVX_CAR_PLLCTRL_REG (QUICKVX_CAR_BASE | 0x00000010) +/* PLL Clock Ratio Register */ +#define QUICKVX_CAR_PLLCLKRATIO_REG (QUICKVX_CAR_BASE | 0x00000014) + + +/*************************************************** + * VEE Block Registers + ***************************************************/ +/* VEE Control Register */ +#define QUICKVX_VEE_VEECTRL_REG (QUICKVX_VEE_BASE | 0x00000000) +/* Strength Register */ +#define QUICKVX_VEE_STRENGTH_REG (QUICKVX_VEE_BASE | 0x0000000C) +/* Variance Register */ +#define QUICKVX_VEE_VARIANCE_REG (QUICKVX_VEE_BASE | 0x00000010) +/* Slope Register */ +#define QUICKVX_VEE_SLOPE_REG (QUICKVX_VEE_BASE | 0x00000014) +/* Sharpen Control0 Register */ +#define QUICKVX_VEE_SHRPCTRL0_REG (QUICKVX_VEE_BASE | 0x0000001C) +/* Sharpen Control1 Register */ +#define QUICKVX_VEE_SHRPCTRL1_REG (QUICKVX_VEE_BASE | 0x00000020) +/* Upper Horizontal Positon Register */ +#define QUICKVX_VEE_UHPOS_REG (QUICKVX_VEE_BASE | 0x00000024) +/* Lower Horizontal Positon Register */ +#define QUICKVX_VEE_LHPOS_REG (QUICKVX_VEE_BASE | 0x00000028) +/* Upper Vertical Positon Register */ +#define QUICKVX_VEE_UVPOS_REG (QUICKVX_VEE_BASE | 0x0000002C) +/* Lower Vertical Positon Register */ +#define QUICKVX_VEE_LVPOS_REG (QUICKVX_VEE_BASE | 0x00000030) +/* Upper Frame Width Register */ +#define QUICKVX_VEE_UFWDTH_REG (QUICKVX_VEE_BASE | 0x00000034) +/* Lower Frame Width Register */ +#define QUICKVX_VEE_LFWDTH_REG (QUICKVX_VEE_BASE | 0x00000038) +/* Upper Frame Height Register */ +#define QUICKVX_VEE_UFHGHT_REG (QUICKVX_VEE_BASE | 0x0000003C) +/* Lower Frame Height Register */ +#define QUICKVX_VEE_LFHGHT_REG (QUICKVX_VEE_BASE | 0x00000040) +/* Control0 Register */ +#define QUICKVX_VEE_CTRL0_REG (QUICKVX_VEE_BASE | 0x00000044) +/* Control1 Register */ +#define QUICKVX_VEE_CTRL1_REG (QUICKVX_VEE_BASE | 0x00000048) +/* Video Enhancement Enable Register */ +#define QUICKVX_VEE_VDOEEN_REG (QUICKVX_VEE_BASE | 0x0000004C) +/* Black Level Register */ +#define QUICKVX_VEE_BLCKLEV_REG (QUICKVX_VEE_BASE | 0x00000050) +/* White Level Register */ +#define QUICKVX_VEE_WHTLEV_REG (QUICKVX_VEE_BASE | 0x00000054) +/* Amplification Limits Register */ +#define QUICKVX_VEE_AMPLMTS_REG (QUICKVX_VEE_BASE | 0x00000060) +/* Dithering Mode Register */ +#define QUICKVX_VEE_DITHMOD_REG (QUICKVX_VEE_BASE | 0x00000064) +/* Upper Look-up Data Register */ +#define QUICKVX_VEE_ULUD_REG (QUICKVX_VEE_BASE | 0x00000080) +/* Lower Look-up Data Register */ +#define QUICKVX_VEE_LLUD_REG (QUICKVX_VEE_BASE | 0x00000084) +/* Look-up Address Register */ +#define QUICKVX_VEE_LUADDR_REG (QUICKVX_VEE_BASE | 0x00000088) +/* Look-up Write Enable Register */ +#define QUICKVX_VEE_LUWREN_REG (QUICKVX_VEE_BASE | 0x0000008C) +/* VEE ID Register */ +#define QUICKVX_VEE_VEEID_REG (QUICKVX_VEE_BASE | 0x000003FC) +/* M_11 Register */ +#define QUICKVX_VEE_M_11_REG (QUICKVX_VEE_BASE | 0x000000C0) +/* M_12 Register */ +#define QUICKVX_VEE_M_12_REG (QUICKVX_VEE_BASE | 0x000000C4) +/* M_13 Register */ +#define QUICKVX_VEE_M_13_REG (QUICKVX_VEE_BASE | 0x000000C8) +/* M_21 Register */ +#define QUICKVX_VEE_M_21_REG (QUICKVX_VEE_BASE | 0x000000CC) +/* M_22 Register */ +#define QUICKVX_VEE_M_22_REG (QUICKVX_VEE_BASE | 0x000000D0) +/* M_23 Register */ +#define QUICKVX_VEE_M_23_REG (QUICKVX_VEE_BASE | 0x000000D4) +/* M_31 Register */ +#define QUICKVX_VEE_M_31_REG (QUICKVX_VEE_BASE | 0x000000D8) +/* M_32 Register */ +#define QUICKVX_VEE_M_32_REG (QUICKVX_VEE_BASE | 0x000000DC) +/* M_33 Register */ +#define QUICKVX_VEE_M_33_REG (QUICKVX_VEE_BASE | 0x000000E0) +/* R Offset Register */ +#define QUICKVX_VEE_OFFSET_R_REG (QUICKVX_VEE_BASE | 0x000000E8) +/* G Offset Register */ +#define QUICKVX_VEE_OFFSET_G_REG (QUICKVX_VEE_BASE | 0x000000EC) +/* B Offset Register */ +#define QUICKVX_VEE_OFFSET_B_REG (QUICKVX_VEE_BASE | 0x000000F0) + +/* LCD Reset Register */ +#define QUICKVX_FB_A2F_LCD_RESET_REG (QUICKVX_FB_A2F_BASE | 0x00000000) + +/* Register bit defines */ +/* PLL Lock bit in the PLL Control Register */ +#define QUICKVX_PLL_LOCK_BIT (1 << 7) + +#define QL_SPI_CTRL_rSPISTart(x) (x) +#define QL_SPI_CTRL_rCPHA(x) (x << 1) +#define QL_SPI_CTRL_rCPOL(x) (x << 2) +#define QL_SPI_CTRL_rLSB(x) (x << 3) +#define QL_SPI_CTRL_rSLVSEL(x) (x << 4) +#define QL_SPI_CTRL_MASK_rTxDone (1 << 9) + +#define QL_SPI_LCD_DEV_ID 0x1c +#define QL_SPI_LCD_RS(x) (x << 1) +#define QL_SPI_LCD_RW(x) (x) +#define QL_SPI_LCD_INDEX_START_BYTE ((QL_SPI_LCD_DEV_ID << 2) | \ + QL_SPI_LCD_RS(0) | QL_SPI_LCD_RW(0)) +#define QL_SPI_LCD_CMD_START_BYTE ((QL_SPI_LCD_DEV_ID << 2) | \ + QL_SPI_LCD_RS(1) | QL_SPI_LCD_RW(0)) +#define QL_SPI_CTRL_LCD_START (QL_SPI_CTRL_rSPISTart(1) | \ + QL_SPI_CTRL_rCPHA(1) | QL_SPI_CTRL_rCPOL(1) | \ + QL_SPI_CTRL_rLSB(0) | QL_SPI_CTRL_rSLVSEL(0)) + +int ql_mddi_write(uint32 address, uint32 value) +{ + uint32 regval = 0; + int ret = 0; + + ret = mddi_queue_register_write(address, value, TRUE, 0); + + if (!ret) { + ret = mddi_queue_register_read(address, ®val, TRUE, 0); + if (regval != value) { + MDDI_MSG_DEBUG("\nMismatch: ql_mddi_write[0x%x]->0x%x " + "r0x%x\n", address, value, regval); + } else { + MDDI_MSG_DEBUG("\nMatch: ql_mddi_write[0x%x]->0x%x " + "r0x%x\n", address, value, regval); + } + } + + return ret; +} + +int ql_mddi_read(uint32 address, uint32 *regval) +{ + int ret = 0; + + ret = mddi_queue_register_read(address, regval, TRUE, 0); + MDDI_MSG_DEBUG("\nql_mddi_read[0x%x]=0x%x", address, *regval); + + return ret; +} + +int ql_send_spi_cmd_to_lcd(uint32 index, uint32 cmd) +{ + int retry, ret; + uint32 readval; + + MDDI_MSG_DEBUG("\n %s(): index 0x%x, cmd 0x%x", __func__, index, cmd); + /* do the index phase */ + /* send 24 bits in the index phase */ + ql_mddi_write(QUICKVX_SPI_TLEN_REG, 23); + + /* send 24 bits in the index phase, starting at bit 23 of TX0 reg */ + ql_mddi_write(QUICKVX_SPI_TX0_REG, + (QL_SPI_LCD_INDEX_START_BYTE << 16) | index); + + /* set start */ + ql_mddi_write(QUICKVX_SPI_CTRL_REG, QL_SPI_CTRL_LCD_START); + retry = 0; + + do { + ret = ql_mddi_read(QUICKVX_SPI_CTRL_REG, &readval); + + if (ret || ++retry > 5) { + MDDI_MSG_DEBUG("\n ql_send_spi_cmd_to_lcd: retry " + "timeout at index phase, ret = %d", ret); + return -EIO; + } + mddi_wait(1); + } while ((readval & QL_SPI_CTRL_MASK_rTxDone) == 0); + + /* do the command phase */ + /* send 24 bits in the cmd phase */ + ql_mddi_write(QUICKVX_SPI_TLEN_REG, 23); + + /* send 24 bits in the cmd phase, starting at bit 23 of TX0 reg. */ + ql_mddi_write(QUICKVX_SPI_TX0_REG, + (QL_SPI_LCD_CMD_START_BYTE << 16) | cmd); + + /* set start */ + ql_mddi_write(QUICKVX_SPI_CTRL_REG, QL_SPI_CTRL_LCD_START); + retry = 0; + + do { + ret = ql_mddi_read(QUICKVX_SPI_CTRL_REG, &readval); + + if (ret || ++retry > 5) { + MDDI_MSG_DEBUG("\n ql_send_spi_cmd_to_lcd: retry " + "timeout at cmd phase, ret = %d", ret); + return -EIO; + } + mddi_wait(1); + } while ((readval & QL_SPI_CTRL_MASK_rTxDone) == 0); + + return 0; +} + + +int ql_send_spi_data_from_lcd(uint32 index, uint32 *value) +{ + int retry, ret; + uint32 readval; + + MDDI_MSG_DEBUG("\n %s(): index 0x%x", __func__, index); + /* do the index phase */ + /* send 24 bits in the index phase */ + ql_mddi_write(QUICKVX_SPI_TLEN_REG, 23); + + /* send 24 bits in the index phase, starting at bit 23 of TX0 reg */ + ql_mddi_write(QUICKVX_SPI_TX0_REG, + (QL_SPI_LCD_INDEX_START_BYTE << 16) | index); + + /* set start */ + ql_mddi_write(QUICKVX_SPI_CTRL_REG, QL_SPI_CTRL_LCD_START); + retry = 0; + + do { + ret = ql_mddi_read(QUICKVX_SPI_CTRL_REG, &readval); + + if (ret || ++retry > 5) { + MDDI_MSG_DEBUG("\n ql_send_spi_cmd_to_lcd: retry " + "timeout at index phase, ret = %d", ret); + return -EIO; + } + mddi_wait(1); + } while ((readval & QL_SPI_CTRL_MASK_rTxDone) == 0); + + /* do the command phase */ + /* send 8 bits and read 24 bits in the cmd phase, so total 32 bits */ + ql_mddi_write(QUICKVX_SPI_TLEN_REG, 31); + + /* send 24 bits in the cmd phase, starting at bit 31 of TX0 reg */ + ql_mddi_write(QUICKVX_SPI_TX0_REG, + ((QL_SPI_LCD_CMD_START_BYTE << 16)) << 8); + + /* set start */ + ql_mddi_write(QUICKVX_SPI_CTRL_REG, QL_SPI_CTRL_LCD_START); + retry = 0; + + do { + ret = ql_mddi_read(QUICKVX_SPI_CTRL_REG, &readval); + + if (ret || ++retry > 5) { + MDDI_MSG_DEBUG("\n ql_send_spi_cmd_to_lcd: retry " + "timeout at cmd phase, ret = %d", ret); + return -EIO; + } + mddi_wait(1); + } while ((readval & QL_SPI_CTRL_MASK_rTxDone) == 0); + + /* value will appear at lower 16 bits */ + ret = ql_mddi_read(QUICKVX_SPI_RX0_REG, value); + + if (!ret) { + *value = *value & 0xffff; + MDDI_MSG_DEBUG("\n QUICKVX_SPI_RX0_REG value = 0x%x", *value); + } else + MDDI_MSG_DEBUG("\n Read QUICKVX_SPI_RX0_REG Failed"); + + return ret; +} + +/* Global Variables */ +static uint32 mddi_quickvx_rows_per_second; +static uint32 mddi_quickvx_usecs_per_refresh; +static uint32 mddi_quickvx_rows_per_refresh; + +void mddi_quickvx_configure_registers(void) +{ + MDDI_MSG_DEBUG("\n%s(): ", __func__); + ql_mddi_write(QUICKVX_CAR_CLKSEL_REG, 0x00007000); + + ql_mddi_write(QUICKVX_RCB_PWMW_REG, 0x0000FFFF); + + ql_mddi_write(QUICKVX_RCB_PWMC_REG, 0x00000001); + + ql_mddi_write(QUICKVX_RCB_CONFDONE_REG, 0x00000000); + + /* display is x width = 480, y width = 864 */ + ql_mddi_write(QUICKVX_RCB_TCON0_REG, 0x035f01df); + + /* VFP=2, VBP=4, HFP=16, HBP=16 */ + ql_mddi_write(QUICKVX_RCB_TCON1_REG, 0x01e301e1); + + /* VSW =2, HSW=8 */ + ql_mddi_write(QUICKVX_RCB_TCON2_REG, 0x000000e1); + + ql_mddi_write(QUICKVX_RCB_DISPATTR_REG, 0x00000000); + + ql_mddi_write(QUICKVX_RCB_USECASE_REG, 0x00000025); + + ql_mddi_write(QUICKVX_RCB_VPARM_REG, 0x00000888); + + ql_mddi_write(QUICKVX_RCB_VEECONF_REG, 0x00000001); + + ql_mddi_write(QUICKVX_RCB_IER_REG, 0x00000000); + + ql_mddi_write(QUICKVX_RCB_RCR_REG, 0x80000010); + + ql_mddi_write(QUICKVX_RCB_CELLBCR_REG, 0x8008746F); + + ql_mddi_write(QUICKVX_RCB_CELLCC_REG, 0x800000A3); + + ql_mddi_write(QUICKVX_RCB_CONFDONE_REG, 0x00000001); +} + +void mddi_quickvx_prim_lcd_init(void) +{ + uint32 value; + + MDDI_MSG_DEBUG("\n%s(): ", __func__); + ql_send_spi_data_from_lcd(0, &value); + + ql_send_spi_cmd_to_lcd(0x0100, 0x3000); /* power control1 */ + ql_send_spi_cmd_to_lcd(0x0101, 0x4010); /* power control2 */ + ql_send_spi_cmd_to_lcd(0x0106, 0x0000); /* auto seq setting */ + mddi_wait(3); + + ql_mddi_write(QUICKVX_FB_A2F_LCD_RESET_REG, 0x00000001); + mddi_wait(1); + ql_mddi_write(QUICKVX_FB_A2F_LCD_RESET_REG, 0x00000000); + mddi_wait(1); + ql_mddi_write(QUICKVX_FB_A2F_LCD_RESET_REG, 0x00000001); + mddi_wait(10); + + ql_send_spi_cmd_to_lcd(0x0001, 0x0310); /* driver out control */ + ql_send_spi_cmd_to_lcd(0x0002, 0x0100); /* lcd ac control */ + ql_send_spi_cmd_to_lcd(0x0003, 0x0000); /* entry mode */ + ql_send_spi_cmd_to_lcd(0x0007, 0x0000); /* disp cont1 */ + ql_send_spi_cmd_to_lcd(0x0008, 0x0004); /* disp cont2 */ + ql_send_spi_cmd_to_lcd(0x0009, 0x000C); /* disp cont3 */ + ql_send_spi_cmd_to_lcd(0x000C, 0x4010); /* disp if cont1 */ + ql_send_spi_cmd_to_lcd(0x000E, 0x0000); /* disp if cont2 */ + ql_send_spi_cmd_to_lcd(0x0020, 0x013F); /* panel if cont1 */ + ql_send_spi_cmd_to_lcd(0x0022, 0x7600); /* panel if cont3 */ + ql_send_spi_cmd_to_lcd(0x0023, 0x1C0A); /* panel if cont4 */ + ql_send_spi_cmd_to_lcd(0x0024, 0x1C2C); /* panel if cont5 */ + ql_send_spi_cmd_to_lcd(0x0025, 0x1C4E); /* panel if cont6 */ + ql_send_spi_cmd_to_lcd(0x0027, 0x0000); /* panel if cont8 */ + ql_send_spi_cmd_to_lcd(0x0028, 0x760C); /* panel if cont9 */ + ql_send_spi_cmd_to_lcd(0x0300, 0x0000); /* gamma adj0 */ + ql_send_spi_cmd_to_lcd(0x0301, 0x0502); /* gamma adj1 */ + ql_send_spi_cmd_to_lcd(0x0302, 0x0705); /* gamma adj2 */ + ql_send_spi_cmd_to_lcd(0x0303, 0x0000); /* gamma adj3 */ + ql_send_spi_cmd_to_lcd(0x0304, 0x0200); /* gamma adj4 */ + ql_send_spi_cmd_to_lcd(0x0305, 0x0707); /* gamma adj5 */ + ql_send_spi_cmd_to_lcd(0x0306, 0x1010); /* gamma adj6 */ + ql_send_spi_cmd_to_lcd(0x0307, 0x0202); /* gamma adj7 */ + ql_send_spi_cmd_to_lcd(0x0308, 0x0704); /* gamma adj8 */ + ql_send_spi_cmd_to_lcd(0x0309, 0x0707); /* gamma adj9 */ + ql_send_spi_cmd_to_lcd(0x030A, 0x0000); /* gamma adja */ + ql_send_spi_cmd_to_lcd(0x030B, 0x0000); /* gamma adjb */ + ql_send_spi_cmd_to_lcd(0x030C, 0x0707); /* gamma adjc */ + ql_send_spi_cmd_to_lcd(0x030D, 0x1010); /* gamma adjd */ + ql_send_spi_cmd_to_lcd(0x0310, 0x0104); /* gamma adj10 */ + ql_send_spi_cmd_to_lcd(0x0311, 0x0503); /* gamma adj11 */ + ql_send_spi_cmd_to_lcd(0x0312, 0x0304); /* gamma adj12 */ + ql_send_spi_cmd_to_lcd(0x0315, 0x0304); /* gamma adj15 */ + ql_send_spi_cmd_to_lcd(0x0316, 0x031C); /* gamma adj16 */ + ql_send_spi_cmd_to_lcd(0x0317, 0x0204); /* gamma adj17 */ + ql_send_spi_cmd_to_lcd(0x0318, 0x0402); /* gamma adj18 */ + ql_send_spi_cmd_to_lcd(0x0319, 0x0305); /* gamma adj19 */ + ql_send_spi_cmd_to_lcd(0x031C, 0x0707); /* gamma adj1c */ + ql_send_spi_cmd_to_lcd(0x031D, 0x021F); /* gamma adj1d */ + ql_send_spi_cmd_to_lcd(0x0320, 0x0507); /* gamma adj20 */ + ql_send_spi_cmd_to_lcd(0x0321, 0x0604); /* gamma adj21 */ + ql_send_spi_cmd_to_lcd(0x0322, 0x0405); /* gamma adj22 */ + ql_send_spi_cmd_to_lcd(0x0327, 0x0203); /* gamma adj27 */ + ql_send_spi_cmd_to_lcd(0x0328, 0x0300); /* gamma adj28 */ + ql_send_spi_cmd_to_lcd(0x0329, 0x0002); /* gamma adj29 */ + ql_send_spi_cmd_to_lcd(0x0100, 0x363C); /* power cont1 */ + mddi_wait(1); + ql_send_spi_cmd_to_lcd(0x0101, 0x4003); /* power cont2 */ + ql_send_spi_cmd_to_lcd(0x0102, 0x0001); /* power cont3 */ + ql_send_spi_cmd_to_lcd(0x0103, 0x3C58); /* power cont4 */ + ql_send_spi_cmd_to_lcd(0x010C, 0x0135); /* power cont6 */ + ql_send_spi_cmd_to_lcd(0x0106, 0x0002); /* auto seq */ + ql_send_spi_cmd_to_lcd(0x0029, 0x03BF); /* panel if cont10 */ + ql_send_spi_cmd_to_lcd(0x0106, 0x0003); /* auto seq */ + mddi_wait(5); + ql_send_spi_cmd_to_lcd(0x0101, 0x4010); /* power cont2 */ + mddi_wait(10); +} + +/* Function to Power On the Primary and Secondary LCD panels */ +static int mddi_quickvx_lcd_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + MDDI_MSG_DEBUG("\n%s(): ", __func__); + mfd = platform_get_drvdata(pdev); + + if (!mfd) { + MDDI_MSG_DEBUG("\n mddi_quickvx_lcd_on: Device not found!"); + return -ENODEV; + } + + if (mfd->key != MFD_KEY) { + MDDI_MSG_DEBUG("\n mddi_quickvx_lcd_on: Invalid MFD key!"); + return -EINVAL; + } + + mddi_host_client_cnt_reset(); + mddi_quickvx_configure_registers(); + mddi_quickvx_prim_lcd_init(); + + return 0; +} + + +/* Function to Power Off the Primary and Secondary LCD panels */ +static int mddi_quickvx_lcd_off(struct platform_device *pdev) +{ + MDDI_MSG_DEBUG("\n%s(): ", __func__); + mddi_wait(1); + ql_send_spi_cmd_to_lcd(0x0106, 0x0002); /* Auto Sequencer setting */ + mddi_wait(10); + ql_send_spi_cmd_to_lcd(0x0106, 0x0000); /* Auto Sequencer setting */ + ql_send_spi_cmd_to_lcd(0x0029, 0x0002); /* Panel IF control 10 */ + ql_send_spi_cmd_to_lcd(0x0100, 0x300D); /* Power Control 1 */ + mddi_wait(1); + + return 0; +} + +/* Function to set the Backlight brightness level */ +static void mddi_quickvx_lcd_set_backlight(struct msm_fb_data_type *mfd) +{ + int32 level, i = 0, ret; + + MDDI_MSG_DEBUG("%s(): ", __func__); + + level = mfd->bl_level; + MDDI_MSG_DEBUG("\n level = %d", level); + if (level < 0) { + MDDI_MSG_DEBUG("mddi_quickvx_lcd_set_backlight: " + "Invalid backlight level (%d)!\n", level); + return; + } + while (i++ < 3) { + ret = pmic_set_led_intensity(LED_LCD, level); + if (ret == 0) + return; + msleep(10); + } + + MDDI_MSG_DEBUG("%s: can't set lcd backlight!\n", + __func__); +} + +/* Driver Probe function */ +static int mddi_quickvx_lcd_probe(struct platform_device *pdev) +{ + MDDI_MSG_DEBUG("\n%s(): id is %d", __func__, pdev->id); + msm_fb_add_device(pdev); + return 0; +} + +/* Driver data structure */ +static struct platform_driver this_driver = { + .probe = mddi_quickvx_lcd_probe, + .driver = { + .name = "mddi_quickvx", + }, +}; + + +/* Primary LCD panel data structure */ +static struct msm_fb_panel_data mddi_quickvx_panel_data0 = { + .on = mddi_quickvx_lcd_on, + .off = mddi_quickvx_lcd_off, + .set_backlight = mddi_quickvx_lcd_set_backlight, +}; + + +/* Primary LCD panel device structure */ +static struct platform_device this_device0 = { + .name = "mddi_quickvx", + .id = MDDI_QUICKVX_1_2, + .dev = { + .platform_data = &mddi_quickvx_panel_data0, + } +}; + +/* Module init - driver main entry point */ +static int __init mddi_quickvx_lcd_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + u32 cid; + MDDI_MSG_DEBUG("\n%s(): ", __func__); + + ret = msm_fb_detect_client("mddi_quickvx"); + + if (ret == -ENODEV) { + /* Device not found */ + MDDI_MSG_DEBUG("\n mddi_quickvx_lcd_init: No device found!"); + return 0; + } + + if (ret) { + cid = mddi_get_client_id(); + + MDDI_MSG_DEBUG("\n cid = 0x%x", cid); + if (((cid >> 16) != QUICKVX_MDDI_MFR_CODE) || + ((cid & 0xFFFF) != QUICKVX_MDDI_PRD_CODE)) { + /* MDDI Client ID not matching */ + MDDI_MSG_DEBUG("\n mddi_quickvx_lcd_init: " + "Client ID missmatch!"); + + return 0; + } + MDDI_MSG_DEBUG("\n mddi_quickvx_lcd_init: " + "QuickVX LCD panel detected!"); + } + +#endif /* CONFIG_FB_MSM_MDDI_AUTO_DETECT */ + + mddi_quickvx_rows_per_refresh = 872; + mddi_quickvx_rows_per_second = 52364; + mddi_quickvx_usecs_per_refresh = 16574; + + ret = platform_driver_register(&this_driver); + + if (!ret) { + pinfo = &mddi_quickvx_panel_data0.panel_info; + pinfo->xres = 480; + pinfo->yres = 864; + MSM_FB_SINGLE_MODE_PANEL(pinfo); + pinfo->type = MDDI_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR; + pinfo->wait_cycle = 0; + pinfo->bpp = 24; + pinfo->fb_num = 2; + + pinfo->clk_rate = 192000000; + pinfo->clk_min = 192000000; + pinfo->clk_max = 200000000; + pinfo->lcd.rev = 1; + pinfo->lcd.vsync_enable = TRUE; + pinfo->lcd.refx100 = (mddi_quickvx_rows_per_second \ + * 100)/mddi_quickvx_rows_per_refresh; + pinfo->mddi.is_type1 = TRUE; + pinfo->lcd.v_back_porch = 4; + pinfo->lcd.v_front_porch = 2; + pinfo->lcd.v_pulse_width = 2; + pinfo->lcd.hw_vsync_mode = TRUE; + pinfo->lcd.vsync_notifier_period = (1 * HZ); + pinfo->bl_max = 10; + pinfo->bl_min = 0; + + ret = platform_device_register(&this_device0); + if (ret) { + platform_driver_unregister(&this_driver); + MDDI_MSG_DEBUG("mddi_quickvx_lcd_init: " + "Primary device registration failed!\n"); + } + } + + return ret; +} + +module_init(mddi_quickvx_lcd_init); + diff --git a/drivers/video/msm/mddi_sharp.c b/drivers/video/msm/mddi_sharp.c new file mode 100644 index 000000000000..7efd638e3c24 --- /dev/null +++ b/drivers/video/msm/mddi_sharp.c @@ -0,0 +1,901 @@ +/* Copyright (c) 2008-2010, 2012 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mddihost.h" +#include "mddihosti.h" + +#define SHARP_QVGA_PRIM 1 +#define SHARP_128X128_SECD 2 + +extern uint32 mddi_host_core_version; +static boolean mddi_debug_prim_wait = FALSE; +static boolean mddi_sharp_vsync_wake = TRUE; +static boolean mddi_sharp_monitor_refresh_value = TRUE; +static boolean mddi_sharp_report_refresh_measurements = FALSE; +static uint32 mddi_sharp_rows_per_second = 13830; /* 5200000/376 */ +static uint32 mddi_sharp_rows_per_refresh = 338; +static uint32 mddi_sharp_usecs_per_refresh = 24440; /* (376+338)/5200000 */ +static boolean mddi_sharp_debug_60hz_refresh = FALSE; + +extern mddi_gpio_info_type mddi_gpio; +extern boolean mddi_vsync_detect_enabled; +static msm_fb_vsync_handler_type mddi_sharp_vsync_handler; +static void *mddi_sharp_vsync_handler_arg; +static uint16 mddi_sharp_vsync_attempts; + +static void mddi_sharp_prim_lcd_init(void); +static void mddi_sharp_sub_lcd_init(void); +static void mddi_sharp_lcd_set_backlight(struct msm_fb_data_type *mfd); +static void mddi_sharp_vsync_set_handler(msm_fb_vsync_handler_type handler, + void *); +static void mddi_sharp_lcd_vsync_detected(boolean detected); +static struct msm_panel_common_pdata *mddi_sharp_pdata; + +#define REG_SYSCTL 0x0000 +#define REG_INTR 0x0006 +#define REG_CLKCNF 0x000C +#define REG_CLKDIV1 0x000E +#define REG_CLKDIV2 0x0010 + +#define REG_GIOD 0x0040 +#define REG_GIOA 0x0042 + +#define REG_AGM 0x010A +#define REG_FLFT 0x0110 +#define REG_FRGT 0x0112 +#define REG_FTOP 0x0114 +#define REG_FBTM 0x0116 +#define REG_FSTRX 0x0118 +#define REG_FSTRY 0x011A +#define REG_VRAM 0x0202 +#define REG_SSDCTL 0x0330 +#define REG_SSD0 0x0332 +#define REG_PSTCTL1 0x0400 +#define REG_PSTCTL2 0x0402 +#define REG_PTGCTL 0x042A +#define REG_PTHP 0x042C +#define REG_PTHB 0x042E +#define REG_PTHW 0x0430 +#define REG_PTHF 0x0432 +#define REG_PTVP 0x0434 +#define REG_PTVB 0x0436 +#define REG_PTVW 0x0438 +#define REG_PTVF 0x043A +#define REG_VBLKS 0x0458 +#define REG_VBLKE 0x045A +#define REG_SUBCTL 0x0700 +#define REG_SUBTCMD 0x0702 +#define REG_SUBTCMDD 0x0704 +#define REG_REVBYTE 0x0A02 +#define REG_REVCNT 0x0A04 +#define REG_REVATTR 0x0A06 +#define REG_REVFMT 0x0A08 + +#define SHARP_SUB_UNKNOWN 0xffffffff +#define SHARP_SUB_HYNIX 1 +#define SHARP_SUB_ROHM 2 + +static uint32 sharp_subpanel_type = SHARP_SUB_UNKNOWN; + +static void sub_through_write(int sub_rs, uint32 sub_data) +{ + mddi_queue_register_write(REG_SUBTCMDD, sub_data, FALSE, 0); + + /* CS=1,RD=1,WE=1,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, FALSE, 0); + + /* CS=0,RD=1,WE=1,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0); + + /* CS=0,RD=1,WE=0,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x0004 | sub_rs, FALSE, 0); + + /* CS=0,RD=1,WE=1,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0); + + /* CS=1,RD=1,WE=1,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, TRUE, 0); +} + +static uint32 sub_through_read(int sub_rs) +{ + uint32 sub_data; + + /* CS=1,RD=1,WE=1,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, FALSE, 0); + + /* CS=0,RD=1,WE=1,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0); + + /* CS=0,RD=1,WE=0,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x0002 | sub_rs, TRUE, 0); + + mddi_queue_register_read(REG_SUBTCMDD, &sub_data, TRUE, 0); + + /* CS=0,RD=1,WE=1,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0); + + /* CS=1,RD=1,WE=1,RS=sub_rs */ + mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, TRUE, 0); + + return sub_data; +} + +static void serigo(uint32 ssd) +{ + uint32 ssdctl; + + mddi_queue_register_read(REG_SSDCTL, &ssdctl, TRUE, 0); + ssdctl = ((ssdctl & 0xE7) | 0x02); + + mddi_queue_register_write(REG_SSD0, ssd, FALSE, 0); + mddi_queue_register_write(REG_SSDCTL, ssdctl, TRUE, 0); + + do { + mddi_queue_register_read(REG_SSDCTL, &ssdctl, TRUE, 0); + } while ((ssdctl & 0x0002) != 0); + + if (mddi_debug_prim_wait) + mddi_wait(2); +} + +static void mddi_sharp_lcd_powerdown(void) +{ + serigo(0x0131); + serigo(0x0300); + mddi_wait(40); + serigo(0x0135); + mddi_wait(20); + serigo(0x2122); + mddi_wait(20); + serigo(0x0201); + mddi_wait(20); + serigo(0x2100); + mddi_wait(20); + serigo(0x2000); + mddi_wait(20); + + mddi_queue_register_write(REG_PSTCTL1, 0x1, TRUE, 0); + mddi_wait(100); + mddi_queue_register_write(REG_PSTCTL1, 0x0, TRUE, 0); + mddi_wait(2); + mddi_queue_register_write(REG_SYSCTL, 0x1, TRUE, 0); + mddi_wait(2); + mddi_queue_register_write(REG_CLKDIV1, 0x3, TRUE, 0); + mddi_wait(2); + mddi_queue_register_write(REG_SSDCTL, 0x0000, TRUE, 0); /* SSDRESET */ + mddi_queue_register_write(REG_SYSCTL, 0x0, TRUE, 0); + mddi_wait(2); +} + +static void mddi_sharp_lcd_set_backlight(struct msm_fb_data_type *mfd) +{ + uint32 regdata; + int32 level; + int max = mfd->panel_info.bl_max; + int min = mfd->panel_info.bl_min; + + if (mddi_sharp_pdata && mddi_sharp_pdata->backlight_level) { + level = mddi_sharp_pdata->backlight_level(mfd->bl_level, + max, + min); + + if (level < 0) + return; + + /* use Rodem GPIO(2:0) to give 8 levels of backlight (7-0) */ + /* Set lower 3 GPIOs as Outputs (set to 0) */ + mddi_queue_register_read(REG_GIOA, ®data, TRUE, 0); + mddi_queue_register_write(REG_GIOA, regdata & 0xfff8, TRUE, 0); + + /* Set lower 3 GPIOs as level */ + mddi_queue_register_read(REG_GIOD, ®data, TRUE, 0); + mddi_queue_register_write(REG_GIOD, + (regdata & 0xfff8) | (0x07 & level), TRUE, 0); + } +} + +static void mddi_sharp_prim_lcd_init(void) +{ + mddi_queue_register_write(REG_SYSCTL, 0x4000, TRUE, 0); + mddi_wait(1); + mddi_queue_register_write(REG_SYSCTL, 0x0000, TRUE, 0); + mddi_wait(5); + mddi_queue_register_write(REG_SYSCTL, 0x0001, FALSE, 0); + mddi_queue_register_write(REG_CLKDIV1, 0x000b, FALSE, 0); + + /* new reg write below */ + if (mddi_sharp_debug_60hz_refresh) + mddi_queue_register_write(REG_CLKCNF, 0x070d, FALSE, 0); + else + mddi_queue_register_write(REG_CLKCNF, 0x0708, FALSE, 0); + + mddi_queue_register_write(REG_SYSCTL, 0x0201, FALSE, 0); + mddi_queue_register_write(REG_PTGCTL, 0x0010, FALSE, 0); + mddi_queue_register_write(REG_PTHP, 4, FALSE, 0); + mddi_queue_register_write(REG_PTHB, 40, FALSE, 0); + mddi_queue_register_write(REG_PTHW, 240, FALSE, 0); + if (mddi_sharp_debug_60hz_refresh) + mddi_queue_register_write(REG_PTHF, 12, FALSE, 0); + else + mddi_queue_register_write(REG_PTHF, 92, FALSE, 0); + + mddi_wait(1); + + mddi_queue_register_write(REG_PTVP, 1, FALSE, 0); + mddi_queue_register_write(REG_PTVB, 2, FALSE, 0); + mddi_queue_register_write(REG_PTVW, 320, FALSE, 0); + mddi_queue_register_write(REG_PTVF, 15, FALSE, 0); + + mddi_wait(1); + + /* vram_color set REG_AGM???? */ + mddi_queue_register_write(REG_AGM, 0x0000, TRUE, 0); + + mddi_queue_register_write(REG_SSDCTL, 0x0000, FALSE, 0); + mddi_queue_register_write(REG_SSDCTL, 0x0001, TRUE, 0); + mddi_wait(1); + mddi_queue_register_write(REG_PSTCTL1, 0x0001, TRUE, 0); + mddi_wait(10); + + serigo(0x0701); + /* software reset */ + mddi_wait(1); + /* Wait over 50us */ + + serigo(0x0400); + /* DCLK~ACHSYNC~ACVSYNC polarity setting */ + serigo(0x2900); + /* EEPROM start read address setting */ + serigo(0x2606); + /* EEPROM start read register setting */ + mddi_wait(20); + /* Wait over 20ms */ + + serigo(0x0503); + /* Horizontal timing setting */ + serigo(0x062C); + /* Veritical timing setting */ + serigo(0x2001); + /* power initialize setting(VDC2) */ + mddi_wait(20); + /* Wait over 20ms */ + + serigo(0x2120); + /* Initialize power setting(CPS) */ + mddi_wait(20); + /* Wait over 20ms */ + + serigo(0x2130); + /* Initialize power setting(CPS) */ + mddi_wait(20); + /* Wait over 20ms */ + + serigo(0x2132); + /* Initialize power setting(CPS) */ + mddi_wait(10); + /* Wait over 10ms */ + + serigo(0x2133); + /* Initialize power setting(CPS) */ + mddi_wait(20); + /* Wait over 20ms */ + + serigo(0x0200); + /* Panel initialize release(INIT) */ + mddi_wait(1); + /* Wait over 1ms */ + + serigo(0x0131); + /* Panel setting(CPS) */ + mddi_wait(1); + /* Wait over 1ms */ + + mddi_queue_register_write(REG_PSTCTL1, 0x0003, TRUE, 0); + + /* if (FFA LCD is upside down) -> serigo(0x0100); */ + serigo(0x0130); + + /* Black mask release(display ON) */ + mddi_wait(1); + /* Wait over 1ms */ + + if (mddi_sharp_vsync_wake) { + mddi_queue_register_write(REG_VBLKS, 0x1001, TRUE, 0); + mddi_queue_register_write(REG_VBLKE, 0x1002, TRUE, 0); + } + + /* Set the MDP pixel data attributes for Primary Display */ + mddi_host_write_pix_attr_reg(0x00C3); + return; + +} + +void mddi_sharp_sub_lcd_init(void) +{ + + mddi_queue_register_write(REG_SYSCTL, 0x4000, FALSE, 0); + mddi_queue_register_write(REG_SYSCTL, 0x0000, TRUE, 0); + mddi_wait(100); + + mddi_queue_register_write(REG_SYSCTL, 0x0001, FALSE, 0); + mddi_queue_register_write(REG_CLKDIV1, 0x000b, FALSE, 0); + mddi_queue_register_write(REG_CLKCNF, 0x0708, FALSE, 0); + mddi_queue_register_write(REG_SYSCTL, 0x0201, FALSE, 0); + mddi_queue_register_write(REG_PTGCTL, 0x0010, FALSE, 0); + mddi_queue_register_write(REG_PTHP, 4, FALSE, 0); + mddi_queue_register_write(REG_PTHB, 40, FALSE, 0); + mddi_queue_register_write(REG_PTHW, 128, FALSE, 0); + mddi_queue_register_write(REG_PTHF, 92, FALSE, 0); + mddi_queue_register_write(REG_PTVP, 1, FALSE, 0); + mddi_queue_register_write(REG_PTVB, 2, FALSE, 0); + mddi_queue_register_write(REG_PTVW, 128, FALSE, 0); + mddi_queue_register_write(REG_PTVF, 15, FALSE, 0); + + /* Now the sub display..... */ + /* Reset High */ + mddi_queue_register_write(REG_SUBCTL, 0x0200, FALSE, 0); + /* CS=1,RD=1,WE=1,RS=1 */ + mddi_queue_register_write(REG_SUBTCMD, 0x000f, TRUE, 0); + mddi_wait(1); + /* Wait 5us */ + + if (sharp_subpanel_type == SHARP_SUB_UNKNOWN) { + uint32 data; + + sub_through_write(1, 0x05); + sub_through_write(1, 0x6A); + sub_through_write(1, 0x1D); + sub_through_write(1, 0x05); + data = sub_through_read(1); + if (data == 0x6A) { + sharp_subpanel_type = SHARP_SUB_HYNIX; + } else { + sub_through_write(0, 0x36); + sub_through_write(1, 0xA8); + sub_through_write(0, 0x09); + data = sub_through_read(1); + data = sub_through_read(1); + if (data == 0x54) { + sub_through_write(0, 0x36); + sub_through_write(1, 0x00); + sharp_subpanel_type = SHARP_SUB_ROHM; + } + } + } + + if (sharp_subpanel_type == SHARP_SUB_HYNIX) { + sub_through_write(1, 0x00); /* Display setting 1 */ + sub_through_write(1, 0x04); + sub_through_write(1, 0x01); + sub_through_write(1, 0x05); + sub_through_write(1, 0x0280); + sub_through_write(1, 0x0301); + sub_through_write(1, 0x0402); + sub_through_write(1, 0x0500); + sub_through_write(1, 0x0681); + sub_through_write(1, 0x077F); + sub_through_write(1, 0x08C0); + sub_through_write(1, 0x0905); + sub_through_write(1, 0x0A02); + sub_through_write(1, 0x0B00); + sub_through_write(1, 0x0C00); + sub_through_write(1, 0x0D00); + sub_through_write(1, 0x0E00); + sub_through_write(1, 0x0F00); + + sub_through_write(1, 0x100B); /* Display setting 2 */ + sub_through_write(1, 0x1103); + sub_through_write(1, 0x1237); + sub_through_write(1, 0x1300); + sub_through_write(1, 0x1400); + sub_through_write(1, 0x1500); + sub_through_write(1, 0x1605); + sub_through_write(1, 0x1700); + sub_through_write(1, 0x1800); + sub_through_write(1, 0x192E); + sub_through_write(1, 0x1A00); + sub_through_write(1, 0x1B00); + sub_through_write(1, 0x1C00); + + sub_through_write(1, 0x151A); /* Power setting */ + + sub_through_write(1, 0x2002); /* Gradation Palette setting */ + sub_through_write(1, 0x2107); + sub_through_write(1, 0x220C); + sub_through_write(1, 0x2310); + sub_through_write(1, 0x2414); + sub_through_write(1, 0x2518); + sub_through_write(1, 0x261C); + sub_through_write(1, 0x2720); + sub_through_write(1, 0x2824); + sub_through_write(1, 0x2928); + sub_through_write(1, 0x2A2B); + sub_through_write(1, 0x2B2E); + sub_through_write(1, 0x2C31); + sub_through_write(1, 0x2D34); + sub_through_write(1, 0x2E37); + sub_through_write(1, 0x2F3A); + sub_through_write(1, 0x303C); + sub_through_write(1, 0x313E); + sub_through_write(1, 0x323F); + sub_through_write(1, 0x3340); + sub_through_write(1, 0x3441); + sub_through_write(1, 0x3543); + sub_through_write(1, 0x3646); + sub_through_write(1, 0x3749); + sub_through_write(1, 0x384C); + sub_through_write(1, 0x394F); + sub_through_write(1, 0x3A52); + sub_through_write(1, 0x3B59); + sub_through_write(1, 0x3C60); + sub_through_write(1, 0x3D67); + sub_through_write(1, 0x3E6E); + sub_through_write(1, 0x3F7F); + sub_through_write(1, 0x4001); + sub_through_write(1, 0x4107); + sub_through_write(1, 0x420C); + sub_through_write(1, 0x4310); + sub_through_write(1, 0x4414); + sub_through_write(1, 0x4518); + sub_through_write(1, 0x461C); + sub_through_write(1, 0x4720); + sub_through_write(1, 0x4824); + sub_through_write(1, 0x4928); + sub_through_write(1, 0x4A2B); + sub_through_write(1, 0x4B2E); + sub_through_write(1, 0x4C31); + sub_through_write(1, 0x4D34); + sub_through_write(1, 0x4E37); + sub_through_write(1, 0x4F3A); + sub_through_write(1, 0x503C); + sub_through_write(1, 0x513E); + sub_through_write(1, 0x523F); + sub_through_write(1, 0x5340); + sub_through_write(1, 0x5441); + sub_through_write(1, 0x5543); + sub_through_write(1, 0x5646); + sub_through_write(1, 0x5749); + sub_through_write(1, 0x584C); + sub_through_write(1, 0x594F); + sub_through_write(1, 0x5A52); + sub_through_write(1, 0x5B59); + sub_through_write(1, 0x5C60); + sub_through_write(1, 0x5D67); + sub_through_write(1, 0x5E6E); + sub_through_write(1, 0x5F7E); + sub_through_write(1, 0x6000); + sub_through_write(1, 0x6107); + sub_through_write(1, 0x620C); + sub_through_write(1, 0x6310); + sub_through_write(1, 0x6414); + sub_through_write(1, 0x6518); + sub_through_write(1, 0x661C); + sub_through_write(1, 0x6720); + sub_through_write(1, 0x6824); + sub_through_write(1, 0x6928); + sub_through_write(1, 0x6A2B); + sub_through_write(1, 0x6B2E); + sub_through_write(1, 0x6C31); + sub_through_write(1, 0x6D34); + sub_through_write(1, 0x6E37); + sub_through_write(1, 0x6F3A); + sub_through_write(1, 0x703C); + sub_through_write(1, 0x713E); + sub_through_write(1, 0x723F); + sub_through_write(1, 0x7340); + sub_through_write(1, 0x7441); + sub_through_write(1, 0x7543); + sub_through_write(1, 0x7646); + sub_through_write(1, 0x7749); + sub_through_write(1, 0x784C); + sub_through_write(1, 0x794F); + sub_through_write(1, 0x7A52); + sub_through_write(1, 0x7B59); + sub_through_write(1, 0x7C60); + sub_through_write(1, 0x7D67); + sub_through_write(1, 0x7E6E); + sub_through_write(1, 0x7F7D); + + sub_through_write(1, 0x1851); /* Display on */ + + mddi_queue_register_write(REG_AGM, 0x0000, TRUE, 0); + + /* 1 pixel / 1 post clock */ + mddi_queue_register_write(REG_CLKDIV2, 0x3b00, FALSE, 0); + + /* SUB LCD select */ + mddi_queue_register_write(REG_PSTCTL2, 0x0080, FALSE, 0); + + /* RS=0,command initiate number=0,select master mode */ + mddi_queue_register_write(REG_SUBCTL, 0x0202, FALSE, 0); + + /* Sub LCD Data transform start */ + mddi_queue_register_write(REG_PSTCTL1, 0x0003, FALSE, 0); + + } else if (sharp_subpanel_type == SHARP_SUB_ROHM) { + + sub_through_write(0, 0x01); /* Display setting */ + sub_through_write(1, 0x00); + + mddi_wait(1); + /* Wait 100us <----- ******* Update 2005/01/24 */ + + sub_through_write(0, 0xB6); + sub_through_write(1, 0x0C); + sub_through_write(1, 0x4A); + sub_through_write(1, 0x20); + sub_through_write(0, 0x3A); + sub_through_write(1, 0x05); + sub_through_write(0, 0xB7); + sub_through_write(1, 0x01); + sub_through_write(0, 0xBA); + sub_through_write(1, 0x20); + sub_through_write(1, 0x02); + sub_through_write(0, 0x25); + sub_through_write(1, 0x4F); + sub_through_write(0, 0xBB); + sub_through_write(1, 0x00); + sub_through_write(0, 0x36); + sub_through_write(1, 0x00); + sub_through_write(0, 0xB1); + sub_through_write(1, 0x05); + sub_through_write(0, 0xBE); + sub_through_write(1, 0x80); + sub_through_write(0, 0x26); + sub_through_write(1, 0x01); + sub_through_write(0, 0x2A); + sub_through_write(1, 0x02); + sub_through_write(1, 0x81); + sub_through_write(0, 0x2B); + sub_through_write(1, 0x00); + sub_through_write(1, 0x7F); + + sub_through_write(0, 0x2C); + sub_through_write(0, 0x11); /* Sleep mode off */ + + mddi_wait(1); + /* Wait 100 ms <----- ******* Update 2005/01/24 */ + + sub_through_write(0, 0x29); /* Display on */ + sub_through_write(0, 0xB3); + sub_through_write(1, 0x20); + sub_through_write(1, 0xAA); + sub_through_write(1, 0xA0); + sub_through_write(1, 0x20); + sub_through_write(1, 0x30); + sub_through_write(1, 0xA6); + sub_through_write(1, 0xFF); + sub_through_write(1, 0x9A); + sub_through_write(1, 0x9F); + sub_through_write(1, 0xAF); + sub_through_write(1, 0xBC); + sub_through_write(1, 0xCF); + sub_through_write(1, 0xDF); + sub_through_write(1, 0x20); + sub_through_write(1, 0x9C); + sub_through_write(1, 0x8A); + + sub_through_write(0, 0x002C); /* Display on */ + + /* 1 pixel / 2 post clock */ + mddi_queue_register_write(REG_CLKDIV2, 0x7b00, FALSE, 0); + + /* SUB LCD select */ + mddi_queue_register_write(REG_PSTCTL2, 0x0080, FALSE, 0); + + /* RS=1,command initiate number=0,select master mode */ + mddi_queue_register_write(REG_SUBCTL, 0x0242, FALSE, 0); + + /* Sub LCD Data transform start */ + mddi_queue_register_write(REG_PSTCTL1, 0x0003, FALSE, 0); + + } + + /* Set the MDP pixel data attributes for Sub Display */ + mddi_host_write_pix_attr_reg(0x00C0); +} + +void mddi_sharp_lcd_vsync_detected(boolean detected) +{ + /* static timetick_type start_time = 0; */ + static struct timeval start_time; + static boolean first_time = TRUE; + /* uint32 mdp_cnt_val = 0; */ + /* timetick_type elapsed_us; */ + struct timeval now; + uint32 elapsed_us; + uint32 num_vsyncs; + + if ((detected) || (mddi_sharp_vsync_attempts > 5)) { + if ((detected) && (mddi_sharp_monitor_refresh_value)) { + /* if (start_time != 0) */ + if (!first_time) { + jiffies_to_timeval(jiffies, &now); + elapsed_us = + (now.tv_sec - start_time.tv_sec) * 1000000 + + now.tv_usec - start_time.tv_usec; + /* + * LCD is configured for a refresh every usecs, + * so to determine the number of vsyncs that + * have occurred since the last measurement add + * half that to the time difference and divide + * by the refresh rate. + */ + num_vsyncs = (elapsed_us + + (mddi_sharp_usecs_per_refresh >> + 1)) / + mddi_sharp_usecs_per_refresh; + /* + * LCD is configured for * hsyncs (rows) per + * refresh cycle. Calculate new rows_per_second + * value based upon these new measurements. + * MDP can update with this new value. + */ + mddi_sharp_rows_per_second = + (mddi_sharp_rows_per_refresh * 1000 * + num_vsyncs) / (elapsed_us / 1000); + } + /* start_time = timetick_get(); */ + first_time = FALSE; + jiffies_to_timeval(jiffies, &start_time); + if (mddi_sharp_report_refresh_measurements) { + /* mdp_cnt_val = MDP_LINE_COUNT; */ + } + } + /* if detected = TRUE, client initiated wakeup was detected */ + if (mddi_sharp_vsync_handler != NULL) { + (*mddi_sharp_vsync_handler) + (mddi_sharp_vsync_handler_arg); + mddi_sharp_vsync_handler = NULL; + } + mddi_vsync_detect_enabled = FALSE; + mddi_sharp_vsync_attempts = 0; + /* need to clear this vsync wakeup */ + if (!mddi_queue_register_write_int(REG_INTR, 0x0000)) { + MDDI_MSG_ERR("Vsync interrupt clear failed!\n"); + } + if (!detected) { + /* give up after 5 failed attempts but show error */ + MDDI_MSG_NOTICE("Vsync detection failed!\n"); + } else if ((mddi_sharp_monitor_refresh_value) && + (mddi_sharp_report_refresh_measurements)) { + MDDI_MSG_NOTICE(" Lines Per Second=%d!\n", + mddi_sharp_rows_per_second); + } + } else + /* if detected = FALSE, we woke up from hibernation, but did not + * detect client initiated wakeup. + */ + mddi_sharp_vsync_attempts++; +} + +/* ISR to be executed */ +void mddi_sharp_vsync_set_handler(msm_fb_vsync_handler_type handler, void *arg) +{ + boolean error = FALSE; + unsigned long flags; + + /* Disable interrupts */ + spin_lock_irqsave(&mddi_host_spin_lock, flags); + /* INTLOCK(); */ + + if (mddi_sharp_vsync_handler != NULL) + error = TRUE; + + /* Register the handler for this particular GROUP interrupt source */ + mddi_sharp_vsync_handler = handler; + mddi_sharp_vsync_handler_arg = arg; + + /* Restore interrupts */ + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + /* INTFREE(); */ + + if (error) + MDDI_MSG_ERR("MDDI: Previous Vsync handler never called\n"); + + /* Enable the vsync wakeup */ + mddi_queue_register_write(REG_INTR, 0x8100, FALSE, 0); + + mddi_sharp_vsync_attempts = 1; + mddi_vsync_detect_enabled = TRUE; +} /* mddi_sharp_vsync_set_handler */ + +static int mddi_sharp_lcd_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + mddi_host_client_cnt_reset(); + + if (mfd->panel.id == SHARP_QVGA_PRIM) + mddi_sharp_prim_lcd_init(); + else + mddi_sharp_sub_lcd_init(); + + return 0; +} + +static int mddi_sharp_lcd_off(struct platform_device *pdev) +{ + if (mddi_sharp_vsync_handler != NULL) { + (*mddi_sharp_vsync_handler) + (mddi_sharp_vsync_handler_arg); + mddi_sharp_vsync_handler = NULL; + printk(KERN_INFO "%s: clean up vsyn_handler=%x\n", __func__, + (int)mddi_sharp_vsync_handler); + } + + mddi_sharp_lcd_powerdown(); + return 0; +} + +static int mddi_sharp_probe(struct platform_device *pdev) +{ + if (pdev->id == 0) { + mddi_sharp_pdata = pdev->dev.platform_data; + return 0; + } + + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = mddi_sharp_probe, + .driver = { + .name = "mddi_sharp_qvga", + }, +}; + +static struct msm_fb_panel_data mddi_sharp_panel_data0 = { + .on = mddi_sharp_lcd_on, + .off = mddi_sharp_lcd_off, + .set_backlight = mddi_sharp_lcd_set_backlight, + .set_vsync_notifier = mddi_sharp_vsync_set_handler, +}; + +static struct platform_device this_device_0 = { + .name = "mddi_sharp_qvga", + .id = SHARP_QVGA_PRIM, + .dev = { + .platform_data = &mddi_sharp_panel_data0, + } +}; + +static struct msm_fb_panel_data mddi_sharp_panel_data1 = { + .on = mddi_sharp_lcd_on, + .off = mddi_sharp_lcd_off, +}; + +static struct platform_device this_device_1 = { + .name = "mddi_sharp_qvga", + .id = SHARP_128X128_SECD, + .dev = { + .platform_data = &mddi_sharp_panel_data1, + } +}; + +static int __init mddi_sharp_init(void) +{ + int ret; + struct msm_panel_info *pinfo; + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + u32 id; + + ret = msm_fb_detect_client("mddi_sharp_qvga"); + if (ret == -ENODEV) + return 0; + + if (ret) { + id = mddi_get_client_id(); + + if (((id >> 16) != 0x0) || ((id & 0xffff) != 0x8835)) + return 0; + } +#endif + if (mddi_host_core_version > 8) { + /* can use faster refresh with newer hw revisions */ + mddi_sharp_debug_60hz_refresh = TRUE; + + /* Timing variables for tracking vsync */ + /* dot_clock = 6.00MHz + * horizontal count = 296 + * vertical count = 338 + * refresh rate = 6000000/(296+338) = 60Hz + */ + mddi_sharp_rows_per_second = 20270; /* 6000000/296 */ + mddi_sharp_rows_per_refresh = 338; + mddi_sharp_usecs_per_refresh = 16674; /* (296+338)/6000000 */ + } else { + /* Timing variables for tracking vsync */ + /* dot_clock = 5.20MHz + * horizontal count = 376 + * vertical count = 338 + * refresh rate = 5200000/(376+338) = 41Hz + */ + mddi_sharp_rows_per_second = 13830; /* 5200000/376 */ + mddi_sharp_rows_per_refresh = 338; + mddi_sharp_usecs_per_refresh = 24440; /* (376+338)/5200000 */ + } + + ret = platform_driver_register(&this_driver); + if (!ret) { + pinfo = &mddi_sharp_panel_data0.panel_info; + pinfo->xres = 240; + pinfo->yres = 320; + MSM_FB_SINGLE_MODE_PANEL(pinfo); + pinfo->type = MDDI_PANEL; + pinfo->pdest = DISPLAY_1; + pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR; + pinfo->wait_cycle = 0; + pinfo->bpp = 18; + pinfo->fb_num = 2; + pinfo->clk_rate = 122880000; + pinfo->clk_min = 120000000; + pinfo->clk_max = 125000000; + pinfo->lcd.vsync_enable = TRUE; + pinfo->mddi.is_type1 = TRUE; + pinfo->lcd.refx100 = + (mddi_sharp_rows_per_second * 100) / + mddi_sharp_rows_per_refresh; + pinfo->lcd.v_back_porch = 12; + pinfo->lcd.v_front_porch = 6; + pinfo->lcd.v_pulse_width = 0; + pinfo->lcd.hw_vsync_mode = FALSE; + pinfo->lcd.vsync_notifier_period = (1 * HZ); + pinfo->bl_max = 7; + pinfo->bl_min = 1; + + ret = platform_device_register(&this_device_0); + if (ret) + platform_driver_unregister(&this_driver); + + pinfo = &mddi_sharp_panel_data1.panel_info; + pinfo->xres = 128; + pinfo->yres = 128; + MSM_FB_SINGLE_MODE_PANEL(pinfo); + pinfo->type = MDDI_PANEL; + pinfo->pdest = DISPLAY_2; + pinfo->mddi.vdopkt = 0x400; + pinfo->wait_cycle = 0; + pinfo->bpp = 18; + pinfo->clk_rate = 122880000; + pinfo->clk_min = 120000000; + pinfo->clk_max = 125000000; + pinfo->fb_num = 2; + + ret = platform_device_register(&this_device_1); + if (ret) { + platform_device_unregister(&this_device_0); + platform_driver_unregister(&this_driver); + } + } + + if (!ret) + mddi_lcd.vsync_detected = mddi_sharp_lcd_vsync_detected; + + return ret; +} + +module_init(mddi_sharp_init); diff --git a/drivers/video/msm/mddi_toshiba.c b/drivers/video/msm/mddi_toshiba.c new file mode 100644 index 000000000000..bba83866a756 --- /dev/null +++ b/drivers/video/msm/mddi_toshiba.c @@ -0,0 +1,1753 @@ +/* Copyright (c) 2008-2009, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mddihost.h" +#include "mddihosti.h" +#include "mddi_toshiba.h" + +#define TM_GET_DID(id) ((id) & 0xff) +#define TM_GET_PID(id) (((id) & 0xff00)>>8) + +#define MDDI_CLIENT_CORE_BASE 0x108000 +#define LCD_CONTROL_BLOCK_BASE 0x110000 +#define SPI_BLOCK_BASE 0x120000 +#define PWM_BLOCK_BASE 0x140000 +#define SYSTEM_BLOCK1_BASE 0x160000 + +#define TTBUSSEL (MDDI_CLIENT_CORE_BASE|0x18) +#define DPSET0 (MDDI_CLIENT_CORE_BASE|0x1C) +#define DPSET1 (MDDI_CLIENT_CORE_BASE|0x20) +#define DPSUS (MDDI_CLIENT_CORE_BASE|0x24) +#define DPRUN (MDDI_CLIENT_CORE_BASE|0x28) +#define SYSCKENA (MDDI_CLIENT_CORE_BASE|0x2C) + +#define BITMAP0 (MDDI_CLIENT_CORE_BASE|0x44) +#define BITMAP1 (MDDI_CLIENT_CORE_BASE|0x48) +#define BITMAP2 (MDDI_CLIENT_CORE_BASE|0x4C) +#define BITMAP3 (MDDI_CLIENT_CORE_BASE|0x50) +#define BITMAP4 (MDDI_CLIENT_CORE_BASE|0x54) + +#define SRST (LCD_CONTROL_BLOCK_BASE|0x00) +#define PORT_ENB (LCD_CONTROL_BLOCK_BASE|0x04) +#define START (LCD_CONTROL_BLOCK_BASE|0x08) +#define PORT (LCD_CONTROL_BLOCK_BASE|0x0C) + +#define INTFLG (LCD_CONTROL_BLOCK_BASE|0x18) +#define INTMSK (LCD_CONTROL_BLOCK_BASE|0x1C) +#define MPLFBUF (LCD_CONTROL_BLOCK_BASE|0x20) + +#define PXL (LCD_CONTROL_BLOCK_BASE|0x30) +#define HCYCLE (LCD_CONTROL_BLOCK_BASE|0x34) +#define HSW (LCD_CONTROL_BLOCK_BASE|0x38) +#define HDE_START (LCD_CONTROL_BLOCK_BASE|0x3C) +#define HDE_SIZE (LCD_CONTROL_BLOCK_BASE|0x40) +#define VCYCLE (LCD_CONTROL_BLOCK_BASE|0x44) +#define VSW (LCD_CONTROL_BLOCK_BASE|0x48) +#define VDE_START (LCD_CONTROL_BLOCK_BASE|0x4C) +#define VDE_SIZE (LCD_CONTROL_BLOCK_BASE|0x50) +#define WAKEUP (LCD_CONTROL_BLOCK_BASE|0x54) +#define REGENB (LCD_CONTROL_BLOCK_BASE|0x5C) +#define VSYNIF (LCD_CONTROL_BLOCK_BASE|0x60) +#define WRSTB (LCD_CONTROL_BLOCK_BASE|0x64) +#define RDSTB (LCD_CONTROL_BLOCK_BASE|0x68) +#define ASY_DATA (LCD_CONTROL_BLOCK_BASE|0x6C) +#define ASY_DATB (LCD_CONTROL_BLOCK_BASE|0x70) +#define ASY_DATC (LCD_CONTROL_BLOCK_BASE|0x74) +#define ASY_DATD (LCD_CONTROL_BLOCK_BASE|0x78) +#define ASY_DATE (LCD_CONTROL_BLOCK_BASE|0x7C) +#define ASY_DATF (LCD_CONTROL_BLOCK_BASE|0x80) +#define ASY_DATG (LCD_CONTROL_BLOCK_BASE|0x84) +#define ASY_DATH (LCD_CONTROL_BLOCK_BASE|0x88) +#define ASY_CMDSET (LCD_CONTROL_BLOCK_BASE|0x8C) +#define MONI (LCD_CONTROL_BLOCK_BASE|0xB0) +#define VPOS (LCD_CONTROL_BLOCK_BASE|0xC0) + +#define SSICTL (SPI_BLOCK_BASE|0x00) +#define SSITIME (SPI_BLOCK_BASE|0x04) +#define SSITX (SPI_BLOCK_BASE|0x08) +#define SSIINTS (SPI_BLOCK_BASE|0x14) + +#define TIMER0LOAD (PWM_BLOCK_BASE|0x00) +#define TIMER0CTRL (PWM_BLOCK_BASE|0x08) +#define PWM0OFF (PWM_BLOCK_BASE|0x1C) +#define TIMER1LOAD (PWM_BLOCK_BASE|0x20) +#define TIMER1CTRL (PWM_BLOCK_BASE|0x28) +#define PWM1OFF (PWM_BLOCK_BASE|0x3C) +#define TIMER2LOAD (PWM_BLOCK_BASE|0x40) +#define TIMER2CTRL (PWM_BLOCK_BASE|0x48) +#define PWM2OFF (PWM_BLOCK_BASE|0x5C) +#define PWMCR (PWM_BLOCK_BASE|0x68) + +#define GPIOIS (GPIO_BLOCK_BASE|0x08) +#define GPIOIEV (GPIO_BLOCK_BASE|0x10) +#define GPIOIC (GPIO_BLOCK_BASE|0x20) + +#define WKREQ (SYSTEM_BLOCK1_BASE|0x00) +#define CLKENB (SYSTEM_BLOCK1_BASE|0x04) +#define DRAMPWR (SYSTEM_BLOCK1_BASE|0x08) +#define INTMASK (SYSTEM_BLOCK1_BASE|0x0C) +#define CNT_DIS (SYSTEM_BLOCK1_BASE|0x10) + +typedef enum { + TOSHIBA_STATE_OFF, + TOSHIBA_STATE_PRIM_SEC_STANDBY, + TOSHIBA_STATE_PRIM_SEC_READY, + TOSHIBA_STATE_PRIM_NORMAL_MODE, + TOSHIBA_STATE_SEC_NORMAL_MODE +} mddi_toshiba_state_t; + +static uint32 mddi_toshiba_curr_vpos; +static boolean mddi_toshiba_monitor_refresh_value = FALSE; +static boolean mddi_toshiba_report_refresh_measurements = FALSE; + +boolean mddi_toshiba_61Hz_refresh = TRUE; + +/* Modifications to timing to increase refresh rate to > 60Hz. + * 20MHz dot clock. + * 646 total rows. + * 506 total columns. + * refresh rate = 61.19Hz + */ +static uint32 mddi_toshiba_rows_per_second = 39526; +static uint32 mddi_toshiba_usecs_per_refresh = 16344; +static uint32 mddi_toshiba_rows_per_refresh = 646; +extern boolean mddi_vsync_detect_enabled; + +static msm_fb_vsync_handler_type mddi_toshiba_vsync_handler; +static void *mddi_toshiba_vsync_handler_arg; +static uint16 mddi_toshiba_vsync_attempts; + +static mddi_toshiba_state_t toshiba_state = TOSHIBA_STATE_OFF; + +static struct msm_panel_common_pdata *mddi_toshiba_pdata; + +static int mddi_toshiba_lcd_on(struct platform_device *pdev); +static int mddi_toshiba_lcd_off(struct platform_device *pdev); + +static void mddi_toshiba_state_transition(mddi_toshiba_state_t a, + mddi_toshiba_state_t b) +{ + if (toshiba_state != a) { + MDDI_MSG_ERR("toshiba state trans. (%d->%d) found %d\n", a, b, + toshiba_state); + } + toshiba_state = b; +} + +#define GORDON_REG_IMGCTL1 0x10 /* Image interface control 1 */ +#define GORDON_REG_IMGCTL2 0x11 /* Image interface control 2 */ +#define GORDON_REG_IMGSET1 0x12 /* Image interface settings 1 */ +#define GORDON_REG_IMGSET2 0x13 /* Image interface settings 2 */ +#define GORDON_REG_IVBP1 0x14 /* DM0: Vert back porch */ +#define GORDON_REG_IHBP1 0x15 /* DM0: Horiz back porch */ +#define GORDON_REG_IVNUM1 0x16 /* DM0: Num of vert lines */ +#define GORDON_REG_IHNUM1 0x17 /* DM0: Num of pixels per line */ +#define GORDON_REG_IVBP2 0x18 /* DM1: Vert back porch */ +#define GORDON_REG_IHBP2 0x19 /* DM1: Horiz back porch */ +#define GORDON_REG_IVNUM2 0x1A /* DM1: Num of vert lines */ +#define GORDON_REG_IHNUM2 0x1B /* DM1: Num of pixels per line */ +#define GORDON_REG_LCDIFCTL1 0x30 /* LCD interface control 1 */ +#define GORDON_REG_VALTRAN 0x31 /* LCD IF ctl: VALTRAN sync flag */ +#define GORDON_REG_AVCTL 0x33 +#define GORDON_REG_LCDIFCTL2 0x34 /* LCD interface control 2 */ +#define GORDON_REG_LCDIFCTL3 0x35 /* LCD interface control 3 */ +#define GORDON_REG_LCDIFSET1 0x36 /* LCD interface settings 1 */ +#define GORDON_REG_PCCTL 0x3C +#define GORDON_REG_TPARAM1 0x40 +#define GORDON_REG_TLCDIF1 0x41 +#define GORDON_REG_TSSPB_ST1 0x42 +#define GORDON_REG_TSSPB_ED1 0x43 +#define GORDON_REG_TSCK_ST1 0x44 +#define GORDON_REG_TSCK_WD1 0x45 +#define GORDON_REG_TGSPB_VST1 0x46 +#define GORDON_REG_TGSPB_VED1 0x47 +#define GORDON_REG_TGSPB_CH1 0x48 +#define GORDON_REG_TGCK_ST1 0x49 +#define GORDON_REG_TGCK_ED1 0x4A +#define GORDON_REG_TPCTL_ST1 0x4B +#define GORDON_REG_TPCTL_ED1 0x4C +#define GORDON_REG_TPCHG_ED1 0x4D +#define GORDON_REG_TCOM_CH1 0x4E +#define GORDON_REG_THBP1 0x4F +#define GORDON_REG_TPHCTL1 0x50 +#define GORDON_REG_EVPH1 0x51 +#define GORDON_REG_EVPL1 0x52 +#define GORDON_REG_EVNH1 0x53 +#define GORDON_REG_EVNL1 0x54 +#define GORDON_REG_TBIAS1 0x55 +#define GORDON_REG_TPARAM2 0x56 +#define GORDON_REG_TLCDIF2 0x57 +#define GORDON_REG_TSSPB_ST2 0x58 +#define GORDON_REG_TSSPB_ED2 0x59 +#define GORDON_REG_TSCK_ST2 0x5A +#define GORDON_REG_TSCK_WD2 0x5B +#define GORDON_REG_TGSPB_VST2 0x5C +#define GORDON_REG_TGSPB_VED2 0x5D +#define GORDON_REG_TGSPB_CH2 0x5E +#define GORDON_REG_TGCK_ST2 0x5F +#define GORDON_REG_TGCK_ED2 0x60 +#define GORDON_REG_TPCTL_ST2 0x61 +#define GORDON_REG_TPCTL_ED2 0x62 +#define GORDON_REG_TPCHG_ED2 0x63 +#define GORDON_REG_TCOM_CH2 0x64 +#define GORDON_REG_THBP2 0x65 +#define GORDON_REG_TPHCTL2 0x66 +#define GORDON_REG_EVPH2 0x67 +#define GORDON_REG_EVPL2 0x68 +#define GORDON_REG_EVNH2 0x69 +#define GORDON_REG_EVNL2 0x6A +#define GORDON_REG_TBIAS2 0x6B +#define GORDON_REG_POWCTL 0x80 +#define GORDON_REG_POWOSC1 0x81 +#define GORDON_REG_POWOSC2 0x82 +#define GORDON_REG_POWSET 0x83 +#define GORDON_REG_POWTRM1 0x85 +#define GORDON_REG_POWTRM2 0x86 +#define GORDON_REG_POWTRM3 0x87 +#define GORDON_REG_POWTRMSEL 0x88 +#define GORDON_REG_POWHIZ 0x89 + +void serigo(uint16 reg, uint8 data) +{ + uint32 mddi_val = 0; + mddi_queue_register_read(SSIINTS, &mddi_val, TRUE, 0); + if (mddi_val & (1 << 8)) + mddi_wait(1); + /* No De-assert of CS and send 2 bytes */ + mddi_val = 0x90000 | ((0x00FF & reg) << 8) | data; + mddi_queue_register_write(SSITX, mddi_val, TRUE, 0); +} + +void gordon_init(void) +{ + /* Image interface settings ***/ + serigo(GORDON_REG_IMGCTL2, 0x00); + serigo(GORDON_REG_IMGSET1, 0x01); + + /* Exchange the RGB signal for J510(Softbank mobile) */ + serigo(GORDON_REG_IMGSET2, 0x12); + serigo(GORDON_REG_LCDIFSET1, 0x00); + mddi_wait(2); + + /* Pre-charge settings */ + serigo(GORDON_REG_PCCTL, 0x09); + serigo(GORDON_REG_LCDIFCTL2, 0x1B); + mddi_wait(1); +} + +void gordon_disp_on(void) +{ + /*gordon_dispmode setting */ + /*VGA settings */ + serigo(GORDON_REG_TPARAM1, 0x30); + serigo(GORDON_REG_TLCDIF1, 0x00); + serigo(GORDON_REG_TSSPB_ST1, 0x8B); + serigo(GORDON_REG_TSSPB_ED1, 0x93); + mddi_wait(2); + serigo(GORDON_REG_TSCK_ST1, 0x88); + serigo(GORDON_REG_TSCK_WD1, 0x00); + serigo(GORDON_REG_TGSPB_VST1, 0x01); + serigo(GORDON_REG_TGSPB_VED1, 0x02); + mddi_wait(2); + serigo(GORDON_REG_TGSPB_CH1, 0x5E); + serigo(GORDON_REG_TGCK_ST1, 0x80); + serigo(GORDON_REG_TGCK_ED1, 0x3C); + serigo(GORDON_REG_TPCTL_ST1, 0x50); + mddi_wait(2); + serigo(GORDON_REG_TPCTL_ED1, 0x74); + serigo(GORDON_REG_TPCHG_ED1, 0x78); + serigo(GORDON_REG_TCOM_CH1, 0x50); + serigo(GORDON_REG_THBP1, 0x84); + mddi_wait(2); + serigo(GORDON_REG_TPHCTL1, 0x00); + serigo(GORDON_REG_EVPH1, 0x70); + serigo(GORDON_REG_EVPL1, 0x64); + serigo(GORDON_REG_EVNH1, 0x56); + mddi_wait(2); + serigo(GORDON_REG_EVNL1, 0x48); + serigo(GORDON_REG_TBIAS1, 0x88); + mddi_wait(2); + serigo(GORDON_REG_TPARAM2, 0x28); + serigo(GORDON_REG_TLCDIF2, 0x14); + serigo(GORDON_REG_TSSPB_ST2, 0x49); + serigo(GORDON_REG_TSSPB_ED2, 0x4B); + mddi_wait(2); + serigo(GORDON_REG_TSCK_ST2, 0x4A); + serigo(GORDON_REG_TSCK_WD2, 0x02); + serigo(GORDON_REG_TGSPB_VST2, 0x02); + serigo(GORDON_REG_TGSPB_VED2, 0x03); + mddi_wait(2); + serigo(GORDON_REG_TGSPB_CH2, 0x2F); + serigo(GORDON_REG_TGCK_ST2, 0x40); + serigo(GORDON_REG_TGCK_ED2, 0x1E); + serigo(GORDON_REG_TPCTL_ST2, 0x2C); + mddi_wait(2); + serigo(GORDON_REG_TPCTL_ED2, 0x3A); + serigo(GORDON_REG_TPCHG_ED2, 0x3C); + serigo(GORDON_REG_TCOM_CH2, 0x28); + serigo(GORDON_REG_THBP2, 0x4D); + mddi_wait(2); + serigo(GORDON_REG_TPHCTL2, 0x1A); + mddi_wait(2); + serigo(GORDON_REG_IVBP1, 0x02); + serigo(GORDON_REG_IHBP1, 0x90); + serigo(GORDON_REG_IVNUM1, 0xA0); + serigo(GORDON_REG_IHNUM1, 0x78); + mddi_wait(2); + serigo(GORDON_REG_IVBP2, 0x02); + serigo(GORDON_REG_IHBP2, 0x48); + serigo(GORDON_REG_IVNUM2, 0x50); + serigo(GORDON_REG_IHNUM2, 0x3C); + mddi_wait(2); + serigo(GORDON_REG_POWCTL, 0x03); + mddi_wait(15); + serigo(GORDON_REG_POWCTL, 0x07); + mddi_wait(15); + serigo(GORDON_REG_POWCTL, 0x0F); + mddi_wait(15); + serigo(GORDON_REG_AVCTL, 0x03); + mddi_wait(15); + serigo(GORDON_REG_POWCTL, 0x1F); + mddi_wait(15); + serigo(GORDON_REG_POWCTL, 0x5F); + mddi_wait(15); + serigo(GORDON_REG_POWCTL, 0x7F); + mddi_wait(15); + serigo(GORDON_REG_LCDIFCTL1, 0x02); + mddi_wait(15); + serigo(GORDON_REG_IMGCTL1, 0x00); + mddi_wait(15); + serigo(GORDON_REG_LCDIFCTL3, 0x00); + mddi_wait(15); + serigo(GORDON_REG_VALTRAN, 0x01); + mddi_wait(15); + serigo(GORDON_REG_LCDIFCTL1, 0x03); + serigo(GORDON_REG_LCDIFCTL1, 0x03); + mddi_wait(1); +} + +void gordon_disp_off(void) +{ + serigo(GORDON_REG_LCDIFCTL2, 0x7B); + serigo(GORDON_REG_VALTRAN, 0x01); + serigo(GORDON_REG_LCDIFCTL1, 0x02); + serigo(GORDON_REG_LCDIFCTL3, 0x01); + mddi_wait(20); + serigo(GORDON_REG_VALTRAN, 0x01); + serigo(GORDON_REG_IMGCTL1, 0x01); + serigo(GORDON_REG_LCDIFCTL1, 0x00); + mddi_wait(20); + serigo(GORDON_REG_POWCTL, 0x1F); + mddi_wait(40); + serigo(GORDON_REG_POWCTL, 0x07); + mddi_wait(40); + serigo(GORDON_REG_POWCTL, 0x03); + mddi_wait(40); + serigo(GORDON_REG_POWCTL, 0x00); + mddi_wait(40); +} + +void gordon_disp_init(void) +{ + gordon_init(); + mddi_wait(20); + gordon_disp_on(); +} + +static void toshiba_common_initial_setup(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) { + write_client_reg(DPSET0 , 0x4bec0066, TRUE); + write_client_reg(DPSET1 , 0x00000113, TRUE); + write_client_reg(DPSUS , 0x00000000, TRUE); + write_client_reg(DPRUN , 0x00000001, TRUE); + mddi_wait(5); + write_client_reg(SYSCKENA , 0x00000001, TRUE); + write_client_reg(CLKENB , 0x0000a0e9, TRUE); + + write_client_reg(GPIODATA , 0x03FF0000, TRUE); + write_client_reg(GPIODIR , 0x0000024D, TRUE); + write_client_reg(GPIOSEL , 0x00000173, TRUE); + write_client_reg(GPIOPC , 0x03C300C0, TRUE); + write_client_reg(WKREQ , 0x00000000, TRUE); + write_client_reg(GPIOIS , 0x00000000, TRUE); + write_client_reg(GPIOIEV , 0x00000001, TRUE); + write_client_reg(GPIOIC , 0x000003FF, TRUE); + write_client_reg(GPIODATA , 0x00040004, TRUE); + + write_client_reg(GPIODATA , 0x00080008, TRUE); + write_client_reg(DRAMPWR , 0x00000001, TRUE); + write_client_reg(CLKENB , 0x0000a0eb, TRUE); + write_client_reg(PWMCR , 0x00000000, TRUE); + mddi_wait(1); + + write_client_reg(SSICTL , 0x00060399, TRUE); + write_client_reg(SSITIME , 0x00000100, TRUE); + write_client_reg(CNT_DIS , 0x00000002, TRUE); + write_client_reg(SSICTL , 0x0006039b, TRUE); + + write_client_reg(SSITX , 0x00000000, TRUE); + mddi_wait(7); + write_client_reg(SSITX , 0x00000000, TRUE); + mddi_wait(7); + write_client_reg(SSITX , 0x00000000, TRUE); + mddi_wait(7); + + write_client_reg(SSITX , 0x000800BA, TRUE); + write_client_reg(SSITX , 0x00000111, TRUE); + write_client_reg(SSITX , 0x00080036, TRUE); + write_client_reg(SSITX , 0x00000100, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x0008003A, TRUE); + write_client_reg(SSITX , 0x00000160, TRUE); + write_client_reg(SSITX , 0x000800B1, TRUE); + write_client_reg(SSITX , 0x0000015D, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800B2, TRUE); + write_client_reg(SSITX , 0x00000133, TRUE); + write_client_reg(SSITX , 0x000800B3, TRUE); + write_client_reg(SSITX , 0x00000122, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800B4, TRUE); + write_client_reg(SSITX , 0x00000102, TRUE); + write_client_reg(SSITX , 0x000800B5, TRUE); + write_client_reg(SSITX , 0x0000011E, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800B6, TRUE); + write_client_reg(SSITX , 0x00000127, TRUE); + write_client_reg(SSITX , 0x000800B7, TRUE); + write_client_reg(SSITX , 0x00000103, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800B9, TRUE); + write_client_reg(SSITX , 0x00000124, TRUE); + write_client_reg(SSITX , 0x000800BD, TRUE); + write_client_reg(SSITX , 0x000001A1, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800BB, TRUE); + write_client_reg(SSITX , 0x00000100, TRUE); + write_client_reg(SSITX , 0x000800BF, TRUE); + write_client_reg(SSITX , 0x00000101, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800BE, TRUE); + write_client_reg(SSITX , 0x00000100, TRUE); + write_client_reg(SSITX , 0x000800C0, TRUE); + write_client_reg(SSITX , 0x00000111, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C1, TRUE); + write_client_reg(SSITX , 0x00000111, TRUE); + write_client_reg(SSITX , 0x000800C2, TRUE); + write_client_reg(SSITX , 0x00000111, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C3, TRUE); + write_client_reg(SSITX , 0x00080132, TRUE); + write_client_reg(SSITX , 0x00000132, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C4, TRUE); + write_client_reg(SSITX , 0x00080132, TRUE); + write_client_reg(SSITX , 0x00000132, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C5, TRUE); + write_client_reg(SSITX , 0x00080132, TRUE); + write_client_reg(SSITX , 0x00000132, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C6, TRUE); + write_client_reg(SSITX , 0x00080132, TRUE); + write_client_reg(SSITX , 0x00000132, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C7, TRUE); + write_client_reg(SSITX , 0x00080164, TRUE); + write_client_reg(SSITX , 0x00000145, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800C8, TRUE); + write_client_reg(SSITX , 0x00000144, TRUE); + write_client_reg(SSITX , 0x000800C9, TRUE); + write_client_reg(SSITX , 0x00000152, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800CA, TRUE); + write_client_reg(SSITX , 0x00000100, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800EC, TRUE); + write_client_reg(SSITX , 0x00080101, TRUE); + write_client_reg(SSITX , 0x000001FC, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800CF, TRUE); + write_client_reg(SSITX , 0x00000101, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800D0, TRUE); + write_client_reg(SSITX , 0x00080110, TRUE); + write_client_reg(SSITX , 0x00000104, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800D1, TRUE); + write_client_reg(SSITX , 0x00000101, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800D2, TRUE); + write_client_reg(SSITX , 0x00080100, TRUE); + write_client_reg(SSITX , 0x00000128, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800D3, TRUE); + write_client_reg(SSITX , 0x00080100, TRUE); + write_client_reg(SSITX , 0x00000128, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800D4, TRUE); + write_client_reg(SSITX , 0x00080126, TRUE); + write_client_reg(SSITX , 0x000001A4, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800D5, TRUE); + write_client_reg(SSITX , 0x00000120, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800EF, TRUE); + write_client_reg(SSITX , 0x00080132, TRUE); + write_client_reg(SSITX , 0x00000100, TRUE); + mddi_wait(1); + + write_client_reg(BITMAP0 , 0x032001E0, TRUE); + write_client_reg(BITMAP1 , 0x032001E0, TRUE); + write_client_reg(BITMAP2 , 0x014000F0, TRUE); + write_client_reg(BITMAP3 , 0x014000F0, TRUE); + write_client_reg(BITMAP4 , 0x014000F0, TRUE); + write_client_reg(CLKENB , 0x0000A1EB, TRUE); + write_client_reg(PORT_ENB , 0x00000001, TRUE); + write_client_reg(PORT , 0x00000004, TRUE); + write_client_reg(PXL , 0x00000002, TRUE); + write_client_reg(MPLFBUF , 0x00000000, TRUE); + write_client_reg(HCYCLE , 0x000000FD, TRUE); + write_client_reg(HSW , 0x00000003, TRUE); + write_client_reg(HDE_START , 0x00000007, TRUE); + write_client_reg(HDE_SIZE , 0x000000EF, TRUE); + write_client_reg(VCYCLE , 0x00000325, TRUE); + write_client_reg(VSW , 0x00000001, TRUE); + write_client_reg(VDE_START , 0x00000003, TRUE); + write_client_reg(VDE_SIZE , 0x0000031F, TRUE); + write_client_reg(START , 0x00000001, TRUE); + mddi_wait(32); + write_client_reg(SSITX , 0x000800BC, TRUE); + write_client_reg(SSITX , 0x00000180, TRUE); + write_client_reg(SSITX , 0x0008003B, TRUE); + write_client_reg(SSITX , 0x00000100, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800B0, TRUE); + write_client_reg(SSITX , 0x00000116, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x000800B8, TRUE); + write_client_reg(SSITX , 0x000801FF, TRUE); + write_client_reg(SSITX , 0x000001F5, TRUE); + mddi_wait(1); + write_client_reg(SSITX , 0x00000011, TRUE); + mddi_wait(5); + write_client_reg(SSITX , 0x00000029, TRUE); + return; + } + + if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) { + write_client_reg(DPSET0, 0x4BEC0066, TRUE); + write_client_reg(DPSET1, 0x00000113, TRUE); + write_client_reg(DPSUS, 0x00000000, TRUE); + write_client_reg(DPRUN, 0x00000001, TRUE); + mddi_wait(14); + write_client_reg(SYSCKENA, 0x00000001, TRUE); + write_client_reg(CLKENB, 0x000000EF, TRUE); + write_client_reg(GPIO_BLOCK_BASE, 0x03FF0000, TRUE); + write_client_reg(GPIODIR, 0x0000024D, TRUE); + write_client_reg(SYSTEM_BLOCK2_BASE, 0x00000173, TRUE); + write_client_reg(GPIOPC, 0x03C300C0, TRUE); + write_client_reg(SYSTEM_BLOCK1_BASE, 0x00000000, TRUE); + write_client_reg(GPIOIS, 0x00000000, TRUE); + write_client_reg(GPIOIEV, 0x00000001, TRUE); + write_client_reg(GPIOIC, 0x000003FF, TRUE); + write_client_reg(GPIO_BLOCK_BASE, 0x00060006, TRUE); + write_client_reg(GPIO_BLOCK_BASE, 0x00080008, TRUE); + write_client_reg(GPIO_BLOCK_BASE, 0x02000200, TRUE); + write_client_reg(DRAMPWR, 0x00000001, TRUE); + write_client_reg(TIMER0CTRL, 0x00000060, TRUE); + write_client_reg(PWM_BLOCK_BASE, 0x00001388, TRUE); + write_client_reg(PWM0OFF, 0x00001387, TRUE); + write_client_reg(TIMER1CTRL, 0x00000060, TRUE); + write_client_reg(TIMER1LOAD, 0x00001388, TRUE); + write_client_reg(PWM1OFF, 0x00001387, TRUE); + write_client_reg(TIMER0CTRL, 0x000000E0, TRUE); + write_client_reg(TIMER1CTRL, 0x000000E0, TRUE); + write_client_reg(PWMCR, 0x00000003, TRUE); + mddi_wait(1); + write_client_reg(SPI_BLOCK_BASE, 0x00063111, TRUE); + write_client_reg(SSITIME, 0x00000100, TRUE); + write_client_reg(SPI_BLOCK_BASE, 0x00063113, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x00000000, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x00000000, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x00000000, TRUE); + mddi_wait(1); + write_client_reg(CLKENB, 0x0000A1EF, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(WRSTB, 0x0000003F, TRUE); + write_client_reg(RDSTB, 0x00000432, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000000, TRUE); + write_client_reg(ASY_DATB, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(10); + write_client_reg(ASY_DATA, 0x80000000, TRUE); + write_client_reg(ASY_DATB, 0x80000000, TRUE); + write_client_reg(ASY_DATC, 0x80000000, TRUE); + write_client_reg(ASY_DATD, 0x80000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000009, TRUE); + write_client_reg(ASY_CMDSET, 0x00000008, TRUE); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(20); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + + write_client_reg(VSYNIF, 0x00000001, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + } else { + write_client_reg(DPSET0, 0x4BEC0066, TRUE); + write_client_reg(DPSET1, 0x00000113, TRUE); + write_client_reg(DPSUS, 0x00000000, TRUE); + write_client_reg(DPRUN, 0x00000001, TRUE); + mddi_wait(14); + write_client_reg(SYSCKENA, 0x00000001, TRUE); + write_client_reg(CLKENB, 0x000000EF, TRUE); + write_client_reg(GPIODATA, 0x03FF0000, TRUE); + write_client_reg(GPIODIR, 0x0000024D, TRUE); + write_client_reg(GPIOSEL, 0x00000173, TRUE); + write_client_reg(GPIOPC, 0x03C300C0, TRUE); + write_client_reg(WKREQ, 0x00000000, TRUE); + write_client_reg(GPIOIS, 0x00000000, TRUE); + write_client_reg(GPIOIEV, 0x00000001, TRUE); + write_client_reg(GPIOIC, 0x000003FF, TRUE); + write_client_reg(GPIODATA, 0x00060006, TRUE); + write_client_reg(GPIODATA, 0x00080008, TRUE); + write_client_reg(GPIODATA, 0x02000200, TRUE); + + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA) { + mddi_wait(400); + write_client_reg(DRAMPWR, 0x00000001, TRUE); + + write_client_reg(CNT_DIS, 0x00000002, TRUE); + write_client_reg(BITMAP0, 0x01E00320, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + write_client_reg(PORT, 0x00000004, TRUE); + write_client_reg(PXL, 0x0000003A, TRUE); + write_client_reg(MPLFBUF, 0x00000000, TRUE); + write_client_reg(HCYCLE, 0x00000253, TRUE); + write_client_reg(HSW, 0x00000003, TRUE); + write_client_reg(HDE_START, 0x00000017, TRUE); + write_client_reg(HDE_SIZE, 0x0000018F, TRUE); + write_client_reg(VCYCLE, 0x000001FF, TRUE); + write_client_reg(VSW, 0x00000001, TRUE); + write_client_reg(VDE_START, 0x00000003, TRUE); + write_client_reg(VDE_SIZE, 0x000001DF, TRUE); + write_client_reg(START, 0x00000001, TRUE); + mddi_wait(1); + write_client_reg(TIMER0CTRL, 0x00000060, TRUE); + write_client_reg(TIMER0LOAD, 0x00001388, TRUE); + write_client_reg(TIMER1CTRL, 0x00000060, TRUE); + write_client_reg(TIMER1LOAD, 0x00001388, TRUE); + write_client_reg(PWM1OFF, 0x00000087, TRUE); + } else { + write_client_reg(DRAMPWR, 0x00000001, TRUE); + write_client_reg(TIMER0CTRL, 0x00000060, TRUE); + write_client_reg(TIMER0LOAD, 0x00001388, TRUE); + write_client_reg(TIMER1CTRL, 0x00000060, TRUE); + write_client_reg(TIMER1LOAD, 0x00001388, TRUE); + write_client_reg(PWM1OFF, 0x00001387, TRUE); + } + + write_client_reg(TIMER0CTRL, 0x000000E0, TRUE); + write_client_reg(TIMER1CTRL, 0x000000E0, TRUE); + write_client_reg(PWMCR, 0x00000003, TRUE); + mddi_wait(1); + write_client_reg(SSICTL, 0x00000799, TRUE); + write_client_reg(SSITIME, 0x00000100, TRUE); + write_client_reg(SSICTL, 0x0000079b, TRUE); + write_client_reg(SSITX, 0x00000000, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x00000000, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x00000000, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x000800BA, TRUE); + write_client_reg(SSITX, 0x00000111, TRUE); + write_client_reg(SSITX, 0x00080036, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800BB, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + write_client_reg(SSITX, 0x0008003A, TRUE); + write_client_reg(SSITX, 0x00000160, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800BF, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + write_client_reg(SSITX, 0x000800B1, TRUE); + write_client_reg(SSITX, 0x0000015D, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800B2, TRUE); + write_client_reg(SSITX, 0x00000133, TRUE); + write_client_reg(SSITX, 0x000800B3, TRUE); + write_client_reg(SSITX, 0x00000122, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800B4, TRUE); + write_client_reg(SSITX, 0x00000102, TRUE); + write_client_reg(SSITX, 0x000800B5, TRUE); + write_client_reg(SSITX, 0x0000011F, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800B6, TRUE); + write_client_reg(SSITX, 0x00000128, TRUE); + write_client_reg(SSITX, 0x000800B7, TRUE); + write_client_reg(SSITX, 0x00000103, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800B9, TRUE); + write_client_reg(SSITX, 0x00000120, TRUE); + write_client_reg(SSITX, 0x000800BD, TRUE); + write_client_reg(SSITX, 0x00000102, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800BE, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + write_client_reg(SSITX, 0x000800C0, TRUE); + write_client_reg(SSITX, 0x00000111, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C1, TRUE); + write_client_reg(SSITX, 0x00000111, TRUE); + write_client_reg(SSITX, 0x000800C2, TRUE); + write_client_reg(SSITX, 0x00000111, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C3, TRUE); + write_client_reg(SSITX, 0x0008010A, TRUE); + write_client_reg(SSITX, 0x0000010A, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C4, TRUE); + write_client_reg(SSITX, 0x00080160, TRUE); + write_client_reg(SSITX, 0x00000160, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C5, TRUE); + write_client_reg(SSITX, 0x00080160, TRUE); + write_client_reg(SSITX, 0x00000160, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C6, TRUE); + write_client_reg(SSITX, 0x00080160, TRUE); + write_client_reg(SSITX, 0x00000160, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C7, TRUE); + write_client_reg(SSITX, 0x00080133, TRUE); + write_client_reg(SSITX, 0x00000143, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800C8, TRUE); + write_client_reg(SSITX, 0x00000144, TRUE); + write_client_reg(SSITX, 0x000800C9, TRUE); + write_client_reg(SSITX, 0x00000133, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800CA, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800EC, TRUE); + write_client_reg(SSITX, 0x00080102, TRUE); + write_client_reg(SSITX, 0x00000118, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800CF, TRUE); + write_client_reg(SSITX, 0x00000101, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D0, TRUE); + write_client_reg(SSITX, 0x00080110, TRUE); + write_client_reg(SSITX, 0x00000104, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D1, TRUE); + write_client_reg(SSITX, 0x00000101, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D2, TRUE); + write_client_reg(SSITX, 0x00080100, TRUE); + write_client_reg(SSITX, 0x0000013A, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D3, TRUE); + write_client_reg(SSITX, 0x00080100, TRUE); + write_client_reg(SSITX, 0x0000013A, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D4, TRUE); + write_client_reg(SSITX, 0x00080124, TRUE); + write_client_reg(SSITX, 0x0000016E, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x000800D5, TRUE); + write_client_reg(SSITX, 0x00000124, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800ED, TRUE); + write_client_reg(SSITX, 0x00080101, TRUE); + write_client_reg(SSITX, 0x0000010A, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D6, TRUE); + write_client_reg(SSITX, 0x00000101, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D7, TRUE); + write_client_reg(SSITX, 0x00080110, TRUE); + write_client_reg(SSITX, 0x0000010A, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D8, TRUE); + write_client_reg(SSITX, 0x00000101, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800D9, TRUE); + write_client_reg(SSITX, 0x00080100, TRUE); + write_client_reg(SSITX, 0x00000114, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800DE, TRUE); + write_client_reg(SSITX, 0x00080100, TRUE); + write_client_reg(SSITX, 0x00000114, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800DF, TRUE); + write_client_reg(SSITX, 0x00080112, TRUE); + write_client_reg(SSITX, 0x0000013F, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E0, TRUE); + write_client_reg(SSITX, 0x0000010B, TRUE); + write_client_reg(SSITX, 0x000800E2, TRUE); + write_client_reg(SSITX, 0x00000101, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E3, TRUE); + write_client_reg(SSITX, 0x00000136, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E4, TRUE); + write_client_reg(SSITX, 0x00080100, TRUE); + write_client_reg(SSITX, 0x00000103, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E5, TRUE); + write_client_reg(SSITX, 0x00080102, TRUE); + write_client_reg(SSITX, 0x00000104, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E6, TRUE); + write_client_reg(SSITX, 0x00000103, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E7, TRUE); + write_client_reg(SSITX, 0x00080104, TRUE); + write_client_reg(SSITX, 0x0000010A, TRUE); + mddi_wait(2); + write_client_reg(SSITX, 0x000800E8, TRUE); + write_client_reg(SSITX, 0x00000104, TRUE); + write_client_reg(CLKENB, 0x000001EF, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(WRSTB, 0x0000003F, TRUE); + write_client_reg(RDSTB, 0x00000432, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000000, TRUE); + write_client_reg(ASY_DATB, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(10); + write_client_reg(ASY_DATA, 0x80000000, TRUE); + write_client_reg(ASY_DATB, 0x80000000, TRUE); + write_client_reg(ASY_DATC, 0x80000000, TRUE); + write_client_reg(ASY_DATD, 0x80000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000009, TRUE); + write_client_reg(ASY_CMDSET, 0x00000008, TRUE); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(20); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + write_client_reg(VSYNIF, 0x00000001, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + } + + mddi_toshiba_state_transition(TOSHIBA_STATE_PRIM_SEC_STANDBY, + TOSHIBA_STATE_PRIM_SEC_READY); +} + +static void toshiba_prim_start(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) { + write_client_reg(BITMAP1, 0x01E000F0, TRUE); + write_client_reg(BITMAP2, 0x01E000F0, TRUE); + write_client_reg(BITMAP3, 0x01E000F0, TRUE); + write_client_reg(BITMAP4, 0x00DC00B0, TRUE); + write_client_reg(CLKENB, 0x000001EF, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + write_client_reg(PORT, 0x00000016, TRUE); + write_client_reg(PXL, 0x00000002, TRUE); + write_client_reg(MPLFBUF, 0x00000000, TRUE); + write_client_reg(HCYCLE, 0x00000185, TRUE); + write_client_reg(HSW, 0x00000018, TRUE); + write_client_reg(HDE_START, 0x0000004A, TRUE); + write_client_reg(HDE_SIZE, 0x000000EF, TRUE); + write_client_reg(VCYCLE, 0x0000028E, TRUE); + write_client_reg(VSW, 0x00000004, TRUE); + write_client_reg(VDE_START, 0x00000009, TRUE); + write_client_reg(VDE_SIZE, 0x0000027F, TRUE); + write_client_reg(START, 0x00000001, TRUE); + write_client_reg(SYSTEM_BLOCK1_BASE, 0x00000002, TRUE); + } else{ + + write_client_reg(VSYNIF, 0x00000001, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + write_client_reg(BITMAP1, 0x01E000F0, TRUE); + write_client_reg(BITMAP2, 0x01E000F0, TRUE); + write_client_reg(BITMAP3, 0x01E000F0, TRUE); + write_client_reg(BITMAP4, 0x00DC00B0, TRUE); + write_client_reg(CLKENB, 0x000001EF, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + write_client_reg(PORT, 0x00000004, TRUE); + write_client_reg(PXL, 0x00000002, TRUE); + write_client_reg(MPLFBUF, 0x00000000, TRUE); + + if (mddi_toshiba_61Hz_refresh) { + write_client_reg(HCYCLE, 0x000000FC, TRUE); + mddi_toshiba_rows_per_second = 39526; + mddi_toshiba_rows_per_refresh = 646; + mddi_toshiba_usecs_per_refresh = 16344; + } else { + write_client_reg(HCYCLE, 0x0000010b, TRUE); + mddi_toshiba_rows_per_second = 37313; + mddi_toshiba_rows_per_refresh = 646; + mddi_toshiba_usecs_per_refresh = 17313; + } + + write_client_reg(HSW, 0x00000003, TRUE); + write_client_reg(HDE_START, 0x00000007, TRUE); + write_client_reg(HDE_SIZE, 0x000000EF, TRUE); + write_client_reg(VCYCLE, 0x00000285, TRUE); + write_client_reg(VSW, 0x00000001, TRUE); + write_client_reg(VDE_START, 0x00000003, TRUE); + write_client_reg(VDE_SIZE, 0x0000027F, TRUE); + write_client_reg(START, 0x00000001, TRUE); + mddi_wait(10); + write_client_reg(SSITX, 0x000800BC, TRUE); + write_client_reg(SSITX, 0x00000180, TRUE); + write_client_reg(SSITX, 0x0008003B, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x000800B0, TRUE); + write_client_reg(SSITX, 0x00000116, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x000800B8, TRUE); + write_client_reg(SSITX, 0x000801FF, TRUE); + write_client_reg(SSITX, 0x000001F5, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x00000011, TRUE); + write_client_reg(SSITX, 0x00000029, TRUE); + write_client_reg(WKREQ, 0x00000000, TRUE); + write_client_reg(WAKEUP, 0x00000000, TRUE); + write_client_reg(INTMSK, 0x00000001, TRUE); + } + + mddi_toshiba_state_transition(TOSHIBA_STATE_PRIM_SEC_READY, + TOSHIBA_STATE_PRIM_NORMAL_MODE); +} + +static void toshiba_sec_start(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(CLKENB, 0x000011EF, TRUE); + write_client_reg(BITMAP0, 0x028001E0, TRUE); + write_client_reg(BITMAP1, 0x00000000, TRUE); + write_client_reg(BITMAP2, 0x00000000, TRUE); + write_client_reg(BITMAP3, 0x00000000, TRUE); + write_client_reg(BITMAP4, 0x00DC00B0, TRUE); + write_client_reg(PORT, 0x00000000, TRUE); + write_client_reg(PXL, 0x00000000, TRUE); + write_client_reg(MPLFBUF, 0x00000004, TRUE); + write_client_reg(HCYCLE, 0x0000006B, TRUE); + write_client_reg(HSW, 0x00000003, TRUE); + write_client_reg(HDE_START, 0x00000007, TRUE); + write_client_reg(HDE_SIZE, 0x00000057, TRUE); + write_client_reg(VCYCLE, 0x000000E6, TRUE); + write_client_reg(VSW, 0x00000001, TRUE); + write_client_reg(VDE_START, 0x00000003, TRUE); + write_client_reg(VDE_SIZE, 0x000000DB, TRUE); + write_client_reg(ASY_DATA, 0x80000001, TRUE); + write_client_reg(ASY_DATB, 0x0000011B, TRUE); + write_client_reg(ASY_DATC, 0x80000002, TRUE); + write_client_reg(ASY_DATD, 0x00000700, TRUE); + write_client_reg(ASY_DATE, 0x80000003, TRUE); + write_client_reg(ASY_DATF, 0x00000230, TRUE); + write_client_reg(ASY_DATG, 0x80000008, TRUE); + write_client_reg(ASY_DATH, 0x00000402, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000009, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_DATC, 0x8000000B, TRUE); + write_client_reg(ASY_DATD, 0x00000000, TRUE); + write_client_reg(ASY_DATE, 0x8000000C, TRUE); + write_client_reg(ASY_DATF, 0x00000000, TRUE); + write_client_reg(ASY_DATG, 0x8000000D, TRUE); + write_client_reg(ASY_DATH, 0x00000409, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x8000000E, TRUE); + write_client_reg(ASY_DATB, 0x00000409, TRUE); + write_client_reg(ASY_DATC, 0x80000030, TRUE); + write_client_reg(ASY_DATD, 0x00000000, TRUE); + write_client_reg(ASY_DATE, 0x80000031, TRUE); + write_client_reg(ASY_DATF, 0x00000100, TRUE); + write_client_reg(ASY_DATG, 0x80000032, TRUE); + write_client_reg(ASY_DATH, 0x00000104, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000033, TRUE); + write_client_reg(ASY_DATB, 0x00000400, TRUE); + write_client_reg(ASY_DATC, 0x80000034, TRUE); + write_client_reg(ASY_DATD, 0x00000306, TRUE); + write_client_reg(ASY_DATE, 0x80000035, TRUE); + write_client_reg(ASY_DATF, 0x00000706, TRUE); + write_client_reg(ASY_DATG, 0x80000036, TRUE); + write_client_reg(ASY_DATH, 0x00000707, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000037, TRUE); + write_client_reg(ASY_DATB, 0x00000004, TRUE); + write_client_reg(ASY_DATC, 0x80000038, TRUE); + write_client_reg(ASY_DATD, 0x00000000, TRUE); + write_client_reg(ASY_DATE, 0x80000039, TRUE); + write_client_reg(ASY_DATF, 0x00000000, TRUE); + write_client_reg(ASY_DATG, 0x8000003A, TRUE); + write_client_reg(ASY_DATH, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000044, TRUE); + write_client_reg(ASY_DATB, 0x0000AF00, TRUE); + write_client_reg(ASY_DATC, 0x80000045, TRUE); + write_client_reg(ASY_DATD, 0x0000DB00, TRUE); + write_client_reg(ASY_DATE, 0x08000042, TRUE); + write_client_reg(ASY_DATF, 0x0000DB00, TRUE); + write_client_reg(ASY_DATG, 0x80000021, TRUE); + write_client_reg(ASY_DATH, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(PXL, 0x0000000C, TRUE); + write_client_reg(VSYNIF, 0x00000001, TRUE); + write_client_reg(ASY_DATA, 0x80000022, TRUE); + write_client_reg(ASY_CMDSET, 0x00000003, TRUE); + write_client_reg(START, 0x00000001, TRUE); + mddi_wait(60); + write_client_reg(PXL, 0x00000000, TRUE); + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000050, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_DATC, 0x80000051, TRUE); + write_client_reg(ASY_DATD, 0x00000E00, TRUE); + write_client_reg(ASY_DATE, 0x80000052, TRUE); + write_client_reg(ASY_DATF, 0x00000D01, TRUE); + write_client_reg(ASY_DATG, 0x80000053, TRUE); + write_client_reg(ASY_DATH, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + write_client_reg(ASY_DATA, 0x80000058, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_DATC, 0x8000005A, TRUE); + write_client_reg(ASY_DATD, 0x00000E01, TRUE); + write_client_reg(ASY_CMDSET, 0x00000009, TRUE); + write_client_reg(ASY_CMDSET, 0x00000008, TRUE); + write_client_reg(ASY_DATA, 0x80000011, TRUE); + write_client_reg(ASY_DATB, 0x00000812, TRUE); + write_client_reg(ASY_DATC, 0x80000012, TRUE); + write_client_reg(ASY_DATD, 0x00000003, TRUE); + write_client_reg(ASY_DATE, 0x80000013, TRUE); + write_client_reg(ASY_DATF, 0x00000909, TRUE); + write_client_reg(ASY_DATG, 0x80000010, TRUE); + write_client_reg(ASY_DATH, 0x00000040, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + mddi_wait(40); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00000340, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(60); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00003340, TRUE); + write_client_reg(ASY_DATC, 0x80000007, TRUE); + write_client_reg(ASY_DATD, 0x00004007, TRUE); + write_client_reg(ASY_CMDSET, 0x00000009, TRUE); + write_client_reg(ASY_CMDSET, 0x00000008, TRUE); + mddi_wait(1); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004017, TRUE); + write_client_reg(ASY_DATC, 0x8000005B, TRUE); + write_client_reg(ASY_DATD, 0x00000000, TRUE); + write_client_reg(ASY_DATE, 0x80000059, TRUE); + write_client_reg(ASY_DATF, 0x00000011, TRUE); + write_client_reg(ASY_CMDSET, 0x0000000D, TRUE); + write_client_reg(ASY_CMDSET, 0x0000000C, TRUE); + mddi_wait(20); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + /* LTPS I/F control */ + write_client_reg(ASY_DATB, 0x00000019, TRUE); + /* Direct cmd transfer enable */ + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + /* Direct cmd transfer disable */ + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(20); + /* Index setting of SUB LCDD */ + write_client_reg(ASY_DATA, 0x80000059, TRUE); + /* LTPS I/F control */ + write_client_reg(ASY_DATB, 0x00000079, TRUE); + /* Direct cmd transfer enable */ + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + /* Direct cmd transfer disable */ + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(20); + /* Index setting of SUB LCDD */ + write_client_reg(ASY_DATA, 0x80000059, TRUE); + /* LTPS I/F control */ + write_client_reg(ASY_DATB, 0x000003FD, TRUE); + /* Direct cmd transfer enable */ + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + /* Direct cmd transfer disable */ + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(20); + mddi_toshiba_state_transition(TOSHIBA_STATE_PRIM_SEC_READY, + TOSHIBA_STATE_SEC_NORMAL_MODE); +} + +static void toshiba_prim_lcd_off(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) { + gordon_disp_off(); + } else{ + + /* Main panel power off (Deep standby in) */ + write_client_reg(SSITX, 0x000800BC, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + write_client_reg(SSITX, 0x00000028, TRUE); + mddi_wait(1); + write_client_reg(SSITX, 0x000800B8, TRUE); + write_client_reg(SSITX, 0x00000180, TRUE); + write_client_reg(SSITX, 0x00000102, TRUE); + write_client_reg(SSITX, 0x00000010, TRUE); + } + write_client_reg(PORT, 0x00000003, TRUE); + write_client_reg(REGENB, 0x00000001, TRUE); + mddi_wait(1); + write_client_reg(PXL, 0x00000000, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(REGENB, 0x00000001, TRUE); + mddi_wait(3); + if (TM_GET_PID(mfd->panel.id) != LCD_SHARP_2P4_VGA) { + write_client_reg(SSITX, 0x000800B0, TRUE); + write_client_reg(SSITX, 0x00000100, TRUE); + } + mddi_toshiba_state_transition(TOSHIBA_STATE_PRIM_NORMAL_MODE, + TOSHIBA_STATE_PRIM_SEC_STANDBY); +} + +static void toshiba_sec_lcd_off(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004016, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000019, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x0000000B, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000002, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(4); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00000300, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(4); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004004, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(PORT, 0x00000000, TRUE); + write_client_reg(PXL, 0x00000000, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(VSYNIF, 0x00000001, TRUE); + write_client_reg(PORT_ENB, 0x00000001, TRUE); + write_client_reg(REGENB, 0x00000001, TRUE); + mddi_toshiba_state_transition(TOSHIBA_STATE_SEC_NORMAL_MODE, + TOSHIBA_STATE_PRIM_SEC_STANDBY); +} + +static void toshiba_sec_cont_update_start(struct msm_fb_data_type *mfd) +{ + + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(INTMASK, 0x00000001, TRUE); + write_client_reg(TTBUSSEL, 0x0000000B, TRUE); + write_client_reg(MONI, 0x00000008, TRUE); + write_client_reg(CLKENB, 0x000000EF, TRUE); + write_client_reg(CLKENB, 0x000010EF, TRUE); + write_client_reg(CLKENB, 0x000011EF, TRUE); + write_client_reg(BITMAP4, 0x00DC00B0, TRUE); + write_client_reg(HCYCLE, 0x0000006B, TRUE); + write_client_reg(HSW, 0x00000003, TRUE); + write_client_reg(HDE_START, 0x00000002, TRUE); + write_client_reg(HDE_SIZE, 0x00000057, TRUE); + write_client_reg(VCYCLE, 0x000000E6, TRUE); + write_client_reg(VSW, 0x00000001, TRUE); + write_client_reg(VDE_START, 0x00000003, TRUE); + write_client_reg(VDE_SIZE, 0x000000DB, TRUE); + write_client_reg(WRSTB, 0x00000015, TRUE); + write_client_reg(MPLFBUF, 0x00000004, TRUE); + write_client_reg(ASY_DATA, 0x80000021, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_DATC, 0x80000022, TRUE); + write_client_reg(ASY_CMDSET, 0x00000007, TRUE); + write_client_reg(PXL, 0x00000089, TRUE); + write_client_reg(VSYNIF, 0x00000001, TRUE); + mddi_wait(2); +} + +static void toshiba_sec_cont_update_stop(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(PXL, 0x00000000, TRUE); + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + mddi_wait(3); + write_client_reg(SRST, 0x00000002, TRUE); + mddi_wait(3); + write_client_reg(SRST, 0x00000003, TRUE); +} + +static void toshiba_sec_backlight_on(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(TIMER0CTRL, 0x00000060, TRUE); + write_client_reg(TIMER0LOAD, 0x00001388, TRUE); + write_client_reg(PWM0OFF, 0x00000001, TRUE); + write_client_reg(TIMER1CTRL, 0x00000060, TRUE); + write_client_reg(TIMER1LOAD, 0x00001388, TRUE); + write_client_reg(PWM1OFF, 0x00001387, TRUE); + write_client_reg(TIMER0CTRL, 0x000000E0, TRUE); + write_client_reg(TIMER1CTRL, 0x000000E0, TRUE); + write_client_reg(PWMCR, 0x00000003, TRUE); +} + +static void toshiba_sec_sleep_in(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004016, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000019, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x0000000B, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000002, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(4); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00000300, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(4); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000000, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004004, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(PORT, 0x00000000, TRUE); + write_client_reg(PXL, 0x00000000, TRUE); + write_client_reg(START, 0x00000000, TRUE); + write_client_reg(REGENB, 0x00000001, TRUE); + /* Sleep in sequence */ + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00000302, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); +} + +static void toshiba_sec_sleep_out(struct msm_fb_data_type *mfd) +{ + if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) + return; + + write_client_reg(VSYNIF, 0x00000000, TRUE); + write_client_reg(PORT_ENB, 0x00000002, TRUE); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00000300, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + /* Display ON sequence */ + write_client_reg(ASY_DATA, 0x80000011, TRUE); + write_client_reg(ASY_DATB, 0x00000812, TRUE); + write_client_reg(ASY_DATC, 0x80000012, TRUE); + write_client_reg(ASY_DATD, 0x00000003, TRUE); + write_client_reg(ASY_DATE, 0x80000013, TRUE); + write_client_reg(ASY_DATF, 0x00000909, TRUE); + write_client_reg(ASY_DATG, 0x80000010, TRUE); + write_client_reg(ASY_DATH, 0x00000040, TRUE); + write_client_reg(ASY_CMDSET, 0x00000001, TRUE); + write_client_reg(ASY_CMDSET, 0x00000000, TRUE); + mddi_wait(4); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00000340, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(6); + write_client_reg(ASY_DATA, 0x80000010, TRUE); + write_client_reg(ASY_DATB, 0x00003340, TRUE); + write_client_reg(ASY_DATC, 0x80000007, TRUE); + write_client_reg(ASY_DATD, 0x00004007, TRUE); + write_client_reg(ASY_CMDSET, 0x00000009, TRUE); + write_client_reg(ASY_CMDSET, 0x00000008, TRUE); + mddi_wait(1); + write_client_reg(ASY_DATA, 0x80000007, TRUE); + write_client_reg(ASY_DATB, 0x00004017, TRUE); + write_client_reg(ASY_DATC, 0x8000005B, TRUE); + write_client_reg(ASY_DATD, 0x00000000, TRUE); + write_client_reg(ASY_DATE, 0x80000059, TRUE); + write_client_reg(ASY_DATF, 0x00000011, TRUE); + write_client_reg(ASY_CMDSET, 0x0000000D, TRUE); + write_client_reg(ASY_CMDSET, 0x0000000C, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000019, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x00000079, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); + write_client_reg(ASY_DATA, 0x80000059, TRUE); + write_client_reg(ASY_DATB, 0x000003FD, TRUE); + write_client_reg(ASY_CMDSET, 0x00000005, TRUE); + write_client_reg(ASY_CMDSET, 0x00000004, TRUE); + mddi_wait(2); +} + +static void mddi_toshiba_lcd_set_backlight(struct msm_fb_data_type *mfd) +{ + int32 level; + int ret = -EPERM; + int max = mfd->panel_info.bl_max; + int min = mfd->panel_info.bl_min; + int i = 0; + + if (mddi_toshiba_pdata && mddi_toshiba_pdata->pmic_backlight) { + while (i++ < 3) { + ret = mddi_toshiba_pdata->pmic_backlight(mfd->bl_level); + if (!ret) + return; + msleep(10); + } + printk(KERN_WARNING "%s: pmic_backlight Failed\n", __func__); + } + + + if (ret && mddi_toshiba_pdata && mddi_toshiba_pdata->backlight_level) { + level = mddi_toshiba_pdata->backlight_level(mfd->bl_level, + max, min); + + if (level < 0) + return; + + if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) + write_client_reg(TIMER0LOAD, 0x00001388, TRUE); + } else { + if (!max) + level = 0; + else + level = (mfd->bl_level * 4999) / max; + } + + write_client_reg(PWM0OFF, level, TRUE); +} + +static void mddi_toshiba_vsync_set_handler(msm_fb_vsync_handler_type handler, /* ISR to be executed */ + void *arg) +{ + boolean error = FALSE; + unsigned long flags; + + /* Disable interrupts */ + spin_lock_irqsave(&mddi_host_spin_lock, flags); + /* INTLOCK(); */ + + if (mddi_toshiba_vsync_handler != NULL) { + error = TRUE; + } else { + /* Register the handler for this particular GROUP interrupt source */ + mddi_toshiba_vsync_handler = handler; + mddi_toshiba_vsync_handler_arg = arg; + } + + /* Restore interrupts */ + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + /* MDDI_INTFREE(); */ + if (error) { + MDDI_MSG_ERR("MDDI: Previous Vsync handler never called\n"); + } else { + /* Enable the vsync wakeup */ + mddi_queue_register_write(INTMSK, 0x0000, FALSE, 0); + + mddi_toshiba_vsync_attempts = 1; + mddi_vsync_detect_enabled = TRUE; + } +} /* mddi_toshiba_vsync_set_handler */ + +static void mddi_toshiba_lcd_vsync_detected(boolean detected) +{ + /* static timetick_type start_time = 0; */ + static struct timeval start_time; + static boolean first_time = TRUE; + /* uint32 mdp_cnt_val = 0; */ + /* timetick_type elapsed_us; */ + struct timeval now; + uint32 elapsed_us; + uint32 num_vsyncs; + + if ((detected) || (mddi_toshiba_vsync_attempts > 5)) { + if ((detected) && (mddi_toshiba_monitor_refresh_value)) { + /* if (start_time != 0) */ + if (!first_time) { + jiffies_to_timeval(jiffies, &now); + elapsed_us = + (now.tv_sec - start_time.tv_sec) * 1000000 + + now.tv_usec - start_time.tv_usec; + /* + * LCD is configured for a refresh every usecs, + * so to determine the number of vsyncs that + * have occurred since the last measurement + * add half that to the time difference and + * divide by the refresh rate. + */ + num_vsyncs = (elapsed_us + + (mddi_toshiba_usecs_per_refresh >> + 1)) / + mddi_toshiba_usecs_per_refresh; + /* + * LCD is configured for * hsyncs (rows) per + * refresh cycle. Calculate new rows_per_second + * value based upon these new measurements. + * MDP can update with this new value. + */ + mddi_toshiba_rows_per_second = + (mddi_toshiba_rows_per_refresh * 1000 * + num_vsyncs) / (elapsed_us / 1000); + } + /* start_time = timetick_get(); */ + first_time = FALSE; + jiffies_to_timeval(jiffies, &start_time); + if (mddi_toshiba_report_refresh_measurements) { + (void)mddi_queue_register_read_int(VPOS, + &mddi_toshiba_curr_vpos); + /* mdp_cnt_val = MDP_LINE_COUNT; */ + } + } + /* if detected = TRUE, client initiated wakeup was detected */ + if (mddi_toshiba_vsync_handler != NULL) { + (*mddi_toshiba_vsync_handler) + (mddi_toshiba_vsync_handler_arg); + mddi_toshiba_vsync_handler = NULL; + } + mddi_vsync_detect_enabled = FALSE; + mddi_toshiba_vsync_attempts = 0; + /* need to disable the interrupt wakeup */ + if (!mddi_queue_register_write_int(INTMSK, 0x0001)) + MDDI_MSG_ERR("Vsync interrupt disable failed!\n"); + if (!detected) { + /* give up after 5 failed attempts but show error */ + MDDI_MSG_NOTICE("Vsync detection failed!\n"); + } else if ((mddi_toshiba_monitor_refresh_value) && + (mddi_toshiba_report_refresh_measurements)) { + MDDI_MSG_NOTICE(" Last Line Counter=%d!\n", + mddi_toshiba_curr_vpos); + /* MDDI_MSG_NOTICE(" MDP Line Counter=%d!\n",mdp_cnt_val); */ + MDDI_MSG_NOTICE(" Lines Per Second=%d!\n", + mddi_toshiba_rows_per_second); + } + /* clear the interrupt */ + if (!mddi_queue_register_write_int(INTFLG, 0x0001)) + MDDI_MSG_ERR("Vsync interrupt clear failed!\n"); + } else { + /* if detected = FALSE, we woke up from hibernation, but did not + * detect client initiated wakeup. + */ + mddi_toshiba_vsync_attempts++; + } +} + +static void mddi_toshiba_prim_init(struct msm_fb_data_type *mfd) +{ + + switch (toshiba_state) { + case TOSHIBA_STATE_PRIM_SEC_READY: + break; + case TOSHIBA_STATE_OFF: + toshiba_state = TOSHIBA_STATE_PRIM_SEC_STANDBY; + toshiba_common_initial_setup(mfd); + break; + case TOSHIBA_STATE_PRIM_SEC_STANDBY: + toshiba_common_initial_setup(mfd); + break; + case TOSHIBA_STATE_SEC_NORMAL_MODE: + toshiba_sec_cont_update_stop(mfd); + toshiba_sec_sleep_in(mfd); + toshiba_sec_sleep_out(mfd); + toshiba_sec_lcd_off(mfd); + toshiba_common_initial_setup(mfd); + break; + default: + MDDI_MSG_ERR("mddi_toshiba_prim_init from state %d\n", + toshiba_state); + } + + toshiba_prim_start(mfd); + if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) + gordon_disp_init(); + mddi_host_write_pix_attr_reg(0x00C3); +} + +static void mddi_toshiba_sec_init(struct msm_fb_data_type *mfd) +{ + + switch (toshiba_state) { + case TOSHIBA_STATE_PRIM_SEC_READY: + break; + case TOSHIBA_STATE_PRIM_SEC_STANDBY: + toshiba_common_initial_setup(mfd); + break; + case TOSHIBA_STATE_PRIM_NORMAL_MODE: + toshiba_prim_lcd_off(mfd); + toshiba_common_initial_setup(mfd); + break; + default: + MDDI_MSG_ERR("mddi_toshiba_sec_init from state %d\n", + toshiba_state); + } + + toshiba_sec_start(mfd); + toshiba_sec_backlight_on(mfd); + toshiba_sec_cont_update_start(mfd); + mddi_host_write_pix_attr_reg(0x0400); +} + +static void mddi_toshiba_lcd_powerdown(struct msm_fb_data_type *mfd) +{ + switch (toshiba_state) { + case TOSHIBA_STATE_PRIM_SEC_READY: + mddi_toshiba_prim_init(mfd); + mddi_toshiba_lcd_powerdown(mfd); + return; + case TOSHIBA_STATE_PRIM_SEC_STANDBY: + break; + case TOSHIBA_STATE_PRIM_NORMAL_MODE: + toshiba_prim_lcd_off(mfd); + break; + case TOSHIBA_STATE_SEC_NORMAL_MODE: + toshiba_sec_cont_update_stop(mfd); + toshiba_sec_sleep_in(mfd); + toshiba_sec_sleep_out(mfd); + toshiba_sec_lcd_off(mfd); + break; + default: + MDDI_MSG_ERR("mddi_toshiba_lcd_powerdown from state %d\n", + toshiba_state); + } +} + +static int mddi_sharpgordon_firsttime = 1; + +static int mddi_toshiba_lcd_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + mfd = platform_get_drvdata(pdev); + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + mddi_host_client_cnt_reset(); + + if (TM_GET_DID(mfd->panel.id) == TOSHIBA_VGA_PRIM) + mddi_toshiba_prim_init(mfd); + else + mddi_toshiba_sec_init(mfd); + if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) { + if (mddi_sharpgordon_firsttime) { + mddi_sharpgordon_firsttime = 0; + write_client_reg(REGENB, 0x00000001, TRUE); + } + } + return 0; +} + +static int mddi_toshiba_lcd_off(struct platform_device *pdev) +{ + if (mddi_toshiba_vsync_handler != NULL) { + (*mddi_toshiba_vsync_handler) + (mddi_toshiba_vsync_handler_arg); + mddi_toshiba_vsync_handler = NULL; + printk(KERN_INFO "%s: clean up vsyn_handler=%x\n", __func__, + (int)mddi_toshiba_vsync_handler); + } + + mddi_toshiba_lcd_powerdown(platform_get_drvdata(pdev)); + return 0; +} + +static int mddi_toshiba_lcd_probe(struct platform_device *pdev) +{ + if (pdev->id == 0) { + mddi_toshiba_pdata = pdev->dev.platform_data; + return 0; + } + + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = mddi_toshiba_lcd_probe, + .driver = { + .name = "mddi_toshiba", + }, +}; + +static struct msm_fb_panel_data toshiba_panel_data = { + .on = mddi_toshiba_lcd_on, + .off = mddi_toshiba_lcd_off, +}; + +static int ch_used[3]; + +int mddi_toshiba_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel) +{ + struct platform_device *pdev = NULL; + int ret; + + if ((channel >= 3) || ch_used[channel]) + return -ENODEV; + + if ((channel != TOSHIBA_VGA_PRIM) && + mddi_toshiba_pdata && mddi_toshiba_pdata->panel_num) + if (mddi_toshiba_pdata->panel_num() < 2) + return -ENODEV; + + ch_used[channel] = TRUE; + + pdev = platform_device_alloc("mddi_toshiba", (panel << 8)|channel); + if (!pdev) + return -ENOMEM; + + if (channel == TOSHIBA_VGA_PRIM) { + toshiba_panel_data.set_backlight = + mddi_toshiba_lcd_set_backlight; + + if (pinfo->lcd.vsync_enable) { + toshiba_panel_data.set_vsync_notifier = + mddi_toshiba_vsync_set_handler; + mddi_lcd.vsync_detected = + mddi_toshiba_lcd_vsync_detected; + } + } else { + toshiba_panel_data.set_backlight = NULL; + toshiba_panel_data.set_vsync_notifier = NULL; + } + + toshiba_panel_data.panel_info = *pinfo; + + ret = platform_device_add_data(pdev, &toshiba_panel_data, + sizeof(toshiba_panel_data)); + if (ret) { + printk(KERN_ERR + "%s: platform_device_add_data failed!\n", __func__); + goto err_device_put; + } + + ret = platform_device_add(pdev); + if (ret) { + printk(KERN_ERR + "%s: platform_device_register failed!\n", __func__); + goto err_device_put; + } + + return 0; + +err_device_put: + platform_device_put(pdev); + return ret; +} + +static int __init mddi_toshiba_lcd_init(void) +{ + return platform_driver_register(&this_driver); +} + +module_init(mddi_toshiba_lcd_init); diff --git a/drivers/video/msm/mddi_toshiba.h b/drivers/video/msm/mddi_toshiba.h new file mode 100644 index 000000000000..854817fb6b5b --- /dev/null +++ b/drivers/video/msm/mddi_toshiba.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2009, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef MDDI_TOSHIBA_H +#define MDDI_TOSHIBA_H + +#define TOSHIBA_VGA_PRIM 1 +#define TOSHIBA_VGA_SECD 2 + +#define LCD_TOSHIBA_2P4_VGA 0 +#define LCD_TOSHIBA_2P4_WVGA 1 +#define LCD_TOSHIBA_2P4_WVGA_PT 2 +#define LCD_SHARP_2P4_VGA 3 + +#define GPIO_BLOCK_BASE 0x150000 +#define SYSTEM_BLOCK2_BASE 0x170000 + +#define GPIODIR (GPIO_BLOCK_BASE|0x04) +#define GPIOSEL (SYSTEM_BLOCK2_BASE|0x00) +#define GPIOPC (GPIO_BLOCK_BASE|0x28) +#define GPIODATA (GPIO_BLOCK_BASE|0x00) + +#define write_client_reg(__X, __Y, __Z) {\ + mddi_queue_register_write(__X, __Y, TRUE, 0);\ +} + +#endif /* MDDI_TOSHIBA_H */ diff --git a/drivers/video/msm/mddi_toshiba_vga.c b/drivers/video/msm/mddi_toshiba_vga.c new file mode 100644 index 000000000000..3b4a85d8bb96 --- /dev/null +++ b/drivers/video/msm/mddi_toshiba_vga.c @@ -0,0 +1,134 @@ +/* Copyright (c) 2009-2010, 2012 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mddihost.h" +#include "mddihosti.h" +#include "mddi_toshiba.h" + +static uint32 read_client_reg(uint32 addr) +{ + uint32 val; + mddi_queue_register_read(addr, &val, TRUE, 0); + return val; +} + +static uint32 toshiba_lcd_gpio_read(void) +{ + uint32 val; + + write_client_reg(GPIODIR, 0x0000000C, TRUE); + write_client_reg(GPIOSEL, 0x00000000, TRUE); + write_client_reg(GPIOSEL, 0x00000000, TRUE); + write_client_reg(GPIOPC, 0x03CF00C0, TRUE); + val = read_client_reg(GPIODATA) & 0x2C0; + + return val; +} + +static u32 mddi_toshiba_panel_detect(void) +{ + mddi_host_type host_idx = MDDI_HOST_PRIM; + uint32 lcd_gpio; + u32 mddi_toshiba_lcd = LCD_TOSHIBA_2P4_VGA; + + /* Toshiba display requires larger drive_lo value */ + mddi_host_reg_out(DRIVE_LO, 0x0050); + + lcd_gpio = toshiba_lcd_gpio_read(); + switch (lcd_gpio) { + case 0x0080: + mddi_toshiba_lcd = LCD_SHARP_2P4_VGA; + break; + + case 0x00C0: + default: + mddi_toshiba_lcd = LCD_TOSHIBA_2P4_VGA; + break; + } + + return mddi_toshiba_lcd; +} + +static int __init mddi_toshiba_vga_init(void) +{ + int ret; + struct msm_panel_info pinfo; + u32 panel; + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + u32 id; + + ret = msm_fb_detect_client("mddi_toshiba_vga"); + if (ret == -ENODEV) + return 0; + + if (ret) { + id = mddi_get_client_id(); + if ((id >> 16) != 0xD263) + return 0; + } +#endif + + panel = mddi_toshiba_panel_detect(); + + pinfo.xres = 480; + pinfo.yres = 640; + pinfo.type = MDDI_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR; + pinfo.wait_cycle = 0; + pinfo.bpp = 18; + pinfo.lcd.vsync_enable = TRUE; + pinfo.mddi.is_type1 = TRUE; + pinfo.lcd.refx100 = 6118; + pinfo.lcd.v_back_porch = 6; + pinfo.lcd.v_front_porch = 0; + pinfo.lcd.v_pulse_width = 0; + pinfo.lcd.hw_vsync_mode = FALSE; + pinfo.lcd.vsync_notifier_period = (1 * HZ); + pinfo.bl_max = 99; + pinfo.bl_min = 1; + pinfo.clk_rate = 122880000; + pinfo.clk_min = 120000000; + pinfo.clk_max = 200000000; + pinfo.fb_num = 2; + + ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_PRIM, panel); + if (ret) { + printk(KERN_ERR "%s: failed to register device!\n", __func__); + return ret; + } + + pinfo.xres = 176; + pinfo.yres = 220; + MSM_FB_SINGLE_MODE_PANEL(&pinfo); + pinfo.type = MDDI_PANEL; + pinfo.pdest = DISPLAY_2; + pinfo.mddi.vdopkt = 0x400; + pinfo.wait_cycle = 0; + pinfo.bpp = 18; + pinfo.clk_rate = 122880000; + pinfo.clk_min = 120000000; + pinfo.clk_max = 200000000; + pinfo.fb_num = 2; + + ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_SECD, panel); + if (ret) + printk(KERN_WARNING + "%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mddi_toshiba_vga_init); diff --git a/drivers/video/msm/mddi_toshiba_wvga.c b/drivers/video/msm/mddi_toshiba_wvga.c new file mode 100644 index 000000000000..7e7b0363cada --- /dev/null +++ b/drivers/video/msm/mddi_toshiba_wvga.c @@ -0,0 +1,61 @@ +/* Copyright (c) 2009-2010, 2012 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mddihost.h" +#include "mddi_toshiba.h" + +static int __init mddi_toshiba_wvga_init(void) +{ + int ret; + struct msm_panel_info pinfo; + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + if (msm_fb_detect_client("mddi_toshiba_wvga")) + return 0; +#endif + + pinfo.xres = 800; + pinfo.yres = 480; + MSM_FB_SINGLE_MODE_PANEL(&pinfo); + pinfo.pdest = DISPLAY_2; + pinfo.type = MDDI_PANEL; + pinfo.mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR; + pinfo.wait_cycle = 0; + pinfo.bpp = 18; + pinfo.lcd.vsync_enable = TRUE; + pinfo.mddi.is_type1 = TRUE; + pinfo.lcd.refx100 = 6118; + pinfo.lcd.v_back_porch = 6; + pinfo.lcd.v_front_porch = 0; + pinfo.lcd.v_pulse_width = 0; + pinfo.lcd.hw_vsync_mode = FALSE; + pinfo.lcd.vsync_notifier_period = (1 * HZ); + pinfo.bl_max = 4; + pinfo.bl_min = 1; + pinfo.clk_rate = 192000000; + pinfo.clk_min = 190000000; + pinfo.clk_max = 200000000; + pinfo.fb_num = 2; + + ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_PRIM, + LCD_TOSHIBA_2P4_WVGA); + if (ret) { + printk(KERN_ERR "%s: failed to register device!\n", __func__); + return ret; + } + + return ret; +} + +module_init(mddi_toshiba_wvga_init); diff --git a/drivers/video/msm/mddi_toshiba_wvga_pt.c b/drivers/video/msm/mddi_toshiba_wvga_pt.c new file mode 100644 index 000000000000..bdb04ff062d8 --- /dev/null +++ b/drivers/video/msm/mddi_toshiba_wvga_pt.c @@ -0,0 +1,69 @@ +/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mddihost.h" +#include "mddihosti.h" +#include "mddi_toshiba.h" + +static struct msm_panel_info pinfo; + +static int __init mddi_toshiba_wvga_pt_init(void) +{ + int ret; +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + uint id; + + ret = msm_fb_detect_client("mddi_toshiba_wvga_pt"); + if (ret == -ENODEV) + return 0; + + if (ret) { + id = mddi_get_client_id(); + if (id != 0xd2638722) + return 0; + } +#endif + + pinfo.xres = 480; + pinfo.yres = 800; + MSM_FB_SINGLE_MODE_PANEL(&pinfo); + pinfo.type = MDDI_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR; + pinfo.wait_cycle = 0; + pinfo.bpp = 18; + pinfo.lcd.vsync_enable = TRUE; + pinfo.lcd.refx100 = 6102; /* adjust refx100 to prevent tearing */ + pinfo.mddi.is_type1 = TRUE; + pinfo.lcd.v_back_porch = 8; /* vsw=10 + vbp = 8 */ + pinfo.lcd.v_front_porch = 2; + pinfo.lcd.v_pulse_width = 10; + pinfo.lcd.hw_vsync_mode = FALSE; + pinfo.lcd.vsync_notifier_period = (1 * HZ); + pinfo.bl_max = 15; + pinfo.bl_min = 1; + pinfo.clk_rate = 222750000; + pinfo.clk_min = 200000000; + pinfo.clk_max = 240000000; + pinfo.fb_num = 2; + + ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_PRIM, + LCD_TOSHIBA_2P4_WVGA_PT); + if (ret) + printk(KERN_ERR "%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mddi_toshiba_wvga_pt_init); diff --git a/drivers/video/msm/mddihost.c b/drivers/video/msm/mddihost.c new file mode 100644 index 000000000000..c2a7af3d70cd --- /dev/null +++ b/drivers/video/msm/mddihost.c @@ -0,0 +1,626 @@ +/* Copyright (c) 2008-2009, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_fb.h" +#include "mddihost.h" +#include "mddihosti.h" + +#include +#include + +struct semaphore mddi_host_mutex; + +struct clk *mddi_io_clk; +static boolean mddi_host_powered = FALSE; +static boolean mddi_host_initialized = FALSE; +extern uint32 *mddi_reg_read_value_ptr; + +mddi_lcd_func_type mddi_lcd; + +extern mddi_client_capability_type mddi_client_capability_pkt; + +#ifdef MDDI_HOST_WINDOW_WORKAROUND +/* Tables showing number of rows that would cause a packet length + * ending in 0x02, for each number of columns. These tables have + * been generated for MDDI packets that have 16 and 16 bits-per-pixel. + * This is a work-around for MDDI clients that declare a CRC error + * on MDDI packets where ((length & 0x00ff) == 0x02). + */ +static uint16 error_vals_16bpp[] = { +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 10, 0, 0, 0, 14, 0, 0, 0, 2, 0, 0, 4, 6, 12, 0, +0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, +0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 11, 4, 0, 12, 0, +0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, +0, 10, 0, 1, 0, 14, 0, 0, 0, 2, 0, 3, 4, 6, 12, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 10, 0, 0, 0, 14, 0, 0, 0, 2, 0, 0, 4, 6, 12, 0, +0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, +0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 11, 4, 0, 12, 0, +0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, +}; + +static uint16 error_vals_18bpp[] = { +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 14, +0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 9, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 7, +0, 0, 0, 0, 0, 0, 1, 0, 0, 16, 0, 0, 0, 0, 0, 6, +14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +7, 0, 0, 0, 0, 0, 0, 4, 0, 16, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, +0, 7, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 9, 0 +}; +#endif + +#ifdef FEATURE_MDDI_HITACHI +extern void mddi_hitachi_window_adjust(uint16 x1, + uint16 x2, uint16 y1, uint16 y2); +#endif + +extern void mddi_toshiba_lcd_init(void); + +#ifdef FEATURE_MDDI_S6D0142 +extern void mddi_s6d0142_lcd_init(void); +extern void mddi_s6d0142_window_adjust(uint16 x1, + uint16 x2, + uint16 y1, + uint16 y2, + mddi_llist_done_cb_type done_cb); +#endif + +void mddi_init(void) +{ + if (mddi_host_initialized) + return; + + mddi_host_initialized = TRUE; + + sema_init(&mddi_host_mutex, 1); + + if (!mddi_host_powered) { + down(&mddi_host_mutex); + mddi_host_init(MDDI_HOST_PRIM); + mddi_host_powered = TRUE; + up(&mddi_host_mutex); + mdelay(10); + } +} + +int mddi_host_register_read(uint32 reg_addr, + uint32 *reg_value_ptr, boolean wait, mddi_host_type host) { + mddi_linked_list_type *curr_llist_ptr; + mddi_register_access_packet_type *regacc_pkt_ptr; + uint16 curr_llist_idx; + int ret = 0; + + if (in_interrupt()) + MDDI_MSG_CRIT("Called from ISR context\n"); + + if (!mddi_host_powered) { + MDDI_MSG_ERR("MDDI powered down!\n"); + mddi_init(); + } + + down(&mddi_host_mutex); + + mddi_reg_read_value_ptr = reg_value_ptr; + curr_llist_idx = mddi_get_reg_read_llist_item(host, TRUE); + if (curr_llist_idx == UNASSIGNED_INDEX) { + up(&mddi_host_mutex); + + /* need to change this to some sort of wait */ + MDDI_MSG_ERR("Attempting to queue up more than 1 reg read\n"); + return -EINVAL; + } + + curr_llist_ptr = &llist_extern[host][curr_llist_idx]; + curr_llist_ptr->link_controller_flags = 0x11; + curr_llist_ptr->packet_header_count = 14; + curr_llist_ptr->packet_data_count = 0; + + curr_llist_ptr->next_packet_pointer = NULL; + curr_llist_ptr->packet_data_pointer = NULL; + curr_llist_ptr->reserved = 0; + + regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt; + + regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count; + regacc_pkt_ptr->packet_type = 146; /* register access packet */ + regacc_pkt_ptr->bClient_ID = 0; + regacc_pkt_ptr->read_write_info = 0x8001; + regacc_pkt_ptr->register_address = reg_addr; + + /* now adjust pointers */ + mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait, + NULL, host); + /* need to check if we can write the pointer or not */ + + up(&mddi_host_mutex); + + if (wait) { + int wait_ret; + + mddi_linked_list_notify_type *llist_notify_ptr; + llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx]; + wait_ret = wait_for_completion_timeout( + &(llist_notify_ptr->done_comp), 5 * HZ); + + if (wait_ret <= 0) + ret = -EBUSY; + + if (wait_ret < 0) + printk(KERN_ERR "%s: failed to wait for completion!\n", + __func__); + else if (!wait_ret) + printk(KERN_ERR "%s: Timed out waiting!\n", __func__); + + if (!ret && (mddi_reg_read_value_ptr == reg_value_ptr) && + (*reg_value_ptr == -EBUSY)) { + printk(KERN_ERR "%s - failed to get data from client", + __func__); + mddi_reg_read_value_ptr = NULL; + ret = -EBUSY; + } + } + + MDDI_MSG_DEBUG("Reg Read value=0x%x\n", *reg_value_ptr); + + return ret; +} /* mddi_host_register_read */ + +int mddi_host_register_write(uint32 reg_addr, + uint32 reg_val, enum mddi_data_packet_size_type packet_size, + boolean wait, mddi_llist_done_cb_type done_cb, mddi_host_type host) { + mddi_linked_list_type *curr_llist_ptr; + mddi_linked_list_type *curr_llist_dma_ptr; + mddi_register_access_packet_type *regacc_pkt_ptr; + uint16 curr_llist_idx; + int ret = 0; + + if (in_interrupt()) + MDDI_MSG_CRIT("Called from ISR context\n"); + + if (!mddi_host_powered) { + MDDI_MSG_ERR("MDDI powered down!\n"); + mddi_init(); + } + + down(&mddi_host_mutex); + + curr_llist_idx = mddi_get_next_free_llist_item(host, TRUE); + curr_llist_ptr = &llist_extern[host][curr_llist_idx]; + curr_llist_dma_ptr = &llist_dma_extern[host][curr_llist_idx]; + + curr_llist_ptr->link_controller_flags = 1; + curr_llist_ptr->packet_header_count = 14; + curr_llist_ptr->packet_data_count = 4; + + curr_llist_ptr->next_packet_pointer = NULL; + curr_llist_ptr->reserved = 0; + + regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt; + + regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count + + (uint16)packet_size; + regacc_pkt_ptr->packet_type = 146; /* register access packet */ + regacc_pkt_ptr->bClient_ID = 0; + regacc_pkt_ptr->read_write_info = 0x0001; + regacc_pkt_ptr->register_address = reg_addr; + regacc_pkt_ptr->register_data_list[0] = reg_val; + + MDDI_MSG_DEBUG("Reg Access write reg=0x%x, value=0x%x\n", + regacc_pkt_ptr->register_address, + regacc_pkt_ptr->register_data_list[0]); + + regacc_pkt_ptr = &curr_llist_dma_ptr->packet_header.register_pkt; + curr_llist_ptr->packet_data_pointer = + (void *)(®acc_pkt_ptr->register_data_list[0]); + + /* now adjust pointers */ + mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait, + done_cb, host); + + up(&mddi_host_mutex); + + if (wait) { + int wait_ret; + + mddi_linked_list_notify_type *llist_notify_ptr; + llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx]; + wait_ret = wait_for_completion_timeout( + &(llist_notify_ptr->done_comp), 5 * HZ); + + if (wait_ret <= 0) + ret = -EBUSY; + + if (wait_ret < 0) + printk(KERN_ERR "%s: failed to wait for completion!\n", + __func__); + else if (!wait_ret) + printk(KERN_ERR "%s: Timed out waiting!\n", __func__); + } + + return ret; +} /* mddi_host_register_write */ + +boolean mddi_host_register_read_int + (uint32 reg_addr, uint32 *reg_value_ptr, mddi_host_type host) { + mddi_linked_list_type *curr_llist_ptr; + mddi_register_access_packet_type *regacc_pkt_ptr; + uint16 curr_llist_idx; + + if (!in_interrupt()) + MDDI_MSG_CRIT("Called from TASK context\n"); + + if (!mddi_host_powered) { + MDDI_MSG_ERR("MDDI powered down!\n"); + return FALSE; + } + + if (down_trylock(&mddi_host_mutex) != 0) + return FALSE; + + mddi_reg_read_value_ptr = reg_value_ptr; + curr_llist_idx = mddi_get_reg_read_llist_item(host, FALSE); + if (curr_llist_idx == UNASSIGNED_INDEX) { + up(&mddi_host_mutex); + return FALSE; + } + + curr_llist_ptr = &llist_extern[host][curr_llist_idx]; + curr_llist_ptr->link_controller_flags = 0x11; + curr_llist_ptr->packet_header_count = 14; + curr_llist_ptr->packet_data_count = 0; + + curr_llist_ptr->next_packet_pointer = NULL; + curr_llist_ptr->packet_data_pointer = NULL; + curr_llist_ptr->reserved = 0; + + regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt; + + regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count; + regacc_pkt_ptr->packet_type = 146; /* register access packet */ + regacc_pkt_ptr->bClient_ID = 0; + regacc_pkt_ptr->read_write_info = 0x8001; + regacc_pkt_ptr->register_address = reg_addr; + + /* now adjust pointers */ + mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, FALSE, + NULL, host); + /* need to check if we can write the pointer or not */ + + up(&mddi_host_mutex); + + return TRUE; + +} /* mddi_host_register_read */ + +boolean mddi_host_register_write_int + (uint32 reg_addr, + uint32 reg_val, mddi_llist_done_cb_type done_cb, mddi_host_type host) { + mddi_linked_list_type *curr_llist_ptr; + mddi_linked_list_type *curr_llist_dma_ptr; + mddi_register_access_packet_type *regacc_pkt_ptr; + uint16 curr_llist_idx; + + if (!in_interrupt()) + MDDI_MSG_CRIT("Called from TASK context\n"); + + if (!mddi_host_powered) { + MDDI_MSG_ERR("MDDI powered down!\n"); + return FALSE; + } + + if (down_trylock(&mddi_host_mutex) != 0) + return FALSE; + + curr_llist_idx = mddi_get_next_free_llist_item(host, FALSE); + if (curr_llist_idx == UNASSIGNED_INDEX) { + up(&mddi_host_mutex); + return FALSE; + } + + curr_llist_ptr = &llist_extern[host][curr_llist_idx]; + curr_llist_dma_ptr = &llist_dma_extern[host][curr_llist_idx]; + + curr_llist_ptr->link_controller_flags = 1; + curr_llist_ptr->packet_header_count = 14; + curr_llist_ptr->packet_data_count = 4; + + curr_llist_ptr->next_packet_pointer = NULL; + curr_llist_ptr->reserved = 0; + + regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt; + + regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count + 4; + regacc_pkt_ptr->packet_type = 146; /* register access packet */ + regacc_pkt_ptr->bClient_ID = 0; + regacc_pkt_ptr->read_write_info = 0x0001; + regacc_pkt_ptr->register_address = reg_addr; + regacc_pkt_ptr->register_data_list[0] = reg_val; + + regacc_pkt_ptr = &curr_llist_dma_ptr->packet_header.register_pkt; + curr_llist_ptr->packet_data_pointer = + (void *)(&(regacc_pkt_ptr->register_data_list[0])); + + /* now adjust pointers */ + mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, FALSE, + done_cb, host); + up(&mddi_host_mutex); + + return TRUE; + +} /* mddi_host_register_write */ + +void mddi_wait(uint16 time_ms) +{ + mdelay(time_ms); +} + +void mddi_client_lcd_vsync_detected(boolean detected) +{ + if (mddi_lcd.vsync_detected) + (*mddi_lcd.vsync_detected) (detected); +} + +/* extended version of function includes done callback */ +void mddi_window_adjust_ext(struct msm_fb_data_type *mfd, + uint16 x1, + uint16 x2, + uint16 y1, + uint16 y2, mddi_llist_done_cb_type done_cb) +{ +#ifdef FEATURE_MDDI_HITACHI + if (mfd->panel.id == HITACHI) + mddi_hitachi_window_adjust(x1, x2, y1, y2); +#elif defined(FEATURE_MDDI_S6D0142) + if (mfd->panel.id == MDDI_LCD_S6D0142) + mddi_s6d0142_window_adjust(x1, x2, y1, y2, done_cb); +#else + /* Do nothing then... except avoid lint/compiler warnings */ + (void)x1; + (void)x2; + (void)y1; + (void)y2; + (void)done_cb; +#endif +} + +void mddi_window_adjust(struct msm_fb_data_type *mfd, + uint16 x1, uint16 x2, uint16 y1, uint16 y2) +{ + mddi_window_adjust_ext(mfd, x1, x2, y1, y2, NULL); +} + +#ifdef MDDI_HOST_WINDOW_WORKAROUND +uint16 mddi_assign_pkt_height(uint16 pkt_width, + uint16 pkt_height, uint16 bpp) +{ + uint16 new_pkt_height; + uint16 problem_height = 0; + + if (pkt_width <= 240) { + if (bpp == 16) + problem_height = error_vals_16bpp[pkt_width-1]; + else if (bpp == 18) + problem_height = error_vals_18bpp[pkt_width-1]; + else { + printk(KERN_ERR"Invalid bpp value"); + return -EINVAL; + } + } + if (problem_height == pkt_height) + new_pkt_height = problem_height - 1; + else + new_pkt_height = pkt_height; + + return new_pkt_height; +} +#endif + +#ifdef ENABLE_MDDI_MULTI_READ_WRITE +int mddi_host_register_multiwrite(uint32 reg_addr, + uint32 *value_list_ptr, + uint32 value_count, boolean wait, mddi_llist_done_cb_type done_cb, + mddi_host_type host) +{ + mddi_linked_list_type *curr_llist_ptr; + mddi_linked_list_type *curr_llist_dma_ptr; + mddi_register_access_packet_type *regacc_pkt_ptr; + uint16 curr_llist_idx; + int ret = 0; + + if (!value_list_ptr || !value_count || + value_count > MDDI_HOST_MAX_CLIENT_REG_IN_SAME_ADDR) { + MDDI_MSG_ERR("\n Invalid value_list or value_count"); + return -EINVAL; + } + + if (in_interrupt()) + MDDI_MSG_CRIT("Called from ISR context\n"); + + if (!mddi_host_powered) { + MDDI_MSG_ERR("MDDI powered down!\n"); + mddi_init(); + } + + down(&mddi_host_mutex); + + curr_llist_idx = mddi_get_next_free_llist_item(host, TRUE); + curr_llist_ptr = &llist_extern[host][curr_llist_idx]; + curr_llist_dma_ptr = &llist_dma_extern[host][curr_llist_idx]; + + curr_llist_ptr->link_controller_flags = 1; + curr_llist_ptr->packet_header_count = 14; + curr_llist_ptr->packet_data_count = + (uint16)(value_count * 4); + + curr_llist_ptr->next_packet_pointer = NULL; + curr_llist_ptr->reserved = 0; + + regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt; + + regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count + + curr_llist_ptr->packet_data_count; + regacc_pkt_ptr->packet_type = 146; /* register access packet */ + regacc_pkt_ptr->bClient_ID = 0; + regacc_pkt_ptr->read_write_info = value_count; + regacc_pkt_ptr->register_address = reg_addr; + memcpy((void *)®acc_pkt_ptr->register_data_list[0], value_list_ptr, + curr_llist_ptr->packet_data_count); + + regacc_pkt_ptr = &curr_llist_dma_ptr->packet_header.register_pkt; + curr_llist_ptr->packet_data_pointer = + (void *)(®acc_pkt_ptr->register_data_list[0]); + MDDI_MSG_DEBUG("MultiReg Access write reg=0x%x, value[0]=0x%x\n", + regacc_pkt_ptr->register_address, + regacc_pkt_ptr->register_data_list[0]); + + /* now adjust pointers */ + mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait, + done_cb, host); + + up(&mddi_host_mutex); + + if (wait) { + int wait_ret; + + mddi_linked_list_notify_type *llist_notify_ptr; + llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx]; + wait_ret = wait_for_completion_timeout( + &(llist_notify_ptr->done_comp), 5 * HZ); + + if (wait_ret <= 0) + ret = -EBUSY; + + if (wait_ret < 0) + printk(KERN_ERR "%s: failed to wait for completion!\n", + __func__); + else if (!wait_ret) + printk(KERN_ERR "%s: Timed out waiting!\n", __func__); + } + + return ret; +} + +int mddi_host_register_multiread(uint32 reg_addr, + uint32 *value_list_ptr, uint32 value_count, + boolean wait, mddi_host_type host) { + mddi_linked_list_type *curr_llist_ptr; + mddi_register_access_packet_type *regacc_pkt_ptr; + uint16 curr_llist_idx; + int ret = 0; + + if (!value_list_ptr || !value_count || + value_count >= MDDI_HOST_MAX_CLIENT_REG_IN_SAME_ADDR) { + MDDI_MSG_ERR("\n Invalid value_list or value_count"); + return -EINVAL; + } + + if (in_interrupt()) + MDDI_MSG_CRIT("Called from ISR context\n"); + + if (!mddi_host_powered) { + MDDI_MSG_ERR("MDDI powered down!\n"); + mddi_init(); + } + + down(&mddi_host_mutex); + + mddi_reg_read_value_ptr = value_list_ptr; + curr_llist_idx = mddi_get_reg_read_llist_item(host, TRUE); + if (curr_llist_idx == UNASSIGNED_INDEX) { + up(&mddi_host_mutex); + + /* need to change this to some sort of wait */ + MDDI_MSG_ERR("Attempting to queue up more than 1 reg read\n"); + return -EINVAL; + } + + curr_llist_ptr = &llist_extern[host][curr_llist_idx]; + curr_llist_ptr->link_controller_flags = 0x11; + curr_llist_ptr->packet_header_count = 14; + curr_llist_ptr->packet_data_count = 0; + + curr_llist_ptr->next_packet_pointer = NULL; + curr_llist_ptr->packet_data_pointer = NULL; + curr_llist_ptr->reserved = 0; + + regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt; + + regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count; + regacc_pkt_ptr->packet_type = 146; /* register access packet */ + regacc_pkt_ptr->bClient_ID = 0; + regacc_pkt_ptr->read_write_info = 0x8000 | value_count; + regacc_pkt_ptr->register_address = reg_addr; + + /* now adjust pointers */ + mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait, + NULL, host); + /* need to check if we can write the pointer or not */ + + up(&mddi_host_mutex); + + if (wait) { + int wait_ret; + + mddi_linked_list_notify_type *llist_notify_ptr; + llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx]; + wait_ret = wait_for_completion_timeout( + &(llist_notify_ptr->done_comp), 5 * HZ); + + if (wait_ret <= 0) + ret = -EBUSY; + + if (wait_ret < 0) + printk(KERN_ERR "%s: failed to wait for completion!\n", + __func__); + else if (!wait_ret) + printk(KERN_ERR "%s: Timed out waiting!\n", __func__); + + if (!ret && (mddi_reg_read_value_ptr == value_list_ptr) && + (*value_list_ptr == -EBUSY)) { + printk(KERN_ERR "%s - failed to get data from client", + __func__); + mddi_reg_read_value_ptr = NULL; + ret = -EBUSY; + } + } + + MDDI_MSG_DEBUG("MultiReg Read value[0]=0x%x\n", *value_list_ptr); + + return ret; +} +#endif diff --git a/drivers/video/msm/mddihost.h b/drivers/video/msm/mddihost.h new file mode 100644 index 000000000000..db2df38aebe4 --- /dev/null +++ b/drivers/video/msm/mddihost.h @@ -0,0 +1,231 @@ +/* Copyright (c) 2008-2009, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef MDDIHOST_H +#define MDDIHOST_H + +#include +#include +#include +#include +#include +#include "linux/proc_fs.h" +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "msm_fb_panel.h" + +#undef FEATURE_MDDI_MC4 +#undef FEATURE_MDDI_S6D0142 +#undef FEATURE_MDDI_HITACHI +#define FEATURE_MDDI_SHARP +#define FEATURE_MDDI_TOSHIBA +#undef FEATURE_MDDI_E751 +#define FEATURE_MDDI_CORONA +#define FEATURE_MDDI_PRISM + +#define T_MSM7500 + +typedef enum { + format_16bpp, + format_18bpp, + format_24bpp +} mddi_video_format; + +typedef enum { + MDDI_LCD_NONE = 0, + MDDI_LCD_MC4, + MDDI_LCD_S6D0142, + MDDI_LCD_SHARP, + MDDI_LCD_E751, + MDDI_LCD_CORONA, + MDDI_LCD_HITACHI, + MDDI_LCD_TOSHIBA, + MDDI_LCD_PRISM, + MDDI_LCD_TP2, + MDDI_NUM_LCD_TYPES, + MDDI_LCD_DEFAULT = MDDI_LCD_TOSHIBA +} mddi_lcd_type; + +typedef enum { + MDDI_HOST_PRIM = 0, + MDDI_HOST_EXT, + MDDI_NUM_HOST_CORES +} mddi_host_type; + +typedef enum { + MDDI_DRIVER_RESET, /* host core registers have not been written. */ + MDDI_DRIVER_DISABLED, /* registers written, interrupts disabled. */ + MDDI_DRIVER_ENABLED /* registers written, interrupts enabled. */ +} mddi_host_driver_state_type; + +typedef enum { + MDDI_GPIO_INT_0 = 0, + MDDI_GPIO_INT_1, + MDDI_GPIO_INT_2, + MDDI_GPIO_INT_3, + MDDI_GPIO_INT_4, + MDDI_GPIO_INT_5, + MDDI_GPIO_INT_6, + MDDI_GPIO_INT_7, + MDDI_GPIO_INT_8, + MDDI_GPIO_INT_9, + MDDI_GPIO_INT_10, + MDDI_GPIO_INT_11, + MDDI_GPIO_INT_12, + MDDI_GPIO_INT_13, + MDDI_GPIO_INT_14, + MDDI_GPIO_INT_15, + MDDI_GPIO_NUM_INTS +} mddi_gpio_int_type; + +enum mddi_data_packet_size_type { + MDDI_DATA_PACKET_4_BYTES = 4, + MDDI_DATA_PACKET_8_BYTES = 8, + MDDI_DATA_PACKET_12_BYTES = 12, + MDDI_DATA_PACKET_16_BYTES = 16, + MDDI_DATA_PACKET_24_BYTES = 24 +}; + +typedef struct { + uint32 addr; + uint32 value; +} mddi_reg_write_type; + +boolean mddi_vsync_set_handler(msm_fb_vsync_handler_type handler, void *arg); + +typedef void (*mddi_llist_done_cb_type) (void); + +typedef void (*mddi_rev_handler_type) (void *); + +boolean mddi_set_rev_handler(mddi_rev_handler_type handler, uint16 pkt_type); + +#define MDDI_DEFAULT_PRIM_PIX_ATTR 0xC3 +#define MDDI_DEFAULT_SECD_PIX_ATTR 0xC0 + +typedef int gpio_int_polarity_type; +typedef int gpio_int_handler_type; + +typedef struct { + void (*vsync_detected) (boolean); +} mddi_lcd_func_type; + +extern mddi_lcd_func_type mddi_lcd; +extern int irq_enabled; +extern unsigned char mddi_timer_shutdown_flag; +extern struct mutex mddi_timer_lock; + +void mddi_init(void); +void mddi_powerdown(void); + +void mddi_host_start_ext_display(void); +void mddi_host_stop_ext_display(void); + +extern spinlock_t mddi_host_spin_lock; +#ifdef T_MSM7500 +void mddi_reset(void); +#ifdef FEATURE_DUAL_PROC_MODEM_DISPLAY +void mddi_host_switch_proc_control(boolean on); +#endif +#endif +void mddi_host_exit_power_collapse(void); + +void mddi_queue_splash_screen + (void *buf_ptr, + boolean clear_area, + int16 src_width, + int16 src_starting_row, + int16 src_starting_column, + int16 num_of_rows, + int16 num_of_columns, int16 dst_starting_row, int16 dst_starting_column); + +void mddi_queue_image + (void *buf_ptr, + uint8 stereo_video, + boolean clear_area, + int16 src_width, + int16 src_starting_row, + int16 src_starting_column, + int16 num_of_rows, + int16 num_of_columns, int16 dst_starting_row, int16 dst_starting_column); + +int mddi_host_register_read + (uint32 reg_addr, + uint32 *reg_value_ptr, boolean wait, mddi_host_type host_idx); +int mddi_host_register_write + (uint32 reg_addr, uint32 reg_val, + enum mddi_data_packet_size_type packet_size, + boolean wait, mddi_llist_done_cb_type done_cb, mddi_host_type host); +boolean mddi_host_register_write_int + (uint32 reg_addr, + uint32 reg_val, mddi_llist_done_cb_type done_cb, mddi_host_type host); +boolean mddi_host_register_read_int + (uint32 reg_addr, uint32 *reg_value_ptr, mddi_host_type host_idx); +void mddi_queue_register_write_static + (uint32 reg_addr, + uint32 reg_val, boolean wait, mddi_llist_done_cb_type done_cb); +void mddi_queue_static_window_adjust + (const mddi_reg_write_type *reg_write, + uint16 num_writes, mddi_llist_done_cb_type done_cb); + +#ifdef ENABLE_MDDI_MULTI_READ_WRITE +int mddi_host_register_multiwrite(uint32 reg_addr, + uint32 *value_list_ptr, uint32 value_count, + boolean wait, mddi_llist_done_cb_type done_cb, + mddi_host_type host); +int mddi_host_register_multiread(uint32 reg_addr, + uint32 *value_list_ptr, uint32 value_count, + boolean wait, mddi_host_type host); +#endif + +#define mddi_queue_register_read(reg, val_ptr, wait, sig) \ + mddi_host_register_read(reg, val_ptr, wait, MDDI_HOST_PRIM) +#define mddi_queue_register_write(reg, val, wait, sig) \ + mddi_host_register_write(reg, val, MDDI_DATA_PACKET_4_BYTES,\ + wait, NULL, MDDI_HOST_PRIM) +#define mddi_queue_register_write_extn(reg, val, pkt_size, wait, sig) \ + mddi_host_register_write(reg, val, pkt_size, \ + wait, NULL, MDDI_HOST_PRIM) +#define mddi_queue_register_write_int(reg, val) \ + mddi_host_register_write_int(reg, val, NULL, MDDI_HOST_PRIM) +#define mddi_queue_register_read_int(reg, val_ptr) \ + mddi_host_register_read_int(reg, val_ptr, MDDI_HOST_PRIM) +#define mddi_queue_register_writes(reg_ptr, val, wait, sig) \ + mddi_host_register_writes(reg_ptr, val, wait, sig, MDDI_HOST_PRIM) + +void mddi_wait(uint16 time_ms); +void mddi_assign_max_pkt_dimensions(uint16 image_cols, + uint16 image_rows, + uint16 bpp, + uint16 *max_cols, uint16 * max_rows); +#ifdef MDDI_HOST_WINDOW_WORKAROUND +uint16 mddi_assign_pkt_height(uint16 pkt_width, uint16 pkt_height, uint16 bpp); +#endif +void mddi_queue_reverse_encapsulation(boolean wait); +int mddi_client_power(unsigned int client_id); +void mddi_disable(int lock); +void mddi_window_adjust(struct msm_fb_data_type *mfd, + uint16 x1, uint16 x2, uint16 y1, uint16 y2); +void mddi_send_fw_link_skew_cal(mddi_host_type host_idx); +int pmdh_clk_func(int enable); + +#endif /* MDDIHOST_H */ diff --git a/drivers/video/msm/mddihost_e.c b/drivers/video/msm/mddihost_e.c new file mode 100644 index 000000000000..275e4ee1c5d8 --- /dev/null +++ b/drivers/video/msm/mddihost_e.c @@ -0,0 +1,59 @@ +/* Copyright (c) 2008-2009, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_fb.h" +#include "mddihost.h" +#include "mddihosti.h" + +#include +#include + +extern struct semaphore mddi_host_mutex; +static boolean mddi_host_ext_powered = FALSE; + +void mddi_host_start_ext_display(void) +{ + down(&mddi_host_mutex); + + if (!mddi_host_ext_powered) { + mddi_host_init(MDDI_HOST_EXT); + + mddi_host_ext_powered = TRUE; + } + + up(&mddi_host_mutex); +} + +void mddi_host_stop_ext_display(void) +{ + down(&mddi_host_mutex); + + if (mddi_host_ext_powered) { + mddi_host_powerdown(MDDI_HOST_EXT); + + mddi_host_ext_powered = FALSE; + } + + up(&mddi_host_mutex); +} diff --git a/drivers/video/msm/mddihosti.c b/drivers/video/msm/mddihosti.c new file mode 100644 index 000000000000..b4429f6bcf87 --- /dev/null +++ b/drivers/video/msm/mddihosti.c @@ -0,0 +1,2268 @@ +/* Copyright (c) 2008-2010, 2012 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_fb_panel.h" +#include "mddihost.h" +#include "mddihosti.h" + +#define FEATURE_MDDI_UNDERRUN_RECOVERY +#ifndef FEATURE_MDDI_DISABLE_REVERSE +static void mddi_read_rev_packet(byte *data_ptr); +#endif + +struct timer_list mddi_host_timer; + +#define MDDI_DEFAULT_TIMER_LENGTH 5000 /* 5 seconds */ +uint32 mddi_rtd_frequency = 60000; /* send RTD every 60 seconds */ +uint32 mddi_client_status_frequency = 60000; /* get status pkt every 60 secs */ + +boolean mddi_vsync_detect_enabled = FALSE; +mddi_gpio_info_type mddi_gpio; + +uint32 mddi_host_core_version; +boolean mddi_debug_log_statistics = FALSE; +/* #define FEATURE_MDDI_HOST_ENABLE_EARLY_HIBERNATION */ +/* default to TRUE in case MDP does not vote */ +static boolean mddi_host_mdp_active_flag = TRUE; +static uint32 mddi_log_stats_counter; +uint32 mddi_log_stats_frequency = 4000; +int32 mddi_client_type; + +#define MDDI_DEFAULT_REV_PKT_SIZE 0x20 + +#ifndef FEATURE_MDDI_DISABLE_REVERSE +static boolean mddi_rev_ptr_workaround = TRUE; +static uint32 mddi_reg_read_retry; +static uint32 mddi_reg_read_retry_max = 20; +static boolean mddi_enable_reg_read_retry = TRUE; +static boolean mddi_enable_reg_read_retry_once = FALSE; + +#define MDDI_MAX_REV_PKT_SIZE 0x60 + +#define MDDI_CLIENT_CAPABILITY_REV_PKT_SIZE 0x60 + +#define MDDI_VIDEO_REV_PKT_SIZE 0x40 +#define MDDI_REV_BUFFER_SIZE MDDI_MAX_REV_PKT_SIZE +static byte rev_packet_data[MDDI_MAX_REV_PKT_SIZE]; +#endif /* FEATURE_MDDI_DISABLE_REVERSE */ +/* leave these variables so graphics will compile */ + +#define MDDI_MAX_REV_DATA_SIZE 128 +/*lint -d__align(x) */ +boolean mddi_debug_clear_rev_data = TRUE; + +uint32 *mddi_reg_read_value_ptr; + +mddi_client_capability_type mddi_client_capability_pkt; +static boolean mddi_client_capability_request = FALSE; + +#ifndef FEATURE_MDDI_DISABLE_REVERSE + +#define MAX_MDDI_REV_HANDLERS 2 +#define INVALID_PKT_TYPE 0xFFFF + +typedef struct { + mddi_rev_handler_type handler; /* ISR to be executed */ + uint16 pkt_type; +} mddi_rev_pkt_handler_type; +static mddi_rev_pkt_handler_type mddi_rev_pkt_handler[MAX_MDDI_REV_HANDLERS] = + { {NULL, INVALID_PKT_TYPE}, {NULL, INVALID_PKT_TYPE} }; + +static boolean mddi_rev_encap_user_request = FALSE; +static mddi_linked_list_notify_type mddi_rev_user; + +spinlock_t mddi_host_spin_lock; +extern uint32 mdp_in_processing; +#endif + +typedef enum { + MDDI_REV_IDLE +#ifndef FEATURE_MDDI_DISABLE_REVERSE + , MDDI_REV_REG_READ_ISSUED, + MDDI_REV_REG_READ_SENT, + MDDI_REV_ENCAP_ISSUED, + MDDI_REV_STATUS_REQ_ISSUED, + MDDI_REV_CLIENT_CAP_ISSUED +#endif +} mddi_rev_link_state_type; + +typedef enum { + MDDI_LINK_DISABLED, + MDDI_LINK_HIBERNATING, + MDDI_LINK_ACTIVATING, + MDDI_LINK_ACTIVE +} mddi_host_link_state_type; + +typedef struct { + uint32 count; + uint32 in_count; + uint32 disp_req_count; + uint32 state_change_count; + uint32 ll_done_count; + uint32 rev_avail_count; + uint32 error_count; + uint32 rev_encap_count; + uint32 llist_ptr_write_1; + uint32 llist_ptr_write_2; +} mddi_host_int_type; + +typedef struct { + uint32 fwd_crc_count; + uint32 rev_crc_count; + uint32 pri_underflow; + uint32 sec_underflow; + uint32 rev_overflow; + uint32 pri_overwrite; + uint32 sec_overwrite; + uint32 rev_overwrite; + uint32 dma_failure; + uint32 rtd_failure; + uint32 reg_read_failure; +#ifdef FEATURE_MDDI_UNDERRUN_RECOVERY + uint32 pri_underrun_detected; +#endif +} mddi_host_stat_type; + +typedef struct { + uint32 rtd_cnt; + uint32 rev_enc_cnt; + uint32 vid_cnt; + uint32 reg_acc_cnt; + uint32 cli_stat_cnt; + uint32 cli_cap_cnt; + uint32 reg_read_cnt; + uint32 link_active_cnt; + uint32 link_hibernate_cnt; + uint32 vsync_response_cnt; + uint32 fwd_crc_cnt; + uint32 rev_crc_cnt; +} mddi_log_params_struct_type; + +typedef struct { + uint32 rtd_value; + uint32 rtd_counter; + uint32 client_status_cnt; + boolean rev_ptr_written; + uint8 *rev_ptr_start; + uint8 *rev_ptr_curr; + uint32 mddi_rev_ptr_write_val; + dma_addr_t rev_data_dma_addr; + uint16 rev_pkt_size; + mddi_rev_link_state_type rev_state; + mddi_host_link_state_type link_state; + mddi_host_driver_state_type driver_state; + boolean disable_hibernation; + uint32 saved_int_reg; + uint32 saved_int_en; + mddi_linked_list_type *llist_ptr; + dma_addr_t llist_dma_addr; + mddi_linked_list_type *llist_dma_ptr; + uint32 *rev_data_buf; + struct completion mddi_llist_avail_comp; + boolean mddi_waiting_for_llist_avail; + mddi_host_int_type int_type; + mddi_host_stat_type stats; + mddi_log_params_struct_type log_parms; + mddi_llist_info_type llist_info; + mddi_linked_list_notify_type llist_notify[MDDI_MAX_NUM_LLIST_ITEMS]; +} mddi_host_cntl_type; + +static mddi_host_type mddi_curr_host = MDDI_HOST_PRIM; +static mddi_host_cntl_type mhctl[MDDI_NUM_HOST_CORES]; +mddi_linked_list_type *llist_extern[MDDI_NUM_HOST_CORES]; +mddi_linked_list_type *llist_dma_extern[MDDI_NUM_HOST_CORES]; +mddi_linked_list_notify_type *llist_extern_notify[MDDI_NUM_HOST_CORES]; +static mddi_log_params_struct_type prev_parms[MDDI_NUM_HOST_CORES]; + +extern uint32 mdp_total_vdopkts; + +static boolean mddi_host_io_clock_on = FALSE; +static boolean mddi_host_hclk_on = FALSE; + +int int_mddi_pri_flag = FALSE; +int int_mddi_ext_flag = FALSE; + +static void mddi_report_errors(uint32 int_reg) +{ + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if (int_reg & MDDI_INT_PRI_UNDERFLOW) { + pmhctl->stats.pri_underflow++; + MDDI_MSG_ERR("!!! MDDI Primary Underflow !!!\n"); + } + if (int_reg & MDDI_INT_SEC_UNDERFLOW) { + pmhctl->stats.sec_underflow++; + MDDI_MSG_ERR("!!! MDDI Secondary Underflow !!!\n"); + } +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (int_reg & MDDI_INT_REV_OVERFLOW) { + pmhctl->stats.rev_overflow++; + MDDI_MSG_ERR("!!! MDDI Reverse Overflow !!!\n"); + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; + mddi_host_reg_out(REV_PTR, pmhctl->mddi_rev_ptr_write_val); + + } + if (int_reg & MDDI_INT_CRC_ERROR) + MDDI_MSG_ERR("!!! MDDI Reverse CRC Error !!!\n"); +#endif + if (int_reg & MDDI_INT_PRI_OVERWRITE) { + pmhctl->stats.pri_overwrite++; + MDDI_MSG_ERR("!!! MDDI Primary Overwrite !!!\n"); + } + if (int_reg & MDDI_INT_SEC_OVERWRITE) { + pmhctl->stats.sec_overwrite++; + MDDI_MSG_ERR("!!! MDDI Secondary Overwrite !!!\n"); + } +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (int_reg & MDDI_INT_REV_OVERWRITE) { + pmhctl->stats.rev_overwrite++; + /* This will show up normally and is not a problem */ + MDDI_MSG_DEBUG("MDDI Reverse Overwrite!\n"); + } + if (int_reg & MDDI_INT_RTD_FAILURE) { + mddi_host_reg_outm(INTEN, MDDI_INT_RTD_FAILURE, 0); + pmhctl->stats.rtd_failure++; + MDDI_MSG_ERR("!!! MDDI RTD Failure !!!\n"); + } +#endif + if (int_reg & MDDI_INT_DMA_FAILURE) { + pmhctl->stats.dma_failure++; + MDDI_MSG_ERR("!!! MDDI DMA Abort !!!\n"); + } +} + +static void mddi_host_enable_io_clock(void) +{ + if (!MDDI_HOST_IS_IO_CLOCK_ON) + MDDI_HOST_ENABLE_IO_CLOCK; +} + +static void mddi_host_enable_hclk(void) +{ + + if (!MDDI_HOST_IS_HCLK_ON) + MDDI_HOST_ENABLE_HCLK; +} + +static void mddi_host_disable_io_clock(void) +{ +#ifndef FEATURE_MDDI_HOST_IO_CLOCK_CONTROL_DISABLE + if (MDDI_HOST_IS_IO_CLOCK_ON) + MDDI_HOST_DISABLE_IO_CLOCK; +#endif +} + +static void mddi_host_disable_hclk(void) +{ +#ifndef FEATURE_MDDI_HOST_HCLK_CONTROL_DISABLE + if (MDDI_HOST_IS_HCLK_ON) + MDDI_HOST_DISABLE_HCLK; +#endif +} + +static void mddi_vote_to_sleep(mddi_host_type host_idx, boolean sleep) +{ + uint16 vote_mask; + + if (host_idx == MDDI_HOST_PRIM) + vote_mask = 0x01; + else + vote_mask = 0x02; +} + +static void mddi_report_state_change(uint32 int_reg) +{ + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if ((pmhctl->saved_int_reg & MDDI_INT_IN_HIBERNATION) && + (pmhctl->saved_int_reg & MDDI_INT_LINK_ACTIVE)) { + /* recover from condition where the io_clock was turned off by the + clock driver during a transition to hibernation. The io_clock + disable is to prevent MDP/MDDI underruns when changing ARM + clock speeds. In the process of halting the ARM, the hclk + divider needs to be set to 1. When it is set to 1, there is + a small time (usecs) when hclk is off or slow, and this can + cause an underrun. To prevent the underrun, clock driver turns + off the MDDI io_clock before making the change. */ + mddi_host_reg_out(CMD, MDDI_CMD_POWERUP); + } + + if (int_reg & MDDI_INT_LINK_ACTIVE) { + pmhctl->link_state = MDDI_LINK_ACTIVE; + pmhctl->log_parms.link_active_cnt++; + pmhctl->rtd_value = mddi_host_reg_in(RTD_VAL); + MDDI_MSG_DEBUG("!!! MDDI Active RTD:0x%x!!!\n", + pmhctl->rtd_value); + /* now interrupt on hibernation */ + mddi_host_reg_outm(INTEN, + (MDDI_INT_IN_HIBERNATION | + MDDI_INT_LINK_ACTIVE), + MDDI_INT_IN_HIBERNATION); + +#ifdef DEBUG_MDDIHOSTI + /* if gpio interrupt is enabled, start polling at fastest + * registered rate + */ + if (mddi_gpio.polling_enabled) { + timer_reg(&mddi_gpio_poll_timer, + mddi_gpio_poll_timer_cb, 0, mddi_gpio.polling_interval, 0); + } +#endif +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (mddi_rev_ptr_workaround) { + /* HW CR: need to reset reverse register stuff */ + pmhctl->rev_ptr_written = FALSE; + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; + } +#endif + /* vote on sleep */ + mddi_vote_to_sleep(host_idx, FALSE); + + if (host_idx == MDDI_HOST_PRIM) { + if (mddi_vsync_detect_enabled) { + /* + * Indicate to client specific code that vsync + * was enabled, but we did not detect a client + * intiated wakeup. The client specific + * handler can either reassert vsync detection, + * or treat this as a valid vsync. + */ + mddi_client_lcd_vsync_detected(FALSE); + pmhctl->log_parms.vsync_response_cnt++; + } + } + } + if (int_reg & MDDI_INT_IN_HIBERNATION) { + pmhctl->link_state = MDDI_LINK_HIBERNATING; + pmhctl->log_parms.link_hibernate_cnt++; + MDDI_MSG_DEBUG("!!! MDDI Hibernating !!!\n"); + + if (mddi_client_type == 2) { + mddi_host_reg_out(PAD_CTL, 0x402a850f); + mddi_host_reg_out(PAD_CAL, 0x10220020); + mddi_host_reg_out(TA1_LEN, 0x0010); + mddi_host_reg_out(TA2_LEN, 0x0040); + } + /* now interrupt on link_active */ +#ifdef FEATURE_MDDI_DISABLE_REVERSE + mddi_host_reg_outm(INTEN, + (MDDI_INT_MDDI_IN | + MDDI_INT_IN_HIBERNATION | + MDDI_INT_LINK_ACTIVE), + MDDI_INT_LINK_ACTIVE); +#else + mddi_host_reg_outm(INTEN, + (MDDI_INT_MDDI_IN | + MDDI_INT_IN_HIBERNATION | + MDDI_INT_LINK_ACTIVE), + (MDDI_INT_MDDI_IN | MDDI_INT_LINK_ACTIVE)); + + pmhctl->rtd_counter = mddi_rtd_frequency; + + if (pmhctl->rev_state != MDDI_REV_IDLE) { + /* a rev_encap will not wake up the link, so we do that here */ + pmhctl->link_state = MDDI_LINK_ACTIVATING; + mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE); + } +#endif + + if (pmhctl->disable_hibernation) { + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE); + mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE); + pmhctl->link_state = MDDI_LINK_ACTIVATING; + } +#ifdef FEATURE_MDDI_UNDERRUN_RECOVERY + if ((pmhctl->llist_info.transmitting_start_idx != + UNASSIGNED_INDEX) + && + ((pmhctl-> + saved_int_reg & (MDDI_INT_PRI_LINK_LIST_DONE | + MDDI_INT_PRI_PTR_READ)) == + MDDI_INT_PRI_PTR_READ)) { + mddi_linked_list_type *llist_dma; + llist_dma = pmhctl->llist_dma_ptr; + /* + * All indications are that we have not received a + * linked list done interrupt, due to an underrun + * condition. Recovery attempt is to send again. + */ + dma_coherent_pre_ops(); + /* Write to primary pointer register again */ + mddi_host_reg_out(PRI_PTR, + &llist_dma[pmhctl->llist_info. + transmitting_start_idx]); + pmhctl->stats.pri_underrun_detected++; + } +#endif + + /* vote on sleep */ + if (pmhctl->link_state == MDDI_LINK_HIBERNATING) { + mddi_vote_to_sleep(host_idx, TRUE); + } + +#ifdef DEBUG_MDDIHOSTI + /* need to stop polling timer */ + if (mddi_gpio.polling_enabled) { + (void) timer_clr(&mddi_gpio_poll_timer, T_NONE); + } +#endif + } +} + +void mddi_host_timer_service(unsigned long data) +{ +#ifndef FEATURE_MDDI_DISABLE_REVERSE + unsigned long flags; +#endif + mddi_host_type host_idx; + mddi_host_cntl_type *pmhctl; + + unsigned long time_ms = MDDI_DEFAULT_TIMER_LENGTH; + init_timer(&mddi_host_timer); + for (host_idx = MDDI_HOST_PRIM; host_idx < MDDI_NUM_HOST_CORES; + host_idx++) { + pmhctl = &(mhctl[host_idx]); + mddi_log_stats_counter += (uint32) time_ms; +#ifndef FEATURE_MDDI_DISABLE_REVERSE + pmhctl->rtd_counter += (uint32) time_ms; + pmhctl->client_status_cnt += (uint32) time_ms; + + if (host_idx == MDDI_HOST_PRIM) { + if (pmhctl->client_status_cnt >= + mddi_client_status_frequency) { + if ((pmhctl->link_state == + MDDI_LINK_HIBERNATING) + && (pmhctl->client_status_cnt > + mddi_client_status_frequency)) { + /* + * special case where we are hibernating + * and mddi_host_isr is not firing, so + * kick the link so that the status can + * be retrieved + */ + + /* need to wake up link before issuing + * rev encap command + */ + MDDI_MSG_INFO("wake up link!\n"); + spin_lock_irqsave(&mddi_host_spin_lock, + flags); + mddi_host_enable_hclk(); + mddi_host_enable_io_clock(); + pmhctl->link_state = + MDDI_LINK_ACTIVATING; + mddi_host_reg_out(CMD, + MDDI_CMD_LINK_ACTIVE); + spin_unlock_irqrestore + (&mddi_host_spin_lock, flags); + } else + if ((pmhctl->link_state == MDDI_LINK_ACTIVE) + && pmhctl->disable_hibernation) { + /* + * special case where we have disabled + * hibernation and mddi_host_isr + * is not firing, so enable interrupt + * for no pkts pending, which will + * generate an interrupt + */ + MDDI_MSG_INFO("kick isr!\n"); + spin_lock_irqsave(&mddi_host_spin_lock, + flags); + mddi_host_enable_hclk(); + mddi_host_reg_outm(INTEN, + MDDI_INT_NO_CMD_PKTS_PEND, + MDDI_INT_NO_CMD_PKTS_PEND); + spin_unlock_irqrestore + (&mddi_host_spin_lock, flags); + } + } + } +#endif /* #ifndef FEATURE_MDDI_DISABLE_REVERSE */ + } + + /* Check if logging is turned on */ + for (host_idx = MDDI_HOST_PRIM; host_idx < MDDI_NUM_HOST_CORES; + host_idx++) { + mddi_log_params_struct_type *prev_ptr = &(prev_parms[host_idx]); + pmhctl = &(mhctl[host_idx]); + + if (mddi_debug_log_statistics) { + + /* get video pkt count from MDP, since MDDI sw cannot know this */ + pmhctl->log_parms.vid_cnt = mdp_total_vdopkts; + + if (mddi_log_stats_counter >= mddi_log_stats_frequency) { + /* mddi_log_stats_counter = 0; */ + if (mddi_debug_log_statistics) { + MDDI_MSG_NOTICE + ("MDDI Statistics since last report:\n"); + MDDI_MSG_NOTICE(" Packets sent:\n"); + MDDI_MSG_NOTICE + (" %d RTD packet(s)\n", + pmhctl->log_parms.rtd_cnt - + prev_ptr->rtd_cnt); + if (prev_ptr->rtd_cnt != + pmhctl->log_parms.rtd_cnt) { + unsigned long flags; + spin_lock_irqsave + (&mddi_host_spin_lock, + flags); + mddi_host_enable_hclk(); + pmhctl->rtd_value = + mddi_host_reg_in(RTD_VAL); + spin_unlock_irqrestore + (&mddi_host_spin_lock, + flags); + MDDI_MSG_NOTICE + (" RTD value=%d\n", + pmhctl->rtd_value); + } + MDDI_MSG_NOTICE + (" %d VIDEO packets\n", + pmhctl->log_parms.vid_cnt - + prev_ptr->vid_cnt); + MDDI_MSG_NOTICE + (" %d Register Access packets\n", + pmhctl->log_parms.reg_acc_cnt - + prev_ptr->reg_acc_cnt); + MDDI_MSG_NOTICE + (" %d Reverse Encapsulation packet(s)\n", + pmhctl->log_parms.rev_enc_cnt - + prev_ptr->rev_enc_cnt); + if (prev_ptr->rev_enc_cnt != + pmhctl->log_parms.rev_enc_cnt) { + /* report # of reverse CRC errors */ + MDDI_MSG_NOTICE + (" %d reverse CRC errors detected\n", + pmhctl->log_parms. + rev_crc_cnt - + prev_ptr->rev_crc_cnt); + } + MDDI_MSG_NOTICE + (" Packets received:\n"); + MDDI_MSG_NOTICE + (" %d Client Status packets", + pmhctl->log_parms.cli_stat_cnt - + prev_ptr->cli_stat_cnt); + if (prev_ptr->cli_stat_cnt != + pmhctl->log_parms.cli_stat_cnt) { + MDDI_MSG_NOTICE + (" %d forward CRC errors reported\n", + pmhctl->log_parms. + fwd_crc_cnt - + prev_ptr->fwd_crc_cnt); + } + MDDI_MSG_NOTICE + (" %d Register Access Read packets\n", + pmhctl->log_parms.reg_read_cnt - + prev_ptr->reg_read_cnt); + + if (pmhctl->link_state == + MDDI_LINK_ACTIVE) { + MDDI_MSG_NOTICE + (" Current Link Status: Active\n"); + } else + if ((pmhctl->link_state == + MDDI_LINK_HIBERNATING) + || (pmhctl->link_state == + MDDI_LINK_ACTIVATING)) { + MDDI_MSG_NOTICE + (" Current Link Status: Hibernation\n"); + } else { + MDDI_MSG_NOTICE + (" Current Link Status: Inactive\n"); + } + MDDI_MSG_NOTICE + (" Active state entered %d times\n", + pmhctl->log_parms.link_active_cnt - + prev_ptr->link_active_cnt); + MDDI_MSG_NOTICE + (" Hibernation state entered %d times\n", + pmhctl->log_parms. + link_hibernate_cnt - + prev_ptr->link_hibernate_cnt); + } + } + prev_parms[host_idx] = pmhctl->log_parms; + } + } + if (mddi_log_stats_counter >= mddi_log_stats_frequency) + mddi_log_stats_counter = 0; + + mutex_lock(&mddi_timer_lock); + if (!mddi_timer_shutdown_flag) { + mddi_host_timer.function = mddi_host_timer_service; + mddi_host_timer.data = 0; + mddi_host_timer.expires = jiffies + ((time_ms * HZ) / 1000); + add_timer(&mddi_host_timer); + } + mutex_unlock(&mddi_timer_lock); + + return; +} /* mddi_host_timer_cb */ + +static void mddi_process_link_list_done(void) +{ + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + /* normal forward linked list packet(s) were sent */ + if (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) { + MDDI_MSG_ERR("**** getting LL done, but no list ****\n"); + } else { + uint16 idx; + +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (pmhctl->rev_state == MDDI_REV_REG_READ_ISSUED) { + /* special case where a register read packet was sent */ + pmhctl->rev_state = MDDI_REV_REG_READ_SENT; + if (pmhctl->llist_info.reg_read_idx == UNASSIGNED_INDEX) { + MDDI_MSG_ERR + ("**** getting LL done, but no list ****\n"); + } + } +#endif + for (idx = pmhctl->llist_info.transmitting_start_idx;;) { + uint16 next_idx = pmhctl->llist_notify[idx].next_idx; + /* with reg read we don't release the waiting tcb until after + * the reverse encapsulation has completed. + */ + if (idx != pmhctl->llist_info.reg_read_idx) { + /* notify task that may be waiting on this completion */ + if (pmhctl->llist_notify[idx].waiting) { + complete(& + (pmhctl->llist_notify[idx]. + done_comp)); + } + if (pmhctl->llist_notify[idx].done_cb != NULL) { + (*(pmhctl->llist_notify[idx].done_cb)) + (); + } + + pmhctl->llist_notify[idx].in_use = FALSE; + pmhctl->llist_notify[idx].waiting = FALSE; + pmhctl->llist_notify[idx].done_cb = NULL; + if (idx < MDDI_NUM_DYNAMIC_LLIST_ITEMS) { + /* static LLIST items are configured only once */ + pmhctl->llist_notify[idx].next_idx = + UNASSIGNED_INDEX; + } + /* + * currently, all linked list packets are + * register access, so we can increment the + * counter for that packet type here. + */ + pmhctl->log_parms.reg_acc_cnt++; + } + if (idx == pmhctl->llist_info.transmitting_end_idx) + break; + idx = next_idx; + if (idx == UNASSIGNED_INDEX) + MDDI_MSG_CRIT("MDDI linked list corruption!\n"); + } + + pmhctl->llist_info.transmitting_start_idx = UNASSIGNED_INDEX; + pmhctl->llist_info.transmitting_end_idx = UNASSIGNED_INDEX; + + if (pmhctl->mddi_waiting_for_llist_avail) { + if (! + (pmhctl-> + llist_notify[pmhctl->llist_info.next_free_idx]. + in_use)) { + pmhctl->mddi_waiting_for_llist_avail = FALSE; + complete(&(pmhctl->mddi_llist_avail_comp)); + } + } + } + + /* Turn off MDDI_INT_PRI_LINK_LIST_DONE interrupt */ + mddi_host_reg_outm(INTEN, MDDI_INT_PRI_LINK_LIST_DONE, 0); + +} + +static void mddi_queue_forward_linked_list(void) +{ + uint16 first_pkt_index; + mddi_linked_list_type *llist_dma; + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + llist_dma = pmhctl->llist_dma_ptr; + + first_pkt_index = UNASSIGNED_INDEX; + + if (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) { +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (pmhctl->llist_info.reg_read_waiting) { + if (pmhctl->rev_state == MDDI_REV_IDLE) { + /* + * we have a register read to send and + * can send it now + */ + pmhctl->rev_state = MDDI_REV_REG_READ_ISSUED; + mddi_reg_read_retry = 0; + first_pkt_index = + pmhctl->llist_info.waiting_start_idx; + pmhctl->llist_info.reg_read_waiting = FALSE; + } + } else +#endif + { + /* + * not register read to worry about, go ahead and write + * anything that may be on the waiting list. + */ + first_pkt_index = pmhctl->llist_info.waiting_start_idx; + } + } + + if (first_pkt_index != UNASSIGNED_INDEX) { + pmhctl->llist_info.transmitting_start_idx = + pmhctl->llist_info.waiting_start_idx; + pmhctl->llist_info.transmitting_end_idx = + pmhctl->llist_info.waiting_end_idx; + pmhctl->llist_info.waiting_start_idx = UNASSIGNED_INDEX; + pmhctl->llist_info.waiting_end_idx = UNASSIGNED_INDEX; + + /* write to the primary pointer register */ + MDDI_MSG_DEBUG("MDDI writing primary ptr with idx=%d\n", + first_pkt_index); + + pmhctl->int_type.llist_ptr_write_2++; + + dma_coherent_pre_ops(); + mddi_host_reg_out(PRI_PTR, &llist_dma[first_pkt_index]); + + /* enable interrupt when complete */ + mddi_host_reg_outm(INTEN, MDDI_INT_PRI_LINK_LIST_DONE, + MDDI_INT_PRI_LINK_LIST_DONE); + + } + +} + +#ifndef FEATURE_MDDI_DISABLE_REVERSE +static void mddi_read_rev_packet(byte *data_ptr) +{ + uint16 i, length; + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + uint8 *rev_ptr_overflow = + (pmhctl->rev_ptr_start + MDDI_REV_BUFFER_SIZE); + + /* first determine the length and handle invalid lengths */ + length = *pmhctl->rev_ptr_curr++; + if (pmhctl->rev_ptr_curr >= rev_ptr_overflow) + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; + length |= ((*pmhctl->rev_ptr_curr++) << 8); + if (pmhctl->rev_ptr_curr >= rev_ptr_overflow) + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; + if (length > (pmhctl->rev_pkt_size - 2)) { + MDDI_MSG_ERR("Invalid rev pkt length %d\n", length); + /* rev_pkt_size should always be <= rev_ptr_size so limit to packet size */ + length = pmhctl->rev_pkt_size - 2; + } + + /* If the data pointer is NULL, just increment the pmhctl->rev_ptr_curr. + * Loop around if necessary. Don't bother reading the data. + */ + if (data_ptr == NULL) { + pmhctl->rev_ptr_curr += length; + if (pmhctl->rev_ptr_curr >= rev_ptr_overflow) + pmhctl->rev_ptr_curr -= MDDI_REV_BUFFER_SIZE; + return; + } + + data_ptr[0] = length & 0x0ff; + data_ptr[1] = length >> 8; + data_ptr += 2; + /* copy the data to data_ptr byte-at-a-time */ + for (i = 0; (i < length) && (pmhctl->rev_ptr_curr < rev_ptr_overflow); + i++) + *data_ptr++ = *pmhctl->rev_ptr_curr++; + if (pmhctl->rev_ptr_curr >= rev_ptr_overflow) + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; + for (; (i < length) && (pmhctl->rev_ptr_curr < rev_ptr_overflow); i++) + *data_ptr++ = *pmhctl->rev_ptr_curr++; +} + +static void mddi_process_rev_packets(void) +{ + uint32 rev_packet_count; + word i; + uint32 crc_errors; + boolean mddi_reg_read_successful = FALSE; + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + pmhctl->log_parms.rev_enc_cnt++; + if ((pmhctl->rev_state != MDDI_REV_ENCAP_ISSUED) && + (pmhctl->rev_state != MDDI_REV_STATUS_REQ_ISSUED) && + (pmhctl->rev_state != MDDI_REV_CLIENT_CAP_ISSUED)) { + MDDI_MSG_ERR("Wrong state %d for reverse int\n", + pmhctl->rev_state); + } + /* Turn off MDDI_INT_REV_AVAIL interrupt */ + mddi_host_reg_outm(INTEN, MDDI_INT_REV_DATA_AVAIL, 0); + + /* Clear rev data avail int */ + mddi_host_reg_out(INT, MDDI_INT_REV_DATA_AVAIL); + + /* Get Number of packets */ + rev_packet_count = mddi_host_reg_in(REV_PKT_CNT); + +#ifndef T_MSM7500 + /* Clear out rev packet counter */ + mddi_host_reg_out(REV_PKT_CNT, 0x0000); +#endif + +#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40) + if ((pmhctl->rev_state == MDDI_REV_CLIENT_CAP_ISSUED) && + (rev_packet_count > 0) && + (mddi_host_core_version == 0x28 || + mddi_host_core_version == 0x30)) { + + uint32 int_reg; + uint32 max_count = 0; + + mddi_host_reg_out(REV_PTR, pmhctl->mddi_rev_ptr_write_val); + int_reg = mddi_host_reg_in(INT); + while ((int_reg & 0x100000) == 0) { + udelay(3); + int_reg = mddi_host_reg_in(INT); + if (++max_count > 100) + break; + } + } +#endif + + /* Get CRC error count */ + crc_errors = mddi_host_reg_in(REV_CRC_ERR); + if (crc_errors != 0) { + pmhctl->log_parms.rev_crc_cnt += crc_errors; + pmhctl->stats.rev_crc_count += crc_errors; + MDDI_MSG_ERR("!!! MDDI %d Reverse CRC Error(s) !!!\n", + crc_errors); +#ifndef T_MSM7500 + /* Clear CRC error count */ + mddi_host_reg_out(REV_CRC_ERR, 0x0000); +#endif + /* also issue an RTD to attempt recovery */ + pmhctl->rtd_counter = mddi_rtd_frequency; + } + + pmhctl->rtd_value = mddi_host_reg_in(RTD_VAL); + + MDDI_MSG_DEBUG("MDDI rev pkt cnt=%d, ptr=0x%x, RTD:0x%x\n", + rev_packet_count, + pmhctl->rev_ptr_curr - pmhctl->rev_ptr_start, + pmhctl->rtd_value); + + if (rev_packet_count >= 1) { + mddi_invalidate_cache_lines((uint32 *) pmhctl->rev_ptr_start, + MDDI_REV_BUFFER_SIZE); + } else { + MDDI_MSG_ERR("Reverse pkt sent, no data rxd\n"); + if (mddi_reg_read_value_ptr) + *mddi_reg_read_value_ptr = -EBUSY; + } + /* order the reads */ + dma_coherent_post_ops(); + for (i = 0; i < rev_packet_count; i++) { + mddi_rev_packet_type *rev_pkt_ptr; + + mddi_read_rev_packet(rev_packet_data); + + rev_pkt_ptr = (mddi_rev_packet_type *) rev_packet_data; + + if (rev_pkt_ptr->packet_length > pmhctl->rev_pkt_size) { + MDDI_MSG_ERR("!!!invalid packet size: %d\n", + rev_pkt_ptr->packet_length); + } + + MDDI_MSG_DEBUG("MDDI rev pkt 0x%x size 0x%x\n", + rev_pkt_ptr->packet_type, + rev_pkt_ptr->packet_length); + + /* Do whatever you want to do with the data based on the packet type */ + switch (rev_pkt_ptr->packet_type) { + case 66: /* Client Capability */ + { + mddi_client_capability_type + *client_capability_pkt_ptr; + + client_capability_pkt_ptr = + (mddi_client_capability_type *) + rev_packet_data; + MDDI_MSG_NOTICE + ("Client Capability: Week=%d, Year=%d\n", + client_capability_pkt_ptr-> + Week_of_Manufacture, + client_capability_pkt_ptr-> + Year_of_Manufacture); + memcpy((void *)&mddi_client_capability_pkt, + (void *)rev_packet_data, + sizeof(mddi_client_capability_type)); + pmhctl->log_parms.cli_cap_cnt++; + } + break; + + case 70: /* Display Status */ + { + mddi_client_status_type *client_status_pkt_ptr; + + client_status_pkt_ptr = + (mddi_client_status_type *) rev_packet_data; + if ((client_status_pkt_ptr->crc_error_count != + 0) + || (client_status_pkt_ptr-> + reverse_link_request != 0)) { + MDDI_MSG_ERR + ("Client Status: RevReq=%d, CrcErr=%d\n", + client_status_pkt_ptr-> + reverse_link_request, + client_status_pkt_ptr-> + crc_error_count); + } else { + MDDI_MSG_DEBUG + ("Client Status: RevReq=%d, CrcErr=%d\n", + client_status_pkt_ptr-> + reverse_link_request, + client_status_pkt_ptr-> + crc_error_count); + } + pmhctl->log_parms.fwd_crc_cnt += + client_status_pkt_ptr->crc_error_count; + pmhctl->stats.fwd_crc_count += + client_status_pkt_ptr->crc_error_count; + pmhctl->log_parms.cli_stat_cnt++; + } + break; + + case 146: /* register access packet */ + { + mddi_register_access_packet_type + * regacc_pkt_ptr; + uint32 data_count; + + regacc_pkt_ptr = + (mddi_register_access_packet_type *) + rev_packet_data; + + /* Bits[0:13] - read data count */ + data_count = regacc_pkt_ptr->read_write_info + & 0x3FFF; + MDDI_MSG_DEBUG("\n MDDI rev read: 0x%x", + regacc_pkt_ptr->read_write_info); + MDDI_MSG_DEBUG("Reg Acc parse reg=0x%x," + "value=0x%x\n", regacc_pkt_ptr-> + register_address, regacc_pkt_ptr-> + register_data_list[0]); + + /* Copy register value to location passed in */ + if (mddi_reg_read_value_ptr) { +#if defined(T_MSM6280) && !defined(T_MSM7200) + /* only least significant 16 bits are valid with 6280 */ + *mddi_reg_read_value_ptr = + regacc_pkt_ptr-> + register_data_list[0] & 0x0000ffff; + mddi_reg_read_successful = TRUE; + mddi_reg_read_value_ptr = NULL; +#else + if (data_count && data_count <= + MDDI_HOST_MAX_CLIENT_REG_IN_SAME_ADDR) { + memcpy(mddi_reg_read_value_ptr, + (void *)®acc_pkt_ptr-> + register_data_list[0], + data_count * 4); + mddi_reg_read_successful = TRUE; + mddi_reg_read_value_ptr = NULL; + } +#endif + } + +#ifdef DEBUG_MDDIHOSTI + if ((mddi_gpio.polling_enabled) && + (regacc_pkt_ptr->register_address == + mddi_gpio.polling_reg)) { + /* + * ToDo: need to call Linux GPIO call + * here... + */ + mddi_client_lcd_gpio_poll( + regacc_pkt_ptr->register_data_list[0]); + } +#endif + pmhctl->log_parms.reg_read_cnt++; + } + break; + + case INVALID_PKT_TYPE: /* 0xFFFF */ + MDDI_MSG_ERR("!!!INVALID_PKT_TYPE rcvd\n"); + break; + + default: /* any other packet */ + { + uint16 hdlr; + + for (hdlr = 0; hdlr < MAX_MDDI_REV_HANDLERS; + hdlr++) { + if (mddi_rev_pkt_handler[hdlr]. + handler == NULL) + continue; + if (mddi_rev_pkt_handler[hdlr]. + pkt_type == + rev_pkt_ptr->packet_type) { + (*(mddi_rev_pkt_handler[hdlr]. + handler)) (rev_pkt_ptr); + /* pmhctl->rev_state = MDDI_REV_IDLE; */ + break; + } + } + if (hdlr >= MAX_MDDI_REV_HANDLERS) + MDDI_MSG_ERR("MDDI unknown rev pkt\n"); + } + break; + } + } + if ((pmhctl->rev_ptr_curr + pmhctl->rev_pkt_size) >= + (pmhctl->rev_ptr_start + MDDI_REV_BUFFER_SIZE)) { + pmhctl->rev_ptr_written = FALSE; + } + + if (pmhctl->rev_state == MDDI_REV_ENCAP_ISSUED) { + pmhctl->rev_state = MDDI_REV_IDLE; + if (mddi_rev_user.waiting) { + mddi_rev_user.waiting = FALSE; + complete(&(mddi_rev_user.done_comp)); + } else if (pmhctl->llist_info.reg_read_idx == UNASSIGNED_INDEX) { + MDDI_MSG_ERR + ("Reverse Encap state, but no reg read in progress\n"); + } else { + if ((!mddi_reg_read_successful) && + (mddi_reg_read_retry < mddi_reg_read_retry_max) && + (mddi_enable_reg_read_retry)) { + /* + * There is a race condition that can happen + * where the reverse encapsulation message is + * sent out by the MDDI host before the register + * read packet is sent. As a work-around for + * that problem we issue the reverse + * encapsulation one more time before giving up. + */ + if (mddi_enable_reg_read_retry_once) + mddi_reg_read_retry = + mddi_reg_read_retry_max; + else + mddi_reg_read_retry++; + pmhctl->rev_state = MDDI_REV_REG_READ_SENT; + pmhctl->stats.reg_read_failure++; + } else { + uint16 reg_read_idx = + pmhctl->llist_info.reg_read_idx; + + mddi_reg_read_retry = 0; + if (pmhctl->llist_notify[reg_read_idx].waiting) { + complete(& + (pmhctl-> + llist_notify[reg_read_idx]. + done_comp)); + } + pmhctl->llist_info.reg_read_idx = + UNASSIGNED_INDEX; + if (pmhctl->llist_notify[reg_read_idx]. + done_cb != NULL) { + (* + (pmhctl->llist_notify[reg_read_idx]. + done_cb)) (); + } + pmhctl->llist_notify[reg_read_idx].next_idx = + UNASSIGNED_INDEX; + pmhctl->llist_notify[reg_read_idx].in_use = + FALSE; + pmhctl->llist_notify[reg_read_idx].waiting = + FALSE; + pmhctl->llist_notify[reg_read_idx].done_cb = + NULL; + if (!mddi_reg_read_successful) + pmhctl->stats.reg_read_failure++; + } + } + } else if (pmhctl->rev_state == MDDI_REV_CLIENT_CAP_ISSUED) { +#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40) + if (mddi_host_core_version == 0x28 || + mddi_host_core_version == 0x30) { + mddi_host_reg_out(FIFO_ALLOC, 0x00); + pmhctl->rev_ptr_written = TRUE; + mddi_host_reg_out(REV_PTR, + pmhctl->mddi_rev_ptr_write_val); + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; + mddi_host_reg_out(CMD, 0xC00); + } +#endif + + if (mddi_rev_user.waiting) { + mddi_rev_user.waiting = FALSE; + complete(&(mddi_rev_user.done_comp)); + } + pmhctl->rev_state = MDDI_REV_IDLE; + } else { + pmhctl->rev_state = MDDI_REV_IDLE; + } + + /* pmhctl->rev_state = MDDI_REV_IDLE; */ + + /* Re-enable interrupt */ + mddi_host_reg_outm(INTEN, MDDI_INT_REV_DATA_AVAIL, + MDDI_INT_REV_DATA_AVAIL); + +} + +static void mddi_issue_reverse_encapsulation(void) +{ + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + /* Only issue a reverse encapsulation packet if: + * 1) another reverse is not in progress (MDDI_REV_IDLE). + * 2) a register read has been sent (MDDI_REV_REG_READ_SENT). + * 3) forward is not in progress, because of a hw bug in client that + * causes forward crc errors on packet immediately after rev encap. + */ + if (((pmhctl->rev_state == MDDI_REV_IDLE) || + (pmhctl->rev_state == MDDI_REV_REG_READ_SENT)) && + (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) && + (!mdp_in_processing)) { + uint32 mddi_command = MDDI_CMD_SEND_REV_ENCAP; + + if ((pmhctl->rev_state == MDDI_REV_REG_READ_SENT) || + (mddi_rev_encap_user_request == TRUE)) { + mddi_host_enable_io_clock(); + if (pmhctl->link_state == MDDI_LINK_HIBERNATING) { + /* need to wake up link before issuing rev encap command */ + MDDI_MSG_DEBUG("wake up link!\n"); + pmhctl->link_state = MDDI_LINK_ACTIVATING; + mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE); + } else { + if (pmhctl->rtd_counter >= mddi_rtd_frequency) { + MDDI_MSG_DEBUG + ("mddi sending RTD command!\n"); + mddi_host_reg_out(CMD, + MDDI_CMD_SEND_RTD); + pmhctl->rtd_counter = 0; + pmhctl->log_parms.rtd_cnt++; + } + if (pmhctl->rev_state != MDDI_REV_REG_READ_SENT) { + /* this is generic reverse request by user, so + * reset the waiting flag. */ + mddi_rev_encap_user_request = FALSE; + } + /* link is active so send reverse encap to get register read results */ + pmhctl->rev_state = MDDI_REV_ENCAP_ISSUED; + mddi_command = MDDI_CMD_SEND_REV_ENCAP; + MDDI_MSG_DEBUG("sending rev encap!\n"); + } + } else + if ((pmhctl->client_status_cnt >= + mddi_client_status_frequency) + || mddi_client_capability_request) { + mddi_host_enable_io_clock(); + if (pmhctl->link_state == MDDI_LINK_HIBERNATING) { + /* only wake up the link if it client status is overdue */ + if ((pmhctl->client_status_cnt >= + (mddi_client_status_frequency * 2)) + || mddi_client_capability_request) { + /* need to wake up link before issuing rev encap command */ + MDDI_MSG_DEBUG("wake up link!\n"); + pmhctl->link_state = + MDDI_LINK_ACTIVATING; + mddi_host_reg_out(CMD, + MDDI_CMD_LINK_ACTIVE); + } + } else { + if (pmhctl->rtd_counter >= mddi_rtd_frequency) { + MDDI_MSG_DEBUG + ("mddi sending RTD command!\n"); + mddi_host_reg_out(CMD, + MDDI_CMD_SEND_RTD); + pmhctl->rtd_counter = 0; + pmhctl->log_parms.rtd_cnt++; + } + /* periodically get client status */ + MDDI_MSG_DEBUG + ("mddi sending rev enc! (get status)\n"); + if (mddi_client_capability_request) { + pmhctl->rev_state = + MDDI_REV_CLIENT_CAP_ISSUED; + mddi_command = MDDI_CMD_GET_CLIENT_CAP; + mddi_client_capability_request = FALSE; + } else { + pmhctl->rev_state = + MDDI_REV_STATUS_REQ_ISSUED; + pmhctl->client_status_cnt = 0; + mddi_command = + MDDI_CMD_GET_CLIENT_STATUS; + } + } + } + if ((pmhctl->rev_state == MDDI_REV_ENCAP_ISSUED) || + (pmhctl->rev_state == MDDI_REV_STATUS_REQ_ISSUED) || + (pmhctl->rev_state == MDDI_REV_CLIENT_CAP_ISSUED)) { + pmhctl->int_type.rev_encap_count++; +#if defined(T_MSM6280) && !defined(T_MSM7200) + mddi_rev_pointer_written = TRUE; + mddi_host_reg_out(REV_PTR, mddi_rev_ptr_write_val); + mddi_rev_ptr_curr = mddi_rev_ptr_start; + /* force new rev ptr command */ + mddi_host_reg_out(CMD, 0xC00); +#else + if (!pmhctl->rev_ptr_written) { + MDDI_MSG_DEBUG("writing reverse pointer!\n"); + pmhctl->rev_ptr_written = TRUE; +#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40) + if ((pmhctl->rev_state == + MDDI_REV_CLIENT_CAP_ISSUED) && + (mddi_host_core_version == 0x28 || + mddi_host_core_version == 0x30)) { + pmhctl->rev_ptr_written = FALSE; + mddi_host_reg_out(FIFO_ALLOC, 0x02); + } else + mddi_host_reg_out(REV_PTR, + pmhctl-> + mddi_rev_ptr_write_val); +#else + mddi_host_reg_out(REV_PTR, + pmhctl-> + mddi_rev_ptr_write_val); +#endif + } +#endif + if (mddi_debug_clear_rev_data) { + uint16 i; + for (i = 0; i < MDDI_MAX_REV_DATA_SIZE / 4; i++) + pmhctl->rev_data_buf[i] = 0xdddddddd; + /* clean cache */ + mddi_flush_cache_lines(pmhctl->rev_data_buf, + MDDI_MAX_REV_DATA_SIZE); + } + + /* send reverse encapsulation to get needed data */ + mddi_host_reg_out(CMD, mddi_command); + } + } + +} + +static void mddi_process_client_initiated_wakeup(void) +{ + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + /* Disable MDDI_INT Interrupt, we detect client initiated wakeup one + * time for each entry into hibernation */ + mddi_host_reg_outm(INTEN, MDDI_INT_MDDI_IN, 0); + + if (host_idx == MDDI_HOST_PRIM) { + if (mddi_vsync_detect_enabled) { + mddi_host_enable_io_clock(); +#ifndef MDDI_HOST_DISP_LISTEN + /* issue command to bring up link */ + /* need to do this to clear the vsync condition */ + if (pmhctl->link_state == MDDI_LINK_HIBERNATING) { + pmhctl->link_state = MDDI_LINK_ACTIVATING; + mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE); + } +#endif + /* + * Indicate to client specific code that vsync was + * enabled, and we did not detect a client initiated + * wakeup. The client specific handler can clear the + * condition if necessary to prevent subsequent + * client initiated wakeups. + */ + mddi_client_lcd_vsync_detected(TRUE); + pmhctl->log_parms.vsync_response_cnt++; + MDDI_MSG_NOTICE("MDDI_INT_IN condition\n"); + + } + } + + if (mddi_gpio.polling_enabled) { + mddi_host_enable_io_clock(); + /* check interrupt status now */ + (void)mddi_queue_register_read_int(mddi_gpio.polling_reg, + &mddi_gpio.polling_val); + } +} +#endif /* FEATURE_MDDI_DISABLE_REVERSE */ + +static void mddi_host_isr(void) +{ + uint32 int_reg, int_en; +#ifndef FEATURE_MDDI_DISABLE_REVERSE + uint32 status_reg; +#endif + mddi_host_type host_idx = mddi_curr_host; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if (!MDDI_HOST_IS_HCLK_ON) { + MDDI_HOST_ENABLE_HCLK; + } + int_reg = mddi_host_reg_in(INT); + int_en = mddi_host_reg_in(INTEN); + pmhctl->saved_int_reg = int_reg; + pmhctl->saved_int_en = int_en; + int_reg = int_reg & int_en; + pmhctl->int_type.count++; + + +#ifndef FEATURE_MDDI_DISABLE_REVERSE + status_reg = mddi_host_reg_in(STAT); + + if ((int_reg & MDDI_INT_MDDI_IN) || + ((int_en & MDDI_INT_MDDI_IN) && + ((int_reg == 0) || (status_reg & MDDI_STAT_CLIENT_WAKEUP_REQ)))) { + /* + * The MDDI_IN condition will clear itself, and so it is + * possible that MDDI_IN was the reason for the isr firing, + * even though the interrupt register does not have the + * MDDI_IN bit set. To check if this was the case we need to + * look at the status register bit that signifies a client + * initiated wakeup. If the status register bit is set, as well + * as the MDDI_IN interrupt enabled, then we treat this as a + * client initiated wakeup. + */ + if (int_reg & MDDI_INT_MDDI_IN) + pmhctl->int_type.in_count++; + mddi_process_client_initiated_wakeup(); + } +#endif + + if (int_reg & MDDI_INT_LINK_STATE_CHANGES) { + pmhctl->int_type.state_change_count++; + mddi_report_state_change(int_reg); + } + + if (int_reg & MDDI_INT_PRI_LINK_LIST_DONE) { + pmhctl->int_type.ll_done_count++; + mddi_process_link_list_done(); + } +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (int_reg & MDDI_INT_REV_DATA_AVAIL) { + pmhctl->int_type.rev_avail_count++; + mddi_process_rev_packets(); + } +#endif + + if (int_reg & MDDI_INT_ERROR_CONDITIONS) { + pmhctl->int_type.error_count++; + mddi_report_errors(int_reg); + + mddi_host_reg_out(INT, int_reg & MDDI_INT_ERROR_CONDITIONS); + } +#ifndef FEATURE_MDDI_DISABLE_REVERSE + mddi_issue_reverse_encapsulation(); + + if ((pmhctl->rev_state != MDDI_REV_ENCAP_ISSUED) && + (pmhctl->rev_state != MDDI_REV_STATUS_REQ_ISSUED)) +#endif + /* don't want simultaneous reverse and forward with Eagle */ + mddi_queue_forward_linked_list(); + + if (int_reg & MDDI_INT_NO_CMD_PKTS_PEND) { + /* this interrupt is used to kick the isr when hibernation is disabled */ + mddi_host_reg_outm(INTEN, MDDI_INT_NO_CMD_PKTS_PEND, 0); + } + + if ((!mddi_host_mdp_active_flag) && + (!mddi_vsync_detect_enabled) && + (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) && + (pmhctl->llist_info.waiting_start_idx == UNASSIGNED_INDEX) && + (pmhctl->rev_state == MDDI_REV_IDLE)) { + if (pmhctl->link_state == MDDI_LINK_HIBERNATING) { + mddi_host_disable_io_clock(); + mddi_host_disable_hclk(); + } +#ifdef FEATURE_MDDI_HOST_ENABLE_EARLY_HIBERNATION + else if ((pmhctl->link_state == MDDI_LINK_ACTIVE) && + (!pmhctl->disable_hibernation)) { + mddi_host_reg_out(CMD, MDDI_CMD_POWERDOWN); + } +#endif + } +} + +static void mddi_host_isr_primary(void) +{ + mddi_curr_host = MDDI_HOST_PRIM; + mddi_host_isr(); +} + +irqreturn_t mddi_pmdh_isr_proxy(int irq, void *ptr) +{ + mddi_host_isr_primary(); + return IRQ_HANDLED; +} + +static void mddi_host_isr_external(void) +{ + mddi_curr_host = MDDI_HOST_EXT; + mddi_host_isr(); + mddi_curr_host = MDDI_HOST_PRIM; +} + +irqreturn_t mddi_emdh_isr_proxy(int irq, void *ptr) +{ + mddi_host_isr_external(); + return IRQ_HANDLED; +} + +static void mddi_host_initialize_registers(mddi_host_type host_idx) +{ + uint32 pad_reg_val; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if (pmhctl->driver_state == MDDI_DRIVER_ENABLED) + return; + + /* turn on HCLK to MDDI host core */ + mddi_host_enable_hclk(); + + /* MDDI Reset command */ + mddi_host_reg_out(CMD, MDDI_CMD_RESET); + + /* Version register (= 0x01) */ + mddi_host_reg_out(VERSION, 0x0001); + + /* Bytes per subframe register */ + mddi_host_reg_out(BPS, MDDI_HOST_BYTES_PER_SUBFRAME); + + /* Subframes per media frames register (= 0x03) */ + mddi_host_reg_out(SPM, 0x0003); + + /* Turn Around 1 register (= 0x05) */ + mddi_host_reg_out(TA1_LEN, 0x0005); + + /* Turn Around 2 register (= 0x0C) */ + mddi_host_reg_out(TA2_LEN, MDDI_HOST_TA2_LEN); + + /* Drive hi register (= 0x96) */ + mddi_host_reg_out(DRIVE_HI, 0x0096); + + /* Drive lo register (= 0x32) */ + mddi_host_reg_out(DRIVE_LO, 0x0032); + + /* Display wakeup count register (= 0x3c) */ + mddi_host_reg_out(DISP_WAKE, 0x003c); + + /* Reverse Rate Divisor register (= 0x2) */ + mddi_host_reg_out(REV_RATE_DIV, MDDI_HOST_REV_RATE_DIV); + +#ifndef FEATURE_MDDI_DISABLE_REVERSE + /* Reverse Pointer Size */ + mddi_host_reg_out(REV_SIZE, MDDI_REV_BUFFER_SIZE); + + /* Rev Encap Size */ + mddi_host_reg_out(REV_ENCAP_SZ, pmhctl->rev_pkt_size); +#endif + + /* Periodic Rev Encap */ + /* don't send periodically */ + mddi_host_reg_out(CMD, MDDI_CMD_PERIODIC_REV_ENCAP); + + pad_reg_val = mddi_host_reg_in(PAD_CTL); + if (pad_reg_val == 0) { + /* If we are turning on band gap, need to wait 5us before turning + * on the rest of the PAD */ + mddi_host_reg_out(PAD_CTL, 0x08000); + udelay(5); + } +#ifdef T_MSM7200 + /* Recommendation from PAD hw team */ + mddi_host_reg_out(PAD_CTL, 0xa850a); +#else + /* Recommendation from PAD hw team */ + mddi_host_reg_out(PAD_CTL, 0xa850f); +#endif + + pad_reg_val = 0x00220020; + +#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40) + mddi_host_reg_out(PAD_IO_CTL, 0x00320000); + mddi_host_reg_out(PAD_CAL, pad_reg_val); +#endif + + mddi_host_core_version = mddi_host_reg_inm(CORE_VER, 0xffff); + +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (mddi_host_core_version >= 8) + mddi_rev_ptr_workaround = FALSE; + pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start; +#endif + + if ((mddi_host_core_version > 8) && (mddi_host_core_version < 0x19)) + mddi_host_reg_out(TEST, 0x2); + + /* Need an even number for counts */ + mddi_host_reg_out(DRIVER_START_CNT, 0x60006); + +#ifndef T_MSM7500 + /* Setup defaults for MDP related register */ + mddi_host_reg_out(MDP_VID_FMT_DES, 0x5666); + mddi_host_reg_out(MDP_VID_PIX_ATTR, 0x00C3); + mddi_host_reg_out(MDP_VID_CLIENTID, 0); +#endif + + /* automatically hibernate after 1 empty subframe */ + if (pmhctl->disable_hibernation) + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE); + else + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE | 1); + + /* Bring up link if display (client) requests it */ +#ifdef MDDI_HOST_DISP_LISTEN + mddi_host_reg_out(CMD, MDDI_CMD_DISP_LISTEN); +#else + mddi_host_reg_out(CMD, MDDI_CMD_DISP_IGNORE); +#endif + +} + +void mddi_host_configure_interrupts(mddi_host_type host_idx, boolean enable) +{ + unsigned long flags; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + spin_lock_irqsave(&mddi_host_spin_lock, flags); + + /* turn on HCLK to MDDI host core if it has been disabled */ + mddi_host_enable_hclk(); + /* Clear MDDI Interrupt enable reg */ + mddi_host_reg_out(INTEN, 0); + + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + + if (enable) { + pmhctl->driver_state = MDDI_DRIVER_ENABLED; + + if (host_idx == MDDI_HOST_PRIM) { + if (request_irq + (INT_MDDI_PRI, mddi_pmdh_isr_proxy, IRQF_DISABLED, + "PMDH", 0) != 0) + printk(KERN_ERR + "a mddi: unable to request_irq\n"); + else { + int_mddi_pri_flag = TRUE; + irq_enabled = 1; + } + } else { + if (request_irq + (INT_MDDI_EXT, mddi_emdh_isr_proxy, IRQF_DISABLED, + "EMDH", 0) != 0) + printk(KERN_ERR + "b mddi: unable to request_irq\n"); + else + int_mddi_ext_flag = TRUE; + } + + /* Set MDDI Interrupt enable reg -- Enable Reverse data avail */ +#ifdef FEATURE_MDDI_DISABLE_REVERSE + mddi_host_reg_out(INTEN, + MDDI_INT_ERROR_CONDITIONS | + MDDI_INT_LINK_STATE_CHANGES); +#else + /* Reverse Pointer register */ + pmhctl->rev_ptr_written = FALSE; + + mddi_host_reg_out(INTEN, + MDDI_INT_REV_DATA_AVAIL | + MDDI_INT_ERROR_CONDITIONS | + MDDI_INT_LINK_STATE_CHANGES); + pmhctl->rtd_counter = mddi_rtd_frequency; + pmhctl->client_status_cnt = 0; +#endif + } else { + if (pmhctl->driver_state == MDDI_DRIVER_ENABLED) + pmhctl->driver_state = MDDI_DRIVER_DISABLED; + } + +} + +/* + * mddi_host_client_cnt_reset: + * reset client_status_cnt to 0 to make sure host does not + * send RTD cmd to client right after resume before mddi + * client be powered up. this fix "MDDI RTD Failure" problem + */ +void mddi_host_client_cnt_reset(void) +{ + unsigned long flags; + mddi_host_cntl_type *pmhctl; + + pmhctl = &(mhctl[MDDI_HOST_PRIM]); + spin_lock_irqsave(&mddi_host_spin_lock, flags); + pmhctl->client_status_cnt = 0; + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); +} + +static void mddi_host_powerup(mddi_host_type host_idx) +{ + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if (pmhctl->link_state != MDDI_LINK_DISABLED) + return; + + /* enable IO_CLK and hclk to MDDI host core */ + mddi_host_enable_io_clock(); + + mddi_host_initialize_registers(host_idx); + mddi_host_configure_interrupts(host_idx, TRUE); + + pmhctl->link_state = MDDI_LINK_ACTIVATING; + + /* Link activate command */ + mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE); + +#ifdef CLKRGM_MDDI_IO_CLOCK_IN_MHZ + MDDI_MSG_NOTICE("MDDI Host: Activating Link %d Mbps\n", + CLKRGM_MDDI_IO_CLOCK_IN_MHZ * 2); +#else + MDDI_MSG_NOTICE("MDDI Host: Activating Link\n"); +#endif + + /* Initialize the timer */ + if (host_idx == MDDI_HOST_PRIM) + mddi_host_timer_service(0); +} + +void mddi_send_fw_link_skew_cal(mddi_host_type host_idx) +{ + mddi_host_reg_out(CMD, MDDI_CMD_FW_LINK_SKEW_CAL); + MDDI_MSG_DEBUG("%s: Skew Calibration done!!\n", __func__); +} + + +void mddi_host_init(mddi_host_type host_idx) +/* Write out the MDDI configuration registers */ +{ + static boolean initialized = FALSE; + mddi_host_cntl_type *pmhctl; + + if (host_idx >= MDDI_NUM_HOST_CORES) { + MDDI_MSG_ERR("Invalid host core index\n"); + return; + } + + if (!initialized) { + uint16 idx; + mddi_host_type host; + + for (host = MDDI_HOST_PRIM; host < MDDI_NUM_HOST_CORES; host++) { + pmhctl = &(mhctl[host]); + initialized = TRUE; + + pmhctl->llist_ptr = + dma_alloc_coherent(NULL, MDDI_LLIST_POOL_SIZE, + &(pmhctl->llist_dma_addr), + GFP_KERNEL); + pmhctl->llist_dma_ptr = + (mddi_linked_list_type *) (void *)pmhctl-> + llist_dma_addr; +#ifdef FEATURE_MDDI_DISABLE_REVERSE + pmhctl->rev_data_buf = NULL; + if (pmhctl->llist_ptr == NULL) +#else + mddi_rev_user.waiting = FALSE; + init_completion(&(mddi_rev_user.done_comp)); + pmhctl->rev_data_buf = + dma_alloc_coherent(NULL, MDDI_MAX_REV_DATA_SIZE, + &(pmhctl->rev_data_dma_addr), + GFP_KERNEL); + if ((pmhctl->llist_ptr == NULL) + || (pmhctl->rev_data_buf == NULL)) +#endif + { + MDDI_MSG_CRIT + ("unable to alloc non-cached memory\n"); + } + llist_extern[host] = pmhctl->llist_ptr; + llist_dma_extern[host] = pmhctl->llist_dma_ptr; + llist_extern_notify[host] = pmhctl->llist_notify; + + for (idx = 0; idx < UNASSIGNED_INDEX; idx++) { + init_completion(& + (pmhctl->llist_notify[idx]. + done_comp)); + } + init_completion(&(pmhctl->mddi_llist_avail_comp)); + spin_lock_init(&mddi_host_spin_lock); + pmhctl->mddi_waiting_for_llist_avail = FALSE; + pmhctl->mddi_rev_ptr_write_val = + (uint32) (void *)(pmhctl->rev_data_dma_addr); + pmhctl->rev_ptr_start = (void *)pmhctl->rev_data_buf; + + pmhctl->rev_pkt_size = MDDI_DEFAULT_REV_PKT_SIZE; + pmhctl->rev_state = MDDI_REV_IDLE; +#ifdef IMAGE_MODEM_PROC + /* assume hibernation state is last state from APPS proc, so that + * we don't reinitialize the host core */ + pmhctl->link_state = MDDI_LINK_HIBERNATING; +#else + pmhctl->link_state = MDDI_LINK_DISABLED; +#endif + pmhctl->driver_state = MDDI_DRIVER_DISABLED; + pmhctl->disable_hibernation = FALSE; + + /* initialize llist variables */ + pmhctl->llist_info.transmitting_start_idx = + UNASSIGNED_INDEX; + pmhctl->llist_info.transmitting_end_idx = + UNASSIGNED_INDEX; + pmhctl->llist_info.waiting_start_idx = UNASSIGNED_INDEX; + pmhctl->llist_info.waiting_end_idx = UNASSIGNED_INDEX; + pmhctl->llist_info.reg_read_idx = UNASSIGNED_INDEX; + pmhctl->llist_info.next_free_idx = + MDDI_FIRST_DYNAMIC_LLIST_IDX; + pmhctl->llist_info.reg_read_waiting = FALSE; + + mddi_vsync_detect_enabled = FALSE; + mddi_gpio.polling_enabled = FALSE; + + pmhctl->int_type.count = 0; + pmhctl->int_type.in_count = 0; + pmhctl->int_type.disp_req_count = 0; + pmhctl->int_type.state_change_count = 0; + pmhctl->int_type.ll_done_count = 0; + pmhctl->int_type.rev_avail_count = 0; + pmhctl->int_type.error_count = 0; + pmhctl->int_type.rev_encap_count = 0; + pmhctl->int_type.llist_ptr_write_1 = 0; + pmhctl->int_type.llist_ptr_write_2 = 0; + + pmhctl->stats.fwd_crc_count = 0; + pmhctl->stats.rev_crc_count = 0; + pmhctl->stats.pri_underflow = 0; + pmhctl->stats.sec_underflow = 0; + pmhctl->stats.rev_overflow = 0; + pmhctl->stats.pri_overwrite = 0; + pmhctl->stats.sec_overwrite = 0; + pmhctl->stats.rev_overwrite = 0; + pmhctl->stats.dma_failure = 0; + pmhctl->stats.rtd_failure = 0; + pmhctl->stats.reg_read_failure = 0; +#ifdef FEATURE_MDDI_UNDERRUN_RECOVERY + pmhctl->stats.pri_underrun_detected = 0; +#endif + + pmhctl->log_parms.rtd_cnt = 0; + pmhctl->log_parms.rev_enc_cnt = 0; + pmhctl->log_parms.vid_cnt = 0; + pmhctl->log_parms.reg_acc_cnt = 0; + pmhctl->log_parms.cli_stat_cnt = 0; + pmhctl->log_parms.cli_cap_cnt = 0; + pmhctl->log_parms.reg_read_cnt = 0; + pmhctl->log_parms.link_active_cnt = 0; + pmhctl->log_parms.link_hibernate_cnt = 0; + pmhctl->log_parms.fwd_crc_cnt = 0; + pmhctl->log_parms.rev_crc_cnt = 0; + pmhctl->log_parms.vsync_response_cnt = 0; + + prev_parms[host_idx] = pmhctl->log_parms; + mddi_client_capability_pkt.packet_length = 0; + } + +#ifndef T_MSM7500 + /* tell clock driver we are user of this PLL */ + MDDI_HOST_ENABLE_IO_CLOCK; +#endif + } + + mddi_host_powerup(host_idx); + pmhctl = &(mhctl[host_idx]); +} + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT +static uint32 mddi_client_id; + +uint32 mddi_get_client_id(void) +{ + +#ifndef FEATURE_MDDI_DISABLE_REVERSE + mddi_host_type host_idx = MDDI_HOST_PRIM; + static boolean client_detection_try = FALSE; + mddi_host_cntl_type *pmhctl; + unsigned long flags; + uint16 saved_rev_pkt_size; + int ret; + + if (!client_detection_try) { + /* Toshiba display requires larger drive_lo value */ + mddi_host_reg_out(DRIVE_LO, 0x0050); + + pmhctl = &(mhctl[MDDI_HOST_PRIM]); + + saved_rev_pkt_size = pmhctl->rev_pkt_size; + + /* Increase Rev Encap Size */ + pmhctl->rev_pkt_size = MDDI_CLIENT_CAPABILITY_REV_PKT_SIZE; + mddi_host_reg_out(REV_ENCAP_SZ, pmhctl->rev_pkt_size); + + /* disable hibernation temporarily */ + if (!pmhctl->disable_hibernation) + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE); + + mddi_rev_user.waiting = TRUE; + INIT_COMPLETION(mddi_rev_user.done_comp); + + spin_lock_irqsave(&mddi_host_spin_lock, flags); + + /* turn on clock(s), if they have been disabled */ + mddi_host_enable_hclk(); + mddi_host_enable_io_clock(); + + mddi_client_capability_request = TRUE; + + if (pmhctl->rev_state == MDDI_REV_IDLE) { + /* attempt to send the reverse encapsulation now */ + mddi_issue_reverse_encapsulation(); + } + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + + wait_for_completion_killable(&(mddi_rev_user.done_comp)); + + /* Set Rev Encap Size back to its original value */ + pmhctl->rev_pkt_size = saved_rev_pkt_size; + mddi_host_reg_out(REV_ENCAP_SZ, pmhctl->rev_pkt_size); + + /* reenable auto-hibernate */ + if (!pmhctl->disable_hibernation) + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE | 1); + + mddi_host_reg_out(DRIVE_LO, 0x0032); + client_detection_try = TRUE; + + mddi_client_id = (mddi_client_capability_pkt.Mfr_Name<<16) | + mddi_client_capability_pkt.Product_Code; + + if (!mddi_client_id) + mddi_disable(1); + + ret = mddi_client_power(mddi_client_id); + if (ret < 0) + MDDI_MSG_ERR("mddi_client_power return %d", ret); + } + +#endif + + return mddi_client_id; +} +#endif + +void mddi_host_powerdown(mddi_host_type host_idx) +{ + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if (host_idx >= MDDI_NUM_HOST_CORES) { + MDDI_MSG_ERR("Invalid host core index\n"); + return; + } + + if (pmhctl->driver_state == MDDI_DRIVER_RESET) { + return; + } + + if (host_idx == MDDI_HOST_PRIM) { + /* disable timer */ + del_timer(&mddi_host_timer); + } + + mddi_host_configure_interrupts(host_idx, FALSE); + + /* turn on HCLK to MDDI host core if it has been disabled */ + mddi_host_enable_hclk(); + + /* MDDI Reset command */ + mddi_host_reg_out(CMD, MDDI_CMD_RESET); + + /* Pad Control Register */ + mddi_host_reg_out(PAD_CTL, 0x0); + + /* disable IO_CLK and hclk to MDDI host core */ + mddi_host_disable_io_clock(); + mddi_host_disable_hclk(); + + pmhctl->link_state = MDDI_LINK_DISABLED; + pmhctl->driver_state = MDDI_DRIVER_RESET; + + MDDI_MSG_NOTICE("MDDI Host: Disabling Link\n"); + +} + +uint16 mddi_get_next_free_llist_item(mddi_host_type host_idx, boolean wait) +{ + unsigned long flags; + uint16 ret_idx; + boolean forced_wait = FALSE; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + ret_idx = pmhctl->llist_info.next_free_idx; + + pmhctl->llist_info.next_free_idx++; + if (pmhctl->llist_info.next_free_idx >= MDDI_NUM_DYNAMIC_LLIST_ITEMS) + pmhctl->llist_info.next_free_idx = MDDI_FIRST_DYNAMIC_LLIST_IDX; + spin_lock_irqsave(&mddi_host_spin_lock, flags); + if (pmhctl->llist_notify[ret_idx].in_use) { + if (!wait) { + pmhctl->llist_info.next_free_idx = ret_idx; + ret_idx = UNASSIGNED_INDEX; + } else { + forced_wait = TRUE; + INIT_COMPLETION(pmhctl->mddi_llist_avail_comp); + } + } + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + + if (forced_wait) { + wait_for_completion_killable(& + (pmhctl-> + mddi_llist_avail_comp)); + MDDI_MSG_ERR("task waiting on mddi llist item\n"); + } + + if (ret_idx != UNASSIGNED_INDEX) { + pmhctl->llist_notify[ret_idx].waiting = FALSE; + pmhctl->llist_notify[ret_idx].done_cb = NULL; + pmhctl->llist_notify[ret_idx].in_use = TRUE; + pmhctl->llist_notify[ret_idx].next_idx = UNASSIGNED_INDEX; + } + + return ret_idx; +} + +uint16 mddi_get_reg_read_llist_item(mddi_host_type host_idx, boolean wait) +{ +#ifdef FEATURE_MDDI_DISABLE_REVERSE + MDDI_MSG_CRIT("No reverse link available\n"); + (void)wait; + return FALSE; +#else + unsigned long flags; + uint16 ret_idx; + boolean error = FALSE; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + spin_lock_irqsave(&mddi_host_spin_lock, flags); + if (pmhctl->llist_info.reg_read_idx != UNASSIGNED_INDEX) { + /* need to block here or is this an error condition? */ + error = TRUE; + ret_idx = UNASSIGNED_INDEX; + } + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + + if (!error) { + ret_idx = pmhctl->llist_info.reg_read_idx = + mddi_get_next_free_llist_item(host_idx, wait); + /* clear the reg_read_waiting flag */ + pmhctl->llist_info.reg_read_waiting = FALSE; + } + + if (error) + MDDI_MSG_ERR("***** Reg read still in progress! ****\n"); + return ret_idx; +#endif + +} + +void mddi_queue_forward_packets(uint16 first_llist_idx, + uint16 last_llist_idx, + boolean wait, + mddi_llist_done_cb_type llist_done_cb, + mddi_host_type host_idx) +{ + unsigned long flags; + mddi_linked_list_type *llist; + mddi_linked_list_type *llist_dma; + mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]); + + if ((first_llist_idx >= UNASSIGNED_INDEX) || + (last_llist_idx >= UNASSIGNED_INDEX)) { + MDDI_MSG_ERR("MDDI queueing invalid linked list\n"); + return; + } + + if (pmhctl->link_state == MDDI_LINK_DISABLED) + MDDI_MSG_CRIT("MDDI host powered down!\n"); + + llist = pmhctl->llist_ptr; + llist_dma = pmhctl->llist_dma_ptr; + + /* clean cache so MDDI host can read data */ + memory_barrier(); + + pmhctl->llist_notify[last_llist_idx].waiting = wait; + if (wait) + INIT_COMPLETION(pmhctl->llist_notify[last_llist_idx].done_comp); + pmhctl->llist_notify[last_llist_idx].done_cb = llist_done_cb; + + spin_lock_irqsave(&mddi_host_spin_lock, flags); + + if ((pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) && + (pmhctl->llist_info.waiting_start_idx == UNASSIGNED_INDEX) && + (pmhctl->rev_state == MDDI_REV_IDLE)) { + /* no packets are currently transmitting */ +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (first_llist_idx == pmhctl->llist_info.reg_read_idx) { + /* This is the special case where the packet is a register read. */ + pmhctl->rev_state = MDDI_REV_REG_READ_ISSUED; + mddi_reg_read_retry = 0; + /* mddi_rev_reg_read_attempt = 1; */ + } +#endif + /* assign transmitting index values */ + pmhctl->llist_info.transmitting_start_idx = first_llist_idx; + pmhctl->llist_info.transmitting_end_idx = last_llist_idx; + + /* turn on clock(s), if they have been disabled */ + mddi_host_enable_hclk(); + mddi_host_enable_io_clock(); + pmhctl->int_type.llist_ptr_write_1++; + /* Write to primary pointer register */ + dma_coherent_pre_ops(); + mddi_host_reg_out(PRI_PTR, &llist_dma[first_llist_idx]); + + /* enable interrupt when complete */ + mddi_host_reg_outm(INTEN, MDDI_INT_PRI_LINK_LIST_DONE, + MDDI_INT_PRI_LINK_LIST_DONE); + + } else if (pmhctl->llist_info.waiting_start_idx == UNASSIGNED_INDEX) { +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (first_llist_idx == pmhctl->llist_info.reg_read_idx) { + /* + * we have a register read to send but need to wait + * for current reverse activity to end or there are + * packets currently transmitting + */ + /* mddi_rev_reg_read_attempt = 0; */ + pmhctl->llist_info.reg_read_waiting = TRUE; + } +#endif + + /* assign waiting index values */ + pmhctl->llist_info.waiting_start_idx = first_llist_idx; + pmhctl->llist_info.waiting_end_idx = last_llist_idx; + } else { + uint16 prev_end_idx = pmhctl->llist_info.waiting_end_idx; +#ifndef FEATURE_MDDI_DISABLE_REVERSE + if (first_llist_idx == pmhctl->llist_info.reg_read_idx) { + /* + * we have a register read to send but need to wait + * for current reverse activity to end or there are + * packets currently transmitting + */ + /* mddi_rev_reg_read_attempt = 0; */ + pmhctl->llist_info.reg_read_waiting = TRUE; + } +#endif + + llist = pmhctl->llist_ptr; + + /* clear end flag in previous last packet */ + llist[prev_end_idx].link_controller_flags = 0; + pmhctl->llist_notify[prev_end_idx].next_idx = first_llist_idx; + + /* set the next_packet_pointer of the previous last packet */ + llist[prev_end_idx].next_packet_pointer = + (void *)(&llist_dma[first_llist_idx]); + + /* clean cache so MDDI host can read data */ + memory_barrier(); + + /* assign new waiting last index value */ + pmhctl->llist_info.waiting_end_idx = last_llist_idx; + } + + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + +} + +void mddi_host_write_pix_attr_reg(uint32 value) +{ + (void)value; +} + +void mddi_queue_reverse_encapsulation(boolean wait) +{ +#ifdef FEATURE_MDDI_DISABLE_REVERSE + MDDI_MSG_CRIT("No reverse link available\n"); + (void)wait; +#else + unsigned long flags; + boolean error = FALSE; + mddi_host_type host_idx = MDDI_HOST_PRIM; + mddi_host_cntl_type *pmhctl = &(mhctl[MDDI_HOST_PRIM]); + + spin_lock_irqsave(&mddi_host_spin_lock, flags); + + /* turn on clock(s), if they have been disabled */ + mddi_host_enable_hclk(); + mddi_host_enable_io_clock(); + + if (wait) { + if (!mddi_rev_user.waiting) { + mddi_rev_user.waiting = TRUE; + INIT_COMPLETION(mddi_rev_user.done_comp); + } else + error = TRUE; + } + mddi_rev_encap_user_request = TRUE; + + if (pmhctl->rev_state == MDDI_REV_IDLE) { + /* attempt to send the reverse encapsulation now */ + mddi_host_type orig_host_idx = mddi_curr_host; + mddi_curr_host = host_idx; + mddi_issue_reverse_encapsulation(); + mddi_curr_host = orig_host_idx; + } + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + + if (error) { + MDDI_MSG_ERR("Reverse Encap request already in progress\n"); + } else if (wait) + wait_for_completion_killable(&(mddi_rev_user.done_comp)); +#endif +} + +/* ISR to be executed */ +boolean mddi_set_rev_handler(mddi_rev_handler_type handler, uint16 pkt_type) +{ +#ifdef FEATURE_MDDI_DISABLE_REVERSE + MDDI_MSG_CRIT("No reverse link available\n"); + (void)handler; + (void)pkt_type; + return (FALSE); +#else + unsigned long flags; + uint16 hdlr; + boolean handler_set = FALSE; + boolean overwrite = FALSE; + mddi_host_type host_idx = MDDI_HOST_PRIM; + mddi_host_cntl_type *pmhctl = &(mhctl[MDDI_HOST_PRIM]); + + /* Disable interrupts */ + spin_lock_irqsave(&mddi_host_spin_lock, flags); + + for (hdlr = 0; hdlr < MAX_MDDI_REV_HANDLERS; hdlr++) { + if (mddi_rev_pkt_handler[hdlr].pkt_type == pkt_type) { + mddi_rev_pkt_handler[hdlr].handler = handler; + if (handler == NULL) { + /* clearing handler from table */ + mddi_rev_pkt_handler[hdlr].pkt_type = + INVALID_PKT_TYPE; + handler_set = TRUE; + if (pkt_type == 0x10) { /* video stream packet */ + /* ensure HCLK on to MDDI host core before register write */ + mddi_host_enable_hclk(); + /* No longer getting video, so reset rev encap size to default */ + pmhctl->rev_pkt_size = + MDDI_DEFAULT_REV_PKT_SIZE; + mddi_host_reg_out(REV_ENCAP_SZ, + pmhctl->rev_pkt_size); + } + } else { + /* already a handler for this packet */ + overwrite = TRUE; + } + break; + } + } + if ((hdlr >= MAX_MDDI_REV_HANDLERS) && (handler != NULL)) { + /* assigning new handler */ + for (hdlr = 0; hdlr < MAX_MDDI_REV_HANDLERS; hdlr++) { + if (mddi_rev_pkt_handler[hdlr].pkt_type == + INVALID_PKT_TYPE) { + if ((pkt_type == 0x10) && /* video stream packet */ + (pmhctl->rev_pkt_size < + MDDI_VIDEO_REV_PKT_SIZE)) { + /* ensure HCLK on to MDDI host core before register write */ + mddi_host_enable_hclk(); + /* Increase Rev Encap Size */ + pmhctl->rev_pkt_size = + MDDI_VIDEO_REV_PKT_SIZE; + mddi_host_reg_out(REV_ENCAP_SZ, + pmhctl->rev_pkt_size); + } + mddi_rev_pkt_handler[hdlr].handler = handler; + mddi_rev_pkt_handler[hdlr].pkt_type = pkt_type; + handler_set = TRUE; + break; + } + } + } + + /* Restore interrupts */ + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + + if (overwrite) + MDDI_MSG_ERR("Overwriting previous rev packet handler\n"); + + return handler_set; + +#endif +} /* mddi_set_rev_handler */ + +void mddi_host_disable_hibernation(boolean disable) +{ + mddi_host_type host_idx = MDDI_HOST_PRIM; + mddi_host_cntl_type *pmhctl = &(mhctl[MDDI_HOST_PRIM]); + + if (disable) { + pmhctl->disable_hibernation = TRUE; + /* hibernation will be turned off by isr next time it is entered */ + } else { + if (pmhctl->disable_hibernation) { + unsigned long flags; + spin_lock_irqsave(&mddi_host_spin_lock, flags); + if (!MDDI_HOST_IS_HCLK_ON) + MDDI_HOST_ENABLE_HCLK; + mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE | 1); + spin_unlock_irqrestore(&mddi_host_spin_lock, flags); + pmhctl->disable_hibernation = FALSE; + } + } +} + +void mddi_mhctl_remove(mddi_host_type host_idx) +{ + mddi_host_cntl_type *pmhctl; + + pmhctl = &(mhctl[host_idx]); + + dma_free_coherent(NULL, MDDI_LLIST_POOL_SIZE, (void *)pmhctl->llist_ptr, + pmhctl->llist_dma_addr); + + dma_free_coherent(NULL, MDDI_MAX_REV_DATA_SIZE, + (void *)pmhctl->rev_data_buf, + pmhctl->rev_data_dma_addr); +} diff --git a/drivers/video/msm/mddihosti.h b/drivers/video/msm/mddihosti.h new file mode 100644 index 000000000000..96675a0b77c3 --- /dev/null +++ b/drivers/video/msm/mddihosti.h @@ -0,0 +1,552 @@ +/* Copyright (c) 2008-2010, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef MDDIHOSTI_H +#define MDDIHOSTI_H + +#include "msm_fb.h" +#include "mddihost.h" +#include + +/* Register offsets in MDDI, applies to both msm_pmdh_base and + * (u32)msm_emdh_base. */ +#define MDDI_CMD 0x0000 +#define MDDI_VERSION 0x0004 +#define MDDI_PRI_PTR 0x0008 +#define MDDI_BPS 0x0010 +#define MDDI_SPM 0x0014 +#define MDDI_INT 0x0018 +#define MDDI_INTEN 0x001c +#define MDDI_REV_PTR 0x0020 +#define MDDI_REV_SIZE 0x0024 +#define MDDI_STAT 0x0028 +#define MDDI_REV_RATE_DIV 0x002c +#define MDDI_REV_CRC_ERR 0x0030 +#define MDDI_TA1_LEN 0x0034 +#define MDDI_TA2_LEN 0x0038 +#define MDDI_TEST 0x0040 +#define MDDI_REV_PKT_CNT 0x0044 +#define MDDI_DRIVE_HI 0x0048 +#define MDDI_DRIVE_LO 0x004c +#define MDDI_DISP_WAKE 0x0050 +#define MDDI_REV_ENCAP_SZ 0x0054 +#define MDDI_RTD_VAL 0x0058 +#define MDDI_PAD_CTL 0x0068 +#define MDDI_DRIVER_START_CNT 0x006c +#define MDDI_CORE_VER 0x008c +#define MDDI_FIFO_ALLOC 0x0090 +#define MDDI_PAD_IO_CTL 0x00a0 +#define MDDI_PAD_CAL 0x00a4 + +#ifdef ENABLE_MDDI_MULTI_READ_WRITE +#define MDDI_HOST_MAX_CLIENT_REG_IN_SAME_ADDR 128 +#else +#define MDDI_HOST_MAX_CLIENT_REG_IN_SAME_ADDR 1 +#endif + +extern int32 mddi_client_type; +extern u32 mddi_msg_level; + +/* No longer need to write to clear these registers */ +#define xxxx_mddi_host_reg_outm(reg, mask, val) \ +do { \ + if (host_idx == MDDI_HOST_PRIM) \ + mddi_host_reg_outm_pmdh(reg, mask, val); \ + else \ + mddi_host_reg_outm_emdh(reg, mask, val); \ +} while (0) + +#define mddi_host_reg_outm(reg, mask, val) \ +do { \ + unsigned long __addr; \ + if (host_idx == MDDI_HOST_PRIM) \ + __addr = (u32)msm_pmdh_base + MDDI_##reg; \ + else \ + __addr = (u32)msm_emdh_base + MDDI_##reg; \ + writel((readl(__addr) & ~(mask)) | ((val) & (mask)), __addr); \ +} while (0) + +#define xxxx_mddi_host_reg_out(reg, val) \ +do { \ + if (host_idx == MDDI_HOST_PRIM) \ + mddi_host_reg_out_pmdh(reg, val); \ + else \ + mddi_host_reg_out_emdh(reg, val); \ + } while (0) + +#define mddi_host_reg_out(reg, val) \ +do { \ + if (host_idx == MDDI_HOST_PRIM) \ + writel(val, (u32)msm_pmdh_base + MDDI_##reg); \ + else \ + writel(val, (u32)msm_emdh_base + MDDI_##reg); \ +} while (0) + +#define xxxx_mddi_host_reg_in(reg) \ + ((host_idx) ? \ + mddi_host_reg_in_emdh(reg) : mddi_host_reg_in_pmdh(reg)); + +#define mddi_host_reg_in(reg) \ +((host_idx) ? \ + readl((u32)msm_emdh_base + MDDI_##reg) : \ + readl((u32)msm_pmdh_base + MDDI_##reg)) \ + +#define xxxx_mddi_host_reg_inm(reg, mask) \ + ((host_idx) ? \ + mddi_host_reg_inm_emdh(reg, mask) : \ + mddi_host_reg_inm_pmdh(reg, mask);) + +#define mddi_host_reg_inm(reg, mask) \ +((host_idx) ? \ + readl((u32)msm_emdh_base + MDDI_##reg) & (mask) : \ + readl((u32)msm_pmdh_base + MDDI_##reg) & (mask)) \ + +/* Using non-cacheable pmem, so do nothing */ +#define mddi_invalidate_cache_lines(addr_start, num_bytes) +/* + * Using non-cacheable pmem, so do nothing with cache + * but, ensure write goes out to memory + */ +#define mddi_flush_cache_lines(addr_start, num_bytes) \ + (void) addr_start; \ + (void) num_bytes; \ + memory_barrier() + +/* Since this translates to Remote Procedure Calls to check on clock status +* just use a local variable to keep track of io_clock */ +#define MDDI_HOST_IS_IO_CLOCK_ON mddi_host_io_clock_on +#define MDDI_HOST_ENABLE_IO_CLOCK +#define MDDI_HOST_DISABLE_IO_CLOCK +#define MDDI_HOST_IS_HCLK_ON mddi_host_hclk_on +#define MDDI_HOST_ENABLE_HCLK +#define MDDI_HOST_DISABLE_HCLK +#define FEATURE_MDDI_HOST_IO_CLOCK_CONTROL_DISABLE +#define FEATURE_MDDI_HOST_HCLK_CONTROL_DISABLE + +#define TRAMP_MDDI_HOST_ISR TRAMP_MDDI_PRI_ISR +#define TRAMP_MDDI_HOST_EXT_ISR TRAMP_MDDI_EXT_ISR +#define MDP_LINE_COUNT_BMSK 0x3ff +#define MDP_SYNC_STATUS 0x000c +#define MDP_LINE_COUNT \ +(readl(msm_mdp_base + MDP_SYNC_STATUS) & MDP_LINE_COUNT_BMSK) + +/* MDP sends 256 pixel packets, so lower value hibernates more without +* significantly increasing latency of waiting for next subframe */ +#define MDDI_HOST_BYTES_PER_SUBFRAME 0x3C00 + +#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40) +#define MDDI_HOST_TA2_LEN 0x001a +#define MDDI_HOST_REV_RATE_DIV 0x0004 +#else +#define MDDI_HOST_TA2_LEN 0x000c +#define MDDI_HOST_REV_RATE_DIV 0x0002 +#endif + +#define MDDI_MSG_EMERG(msg, ...) \ + if (mddi_msg_level > 0) \ + printk(KERN_EMERG msg, ## __VA_ARGS__); +#define MDDI_MSG_ALERT(msg, ...) \ + if (mddi_msg_level > 1) \ + printk(KERN_ALERT msg, ## __VA_ARGS__); +#define MDDI_MSG_CRIT(msg, ...) \ + if (mddi_msg_level > 2) \ + printk(KERN_CRIT msg, ## __VA_ARGS__); +#define MDDI_MSG_ERR(msg, ...) \ + if (mddi_msg_level > 3) \ + printk(KERN_ERR msg, ## __VA_ARGS__); +#define MDDI_MSG_WARNING(msg, ...) \ + if (mddi_msg_level > 4) \ + printk(KERN_WARNING msg, ## __VA_ARGS__); +#define MDDI_MSG_NOTICE(msg, ...) \ + if (mddi_msg_level > 5) \ + printk(KERN_NOTICE msg, ## __VA_ARGS__); +#define MDDI_MSG_INFO(msg, ...) \ + if (mddi_msg_level > 6) \ + printk(KERN_INFO msg, ## __VA_ARGS__); +#define MDDI_MSG_DEBUG(msg, ...) \ + if (mddi_msg_level > 7) \ + printk(KERN_DEBUG msg, ## __VA_ARGS__); + +#define GCC_PACKED __attribute__((packed)) +typedef struct GCC_PACKED { + uint16 packet_length; + /* total # of bytes in the packet not including + the packet_length field. */ + + uint16 packet_type; + /* A Packet Type of 70 identifies the packet as + a Client status Packet. */ + + uint16 bClient_ID; + /* This field is reserved for future use and shall + be set to zero. */ + +} mddi_rev_packet_type; + +typedef struct GCC_PACKED { + uint16 packet_length; + /* total # of bytes in the packet not including + the packet_length field. */ + + uint16 packet_type; + /* A Packet Type of 70 identifies the packet as + a Client status Packet. */ + + uint16 bClient_ID; + /* This field is reserved for future use and shall + be set to zero. */ + + uint16 reverse_link_request; + /* 16 bit unsigned integer with number of bytes client + needs in the * reverse encapsulation message + to transmit data. */ + + uint8 crc_error_count; + uint8 capability_change; + uint16 graphics_busy_flags; + + uint16 parameter_CRC; + /* 16-bit CRC of all the bytes in the packet + including Packet Length. */ + +} mddi_client_status_type; + +typedef struct GCC_PACKED { + uint16 packet_length; + /* total # of bytes in the packet not including + the packet_length field. */ + + uint16 packet_type; + /* A Packet Type of 66 identifies the packet as + a Client Capability Packet. */ + + uint16 bClient_ID; + /* This field is reserved for future use and + shall be set to zero. */ + + uint16 Protocol_Version; + uint16 Minimum_Protocol_Version; + uint16 Data_Rate_Capability; + uint8 Interface_Type_Capability; + uint8 Number_of_Alt_Displays; + uint16 PostCal_Data_Rate; + uint16 Bitmap_Width; + uint16 Bitmap_Height; + uint16 Display_Window_Width; + uint16 Display_Window_Height; + uint32 Color_Map_Size; + uint16 Color_Map_RGB_Width; + uint16 RGB_Capability; + uint8 Monochrome_Capability; + uint8 Reserved_1; + uint16 Y_Cb_Cr_Capability; + uint16 Bayer_Capability; + uint16 Alpha_Cursor_Image_Planes; + uint32 Client_Feature_Capability_Indicators; + uint8 Maximum_Video_Frame_Rate_Capability; + uint8 Minimum_Video_Frame_Rate_Capability; + uint16 Minimum_Sub_frame_Rate; + uint16 Audio_Buffer_Depth; + uint16 Audio_Channel_Capability; + uint16 Audio_Sample_Rate_Capability; + uint8 Audio_Sample_Resolution; + uint8 Mic_Audio_Sample_Resolution; + uint16 Mic_Sample_Rate_Capability; + uint8 Keyboard_Data_Format; + uint8 pointing_device_data_format; + uint16 content_protection_type; + uint16 Mfr_Name; + uint16 Product_Code; + uint16 Reserved_3; + uint32 Serial_Number; + uint8 Week_of_Manufacture; + uint8 Year_of_Manufacture; + + uint16 parameter_CRC; + /* 16-bit CRC of all the bytes in the packet including Packet Length. */ + +} mddi_client_capability_type; + +typedef struct GCC_PACKED { + uint16 packet_length; + /* total # of bytes in the packet not including the packet_length field. */ + + uint16 packet_type; + /* A Packet Type of 16 identifies the packet as a Video Stream Packet. */ + + uint16 bClient_ID; + /* This field is reserved for future use and shall be set to zero. */ + + uint16 video_data_format_descriptor; + /* format of each pixel in the Pixel Data in the present stream in the + * present packet. + * If bits [15:13] = 000 monochrome + * If bits [15:13] = 001 color pixels (palette). + * If bits [15:13] = 010 color pixels in raw RGB + * If bits [15:13] = 011 data in 4:2:2 Y Cb Cr format + * If bits [15:13] = 100 Bayer pixels + */ + + uint16 pixel_data_attributes; + /* interpreted as follows: + * Bits [1:0] = 11 pixel data is displayed to both eyes + * Bits [1:0] = 10 pixel data is routed to the left eye only. + * Bits [1:0] = 01 pixel data is routed to the right eye only. + * Bits [1:0] = 00 pixel data is routed to the alternate display. + * Bit 2 is 0 Pixel Data is in the standard progressive format. + * Bit 2 is 1 Pixel Data is in interlace format. + * Bit 3 is 0 Pixel Data is in the standard progressive format. + * Bit 3 is 1 Pixel Data is in alternate pixel format. + * Bit 4 is 0 Pixel Data is to or from the display frame buffer. + * Bit 4 is 1 Pixel Data is to or from the camera. + * Bit 5 is 0 pixel data contains the next consecutive row of pixels. + * Bit 5 is 1 X Left Edge, Y Top Edge, X Right Edge, Y Bottom Edge, + * X Start, and Y Start parameters are not defined and + * shall be ignored by the client. + * Bits [7:6] = 01 Pixel data is written to the offline image buffer. + * Bits [7:6] = 00 Pixel data is written to the buffer to refresh display. + * Bits [7:6] = 11 Pixel data is written to all image buffers. + * Bits [7:6] = 10 Invalid. Reserved for future use. + * Bits 8 through 11 alternate display number. + * Bits 12 through 14 are reserved for future use and shall be set to zero. + * Bit 15 is 1 the row of pixels is the last row of pixels in a frame. + */ + + uint16 x_left_edge; + uint16 y_top_edge; + /* X,Y coordinate of the top left edge of the screen window */ + + uint16 x_right_edge; + uint16 y_bottom_edge; + /* X,Y coordinate of the bottom right edge of the window being updated. */ + + uint16 x_start; + uint16 y_start; + /* (X Start, Y Start) is the first pixel in the Pixel Data field below. */ + + uint16 pixel_count; + /* number of pixels in the Pixel Data field below. */ + + uint16 parameter_CRC; + /* 16-bit CRC of all bytes from the Packet Length to the Pixel Count. */ + + uint16 reserved; + /* 16-bit variable to make structure align on 4 byte boundary */ + +} mddi_video_stream_packet_type; + +typedef struct GCC_PACKED { + uint16 packet_length; + /* total # of bytes in the packet not including the packet_length field. */ + + uint16 packet_type; + /* A Packet Type of 146 identifies the packet as a Register Access Packet. */ + + uint16 bClient_ID; + /* This field is reserved for future use and shall be set to zero. */ + + uint16 read_write_info; + /* Bits 13:0 a 14-bit unsigned integer that specifies the number of + * 32-bit Register Data List items to be transferred in the + * Register Data List field. + * Bits[15:14] = 00 Write to register(s); + * Bits[15:14] = 10 Read from register(s); + * Bits[15:14] = 11 Response to a Read. + * Bits[15:14] = 01 this value is reserved for future use. */ + + uint32 register_address; + /* the register address that is to be written to or read from. */ + + uint16 parameter_CRC; + /* 16-bit CRC of all bytes from the Packet Length to the Register Address. */ + + uint32 register_data_list[MDDI_HOST_MAX_CLIENT_REG_IN_SAME_ADDR]; + /* list of 4-byte register data values for/from client registers */ + /* For multi-read/write, 512(128 * 4) bytes of data available */ + +} mddi_register_access_packet_type; + +typedef union GCC_PACKED { + mddi_video_stream_packet_type video_pkt; + mddi_register_access_packet_type register_pkt; +#ifdef ENABLE_MDDI_MULTI_READ_WRITE + /* add 1008 byte pad to ensure 1024 byte llist struct, that can be + * manipulated easily with cache */ + uint32 alignment_pad[252]; /* 1008 bytes */ +#else + /* add 48 byte pad to ensure 64 byte llist struct, that can be + * manipulated easily with cache */ + uint32 alignment_pad[12]; /* 48 bytes */ +#endif +} mddi_packet_header_type; + +typedef struct GCC_PACKED mddi_host_llist_struct { + uint16 link_controller_flags; + uint16 packet_header_count; + uint16 packet_data_count; + void *packet_data_pointer; + struct mddi_host_llist_struct *next_packet_pointer; + uint16 reserved; + mddi_packet_header_type packet_header; +} mddi_linked_list_type; + +typedef struct { + struct completion done_comp; + mddi_llist_done_cb_type done_cb; + uint16 next_idx; + boolean waiting; + boolean in_use; +} mddi_linked_list_notify_type; + +#ifdef ENABLE_MDDI_MULTI_READ_WRITE +#define MDDI_LLIST_POOL_SIZE 0x10000 +#else +#define MDDI_LLIST_POOL_SIZE 0x1000 +#endif +#define MDDI_MAX_NUM_LLIST_ITEMS (MDDI_LLIST_POOL_SIZE / \ + sizeof(mddi_linked_list_type)) +#define UNASSIGNED_INDEX MDDI_MAX_NUM_LLIST_ITEMS +#define MDDI_FIRST_DYNAMIC_LLIST_IDX 0 + +/* Static llist items can be used for applications that frequently send + * the same set of packets using the linked list interface. */ +/* Here we configure for 6 static linked list items: + * The 1st is used for a the adaptive backlight setting. + * and the remaining 5 are used for sending window adjustments for + * MDDI clients that need windowing info sent separate from video + * packets. */ +#define MDDI_NUM_STATIC_ABL_ITEMS 1 +#define MDDI_NUM_STATIC_WINDOW_ITEMS 5 +#define MDDI_NUM_STATIC_LLIST_ITEMS (MDDI_NUM_STATIC_ABL_ITEMS + \ + MDDI_NUM_STATIC_WINDOW_ITEMS) +#define MDDI_NUM_DYNAMIC_LLIST_ITEMS (MDDI_MAX_NUM_LLIST_ITEMS - \ + MDDI_NUM_STATIC_LLIST_ITEMS) + +#define MDDI_FIRST_STATIC_LLIST_IDX MDDI_NUM_DYNAMIC_LLIST_ITEMS +#define MDDI_FIRST_STATIC_ABL_IDX MDDI_FIRST_STATIC_LLIST_IDX +#define MDDI_FIRST_STATIC_WINDOW_IDX (MDDI_FIRST_STATIC_LLIST_IDX + \ + MDDI_NUM_STATIC_ABL_ITEMS) + +/* GPIO registers */ +#define VSYNC_WAKEUP_REG 0x80 +#define GPIO_REG 0x81 +#define GPIO_OUTPUT_REG 0x82 +#define GPIO_INTERRUPT_REG 0x83 +#define GPIO_INTERRUPT_ENABLE_REG 0x84 +#define GPIO_POLARITY_REG 0x85 + +/* Interrupt Bits */ +#define MDDI_INT_PRI_PTR_READ 0x0001 +#define MDDI_INT_SEC_PTR_READ 0x0002 +#define MDDI_INT_REV_DATA_AVAIL 0x0004 +#define MDDI_INT_DISP_REQ 0x0008 +#define MDDI_INT_PRI_UNDERFLOW 0x0010 +#define MDDI_INT_SEC_UNDERFLOW 0x0020 +#define MDDI_INT_REV_OVERFLOW 0x0040 +#define MDDI_INT_CRC_ERROR 0x0080 +#define MDDI_INT_MDDI_IN 0x0100 +#define MDDI_INT_PRI_OVERWRITE 0x0200 +#define MDDI_INT_SEC_OVERWRITE 0x0400 +#define MDDI_INT_REV_OVERWRITE 0x0800 +#define MDDI_INT_DMA_FAILURE 0x1000 +#define MDDI_INT_LINK_ACTIVE 0x2000 +#define MDDI_INT_IN_HIBERNATION 0x4000 +#define MDDI_INT_PRI_LINK_LIST_DONE 0x8000 +#define MDDI_INT_SEC_LINK_LIST_DONE 0x10000 +#define MDDI_INT_NO_CMD_PKTS_PEND 0x20000 +#define MDDI_INT_RTD_FAILURE 0x40000 + +#define MDDI_INT_ERROR_CONDITIONS ( \ + MDDI_INT_PRI_UNDERFLOW | MDDI_INT_SEC_UNDERFLOW | \ + MDDI_INT_REV_OVERFLOW | MDDI_INT_CRC_ERROR | \ + MDDI_INT_PRI_OVERWRITE | MDDI_INT_SEC_OVERWRITE | \ + MDDI_INT_RTD_FAILURE | \ + MDDI_INT_REV_OVERWRITE | MDDI_INT_DMA_FAILURE) + +#define MDDI_INT_LINK_STATE_CHANGES ( \ + MDDI_INT_LINK_ACTIVE | MDDI_INT_IN_HIBERNATION) + +/* Status Bits */ +#define MDDI_STAT_LINK_ACTIVE 0x0001 +#define MDDI_STAT_NEW_REV_PTR 0x0002 +#define MDDI_STAT_NEW_PRI_PTR 0x0004 +#define MDDI_STAT_NEW_SEC_PTR 0x0008 +#define MDDI_STAT_IN_HIBERNATION 0x0010 +#define MDDI_STAT_PRI_LINK_LIST_DONE 0x0020 +#define MDDI_STAT_SEC_LINK_LIST_DONE 0x0040 +#define MDDI_STAT_PENDING_TIMING_PKT 0x0080 +#define MDDI_STAT_PENDING_REV_ENCAP 0x0100 +#define MDDI_STAT_PENDING_POWERDOWN 0x0200 +#define MDDI_STAT_RTD_MEAS_FAIL 0x0800 +#define MDDI_STAT_CLIENT_WAKEUP_REQ 0x1000 + +/* Command Bits */ +#define MDDI_CMD_POWERDOWN 0x0100 +#define MDDI_CMD_POWERUP 0x0200 +#define MDDI_CMD_HIBERNATE 0x0300 +#define MDDI_CMD_RESET 0x0400 +#define MDDI_CMD_DISP_IGNORE 0x0501 +#define MDDI_CMD_DISP_LISTEN 0x0500 +#define MDDI_CMD_SEND_REV_ENCAP 0x0600 +#define MDDI_CMD_GET_CLIENT_CAP 0x0601 +#define MDDI_CMD_GET_CLIENT_STATUS 0x0602 +#define MDDI_CMD_SEND_RTD 0x0700 +#define MDDI_CMD_LINK_ACTIVE 0x0900 +#define MDDI_CMD_PERIODIC_REV_ENCAP 0x0A00 +#define MDDI_CMD_FW_LINK_SKEW_CAL 0x0D00 + +extern void mddi_host_init(mddi_host_type host); +extern void mddi_host_powerdown(mddi_host_type host); +extern uint16 mddi_get_next_free_llist_item(mddi_host_type host, boolean wait); +extern uint16 mddi_get_reg_read_llist_item(mddi_host_type host, boolean wait); +extern void mddi_queue_forward_packets(uint16 first_llist_idx, + uint16 last_llist_idx, + boolean wait, + mddi_llist_done_cb_type llist_done_cb, + mddi_host_type host); + +extern void mddi_host_write_pix_attr_reg(uint32 value); +extern void mddi_client_lcd_gpio_poll(uint32 poll_reg_val); +extern void mddi_client_lcd_vsync_detected(boolean detected); +extern void mddi_host_disable_hibernation(boolean disable); + +extern mddi_linked_list_type *llist_extern[]; +extern mddi_linked_list_type *llist_dma_extern[]; +extern mddi_linked_list_notify_type *llist_extern_notify[]; +extern struct timer_list mddi_host_timer; + +typedef struct { + uint16 transmitting_start_idx; + uint16 transmitting_end_idx; + uint16 waiting_start_idx; + uint16 waiting_end_idx; + uint16 reg_read_idx; + uint16 next_free_idx; + boolean reg_read_waiting; +} mddi_llist_info_type; + +extern mddi_llist_info_type mddi_llist; + +#define MDDI_GPIO_DEFAULT_POLLING_INTERVAL 200 +typedef struct { + uint32 polling_reg; + uint32 polling_val; + uint32 polling_interval; + boolean polling_enabled; +} mddi_gpio_info_type; + +uint32 mddi_get_client_id(void); +void mddi_mhctl_remove(mddi_host_type host_idx); +void mddi_host_timer_service(unsigned long data); +void mddi_host_client_cnt_reset(void); +#endif /* MDDIHOSTI_H */ diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c new file mode 100644 index 000000000000..85ba24966f33 --- /dev/null +++ b/drivers/video/msm/mdp.c @@ -0,0 +1,2701 @@ +/* drivers/video/msm_fb/mdp.c + * + * MSM MDP Interface (used by framebuffer core) + * + * Copyright (c) 2007-2012, The Linux Foundation. All rights reserved. + * Copyright (C) 2007 Google Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mdp.h" +#include "msm_fb.h" +#ifdef CONFIG_FB_MSM_MDP40 +#include "mdp4.h" +#endif +#include "mipi_dsi.h" + +uint32 mdp4_extn_disp; + +static struct clk *mdp_clk; +static struct clk *mdp_pclk; +static struct clk *mdp_lut_clk; +int mdp_rev; + +static struct platform_device *mdp_init_pdev; +static struct regulator *footswitch; +static unsigned int mdp_footswitch_on; + +struct completion mdp_ppp_comp; +struct semaphore mdp_ppp_mutex; +struct semaphore mdp_pipe_ctrl_mutex; + +unsigned long mdp_timer_duration = (HZ/20); /* 50 msecond */ + +boolean mdp_ppp_waiting = FALSE; +uint32 mdp_tv_underflow_cnt; +uint32 mdp_lcdc_underflow_cnt; + +boolean mdp_current_clk_on = FALSE; +boolean mdp_is_in_isr = FALSE; + +/* + * legacy mdp_in_processing is only for DMA2-MDDI + * this applies to DMA2 block only + */ +uint32 mdp_in_processing = FALSE; + +#ifdef CONFIG_FB_MSM_MDP40 +uint32 mdp_intr_mask = MDP4_ANY_INTR_MASK; +#else +uint32 mdp_intr_mask = MDP_ANY_INTR_MASK; +#endif + +MDP_BLOCK_TYPE mdp_debug[MDP_MAX_BLOCK]; + +atomic_t mdp_block_power_cnt[MDP_MAX_BLOCK]; + +spinlock_t mdp_spin_lock; +struct workqueue_struct *mdp_dma_wq; /*mdp dma wq */ +struct workqueue_struct *mdp_vsync_wq; /*mdp vsync wq */ + +struct workqueue_struct *mdp_hist_wq; /*mdp histogram wq */ + +static struct workqueue_struct *mdp_pipe_ctrl_wq; /* mdp mdp pipe ctrl wq */ +static struct delayed_work mdp_pipe_ctrl_worker; + +static boolean mdp_suspended = FALSE; +DEFINE_MUTEX(mdp_suspend_mutex); + +#ifdef CONFIG_FB_MSM_MDP40 +struct mdp_dma_data dma2_data; +struct mdp_dma_data dma_s_data; +struct mdp_dma_data dma_e_data; +ulong mdp4_display_intf; +#else +static struct mdp_dma_data dma2_data; +static struct mdp_dma_data dma_s_data; +#ifndef CONFIG_FB_MSM_MDP303 +static struct mdp_dma_data dma_e_data; +#endif +#endif + +#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL +struct mdp_dma_data dma_wb_data; +#endif + +static struct mdp_dma_data dma3_data; + +extern ktime_t mdp_dma2_last_update_time; + +extern uint32 mdp_dma2_update_time_in_usec; +extern int mdp_lcd_rd_cnt_offset_slow; +extern int mdp_lcd_rd_cnt_offset_fast; +extern int mdp_usec_diff_threshold; + +extern int first_pixel_start_x; +extern int first_pixel_start_y; + +#ifdef MSM_FB_ENABLE_DBGFS +struct dentry *mdp_dir; +#endif + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static int mdp_suspend(struct platform_device *pdev, pm_message_t state); +#else +#define mdp_suspend NULL +#endif + +struct timeval mdp_dma2_timeval; +struct timeval mdp_ppp_timeval; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static struct early_suspend early_suspend; +#endif + +static u32 mdp_irq; + +static uint32 mdp_prim_panel_type = NO_PANEL; +#ifndef CONFIG_FB_MSM_MDP22 + +struct list_head mdp_hist_lut_list; +DEFINE_MUTEX(mdp_hist_lut_list_mutex); + +uint32_t mdp_block2base(uint32_t block) +{ + uint32_t base = 0x0; + switch (block) { + case MDP_BLOCK_DMA_P: + base = 0x90000; + break; + case MDP_BLOCK_DMA_S: + base = 0xA0000; + break; + case MDP_BLOCK_VG_1: + base = 0x20000; + break; + case MDP_BLOCK_VG_2: + base = 0x30000; + break; + case MDP_BLOCK_RGB_1: + base = 0x40000; + break; + case MDP_BLOCK_RGB_2: + base = 0x50000; + break; + case MDP_BLOCK_OVERLAY_0: + base = 0x10000; + break; + case MDP_BLOCK_OVERLAY_1: + base = 0x18000; + break; + case MDP_BLOCK_OVERLAY_2: + base = (mdp_rev >= MDP_REV_44) ? 0x88000 : 0; + break; + default: + break; + } + return base; +} + +static uint32_t mdp_pp_block2hist_lut(uint32_t block) +{ + uint32_t valid = 0; + switch (block) { + case MDP_BLOCK_DMA_P: + valid = (mdp_rev >= MDP_REV_40) ? 1 : 0; + break; + case MDP_BLOCK_DMA_S: + valid = (mdp_rev >= MDP_REV_40) ? 1 : 0; + break; + case MDP_BLOCK_VG_1: + valid = (mdp_rev >= MDP_REV_40) ? 1 : 0; + break; + case MDP_BLOCK_VG_2: + valid = (mdp_rev >= MDP_REV_40) ? 1 : 0; + break; + default: + break; + } + return valid; +} + +static void mdp_hist_lut_init_mgmt(struct mdp_hist_lut_mgmt *mgmt, + uint32_t block) +{ + mutex_init(&mgmt->lock); + mgmt->block = block; + + mutex_lock(&mdp_hist_lut_list_mutex); + list_add(&mgmt->list, &mdp_hist_lut_list); + mutex_unlock(&mdp_hist_lut_list_mutex); +} + +static int mdp_hist_lut_init(void) +{ + struct mdp_hist_lut_mgmt *temp; + struct list_head *pos, *q; + INIT_LIST_HEAD(&mdp_hist_lut_list); + + if (mdp_rev >= MDP_REV_30) { + temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL); + if (!temp) + goto exit; + mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_DMA_P); + } + + if (mdp_rev >= MDP_REV_40) { + temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL); + if (!temp) + goto exit_list; + mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_VG_1); + + temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL); + if (!temp) + goto exit_list; + mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_VG_2); + } + + if (mdp_rev > MDP_REV_42) { + temp = kmalloc(sizeof(struct mdp_hist_lut_mgmt), GFP_KERNEL); + if (!temp) + goto exit_list; + mdp_hist_lut_init_mgmt(temp, MDP_BLOCK_DMA_S); + } + return 0; + +exit_list: + mutex_lock(&mdp_hist_lut_list_mutex); + list_for_each_safe(pos, q, &mdp_hist_lut_list) { + temp = list_entry(pos, struct mdp_hist_lut_mgmt, list); + list_del(pos); + kfree(temp); + } + mutex_unlock(&mdp_hist_lut_list_mutex); +exit: + pr_err("Failed initializing histogram LUT memory\n"); + return -ENOMEM; +} + +static int mdp_hist_lut_block2mgmt(uint32_t block, + struct mdp_hist_lut_mgmt **mgmt) +{ + struct mdp_hist_lut_mgmt *temp, *output; + int ret = 0; + + output = NULL; + + mutex_lock(&mdp_hist_lut_list_mutex); + list_for_each_entry(temp, &mdp_hist_lut_list, list) { + if (temp->block == block) + output = temp; + } + mutex_unlock(&mdp_hist_lut_list_mutex); + + if (output == NULL) + ret = -EINVAL; + else + *mgmt = output; + + return ret; +} + +#define MDP_HIST_LUT_SIZE (256) +static int mdp_hist_lut_write_off(struct mdp_hist_lut_data *data, + struct mdp_hist_lut_info *info, uint32_t offset) +{ + int i; + uint32_t element[MDP_HIST_LUT_SIZE]; + uint32_t base = mdp_block2base(info->block); + uint32_t sel = info->bank_sel; + + + if (data->len != MDP_HIST_LUT_SIZE) { + pr_err("%s: data->len != %d", __func__, MDP_HIST_LUT_SIZE); + return -EINVAL; + } + + if (copy_from_user(&element, data->data, + MDP_HIST_LUT_SIZE * sizeof(uint32_t))) { + pr_err("%s: Error copying histogram data", __func__); + return -ENOMEM; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < MDP_HIST_LUT_SIZE; i++) + MDP_OUTP(MDP_BASE + base + offset + (0x400*(sel)) + (4*i), + element[i]); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + return 0; +} + +static int mdp_hist_lut_write(struct mdp_hist_lut_data *data, + struct mdp_hist_lut_info *info) +{ + int ret = 0; + + if (data->block != info->block) { + ret = -1; + pr_err("%s, data/info mdp_block mismatch! %d != %d\n", + __func__, data->block, info->block); + goto error; + } + + switch (data->block) { + case MDP_BLOCK_VG_1: + case MDP_BLOCK_VG_2: + ret = mdp_hist_lut_write_off(data, info, 0x3400); + break; + case MDP_BLOCK_DMA_P: + case MDP_BLOCK_DMA_S: + ret = mdp_hist_lut_write_off(data, info, 0x4800); + break; + default: + ret = -EINVAL; + goto error; + } + +error: + return ret; +} + +#define MDP_HIST_LUT_VG_EN_MASK (0x20000) +#define MDP_HIST_LUT_VG_EN_SHIFT (17) +#define MDP_HIST_LUT_VG_EN_OFFSET (0x0058) +#define MDP_HIST_LUT_VG_SEL_OFFSET (0x0064) +static void mdp_hist_lut_commit_vg(struct mdp_hist_lut_info *info) +{ + uint32_t out_en, temp_en; + uint32_t base = mdp_block2base(info->block); + temp_en = (info->is_enabled) ? (1 << MDP_HIST_LUT_VG_EN_SHIFT) : 0x0; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + out_en = inpdw(MDP_BASE + base + MDP_HIST_LUT_VG_EN_OFFSET) & + ~MDP_HIST_LUT_VG_EN_MASK; + MDP_OUTP(MDP_BASE + base + MDP_HIST_LUT_VG_EN_OFFSET, out_en | temp_en); + + if (info->has_sel_update) + MDP_OUTP(MDP_BASE + base + MDP_HIST_LUT_VG_SEL_OFFSET, + info->bank_sel); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +#define MDP_HIST_LUT_DMA_EN_MASK (0x7) +#define MDP_HIST_LUT_DMA_SEL_MASK (0x400) +#define MDP_HIST_LUT_DMA_SEL_SHIFT (10) +#define MDP_HIST_LUT_DMA_P_OFFSET (0x0070) +#define MDP_HIST_LUT_DMA_S_OFFSET (0x0028) +static void mdp_hist_lut_commit_dma(struct mdp_hist_lut_info *info) +{ + uint32_t out, temp, mask; + uint32_t base = mdp_block2base(info->block); + uint32_t offset = (info->block == MDP_BLOCK_DMA_P) ? + MDP_HIST_LUT_DMA_P_OFFSET : MDP_HIST_LUT_DMA_S_OFFSET; + + mask = MDP_HIST_LUT_DMA_EN_MASK; + temp = (info->is_enabled) ? 0x7 : 0x0; + + if (info->has_sel_update) { + mask |= MDP_HIST_LUT_DMA_SEL_MASK; + temp |= ((info->bank_sel & 0x1) << MDP_HIST_LUT_DMA_SEL_SHIFT); + } + + out = inpdw(MDP_BASE + base + offset) & ~mask; + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + MDP_OUTP(MDP_BASE + base + offset, out | temp); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +static void mdp_hist_lut_commit_info(struct mdp_hist_lut_info *info) +{ + switch (info->block) { + case MDP_BLOCK_VG_1: + case MDP_BLOCK_VG_2: + mdp_hist_lut_commit_vg(info); + break; + case MDP_BLOCK_DMA_P: + case MDP_BLOCK_DMA_S: + mdp_hist_lut_commit_dma(info); + break; + default: + goto error; + } + +error: + return; +} + +static void mdp_hist_lut_update_info(struct mdp_hist_lut_info *info, int ops) +{ + info->bank_sel = (ops & 0x8) >> 3; + info->is_enabled = (ops & 0x1) ? TRUE : FALSE; + info->has_sel_update = (ops & 0x10) ? TRUE : FALSE; +} + +int mdp_hist_lut_config(struct mdp_hist_lut_data *data) +{ + struct mdp_hist_lut_mgmt *mgmt = NULL; + struct mdp_hist_lut_info info; + int ret = 0; + + if (!mdp_pp_block2hist_lut(data->block)) { + ret = -ENOTTY; + goto error; + } + + ret = mdp_hist_lut_block2mgmt(data->block, &mgmt); + if (ret) + goto error; + + mutex_lock(&mgmt->lock); + + info.block = mgmt->block; + + mdp_hist_lut_update_info(&info, data->ops); + + switch ((data->ops & 0x6) >> 1) { + case 0x1: + pr_info("%s: histogram LUT read not supported\n", __func__); + break; + case 0x2: + ret = mdp_hist_lut_write(data, &info); + if (ret) + goto error_lock; + break; + default: + break; + } + + mdp_hist_lut_commit_info(&info); + +error_lock: + mutex_unlock(&mgmt->lock); +error: + return ret; +} + +DEFINE_MUTEX(mdp_lut_push_sem); +static int mdp_lut_i; +static int mdp_lut_hw_update(struct fb_cmap *cmap) +{ + int i; + u16 *c[3]; + u16 r, g, b; + + c[0] = cmap->green; + c[1] = cmap->blue; + c[2] = cmap->red; + + for (i = 0; i < cmap->len; i++) { + if (copy_from_user(&r, cmap->red++, sizeof(r)) || + copy_from_user(&g, cmap->green++, sizeof(g)) || + copy_from_user(&b, cmap->blue++, sizeof(b))) + return -EFAULT; + +#ifdef CONFIG_FB_MSM_MDP40 + MDP_OUTP(MDP_BASE + 0x94800 + +#else + MDP_OUTP(MDP_BASE + 0x93800 + +#endif + (0x400*mdp_lut_i) + cmap->start*4 + i*4, + ((g & 0xff) | + ((b & 0xff) << 8) | + ((r & 0xff) << 16))); + } + + return 0; +} + +static int mdp_lut_push; +static int mdp_lut_push_i; +static int mdp_lut_update_nonlcdc(struct fb_info *info, struct fb_cmap *cmap) +{ + int ret; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + ret = mdp_lut_hw_update(cmap); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + if (ret) + return ret; + + mutex_lock(&mdp_lut_push_sem); + mdp_lut_push = 1; + mdp_lut_push_i = mdp_lut_i; + mutex_unlock(&mdp_lut_push_sem); + + mdp_lut_i = (mdp_lut_i + 1)%2; + + return 0; +} + +static int mdp_lut_update_lcdc(struct fb_info *info, struct fb_cmap *cmap) +{ + int ret; + uint32_t out; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + ret = mdp_lut_hw_update(cmap); + + if (ret) { + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + return ret; + } + + /*mask off non LUT select bits*/ + out = inpdw(MDP_BASE + 0x90070) & ~((0x1 << 10) | 0x7); + MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | 0x7 | out); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + mdp_lut_i = (mdp_lut_i + 1)%2; + + return 0; +} + +static void mdp_lut_enable(void) +{ + uint32_t out; + if (mdp_lut_push) { + mutex_lock(&mdp_lut_push_sem); + mdp_lut_push = 0; + out = inpdw(MDP_BASE + 0x90070) & ~((0x1 << 10) | 0x7); + MDP_OUTP(MDP_BASE + 0x90070, + (mdp_lut_push_i << 10) | 0x7 | out); + mutex_unlock(&mdp_lut_push_sem); + } +} + +#define MDP_REV42_HIST_MAX_BIN 128 +#define MDP_REV41_HIST_MAX_BIN 32 + +#define MDP_HIST_DATA32_R_OFF 0x0100 +#define MDP_HIST_DATA32_G_OFF 0x0200 +#define MDP_HIST_DATA32_B_OFF 0x0300 + +#define MDP_HIST_DATA128_R_OFF 0x0400 +#define MDP_HIST_DATA128_G_OFF 0x0800 +#define MDP_HIST_DATA128_B_OFF 0x0C00 + +#define MDP_HIST_DATA_LUMA_OFF 0x0200 + +#define MDP_HIST_EXTRA_DATA0_OFF 0x0028 +#define MDP_HIST_EXTRA_DATA1_OFF 0x002C + +struct mdp_hist_mgmt *mdp_hist_mgmt_array[MDP_HIST_MGMT_MAX]; + +void __mdp_histogram_kickoff(struct mdp_hist_mgmt *mgmt) +{ + char *mdp_hist_base = MDP_BASE + mgmt->base; + if (mgmt->mdp_is_hist_data == TRUE) { + MDP_OUTP(mdp_hist_base + 0x0004, mgmt->frame_cnt); + MDP_OUTP(mdp_hist_base, 1); + } +} + +void __mdp_histogram_reset(struct mdp_hist_mgmt *mgmt) +{ + char *mdp_hist_base = MDP_BASE + mgmt->base; + MDP_OUTP(mdp_hist_base + 0x000C, 1); +} + +static void mdp_hist_read_work(struct work_struct *data); + +static int mdp_hist_init_mgmt(struct mdp_hist_mgmt *mgmt, uint32_t block) +{ + uint32_t bins, extra, index, term = 0; + init_completion(&mgmt->mdp_hist_comp); + mutex_init(&mgmt->mdp_hist_mutex); + mutex_init(&mgmt->mdp_do_hist_mutex); + mgmt->block = block; + mgmt->base = mdp_block2base(block); + mgmt->mdp_is_hist_start = FALSE; + mgmt->mdp_is_hist_data = FALSE; + mgmt->mdp_is_hist_valid = FALSE; + mgmt->mdp_is_hist_init = FALSE; + mgmt->frame_cnt = 0; + mgmt->bit_mask = 0; + mgmt->num_bins = 0; + switch (block) { + case MDP_BLOCK_DMA_P: + term = MDP_HISTOGRAM_TERM_DMA_P; + bins = (mdp_rev >= MDP_REV_42) ? MDP_REV42_HIST_MAX_BIN : + MDP_REV41_HIST_MAX_BIN; + extra = 2; + mgmt->base += (mdp_rev >= MDP_REV_40) ? 0x5000 : 0x4000; + index = MDP_HIST_MGMT_DMA_P; + break; + case MDP_BLOCK_DMA_S: + term = MDP_HISTOGRAM_TERM_DMA_S; + bins = MDP_REV42_HIST_MAX_BIN; + extra = 2; + mgmt->base += 0x5000; + index = MDP_HIST_MGMT_DMA_S; + break; + case MDP_BLOCK_VG_1: + term = MDP_HISTOGRAM_TERM_VG_1; + bins = MDP_REV42_HIST_MAX_BIN; + extra = 1; + mgmt->base += 0x6000; + index = MDP_HIST_MGMT_VG_1; + break; + case MDP_BLOCK_VG_2: + term = MDP_HISTOGRAM_TERM_VG_2; + bins = MDP_REV42_HIST_MAX_BIN; + extra = 1; + mgmt->base += 0x6000; + index = MDP_HIST_MGMT_VG_2; + break; + default: + term = MDP_HISTOGRAM_TERM_DMA_P; + bins = (mdp_rev >= MDP_REV_42) ? MDP_REV42_HIST_MAX_BIN : + MDP_REV41_HIST_MAX_BIN; + extra = 2; + mgmt->base += (mdp_rev >= MDP_REV_40) ? 0x5000 : 0x4000; + index = MDP_HIST_MGMT_DMA_P; + } + mgmt->irq_term = term; + + mgmt->c0 = kmalloc(bins * sizeof(uint32_t), GFP_KERNEL); + if (mgmt->c0 == NULL) + goto error; + + mgmt->c1 = kmalloc(bins * sizeof(uint32_t), GFP_KERNEL); + if (mgmt->c1 == NULL) + goto error_1; + + mgmt->c2 = kmalloc(bins * sizeof(uint32_t), GFP_KERNEL); + if (mgmt->c2 == NULL) + goto error_2; + + mgmt->extra_info = kmalloc(extra * sizeof(uint32_t), GFP_KERNEL); + if (mgmt->extra_info == NULL) + goto error_extra; + + INIT_WORK(&mgmt->mdp_histogram_worker, mdp_hist_read_work); + mgmt->hist = NULL; + + mdp_hist_mgmt_array[index] = mgmt; + return 0; + +error_extra: + kfree(mgmt->c2); +error_2: + kfree(mgmt->c1); +error_1: + kfree(mgmt->c0); +error: + return -ENOMEM; +} + +static void mdp_hist_del_mgmt(struct mdp_hist_mgmt *mgmt) +{ + kfree(mgmt->extra_info); + kfree(mgmt->c2); + kfree(mgmt->c1); + kfree(mgmt->c0); +} + +static int mdp_histogram_init(void) +{ + struct mdp_hist_mgmt *temp; + int i, ret; + mdp_hist_wq = alloc_workqueue("mdp_hist_wq", + WQ_NON_REENTRANT | WQ_UNBOUND, 0); + + for (i = 0; i < MDP_HIST_MGMT_MAX; i++) + mdp_hist_mgmt_array[i] = NULL; + + if (mdp_rev >= MDP_REV_30) { + temp = kmalloc(sizeof(struct mdp_hist_mgmt), GFP_KERNEL); + if (!temp) + goto exit; + ret = mdp_hist_init_mgmt(temp, MDP_BLOCK_DMA_P); + if (ret) { + kfree(temp); + goto exit; + } + } + + if (mdp_rev >= MDP_REV_40) { + temp = kmalloc(sizeof(struct mdp_hist_mgmt), GFP_KERNEL); + if (!temp) + goto exit_list; + ret = mdp_hist_init_mgmt(temp, MDP_BLOCK_VG_1); + if (ret) + goto exit_list; + + temp = kmalloc(sizeof(struct mdp_hist_mgmt), GFP_KERNEL); + if (!temp) + goto exit_list; + ret = mdp_hist_init_mgmt(temp, MDP_BLOCK_VG_2); + if (ret) + goto exit_list; + } + + if (mdp_rev >= MDP_REV_42) { + temp = kmalloc(sizeof(struct mdp_hist_mgmt), GFP_KERNEL); + if (!temp) + goto exit_list; + ret = mdp_hist_init_mgmt(temp, MDP_BLOCK_DMA_S); + if (ret) + goto exit_list; + } + + return 0; + +exit_list: + for (i = 0; i < MDP_HIST_MGMT_MAX; i++) { + temp = mdp_hist_mgmt_array[i]; + if (!temp) + continue; + mdp_hist_del_mgmt(temp); + kfree(temp); + mdp_hist_mgmt_array[i] = NULL; + } +exit: + return -ENOMEM; +} + +int mdp_histogram_block2mgmt(uint32_t block, struct mdp_hist_mgmt **mgmt) +{ + struct mdp_hist_mgmt *temp, *output; + int i, ret = 0; + + output = NULL; + + for (i = 0; i < MDP_HIST_MGMT_MAX; i++) { + temp = mdp_hist_mgmt_array[i]; + if (!temp) + continue; + + if (temp->block == block) { + output = temp; + break; + } + } + + if (output == NULL) + ret = -EINVAL; + else + *mgmt = output; + + return ret; +} + +static int mdp_histogram_enable(struct mdp_hist_mgmt *mgmt) +{ + uint32_t base; + if (mgmt->mdp_is_hist_data == TRUE) { + pr_err("%s histogram already started\n", __func__); + return -EINVAL; + } + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + mdp_enable_irq(mgmt->irq_term); + INIT_COMPLETION(mgmt->mdp_hist_comp); + + base = (uint32_t) (MDP_BASE + mgmt->base); + MDP_OUTP(base + 0x0018, INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE); + MDP_OUTP(base + 0x0010, 1); + MDP_OUTP(base + 0x001C, INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE); + + MDP_OUTP(base + 0x0004, mgmt->frame_cnt); + if (mgmt->block != MDP_BLOCK_VG_1 && mgmt->block != MDP_BLOCK_VG_2) + MDP_OUTP(base + 0x0008, mgmt->bit_mask); + mgmt->mdp_is_hist_data = TRUE; + mgmt->mdp_is_hist_valid = TRUE; + mgmt->mdp_is_hist_init = FALSE; + __mdp_histogram_reset(mgmt); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + return 0; +} + +static int mdp_histogram_disable(struct mdp_hist_mgmt *mgmt) +{ + uint32_t base, status; + if (mgmt->mdp_is_hist_data == FALSE) { + pr_err("%s histogram already stopped\n", __func__); + return -EINVAL; + } + + mgmt->mdp_is_hist_data = FALSE; + mgmt->mdp_is_hist_valid = FALSE; + mgmt->mdp_is_hist_init = FALSE; + + base = (uint32_t) (MDP_BASE + mgmt->base); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + if (mdp_rev >= MDP_REV_42) + MDP_OUTP(base + 0x0020, 1); + status = inpdw(base + 0x001C); + status &= ~(INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE); + MDP_OUTP(base + 0x001C, status); + + MDP_OUTP(base + 0x0018, INTR_HIST_DONE | INTR_HIST_RESET_SEQ_DONE); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + complete(&mgmt->mdp_hist_comp); + mdp_disable_irq(mgmt->irq_term); + return 0; +} + +/*call when spanning mgmt_array only*/ +int _mdp_histogram_ctrl(boolean en, struct mdp_hist_mgmt *mgmt) +{ + int ret = 0; + + mutex_lock(&mgmt->mdp_hist_mutex); + if (mgmt->mdp_is_hist_start == TRUE) { + if (en) + ret = mdp_histogram_enable(mgmt); + else + ret = mdp_histogram_disable(mgmt); + } + mutex_unlock(&mgmt->mdp_hist_mutex); + + if (en == false) + cancel_work_sync(&mgmt->mdp_histogram_worker); + + return ret; +} + +int mdp_histogram_ctrl(boolean en, uint32_t block) +{ + struct mdp_hist_mgmt *mgmt = NULL; + int ret = 0; + + ret = mdp_histogram_block2mgmt(block, &mgmt); + if (ret) + goto error; + + ret = _mdp_histogram_ctrl(en, mgmt); +error: + return ret; +} + +int mdp_histogram_ctrl_all(boolean en) +{ + struct mdp_hist_mgmt *temp; + int i, ret = 0, ret_temp = 0; + + for (i = 0; i < MDP_HIST_MGMT_MAX; i++) { + temp = mdp_hist_mgmt_array[i]; + if (!temp) + continue; + + ret_temp = _mdp_histogram_ctrl(en, temp); + if (ret_temp) + ret = ret_temp; + } + return ret; +} + +int mdp_histogram_start(struct mdp_histogram_start_req *req) +{ + struct mdp_hist_mgmt *mgmt = NULL; + int ret; + + ret = mdp_histogram_block2mgmt(req->block, &mgmt); + if (ret) { + ret = -ENOTTY; + goto error; + } + + mutex_lock(&mgmt->mdp_hist_mutex); + if (mgmt->mdp_is_hist_start == TRUE) { + pr_err("%s histogram already started\n", __func__); + ret = -EPERM; + goto error_lock; + } + + mgmt->block = req->block; + mgmt->frame_cnt = req->frame_cnt; + mgmt->bit_mask = req->bit_mask; + mgmt->num_bins = req->num_bins; + mgmt->hist = NULL; + + ret = mdp_histogram_enable(mgmt); + + mgmt->mdp_is_hist_start = TRUE; + +error_lock: + mutex_unlock(&mgmt->mdp_hist_mutex); +error: + return ret; +} + +int mdp_histogram_stop(struct fb_info *info, uint32_t block) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *) info->par; + struct mdp_hist_mgmt *mgmt = NULL; + int ret; + + ret = mdp_histogram_block2mgmt(block, &mgmt); + if (ret) { + ret = -ENOTTY; + goto error; + } + + mutex_lock(&mgmt->mdp_hist_mutex); + if (mgmt->mdp_is_hist_start == FALSE) { + pr_err("%s histogram already stopped\n", __func__); + ret = -EPERM; + goto error_lock; + } + + mgmt->mdp_is_hist_start = FALSE; + + if (!mfd->panel_power_on) { + mgmt->mdp_is_hist_data = FALSE; + complete(&mgmt->mdp_hist_comp); + ret = -EINVAL; + goto error_lock; + } + + ret = mdp_histogram_disable(mgmt); + + mutex_unlock(&mgmt->mdp_hist_mutex); + cancel_work_sync(&mgmt->mdp_histogram_worker); + return ret; + +error_lock: + mutex_unlock(&mgmt->mdp_hist_mutex); +error: + return ret; +} + +/*call from within mdp_hist_mutex context*/ +static int _mdp_histogram_read_dma_data(struct mdp_hist_mgmt *mgmt) +{ + char *mdp_hist_base; + uint32_t r_data_offset, g_data_offset, b_data_offset; + int i, ret = 0; + + mdp_hist_base = MDP_BASE + mgmt->base; + + r_data_offset = (32 == mgmt->num_bins) ? MDP_HIST_DATA32_R_OFF : + MDP_HIST_DATA128_R_OFF; + g_data_offset = (32 == mgmt->num_bins) ? MDP_HIST_DATA32_G_OFF : + MDP_HIST_DATA128_G_OFF; + b_data_offset = (32 == mgmt->num_bins) ? MDP_HIST_DATA32_B_OFF : + MDP_HIST_DATA128_B_OFF; + + if (mgmt->c0 == NULL || mgmt->c1 == NULL || mgmt->c2 == NULL) { + ret = -ENOMEM; + goto hist_err; + } + + if (!mgmt->hist) { + pr_err("%s: mgmt->hist not set, mgmt->hist = 0x%08x", + __func__, (uint32_t) mgmt->hist); + return -EINVAL; + } + + if (mgmt->hist->bin_cnt != mgmt->num_bins) { + pr_err("%s, bins config = %d, bin requested = %d", __func__, + mgmt->num_bins, mgmt->hist->bin_cnt); + return -EINVAL; + } + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < mgmt->num_bins; i++) { + mgmt->c0[i] = inpdw(mdp_hist_base + r_data_offset + (4*i)); + mgmt->c1[i] = inpdw(mdp_hist_base + g_data_offset + (4*i)); + mgmt->c2[i] = inpdw(mdp_hist_base + b_data_offset + (4*i)); + } + + if (mdp_rev >= MDP_REV_42) { + if (mgmt->extra_info) { + mgmt->extra_info[0] = inpdw(mdp_hist_base + + MDP_HIST_EXTRA_DATA0_OFF); + mgmt->extra_info[1] = inpdw(mdp_hist_base + + MDP_HIST_EXTRA_DATA0_OFF + 4); + } else + ret = -ENOMEM; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + if (!ret) + return ret; + +hist_err: + pr_err("%s: invalid hist buffer\n", __func__); + return ret; +} + +/*call from within mdp_hist_mutex context*/ +static int _mdp_histogram_read_vg_data(struct mdp_hist_mgmt *mgmt) +{ + char *mdp_hist_base; + int i, ret = 0; + + mdp_hist_base = MDP_BASE + mgmt->base; + + if (mgmt->c0 == NULL) { + ret = -ENOMEM; + goto hist_err; + } + + if (!mgmt->hist) { + pr_err("%s: mgmt->hist not set", __func__); + return -EINVAL; + } + + if (mgmt->hist->bin_cnt != mgmt->num_bins) { + pr_err("%s, bins config = %d, bin requested = %d", __func__, + mgmt->num_bins, mgmt->hist->bin_cnt); + return -EINVAL; + } + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < mgmt->num_bins; i++) + mgmt->c0[i] = inpdw(mdp_hist_base + MDP_HIST_DATA_LUMA_OFF + + (4*i)); + + if (mdp_rev >= MDP_REV_42) { + if (mgmt->extra_info) { + mgmt->extra_info[0] = inpdw(mdp_hist_base + + MDP_HIST_EXTRA_DATA0_OFF); + } else + ret = -ENOMEM; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + if (!ret) + return ret; + +hist_err: + pr_err("%s: invalid hist buffer\n", __func__); + return ret; +} + +static void mdp_hist_read_work(struct work_struct *data) +{ + struct mdp_hist_mgmt *mgmt = container_of(data, struct mdp_hist_mgmt, + mdp_histogram_worker); + int ret = 0; + mutex_lock(&mgmt->mdp_hist_mutex); + if (mgmt->mdp_is_hist_data == FALSE) { + pr_debug("%s, Histogram disabled before read.\n", __func__); + ret = -EINVAL; + goto error; + } + + switch (mgmt->block) { + case MDP_BLOCK_DMA_P: + case MDP_BLOCK_DMA_S: + ret = _mdp_histogram_read_dma_data(mgmt); + break; + case MDP_BLOCK_VG_1: + case MDP_BLOCK_VG_2: + ret = _mdp_histogram_read_vg_data(mgmt); + break; + default: + pr_err("%s, invalid MDP block = %d\n", __func__, mgmt->block); + ret = -EINVAL; + goto error; + } + + /* + * if read was triggered by an underrun or failed copying, + * don't wake up readers + */ + if (!ret && mgmt->mdp_is_hist_valid && mgmt->mdp_is_hist_init) { + mgmt->hist = NULL; + complete(&mgmt->mdp_hist_comp); + } + + if (mgmt->mdp_is_hist_valid == FALSE) + mgmt->mdp_is_hist_valid = TRUE; + if (mgmt->mdp_is_hist_init == FALSE) + mgmt->mdp_is_hist_init = TRUE; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + if (!ret) + __mdp_histogram_kickoff(mgmt); + else + __mdp_histogram_reset(mgmt); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + +error: + mutex_unlock(&mgmt->mdp_hist_mutex); +} + +/*call from within mdp_hist_mutex*/ +static int _mdp_copy_hist_data(struct mdp_histogram_data *hist, + struct mdp_hist_mgmt *mgmt) +{ + int ret; + + if (hist->c0) { + ret = copy_to_user(hist->c0, mgmt->c0, + sizeof(uint32_t) * (hist->bin_cnt)); + if (ret) + goto err; + } + if (hist->c1) { + ret = copy_to_user(hist->c1, mgmt->c1, + sizeof(uint32_t) * (hist->bin_cnt)); + if (ret) + goto err; + } + if (hist->c2) { + ret = copy_to_user(hist->c2, mgmt->c2, + sizeof(uint32_t) * (hist->bin_cnt)); + if (ret) + goto err; + } + if (hist->extra_info) { + ret = copy_to_user(hist->extra_info, mgmt->extra_info, + sizeof(uint32_t) * ((hist->block > MDP_BLOCK_VG_2) ? 2 : 1)); + if (ret) + goto err; + } +err: + return ret; +} + +static int mdp_do_histogram(struct fb_info *info, + struct mdp_histogram_data *hist) +{ + struct mdp_hist_mgmt *mgmt = NULL; + int ret = 0; + + ret = mdp_histogram_block2mgmt(hist->block, &mgmt); + if (ret) { + pr_info("%s - %d", __func__, __LINE__); + ret = -EINVAL; + return ret; + } + + mutex_lock(&mgmt->mdp_do_hist_mutex); + if (!mgmt->frame_cnt || (mgmt->num_bins == 0)) { + pr_info("%s - frame_cnt = %d, num_bins = %d", __func__, + mgmt->frame_cnt, mgmt->num_bins); + ret = -EINVAL; + goto error; +} + if ((mdp_rev <= MDP_REV_41 && hist->bin_cnt > MDP_REV41_HIST_MAX_BIN) + || (mdp_rev == MDP_REV_42 && + hist->bin_cnt > MDP_REV42_HIST_MAX_BIN)) { + pr_info("%s - mdp_rev = %d, num_bins = %d", __func__, mdp_rev, + hist->bin_cnt); + ret = -EINVAL; + goto error; +} + mutex_lock(&mgmt->mdp_hist_mutex); + if (!mgmt->mdp_is_hist_data) { + pr_info("%s - hist_data = false!", __func__); + ret = -EINVAL; + goto error_lock; + } + + if (!mgmt->mdp_is_hist_start) { + pr_err("%s histogram not started\n", __func__); + ret = -EPERM; + goto error_lock; + } + + if (mgmt->hist != NULL) { + pr_err("%s; histogram attempted to be read twice\n", __func__); + ret = -EPERM; + goto error_lock; + } + mgmt->hist = hist; + mutex_unlock(&mgmt->mdp_hist_mutex); + + if (wait_for_completion_killable(&mgmt->mdp_hist_comp)) { + pr_err("%s(): histogram bin collection killed", __func__); + ret = -EINVAL; + goto error; + } + + mutex_lock(&mgmt->mdp_hist_mutex); + if (mgmt->mdp_is_hist_data && mgmt->mdp_is_hist_init) + ret = _mdp_copy_hist_data(hist, mgmt); + else + ret = -ENODATA; +error_lock: + mutex_unlock(&mgmt->mdp_hist_mutex); +error: + mutex_unlock(&mgmt->mdp_do_hist_mutex); + return ret; +} +#endif + +/* Returns < 0 on error, 0 on timeout, or > 0 on successful wait */ + +int mdp_ppp_pipe_wait(void) +{ + int ret = 1; + boolean wait; + unsigned long flag; + + /* wait 5 seconds for the operation to complete before declaring + the MDP hung */ + spin_lock_irqsave(&mdp_spin_lock, flag); + wait = mdp_ppp_waiting; + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + if (wait == TRUE) { + ret = wait_for_completion_interruptible_timeout(&mdp_ppp_comp, + 5 * HZ); + + if (!ret) + printk(KERN_ERR "%s: Timed out waiting for the MDP.\n", + __func__); + } + + return ret; +} + +static DEFINE_SPINLOCK(mdp_lock); +static int mdp_irq_mask; +static int mdp_irq_enabled; + +/* + * mdp_enable_irq: can not be called from isr + */ +void mdp_enable_irq(uint32 term) +{ + unsigned long irq_flags; + + spin_lock_irqsave(&mdp_lock, irq_flags); + if (mdp_irq_mask & term) { + printk(KERN_ERR "%s: MDP IRQ term-0x%x is already set, mask=%x irq=%d\n", + __func__, term, mdp_irq_mask, mdp_irq_enabled); + } else { + mdp_irq_mask |= term; + if (mdp_irq_mask && !mdp_irq_enabled) { + mdp_irq_enabled = 1; + enable_irq(mdp_irq); + } + } + spin_unlock_irqrestore(&mdp_lock, irq_flags); +} + +/* + * mdp_disable_irq: can not be called from isr + */ +void mdp_disable_irq(uint32 term) +{ + unsigned long irq_flags; + + spin_lock_irqsave(&mdp_lock, irq_flags); + if (!(mdp_irq_mask & term)) { + printk(KERN_ERR "%s: MDP IRQ term-0x%x is NOT set, mask=%x irq=%d\n", + __func__, term, mdp_irq_mask, mdp_irq_enabled); + } else { + mdp_irq_mask &= ~term; + if (!mdp_irq_mask && mdp_irq_enabled) { + mdp_irq_enabled = 0; + disable_irq(mdp_irq); + } + } + spin_unlock_irqrestore(&mdp_lock, irq_flags); +} + +void mdp_disable_irq_nosync(uint32 term) +{ + spin_lock(&mdp_lock); + if (!(mdp_irq_mask & term)) { + printk(KERN_ERR "%s: MDP IRQ term-0x%x is NOT set, mask=%x irq=%d\n", + __func__, term, mdp_irq_mask, mdp_irq_enabled); + } else { + mdp_irq_mask &= ~term; + if (!mdp_irq_mask && mdp_irq_enabled) { + mdp_irq_enabled = 0; + disable_irq_nosync(mdp_irq); + } + } + spin_unlock(&mdp_lock); +} + +void mdp_pipe_kickoff(uint32 term, struct msm_fb_data_type *mfd) +{ + unsigned long flag; + /* complete all the writes before starting */ + wmb(); + + /* kick off PPP engine */ + if (term == MDP_PPP_TERM) { + if (mdp_debug[MDP_PPP_BLOCK]) + jiffies_to_timeval(jiffies, &mdp_ppp_timeval); + + /* let's turn on PPP block */ + mdp_pipe_ctrl(MDP_PPP_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + mdp_enable_irq(term); + INIT_COMPLETION(mdp_ppp_comp); + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_ppp_waiting = TRUE; + spin_unlock_irqrestore(&mdp_spin_lock, flag); + outpdw(MDP_BASE + 0x30, 0x1000); + wait_for_completion_killable(&mdp_ppp_comp); + mdp_disable_irq(term); + + if (mdp_debug[MDP_PPP_BLOCK]) { + struct timeval now; + + jiffies_to_timeval(jiffies, &now); + mdp_ppp_timeval.tv_usec = + now.tv_usec - mdp_ppp_timeval.tv_usec; + MSM_FB_DEBUG("MDP-PPP: %d\n", + (int)mdp_ppp_timeval.tv_usec); + } + } else if (term == MDP_DMA2_TERM) { + if (mdp_debug[MDP_DMA2_BLOCK]) { + MSM_FB_DEBUG("MDP-DMA2: %d\n", + (int)mdp_dma2_timeval.tv_usec); + jiffies_to_timeval(jiffies, &mdp_dma2_timeval); + } + /* DMA update timestamp */ + mdp_dma2_last_update_time = ktime_get_real(); + /* let's turn on DMA2 block */ +#ifdef CONFIG_FB_MSM_MDP22 + outpdw(MDP_CMD_DEBUG_ACCESS_BASE + 0x0044, 0x0);/* start DMA */ +#else + mdp_lut_enable(); + +#ifdef CONFIG_FB_MSM_MDP40 + outpdw(MDP_BASE + 0x000c, 0x0); /* start DMA */ +#else + outpdw(MDP_BASE + 0x0044, 0x0); /* start DMA */ + +#ifdef CONFIG_FB_MSM_MDP303 + +#ifdef CONFIG_FB_MSM_MIPI_DSI + mipi_dsi_cmd_mdp_start(); +#endif + +#endif + +#endif +#endif +#ifdef CONFIG_FB_MSM_MDP40 + } else if (term == MDP_DMA_S_TERM) { + mdp_pipe_ctrl(MDP_DMA_S_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + outpdw(MDP_BASE + 0x0010, 0x0); /* start DMA */ + } else if (term == MDP_DMA_E_TERM) { + mdp_pipe_ctrl(MDP_DMA_E_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + outpdw(MDP_BASE + 0x0014, 0x0); /* start DMA */ + } else if (term == MDP_OVERLAY0_TERM) { + mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + mdp_lut_enable(); + outpdw(MDP_BASE + 0x0004, 0); + } else if (term == MDP_OVERLAY1_TERM) { + mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + mdp_lut_enable(); + outpdw(MDP_BASE + 0x0008, 0); + } else if (term == MDP_OVERLAY2_TERM) { + mdp_pipe_ctrl(MDP_OVERLAY2_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + mdp_lut_enable(); + outpdw(MDP_BASE + 0x00D0, 0); + } +#else + } else if (term == MDP_DMA_S_TERM) { + mdp_pipe_ctrl(MDP_DMA_S_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + outpdw(MDP_BASE + 0x0048, 0x0); /* start DMA */ + } else if (term == MDP_DMA_E_TERM) { + mdp_pipe_ctrl(MDP_DMA_E_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + outpdw(MDP_BASE + 0x004C, 0x0); + } +#endif +} + +static int mdp_clk_rate; +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; + +static void mdp_pipe_ctrl_workqueue_handler(struct work_struct *work) +{ + mdp_pipe_ctrl(MDP_MASTER_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} +void mdp_pipe_ctrl(MDP_BLOCK_TYPE block, MDP_BLOCK_POWER_STATE state, + boolean isr) +{ + boolean mdp_all_blocks_off = TRUE; + int i; + unsigned long flag; + struct msm_fb_panel_data *pdata; + + /* + * It is assumed that if isr = TRUE then start = OFF + * if start = ON when isr = TRUE it could happen that the usercontext + * could turn off the clocks while the interrupt is updating the + * power to ON + */ + WARN_ON(isr == TRUE && state == MDP_BLOCK_POWER_ON); + + spin_lock_irqsave(&mdp_spin_lock, flag); + if (MDP_BLOCK_POWER_ON == state) { + atomic_inc(&mdp_block_power_cnt[block]); + + if (MDP_DMA2_BLOCK == block) + mdp_in_processing = TRUE; + } else { + atomic_dec(&mdp_block_power_cnt[block]); + + if (atomic_read(&mdp_block_power_cnt[block]) < 0) { + /* + * Master has to serve a request to power off MDP always + * It also has a timer to power off. So, in case of + * timer expires first and DMA2 finishes later, + * master has to power off two times + * There shouldn't be multiple power-off request for + * other blocks + */ + if (block != MDP_MASTER_BLOCK) { + MSM_FB_INFO("mdp_block_power_cnt[block=%d] \ + multiple power-off request\n", block); + } + atomic_set(&mdp_block_power_cnt[block], 0); + } + + if (MDP_DMA2_BLOCK == block) + mdp_in_processing = FALSE; + } + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + /* + * If it's in isr, we send our request to workqueue. + * Otherwise, processing happens in the current context + */ + if (isr) { + if (mdp_current_clk_on) { + /* checking all blocks power state */ + for (i = 0; i < MDP_MAX_BLOCK; i++) { + if (atomic_read(&mdp_block_power_cnt[i]) > 0) { + mdp_all_blocks_off = FALSE; + break; + } + } + + if (mdp_all_blocks_off) { + /* send workqueue to turn off mdp power */ + queue_delayed_work(mdp_pipe_ctrl_wq, + &mdp_pipe_ctrl_worker, + mdp_timer_duration); + } + } + } else { + down(&mdp_pipe_ctrl_mutex); + /* checking all blocks power state */ + for (i = 0; i < MDP_MAX_BLOCK; i++) { + if (atomic_read(&mdp_block_power_cnt[i]) > 0) { + mdp_all_blocks_off = FALSE; + break; + } + } + + /* + * find out whether a delayable work item is currently + * pending + */ + + if (delayed_work_pending(&mdp_pipe_ctrl_worker)) { + /* + * try to cancel the current work if it fails to + * stop (which means del_timer can't delete it + * from the list, it's about to expire and run), + * we have to let it run. queue_delayed_work won't + * accept the next job which is same as + * queue_delayed_work(mdp_timer_duration = 0) + */ + cancel_delayed_work(&mdp_pipe_ctrl_worker); + } + + if ((mdp_all_blocks_off) && (mdp_current_clk_on)) { + mutex_lock(&mdp_suspend_mutex); + if (block == MDP_MASTER_BLOCK || mdp_suspended) { + mdp_current_clk_on = FALSE; + mb(); + /* turn off MDP clks */ + mdp_vsync_clk_disable(); + for (i = 0; i < pdev_list_cnt; i++) { + pdata = (struct msm_fb_panel_data *) + pdev_list[i]->dev.platform_data; + if (pdata && pdata->clk_func) + pdata->clk_func(0); + } + if (mdp_clk != NULL) { + mdp_clk_rate = clk_get_rate(mdp_clk); + clk_disable_unprepare(mdp_clk); + if (mdp_hw_revision <= + MDP4_REVISION_V2_1 && + mdp_clk_rate > 122880000) { + clk_set_rate(mdp_clk, + 122880000); + } + MSM_FB_DEBUG("MDP CLK OFF\n"); + } + if (mdp_pclk != NULL) { + clk_disable_unprepare(mdp_pclk); + MSM_FB_DEBUG("MDP PCLK OFF\n"); + } + if (mdp_lut_clk != NULL) + clk_disable_unprepare(mdp_lut_clk); + } else { + /* send workqueue to turn off mdp power */ + queue_delayed_work(mdp_pipe_ctrl_wq, + &mdp_pipe_ctrl_worker, + mdp_timer_duration); + } + mutex_unlock(&mdp_suspend_mutex); + } else if ((!mdp_all_blocks_off) && (!mdp_current_clk_on)) { + mdp_current_clk_on = TRUE; + /* turn on MDP clks */ + for (i = 0; i < pdev_list_cnt; i++) { + pdata = (struct msm_fb_panel_data *) + pdev_list[i]->dev.platform_data; + if (pdata && pdata->clk_func) + pdata->clk_func(1); + } + if (mdp_clk != NULL) { + if (mdp_hw_revision <= + MDP4_REVISION_V2_1 && + mdp_clk_rate > 122880000) { + clk_set_rate(mdp_clk, + mdp_clk_rate); + } + clk_prepare_enable(mdp_clk); + MSM_FB_DEBUG("MDP CLK ON\n"); + } + if (mdp_pclk != NULL) { + clk_prepare_enable(mdp_pclk); + MSM_FB_DEBUG("MDP PCLK ON\n"); + } + if (mdp_lut_clk != NULL) + clk_prepare_enable(mdp_lut_clk); + mdp_vsync_clk_enable(); + } + up(&mdp_pipe_ctrl_mutex); + } +} + +void mdp_histogram_handle_isr(struct mdp_hist_mgmt *mgmt) +{ + uint32 isr, mask; + char *base_addr = MDP_BASE + mgmt->base; + isr = inpdw(base_addr + MDP_HIST_INTR_STATUS_OFF); + mask = inpdw(base_addr + MDP_HIST_INTR_ENABLE_OFF); + outpdw(base_addr + MDP_HIST_INTR_CLEAR_OFF, isr); + mb(); + isr &= mask; + if (isr & INTR_HIST_RESET_SEQ_DONE) + __mdp_histogram_kickoff(mgmt); + + if (isr & INTR_HIST_DONE) { + if ((waitqueue_active(&mgmt->mdp_hist_comp.wait)) + && (mgmt->hist != NULL)) { + if (!queue_work(mdp_hist_wq, + &mgmt->mdp_histogram_worker)) { + pr_err("%s %d- can't queue hist_read\n", + __func__, mgmt->block); + } + } else { + __mdp_histogram_reset(mgmt); + } + } +} + +#ifndef CONFIG_FB_MSM_MDP40 +irqreturn_t mdp_isr(int irq, void *ptr) +{ + uint32 mdp_interrupt = 0; + struct mdp_dma_data *dma; + unsigned long flag; + struct mdp_hist_mgmt *mgmt = NULL; + char *base_addr; + int i, ret; + /* Ensure all the register write are complete */ + mb(); + + mdp_is_in_isr = TRUE; + + mdp_interrupt = inp32(MDP_INTR_STATUS); + outp32(MDP_INTR_CLEAR, mdp_interrupt); + + mdp_interrupt &= mdp_intr_mask; + + if (mdp_interrupt & TV_ENC_UNDERRUN) { + mdp_interrupt &= ~(TV_ENC_UNDERRUN); + mdp_tv_underflow_cnt++; + } + + if (!mdp_interrupt) + goto out; + + /* DMA3 TV-Out Start */ + if (mdp_interrupt & TV_OUT_DMA3_START) { + /* let's disable TV out interrupt */ + mdp_intr_mask &= ~TV_OUT_DMA3_START; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + + dma = &dma3_data; + if (dma->waiting) { + dma->waiting = FALSE; + complete(&dma->comp); + } + } + + if (mdp_rev >= MDP_REV_30) { + /* Only DMA_P histogram exists for this MDP rev*/ + if (mdp_interrupt & MDP_HIST_DONE) { + ret = mdp_histogram_block2mgmt(MDP_BLOCK_DMA_P, &mgmt); + if (!ret) + mdp_histogram_handle_isr(mgmt); + outp32(MDP_INTR_CLEAR, MDP_HIST_DONE); + } + + /* LCDC UnderFlow */ + if (mdp_interrupt & LCDC_UNDERFLOW) { + mdp_lcdc_underflow_cnt++; + /*when underflow happens HW resets all the histogram + registers that were set before so restore them back + to normal.*/ + for (i = 0; i < MDP_HIST_MGMT_MAX; i++) { + mgmt = mdp_hist_mgmt_array[i]; + if (!mgmt) + continue; + + base_addr = MDP_BASE + mgmt->base; + outpdw(base_addr + 0x010, 1); + outpdw(base_addr + 0x01C, INTR_HIST_DONE | + INTR_HIST_RESET_SEQ_DONE); + mgmt->mdp_is_hist_valid = FALSE; + __mdp_histogram_reset(mgmt); + } + } + + /* LCDC Frame Start */ + if (mdp_interrupt & LCDC_FRAME_START) { + dma = &dma2_data; + spin_lock_irqsave(&mdp_spin_lock, flag); + /* let's disable LCDC interrupt */ + mdp_intr_mask &= ~LCDC_FRAME_START; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + if (dma->waiting) { + dma->waiting = FALSE; + complete(&dma->comp); + } + spin_unlock_irqrestore(&mdp_spin_lock, flag); + } + + /* DMA2 LCD-Out Complete */ + if (mdp_interrupt & MDP_DMA_S_DONE) { + dma = &dma_s_data; + dma->busy = FALSE; + mdp_pipe_ctrl(MDP_DMA_S_BLOCK, MDP_BLOCK_POWER_OFF, + TRUE); + complete(&dma->comp); + } + + /* DMA_E LCD-Out Complete */ + if (mdp_interrupt & MDP_DMA_E_DONE) { + dma = &dma_s_data; + dma->busy = FALSE; + mdp_pipe_ctrl(MDP_DMA_E_BLOCK, MDP_BLOCK_POWER_OFF, + TRUE); + complete(&dma->comp); + } + } + + /* DMA2 LCD-Out Complete */ + if (mdp_interrupt & MDP_DMA_P_DONE) { + struct timeval now; + + mdp_dma2_last_update_time = ktime_sub(ktime_get_real(), + mdp_dma2_last_update_time); + if (mdp_debug[MDP_DMA2_BLOCK]) { + jiffies_to_timeval(jiffies, &now); + mdp_dma2_timeval.tv_usec = + now.tv_usec - mdp_dma2_timeval.tv_usec; + } +#ifndef CONFIG_FB_MSM_MDP303 + dma = &dma2_data; + spin_lock_irqsave(&mdp_spin_lock, flag); + dma->busy = FALSE; + spin_unlock_irqrestore(&mdp_spin_lock, flag); + mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF, TRUE); + complete(&dma->comp); +#else + if (mdp_prim_panel_type == MIPI_CMD_PANEL) { + dma = &dma2_data; + spin_lock_irqsave(&mdp_spin_lock, flag); + dma->busy = FALSE; + spin_unlock_irqrestore(&mdp_spin_lock, flag); + mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF, + TRUE); + complete(&dma->comp); + } +#endif + } + + /* PPP Complete */ + if (mdp_interrupt & MDP_PPP_DONE) { +#ifdef CONFIG_FB_MSM_MDP31 + MDP_OUTP(MDP_BASE + 0x00100, 0xFFFF); +#endif + mdp_pipe_ctrl(MDP_PPP_BLOCK, MDP_BLOCK_POWER_OFF, TRUE); + spin_lock_irqsave(&mdp_spin_lock, flag); + if (mdp_ppp_waiting) { + mdp_ppp_waiting = FALSE; + complete(&mdp_ppp_comp); + } + spin_unlock_irqrestore(&mdp_spin_lock, flag); + } + +out: +mdp_is_in_isr = FALSE; + + return IRQ_HANDLED; +} +#endif + +static void mdp_drv_init(void) +{ + int i; + + for (i = 0; i < MDP_MAX_BLOCK; i++) { + mdp_debug[i] = 0; + } + + /* initialize spin lock and workqueue */ + spin_lock_init(&mdp_spin_lock); + mdp_dma_wq = create_singlethread_workqueue("mdp_dma_wq"); + mdp_vsync_wq = create_singlethread_workqueue("mdp_vsync_wq"); + mdp_pipe_ctrl_wq = create_singlethread_workqueue("mdp_pipe_ctrl_wq"); + INIT_DELAYED_WORK(&mdp_pipe_ctrl_worker, + mdp_pipe_ctrl_workqueue_handler); + + /* initialize semaphore */ + init_completion(&mdp_ppp_comp); + sema_init(&mdp_ppp_mutex, 1); + sema_init(&mdp_pipe_ctrl_mutex, 1); + + dma2_data.busy = FALSE; + dma2_data.dmap_busy = FALSE; + dma2_data.waiting = FALSE; + init_completion(&dma2_data.comp); + init_completion(&dma2_data.dmap_comp); + sema_init(&dma2_data.mutex, 1); + mutex_init(&dma2_data.ov_mutex); + + dma3_data.busy = FALSE; + dma3_data.waiting = FALSE; + init_completion(&dma3_data.comp); + sema_init(&dma3_data.mutex, 1); + + dma_s_data.busy = FALSE; + dma_s_data.waiting = FALSE; + init_completion(&dma_s_data.comp); + sema_init(&dma_s_data.mutex, 1); + +#ifndef CONFIG_FB_MSM_MDP303 + dma_e_data.busy = FALSE; + dma_e_data.waiting = FALSE; + init_completion(&dma_e_data.comp); + mutex_init(&dma_e_data.ov_mutex); +#endif +#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL + dma_wb_data.busy = FALSE; + dma_wb_data.waiting = FALSE; + init_completion(&dma_wb_data.comp); + mutex_init(&dma_wb_data.ov_mutex); +#endif + + /* initializing mdp power block counter to 0 */ + for (i = 0; i < MDP_MAX_BLOCK; i++) { + atomic_set(&mdp_block_power_cnt[i], 0); + } + +#ifdef MSM_FB_ENABLE_DBGFS + { + struct dentry *root; + char sub_name[] = "mdp"; + + root = msm_fb_get_debugfs_root(); + if (root != NULL) { + mdp_dir = debugfs_create_dir(sub_name, root); + + if (mdp_dir) { + msm_fb_debugfs_file_create(mdp_dir, + "dma2_update_time_in_usec", + (u32 *) &mdp_dma2_update_time_in_usec); + msm_fb_debugfs_file_create(mdp_dir, + "vs_rdcnt_slow", + (u32 *) &mdp_lcd_rd_cnt_offset_slow); + msm_fb_debugfs_file_create(mdp_dir, + "vs_rdcnt_fast", + (u32 *) &mdp_lcd_rd_cnt_offset_fast); + msm_fb_debugfs_file_create(mdp_dir, + "mdp_usec_diff_threshold", + (u32 *) &mdp_usec_diff_threshold); + msm_fb_debugfs_file_create(mdp_dir, + "mdp_current_clk_on", + (u32 *) &mdp_current_clk_on); +#ifdef CONFIG_FB_MSM_LCDC + msm_fb_debugfs_file_create(mdp_dir, + "lcdc_start_x", + (u32 *) &first_pixel_start_x); + msm_fb_debugfs_file_create(mdp_dir, + "lcdc_start_y", + (u32 *) &first_pixel_start_y); +#endif + } + } + } +#endif +} + +static int mdp_probe(struct platform_device *pdev); +static int mdp_remove(struct platform_device *pdev); + +static int mdp_runtime_suspend(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: suspending...\n"); + return 0; +} + +static int mdp_runtime_resume(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: resuming...\n"); + return 0; +} + +static struct dev_pm_ops mdp_dev_pm_ops = { + .runtime_suspend = mdp_runtime_suspend, + .runtime_resume = mdp_runtime_resume, +}; + + +static struct platform_driver mdp_driver = { + .probe = mdp_probe, + .remove = mdp_remove, +#ifndef CONFIG_HAS_EARLYSUSPEND + .suspend = mdp_suspend, + .resume = NULL, +#endif + .shutdown = NULL, + .driver = { + /* + * Driver name must match the device name added in + * platform.c. + */ + .name = "mdp", + .pm = &mdp_dev_pm_ops, + }, +}; + +static int mdp_off(struct platform_device *pdev) +{ + int ret = 0; + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); + + mdp_histogram_ctrl_all(FALSE); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + ret = panel_next_off(pdev); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + if (mdp_rev >= MDP_REV_41 && mfd->panel.type == MIPI_CMD_PANEL) + mdp_dsi_cmd_overlay_suspend(mfd); + return ret; +} + +static int mdp_on(struct platform_device *pdev) +{ + int ret = 0; + +#ifdef CONFIG_FB_MSM_MDP40 + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + if (is_mdp4_hw_reset()) { + mdp_vsync_cfg_regs(mfd, FALSE); + mdp4_hw_init(); + outpdw(MDP_BASE + 0x0038, mdp4_display_intf); + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +#endif + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + ret = panel_next_on(pdev); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + +#ifdef CONFIG_FB_MSM_MDP40 + if (mfd->panel.type == MIPI_CMD_PANEL) + mdp4_dsi_cmd_overlay_restore(); + else if (mfd->panel.type == MDDI_PANEL) + mdp4_mddi_overlay_restore(); +#endif + + mdp_histogram_ctrl_all(TRUE); + + return ret; +} + +static int mdp_resource_initialized; +static struct msm_panel_common_pdata *mdp_pdata; + +uint32 mdp_hw_revision; + +/* + * mdp_hw_revision: + * 0 == V1 + * 1 == V2 + * 2 == V2.1 + * + */ +void mdp_hw_version(void) +{ + char *cp; + uint32 *hp; + + if (mdp_pdata == NULL) + return; + + mdp_hw_revision = MDP4_REVISION_NONE; + if (mdp_pdata->hw_revision_addr == 0) + return; + + /* tlmmgpio2 shadow */ + cp = (char *)ioremap(mdp_pdata->hw_revision_addr, 0x16); + + if (cp == NULL) + return; + + hp = (uint32 *)cp; /* HW_REVISION_NUMBER */ + mdp_hw_revision = *hp; + iounmap(cp); + + mdp_hw_revision >>= 28; /* bit 31:28 */ + mdp_hw_revision &= 0x0f; + + MSM_FB_DEBUG("%s: mdp_hw_revision=%x\n", + __func__, mdp_hw_revision); +} + +#ifdef CONFIG_FB_MSM_MDP40 +static void configure_mdp_core_clk_table(uint32 min_clk_rate) +{ + uint8 count; + uint32 current_rate; + if (mdp_clk && mdp_pdata && mdp_pdata->mdp_core_clk_table) { + min_clk_rate = clk_round_rate(mdp_clk, min_clk_rate); + if (clk_set_rate(mdp_clk, min_clk_rate) < 0) + printk(KERN_ERR "%s: clk_set_rate failed\n", + __func__); + else { + count = 0; + current_rate = clk_get_rate(mdp_clk); + while (count < mdp_pdata->num_mdp_clk) { + if (mdp_pdata->mdp_core_clk_table[count] + < current_rate) { + mdp_pdata-> + mdp_core_clk_table[count] = + current_rate; + } + count++; + } + } + } +} +#endif + +#ifdef CONFIG_MSM_BUS_SCALING +static uint32_t mdp_bus_scale_handle; +int mdp_bus_scale_update_request(uint32_t index) +{ + if (!mdp_pdata && (!mdp_pdata->mdp_bus_scale_table + || index > (mdp_pdata->mdp_bus_scale_table->num_usecases - 1))) { + printk(KERN_ERR "%s invalid table or index\n", __func__); + return -EINVAL; + } + if (mdp_bus_scale_handle < 1) { + pr_debug("%s invalid bus handle\n", __func__); + return -EINVAL; + } + return msm_bus_scale_client_update_request(mdp_bus_scale_handle, + index); +} +#endif +DEFINE_MUTEX(mdp_clk_lock); +int mdp_set_core_clk(uint16 perf_level) +{ + int ret = -EINVAL; + if (mdp_clk && mdp_pdata + && mdp_pdata->mdp_core_clk_table) { + if (perf_level > mdp_pdata->num_mdp_clk) + printk(KERN_ERR "%s invalid perf level\n", __func__); + else { + mutex_lock(&mdp_clk_lock); + ret = clk_set_rate(mdp_clk, + mdp_pdata-> + mdp_core_clk_table[mdp_pdata->num_mdp_clk + - perf_level]); + mutex_unlock(&mdp_clk_lock); + if (ret) { + printk(KERN_ERR "%s unable to set mdp_core_clk rate\n", + __func__); + } + } + } + return ret; +} + +unsigned long mdp_get_core_clk(void) +{ + unsigned long clk_rate = 0; + if (mdp_clk) { + mutex_lock(&mdp_clk_lock); + clk_rate = clk_get_rate(mdp_clk); + mutex_unlock(&mdp_clk_lock); + } + + return clk_rate; +} + +unsigned long mdp_perf_level2clk_rate(uint32 perf_level) +{ + unsigned long clk_rate = 0; + + if (mdp_pdata && mdp_pdata->mdp_core_clk_table) { + if (perf_level > mdp_pdata->num_mdp_clk) { + printk(KERN_ERR "%s invalid perf level\n", __func__); + clk_rate = mdp_get_core_clk(); + } else { + clk_rate = mdp_pdata-> + mdp_core_clk_table[mdp_pdata->num_mdp_clk + - perf_level]; + } + } else + clk_rate = mdp_get_core_clk(); + + return clk_rate; +} + +static int mdp_irq_clk_setup(struct platform_device *pdev, + char cont_splashScreen) +{ + int ret; + +#ifdef CONFIG_FB_MSM_MDP40 + ret = request_irq(mdp_irq, mdp4_isr, IRQF_DISABLED, "MDP", 0); +#else + ret = request_irq(mdp_irq, mdp_isr, IRQF_DISABLED, "MDP", 0); +#endif + if (ret) { + printk(KERN_ERR "mdp request_irq() failed!\n"); + return ret; + } + disable_irq(mdp_irq); + + footswitch = regulator_get(&pdev->dev, "vdd"); + if (IS_ERR(footswitch)) + footswitch = NULL; + else { + regulator_enable(footswitch); + mdp_footswitch_on = 1; + + if (mdp_rev == MDP_REV_42 && !cont_splashScreen) { + regulator_disable(footswitch); + msleep(20); + regulator_enable(footswitch); + } + } + + mdp_clk = clk_get(&pdev->dev, "core_clk"); + if (IS_ERR(mdp_clk)) { + ret = PTR_ERR(mdp_clk); + printk(KERN_ERR "can't get mdp_clk error:%d!\n", ret); + free_irq(mdp_irq, 0); + return ret; + } + + mdp_pclk = clk_get(&pdev->dev, "iface_clk"); + if (IS_ERR(mdp_pclk)) + mdp_pclk = NULL; + + if (mdp_rev >= MDP_REV_42) { + mdp_lut_clk = clk_get(&pdev->dev, "lut_clk"); + if (IS_ERR(mdp_lut_clk)) { + ret = PTR_ERR(mdp_lut_clk); + pr_err("can't get mdp_clk error:%d!\n", ret); + clk_put(mdp_clk); + free_irq(mdp_irq, 0); + return ret; + } + } else { + mdp_lut_clk = NULL; + } + +#ifdef CONFIG_FB_MSM_MDP40 + /* + * mdp_clk should greater than mdp_pclk always + */ + if (mdp_pdata && mdp_pdata->mdp_core_clk_rate) { + if (cont_splashScreen) + mdp_clk_rate = clk_get_rate(mdp_clk); + else + mdp_clk_rate = mdp_pdata->mdp_core_clk_rate; + + mutex_lock(&mdp_clk_lock); + clk_set_rate(mdp_clk, mdp_clk_rate); + if (mdp_lut_clk != NULL) + clk_set_rate(mdp_lut_clk, mdp_clk_rate); + mutex_unlock(&mdp_clk_lock); + } + + MSM_FB_DEBUG("mdp_clk: mdp_clk=%d\n", (int)clk_get_rate(mdp_clk)); +#endif + return 0; +} + +static int mdp_probe(struct platform_device *pdev) +{ + struct platform_device *msm_fb_dev = NULL; + struct msm_fb_data_type *mfd; + struct msm_fb_panel_data *pdata = NULL; + int rc; + resource_size_t size ; + unsigned long flag; +#ifdef CONFIG_FB_MSM_MDP40 + int intf, if_no; +#endif +#if defined(CONFIG_FB_MSM_MIPI_DSI) && defined(CONFIG_FB_MSM_MDP40) + struct mipi_panel_info *mipi; +#endif + static int contSplash_update_done; + + if ((pdev->id == 0) && (pdev->num_resources > 0)) { + mdp_init_pdev = pdev; + mdp_pdata = pdev->dev.platform_data; + + size = resource_size(&pdev->resource[0]); + msm_mdp_base = ioremap(pdev->resource[0].start, size); + + MSM_FB_DEBUG("MDP HW Base phy_Address = 0x%x virt = 0x%x\n", + (int)pdev->resource[0].start, (int)msm_mdp_base); + + if (unlikely(!msm_mdp_base)) + return -ENOMEM; + + mdp_irq = platform_get_irq(pdev, 0); + if (mdp_irq < 0) { + pr_err("mdp: can not get mdp irq\n"); + return -ENOMEM; + } + + mdp_rev = mdp_pdata->mdp_rev; + + rc = mdp_irq_clk_setup(pdev, mdp_pdata->cont_splash_enabled); + + if (rc) + return rc; + + mdp_hw_version(); + + /* initializing mdp hw */ +#ifdef CONFIG_FB_MSM_MDP40 + if (!(mdp_pdata->cont_splash_enabled)) + mdp4_hw_init(); +#else + mdp_hw_init(); +#endif + +#ifdef CONFIG_FB_MSM_OVERLAY + mdp_hw_cursor_init(); +#endif + mdp_resource_initialized = 1; + return 0; + } + + if (!mdp_resource_initialized) + return -EPERM; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) + return -ENOMEM; + + msm_fb_dev = platform_device_alloc("msm_fb", pdev->id); + if (!msm_fb_dev) + return -ENOMEM; + + /* link to the latest pdev */ + mfd->pdev = msm_fb_dev; + mfd->mdp_rev = mdp_rev; + + if (mdp_pdata) { + if (mdp_pdata->cont_splash_enabled) { + mfd->cont_splash_done = 0; + if (!contSplash_update_done) { + mdp_pipe_ctrl(MDP_CMD_BLOCK, + MDP_BLOCK_POWER_ON, FALSE); + contSplash_update_done = 1; + } + } else + mfd->cont_splash_done = 1; + } + + mfd->ov0_wb_buf = MDP_ALLOC(sizeof(struct mdp_buf_type)); + mfd->ov1_wb_buf = MDP_ALLOC(sizeof(struct mdp_buf_type)); + memset((void *)mfd->ov0_wb_buf, 0, sizeof(struct mdp_buf_type)); + memset((void *)mfd->ov1_wb_buf, 0, sizeof(struct mdp_buf_type)); + + if (mdp_pdata) { + mfd->ov0_wb_buf->size = mdp_pdata->ov0_wb_size; + mfd->ov1_wb_buf->size = mdp_pdata->ov1_wb_size; + mfd->mem_hid = mdp_pdata->mem_hid; + } else { + mfd->ov0_wb_buf->size = 0; + mfd->ov1_wb_buf->size = 0; + mfd->mem_hid = 0; + } + mfd->ov0_blt_state = 0; + mfd->use_ov0_blt = 0 ; + + /* initialize Post Processing data*/ + mdp_hist_lut_init(); + mdp_histogram_init(); + + /* add panel data */ + if (platform_device_add_data + (msm_fb_dev, pdev->dev.platform_data, + sizeof(struct msm_fb_panel_data))) { + printk(KERN_ERR "mdp_probe: platform_device_add_data failed!\n"); + rc = -ENOMEM; + goto mdp_probe_err; + } + /* data chain */ + pdata = msm_fb_dev->dev.platform_data; + pdata->on = mdp_on; + pdata->off = mdp_off; + pdata->next = pdev; + + mdp_prim_panel_type = mfd->panel.type; + switch (mfd->panel.type) { + case EXT_MDDI_PANEL: + case MDDI_PANEL: + case EBI2_PANEL: + INIT_WORK(&mfd->dma_update_worker, + mdp_lcd_update_workqueue_handler); + INIT_WORK(&mfd->vsync_resync_worker, + mdp_vsync_resync_workqueue_handler); + mfd->hw_refresh = FALSE; + + if (mfd->panel.type == EXT_MDDI_PANEL) { + /* 15 fps -> 66 msec */ + mfd->refresh_timer_duration = (66 * HZ / 1000); + } else { + /* 24 fps -> 42 msec */ + mfd->refresh_timer_duration = (42 * HZ / 1000); + } + +#ifdef CONFIG_FB_MSM_MDP22 + mfd->dma_fnc = mdp_dma2_update; + mfd->dma = &dma2_data; +#else + if (mfd->panel_info.pdest == DISPLAY_1) { +#if defined(CONFIG_FB_MSM_OVERLAY) && defined(CONFIG_FB_MSM_MDDI) + mfd->dma_fnc = mdp4_mddi_overlay; + mfd->cursor_update = mdp4_mddi_overlay_cursor; +#else + mfd->dma_fnc = mdp_dma2_update; +#endif + mfd->dma = &dma2_data; + mfd->lut_update = mdp_lut_update_nonlcdc; + mfd->do_histogram = mdp_do_histogram; + mfd->start_histogram = mdp_histogram_start; + mfd->stop_histogram = mdp_histogram_stop; + } else { + mfd->dma_fnc = mdp_dma_s_update; + mfd->dma = &dma_s_data; + } +#endif + if (mdp_pdata) + mfd->vsync_gpio = mdp_pdata->gpio; + else + mfd->vsync_gpio = -1; + +#ifdef CONFIG_FB_MSM_MDP40 + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_intr_mask |= INTR_OVERLAY0_DONE; + if (mdp_hw_revision < MDP4_REVISION_V2_1) { + /* dmas dmap switch */ + mdp_intr_mask |= INTR_DMA_S_DONE; + } + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + spin_unlock_irqrestore(&mdp_spin_lock, flag); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + if (mfd->panel.type == EBI2_PANEL) + intf = EBI2_INTF; + else + intf = MDDI_INTF; + + if (mfd->panel_info.pdest == DISPLAY_1) + if_no = PRIMARY_INTF_SEL; + else + if_no = SECONDARY_INTF_SEL; + + mdp4_display_intf_sel(if_no, intf); +#endif + mdp_config_vsync(mdp_init_pdev, mfd); + break; + +#ifdef CONFIG_FB_MSM_MIPI_DSI + case MIPI_VIDEO_PANEL: +#ifndef CONFIG_FB_MSM_MDP303 + pdata->on = mdp4_dsi_video_on; + pdata->off = mdp4_dsi_video_off; + mfd->hw_refresh = TRUE; + mfd->dma_fnc = mdp4_dsi_video_overlay; + mfd->lut_update = mdp_lut_update_lcdc; + mfd->do_histogram = mdp_do_histogram; + mfd->start_histogram = mdp_histogram_start; + mfd->stop_histogram = mdp_histogram_stop; + if (mfd->panel_info.pdest == DISPLAY_1) { + if_no = PRIMARY_INTF_SEL; + mfd->dma = &dma2_data; + } else { + if_no = EXTERNAL_INTF_SEL; + mfd->dma = &dma_e_data; + } + mdp4_display_intf_sel(if_no, DSI_VIDEO_INTF); +#else + pdata->on = mdp_dsi_video_on; + pdata->off = mdp_dsi_video_off; + mfd->hw_refresh = TRUE; + mfd->dma_fnc = mdp_dsi_video_update; + mfd->do_histogram = mdp_do_histogram; + mfd->start_histogram = mdp_histogram_start; + mfd->stop_histogram = mdp_histogram_stop; + if (mfd->panel_info.pdest == DISPLAY_1) + mfd->dma = &dma2_data; + else { + printk(KERN_ERR "Invalid Selection of destination panel\n"); + rc = -ENODEV; + goto mdp_probe_err; + } + +#endif + if (mdp_rev >= MDP_REV_40) + mfd->cursor_update = mdp_hw_cursor_sync_update; + else + mfd->cursor_update = mdp_hw_cursor_update; + break; + + case MIPI_CMD_PANEL: +#ifndef CONFIG_FB_MSM_MDP303 + mfd->dma_fnc = mdp4_dsi_cmd_overlay; + mipi = &mfd->panel_info.mipi; + configure_mdp_core_clk_table((mipi->dsi_pclk_rate) * 3 / 2); + if (mfd->panel_info.pdest == DISPLAY_1) { + if_no = PRIMARY_INTF_SEL; + mfd->dma = &dma2_data; + } else { + if_no = SECONDARY_INTF_SEL; + mfd->dma = &dma_s_data; + } + mfd->lut_update = mdp_lut_update_nonlcdc; + mfd->do_histogram = mdp_do_histogram; + mfd->start_histogram = mdp_histogram_start; + mfd->stop_histogram = mdp_histogram_stop; + mdp4_display_intf_sel(if_no, DSI_CMD_INTF); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_intr_mask |= INTR_OVERLAY0_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + spin_unlock_irqrestore(&mdp_spin_lock, flag); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +#else + mfd->dma_fnc = mdp_dma2_update; + mfd->do_histogram = mdp_do_histogram; + mfd->start_histogram = mdp_histogram_start; + mfd->stop_histogram = mdp_histogram_stop; + if (mfd->panel_info.pdest == DISPLAY_1) + mfd->dma = &dma2_data; + else { + printk(KERN_ERR "Invalid Selection of destination panel\n"); + rc = -ENODEV; + goto mdp_probe_err; + } + INIT_WORK(&mfd->dma_update_worker, + mdp_lcd_update_workqueue_handler); +#endif + mdp_config_vsync(mdp_init_pdev, mfd); + break; +#endif + +#ifdef CONFIG_FB_MSM_DTV + case DTV_PANEL: + pdata->on = mdp4_dtv_on; + pdata->off = mdp4_dtv_off; + mfd->hw_refresh = TRUE; + mfd->cursor_update = mdp_hw_cursor_update; + mfd->dma_fnc = mdp4_dtv_overlay; + mfd->dma = &dma_e_data; + mdp4_display_intf_sel(EXTERNAL_INTF_SEL, DTV_INTF); + break; +#endif + case HDMI_PANEL: + case LCDC_PANEL: + case LVDS_PANEL: + pdata->on = mdp_lcdc_on; + pdata->off = mdp_lcdc_off; + mfd->hw_refresh = TRUE; +#if defined(CONFIG_FB_MSM_OVERLAY) && defined(CONFIG_FB_MSM_MDP40) + mfd->cursor_update = mdp_hw_cursor_sync_update; +#else + mfd->cursor_update = mdp_hw_cursor_update; +#endif +#ifndef CONFIG_FB_MSM_MDP22 + mfd->lut_update = mdp_lut_update_lcdc; + mfd->do_histogram = mdp_do_histogram; + mfd->start_histogram = mdp_histogram_start; + mfd->stop_histogram = mdp_histogram_stop; +#endif +#ifdef CONFIG_FB_MSM_OVERLAY + mfd->dma_fnc = mdp4_lcdc_overlay; +#else + mfd->dma_fnc = mdp_lcdc_update; +#endif + +#ifdef CONFIG_FB_MSM_MDP40 + configure_mdp_core_clk_table((mfd->panel_info.clk_rate) + * 23 / 20); + if (mfd->panel.type == HDMI_PANEL) { + mfd->dma = &dma_e_data; + mdp4_display_intf_sel(EXTERNAL_INTF_SEL, LCDC_RGB_INTF); + } else { + mfd->dma = &dma2_data; + mdp4_display_intf_sel(PRIMARY_INTF_SEL, LCDC_RGB_INTF); + } +#else + mfd->dma = &dma2_data; + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_intr_mask &= ~MDP_DMA_P_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + spin_unlock_irqrestore(&mdp_spin_lock, flag); +#endif + break; + + case TV_PANEL: +#if defined(CONFIG_FB_MSM_OVERLAY) && defined(CONFIG_FB_MSM_TVOUT) + pdata->on = mdp4_atv_on; + pdata->off = mdp4_atv_off; + mfd->dma_fnc = mdp4_atv_overlay; + mfd->dma = &dma_e_data; + mdp4_display_intf_sel(EXTERNAL_INTF_SEL, TV_INTF); +#else + pdata->on = mdp_dma3_on; + pdata->off = mdp_dma3_off; + mfd->hw_refresh = TRUE; + mfd->dma_fnc = mdp_dma3_update; + mfd->dma = &dma3_data; +#endif + break; + +#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL + case WRITEBACK_PANEL: + { + unsigned int mdp_version; + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, + FALSE); + mdp_version = inpdw(MDP_BASE + 0x0); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, + FALSE); + if (mdp_version < 0x04030303) { + pr_err("%s: writeback panel not supprted\n", + __func__); + platform_device_put(msm_fb_dev); + return -ENODEV; + } + pdata->on = mdp4_overlay_writeback_on; + pdata->off = mdp4_overlay_writeback_off; + mfd->dma_fnc = mdp4_writeback_overlay; + mfd->dma = &dma_wb_data; + mdp4_display_intf_sel(EXTERNAL_INTF_SEL, DTV_INTF); + } + break; +#endif + default: + printk(KERN_ERR "mdp_probe: unknown device type!\n"); + rc = -ENODEV; + goto mdp_probe_err; + } +#ifdef CONFIG_FB_MSM_MDP40 + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + mdp4_display_intf = inpdw(MDP_BASE + 0x0038); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +#endif + +#ifdef CONFIG_MSM_BUS_SCALING + if (!mdp_bus_scale_handle && mdp_pdata && + mdp_pdata->mdp_bus_scale_table) { + mdp_bus_scale_handle = + msm_bus_scale_register_client( + mdp_pdata->mdp_bus_scale_table); + if (!mdp_bus_scale_handle) { + printk(KERN_ERR "%s not able to get bus scale\n", + __func__); + return -ENOMEM; + } + } + + /* req bus bandwidth immediately */ + if (!(mfd->cont_splash_done)) + mdp_bus_scale_update_request(5); + +#endif + + /* set driver data */ + platform_set_drvdata(msm_fb_dev, mfd); + + rc = platform_device_add(msm_fb_dev); + if (rc) { + goto mdp_probe_err; + } + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + pdev_list[pdev_list_cnt++] = pdev; + mdp4_extn_disp = 0; + return 0; + + mdp_probe_err: + platform_device_put(msm_fb_dev); +#ifdef CONFIG_MSM_BUS_SCALING + if (mdp_pdata && mdp_pdata->mdp_bus_scale_table && + mdp_bus_scale_handle > 0) + msm_bus_scale_unregister_client(mdp_bus_scale_handle); +#endif + return rc; +} + +void mdp_footswitch_ctrl(boolean on) +{ + mutex_lock(&mdp_suspend_mutex); + if (!mdp_suspended || mdp4_extn_disp || !footswitch || + mdp_rev <= MDP_REV_41) { + mutex_unlock(&mdp_suspend_mutex); + return; + } + + if (on && !mdp_footswitch_on) { + pr_debug("Enable MDP FS\n"); + regulator_enable(footswitch); + mdp_footswitch_on = 1; + } else if (!on && mdp_footswitch_on) { + pr_debug("Disable MDP FS\n"); + regulator_disable(footswitch); + mdp_footswitch_on = 0; + } + + mutex_unlock(&mdp_suspend_mutex); +} + +#ifdef CONFIG_PM +static void mdp_suspend_sub(void) +{ + /* cancel pipe ctrl worker */ + cancel_delayed_work(&mdp_pipe_ctrl_worker); + + /* for workder can't be cancelled... */ + flush_workqueue(mdp_pipe_ctrl_wq); + + /* let's wait for PPP completion */ + while (atomic_read(&mdp_block_power_cnt[MDP_PPP_BLOCK]) > 0) + cpu_relax(); + + /* try to power down */ + mdp_pipe_ctrl(MDP_MASTER_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + mutex_lock(&mdp_suspend_mutex); + mdp_suspended = TRUE; + mutex_unlock(&mdp_suspend_mutex); +} +#endif + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static int mdp_suspend(struct platform_device *pdev, pm_message_t state) +{ + if (pdev->id == 0) { + mdp_suspend_sub(); + if (mdp_current_clk_on) { + printk(KERN_WARNING"MDP suspend failed\n"); + return -EBUSY; + } + } + + return 0; +} +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mdp_early_suspend(struct early_suspend *h) +{ + mdp_suspend_sub(); +#ifdef CONFIG_FB_MSM_DTV + mdp4_dtv_set_black_screen(); +#endif + mdp_footswitch_ctrl(FALSE); +} + +static void mdp_early_resume(struct early_suspend *h) +{ + mdp_footswitch_ctrl(TRUE); + mutex_lock(&mdp_suspend_mutex); + mdp_suspended = FALSE; + mutex_unlock(&mdp_suspend_mutex); +} +#endif + +static int mdp_remove(struct platform_device *pdev) +{ + if (footswitch != NULL) + regulator_put(footswitch); + iounmap(msm_mdp_base); + pm_runtime_disable(&pdev->dev); +#ifdef CONFIG_MSM_BUS_SCALING + if (mdp_pdata && mdp_pdata->mdp_bus_scale_table && + mdp_bus_scale_handle > 0) + msm_bus_scale_unregister_client(mdp_bus_scale_handle); +#endif + return 0; +} + +static int mdp_register_driver(void) +{ +#ifdef CONFIG_HAS_EARLYSUSPEND + early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1; + early_suspend.suspend = mdp_early_suspend; + early_suspend.resume = mdp_early_resume; + register_early_suspend(&early_suspend); +#endif + + return platform_driver_register(&mdp_driver); +} + +static int __init mdp_driver_init(void) +{ + int ret; + + mdp_drv_init(); + + ret = mdp_register_driver(); + if (ret) { + printk(KERN_ERR "mdp_register_driver() failed!\n"); + return ret; + } + +#if defined(CONFIG_DEBUG_FS) + mdp_debugfs_init(); +#endif + + return 0; + +} + +module_init(mdp_driver_init); diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h new file mode 100644 index 000000000000..8f38b988b383 --- /dev/null +++ b/drivers/video/msm/mdp.h @@ -0,0 +1,840 @@ +/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef MDP_H +#define MDP_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_MSM_BUS_SCALING +#include +#include +#endif + +#include + +#include +#include + +#include "msm_fb_panel.h" + +extern uint32 mdp_hw_revision; +extern ulong mdp4_display_intf; +extern spinlock_t mdp_spin_lock; +extern int mdp_rev; +extern struct mdp_csc_cfg mdp_csc_convert[4]; + +extern struct workqueue_struct *mdp_hist_wq; + +#define MDP4_REVISION_V1 0 +#define MDP4_REVISION_V2 1 +#define MDP4_REVISION_V2_1 2 +#define MDP4_REVISION_NONE 0xffffffff + +#ifdef BIT +#undef BIT +#endif + +#define BIT(x) (1<<(x)) + +#define MDPOP_NOP 0 +#define MDPOP_LR BIT(0) /* left to right flip */ +#define MDPOP_UD BIT(1) /* up and down flip */ +#define MDPOP_ROT90 BIT(2) /* rotate image to 90 degree */ +#define MDPOP_ROT180 (MDPOP_UD|MDPOP_LR) +#define MDPOP_ROT270 (MDPOP_ROT90|MDPOP_UD|MDPOP_LR) +#define MDPOP_ASCALE BIT(7) +#define MDPOP_ALPHAB BIT(8) /* enable alpha blending */ +#define MDPOP_TRANSP BIT(9) /* enable transparency */ +#define MDPOP_DITHER BIT(10) /* enable dither */ +#define MDPOP_SHARPENING BIT(11) /* enable sharpening */ +#define MDPOP_BLUR BIT(12) /* enable blur */ +#define MDPOP_FG_PM_ALPHA BIT(13) +#define MDP_ALLOC(x) kmalloc(x, GFP_KERNEL) + +struct mdp_buf_type { + struct ion_handle *ihdl; + u32 phys_addr; + u32 size; +}; + +struct mdp_table_entry { + uint32_t reg; + uint32_t val; +}; + +extern struct mdp_ccs mdp_ccs_yuv2rgb ; +extern struct mdp_ccs mdp_ccs_rgb2yuv ; +extern unsigned char hdmi_prim_display; + +/* + * MDP Image Structure + */ +typedef struct mdpImg_ { + uint32 imgType; /* Image type */ + uint32 *bmy_addr; /* bitmap or y addr */ + uint32 *cbcr_addr; /* cbcr addr */ + uint32 width; /* image width */ + uint32 mdpOp; /* image opertion (rotation,flip up/down, alpha/tp) */ + uint32 tpVal; /* transparency color */ + uint32 alpha; /* alpha percentage 0%(0x0) ~ 100%(0x100) */ + int sp_value; /* sharpening strength */ +} MDPIMG; + +#define MDP_OUTP(addr, data) outpdw((addr), (data)) + +#define MDP_BASE msm_mdp_base + +typedef enum { + MDP_BC_SCALE_POINT2_POINT4, + MDP_BC_SCALE_POINT4_POINT6, + MDP_BC_SCALE_POINT6_POINT8, + MDP_BC_SCALE_POINT8_1, + MDP_BC_SCALE_UP, + MDP_PR_SCALE_POINT2_POINT4, + MDP_PR_SCALE_POINT4_POINT6, + MDP_PR_SCALE_POINT6_POINT8, + MDP_PR_SCALE_POINT8_1, + MDP_PR_SCALE_UP, + MDP_SCALE_BLUR, + MDP_INIT_SCALE +} MDP_SCALE_MODE; + +typedef enum { + MDP_BLOCK_POWER_OFF, + MDP_BLOCK_POWER_ON +} MDP_BLOCK_POWER_STATE; + +typedef enum { + MDP_CMD_BLOCK, + MDP_OVERLAY0_BLOCK, + MDP_MASTER_BLOCK, + MDP_PPP_BLOCK, + MDP_DMA2_BLOCK, + MDP_DMA3_BLOCK, + MDP_DMA_S_BLOCK, + MDP_DMA_E_BLOCK, + MDP_OVERLAY1_BLOCK, + MDP_OVERLAY2_BLOCK, + MDP_MAX_BLOCK +} MDP_BLOCK_TYPE; + +/* Let's keep Q Factor power of 2 for optimization */ +#define MDP_SCALE_Q_FACTOR 512 + +#ifdef CONFIG_FB_MSM_MDP31 +#define MDP_MAX_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*8) +#define MDP_MIN_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/8) +#define MDP_MAX_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*8) +#define MDP_MIN_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/8) +#else +#define MDP_MAX_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*4) +#define MDP_MIN_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/4) +#define MDP_MAX_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*4) +#define MDP_MIN_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/4) +#endif + +/* SHIM Q Factor */ +#define PHI_Q_FACTOR 29 +#define PQF_PLUS_5 (PHI_Q_FACTOR + 5) /* due to 32 phases */ +#define PQF_PLUS_4 (PHI_Q_FACTOR + 4) +#define PQF_PLUS_2 (PHI_Q_FACTOR + 2) /* to get 4.0 */ +#define PQF_MINUS_2 (PHI_Q_FACTOR - 2) /* to get 0.25 */ +#define PQF_PLUS_5_PLUS_2 (PQF_PLUS_5 + 2) +#define PQF_PLUS_5_MINUS_2 (PQF_PLUS_5 - 2) + +#define MDP_CONVTP(tpVal) (((tpVal&0xF800)<<8)|((tpVal&0x7E0)<<5)|((tpVal&0x1F)<<3)) + +#define MDPOP_ROTATION (MDPOP_ROT90|MDPOP_LR|MDPOP_UD) +#define MDP_CHKBIT(val, bit) ((bit) == ((val) & (bit))) + +/* overlay interface API defines */ +typedef enum { + MORE_IBUF, + FINAL_IBUF, + COMPLETE_IBUF +} MDP_IBUF_STATE; + +struct mdp_dirty_region { + __u32 xoffset; /* source origin in the x-axis */ + __u32 yoffset; /* source origin in the y-axis */ + __u32 width; /* number of pixels in the x-axis */ + __u32 height; /* number of pixels in the y-axis */ +}; + +/* + * MDP extended data types + */ +typedef struct mdp_roi_s { + uint32 x; + uint32 y; + uint32 width; + uint32 height; + int32 lcd_x; + int32 lcd_y; + uint32 dst_width; + uint32 dst_height; +} MDP_ROI; + +typedef struct mdp_ibuf_s { + uint8 *buf; + uint32 bpp; + uint32 ibuf_type; + uint32 ibuf_width; + uint32 ibuf_height; + + MDP_ROI roi; + MDPIMG mdpImg; + + int32 dma_x; + int32 dma_y; + uint32 dma_w; + uint32 dma_h; + + uint32 vsync_enable; +} MDPIBUF; + +struct mdp_dma_data { + boolean busy; + boolean dmap_busy; + boolean waiting; + struct mutex ov_mutex; + struct semaphore mutex; + struct completion comp; + struct completion dmap_comp; +}; + +extern struct list_head mdp_hist_lut_list; +extern struct mutex mdp_hist_lut_list_mutex; +struct mdp_hist_lut_mgmt { + uint32_t block; + struct mutex lock; + struct list_head list; +}; + +struct mdp_hist_lut_info { + uint32_t block; + boolean is_enabled, has_sel_update; + int bank_sel; +}; + +struct mdp_hist_mgmt { + uint32_t block; + uint32_t irq_term; + uint32_t base; + struct completion mdp_hist_comp; + struct mutex mdp_hist_mutex; + struct mutex mdp_do_hist_mutex; + boolean mdp_is_hist_start, mdp_is_hist_data; + boolean mdp_is_hist_valid, mdp_is_hist_init; + uint8_t frame_cnt, bit_mask, num_bins; + struct work_struct mdp_histogram_worker; + struct mdp_histogram_data *hist; + uint32_t *c0, *c1, *c2; + uint32_t *extra_info; +}; + +enum { + MDP_HIST_MGMT_DMA_P = 0, + MDP_HIST_MGMT_DMA_S, + MDP_HIST_MGMT_VG_1, + MDP_HIST_MGMT_VG_2, + MDP_HIST_MGMT_MAX, +}; + +extern struct mdp_hist_mgmt *mdp_hist_mgmt_array[]; + +#define MDP_CMD_DEBUG_ACCESS_BASE (MDP_BASE+0x10000) + +#define MDP_DMA2_TERM 0x1 +#define MDP_DMA3_TERM 0x2 +#define MDP_PPP_TERM 0x4 +#define MDP_DMA_S_TERM 0x8 +#define MDP_DMA_E_TERM 0x10 +#ifdef CONFIG_FB_MSM_MDP40 +#define MDP_OVERLAY0_TERM 0x20 +#define MDP_OVERLAY1_TERM 0x40 +#endif +#define MDP_OVERLAY2_TERM 0x80 +#define MDP_HISTOGRAM_TERM_DMA_P 0x100 +#define MDP_HISTOGRAM_TERM_DMA_S 0x200 +#define MDP_HISTOGRAM_TERM_VG_1 0x400 +#define MDP_HISTOGRAM_TERM_VG_2 0x800 + +#define ACTIVE_START_X_EN BIT(31) +#define ACTIVE_START_Y_EN BIT(31) +#define ACTIVE_HIGH 0 +#define ACTIVE_LOW 1 +#define MDP_DMA_S_DONE BIT(2) +#define MDP_DMA_E_DONE BIT(3) +#define LCDC_FRAME_START BIT(15) +#define LCDC_UNDERFLOW BIT(16) + +#ifdef CONFIG_FB_MSM_MDP22 +#define MDP_DMA_P_DONE BIT(2) +#else +#define MDP_DMA_P_DONE BIT(14) +#endif + +#define MDP_PPP_DONE BIT(0) +#define TV_OUT_DMA3_DONE BIT(6) +#define TV_ENC_UNDERRUN BIT(7) +#define TV_OUT_DMA3_START BIT(13) +#define MDP_HIST_DONE BIT(20) + +/* histogram interrupts */ +#define INTR_HIST_DONE BIT(1) +#define INTR_HIST_RESET_SEQ_DONE BIT(0) + +#ifdef CONFIG_FB_MSM_MDP22 +#define MDP_ANY_INTR_MASK (MDP_PPP_DONE| \ + MDP_DMA_P_DONE| \ + TV_ENC_UNDERRUN) +#else +#define MDP_ANY_INTR_MASK (MDP_PPP_DONE| \ + MDP_DMA_P_DONE| \ + MDP_DMA_S_DONE| \ + MDP_DMA_E_DONE| \ + LCDC_UNDERFLOW| \ + MDP_HIST_DONE| \ + TV_ENC_UNDERRUN) +#endif + +#define MDP_TOP_LUMA 16 +#define MDP_TOP_CHROMA 0 +#define MDP_BOTTOM_LUMA 19 +#define MDP_BOTTOM_CHROMA 3 +#define MDP_LEFT_LUMA 22 +#define MDP_LEFT_CHROMA 6 +#define MDP_RIGHT_LUMA 25 +#define MDP_RIGHT_CHROMA 9 + +#define CLR_G 0x0 +#define CLR_B 0x1 +#define CLR_R 0x2 +#define CLR_ALPHA 0x3 + +#define CLR_Y CLR_G +#define CLR_CB CLR_B +#define CLR_CR CLR_R + +/* from lsb to msb */ +#define MDP_GET_PACK_PATTERN(a,x,y,z,bit) (((a)<<(bit*3))|((x)<<(bit*2))|((y)<= 0x0402030b); +} + +int mdp4_overlay_dtv_set(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe); +int mdp4_overlay_dtv_unset(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe); +void mdp4_dtv_base_swap(struct mdp4_overlay_pipe *pipe); +void mdp4_dtv_overlay(struct msm_fb_data_type *mfd); +int mdp4_dtv_on(struct platform_device *pdev); +int mdp4_dtv_off(struct platform_device *pdev); +void mdp4_atv_overlay(struct msm_fb_data_type *mfd); +int mdp4_atv_on(struct platform_device *pdev); +int mdp4_atv_off(struct platform_device *pdev); +void mdp4_dsi_video_fxn_register(cmd_fxn_t fxn); +void mdp4_dsi_video_overlay(struct msm_fb_data_type *mfd); +int mdp4_dsi_video_on(struct platform_device *pdev); +int mdp4_dsi_video_off(struct platform_device *pdev); +void mdp4_overlay0_done_dsi_video(struct mdp_dma_data *dma); +void mdp4_overlay0_done_dsi_cmd(struct mdp_dma_data *dma); +void mdp4_dsi_cmd_overlay(struct msm_fb_data_type *mfd); +void mdp4_overlay_dsi_state_set(int state); +int mdp4_overlay_dsi_state_get(void); +void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe); +void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all); +void mdp4_mixer_blend_setup(int mixer); +struct mdp4_overlay_pipe *mdp4_overlay_stage_pipe(int mixer, int stage); +void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe); +void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe); +void mdp4_mixer_pipe_cleanup(int mixer); +int mdp4_mixer_stage_can_run(struct mdp4_overlay_pipe *pipe); +void mdp4_overlayproc_cfg(struct mdp4_overlay_pipe *pipe); +void mdp4_mddi_overlay(struct msm_fb_data_type *mfd); +int mdp4_overlay_format2type(uint32 format); +int mdp4_overlay_format2pipe(struct mdp4_overlay_pipe *pipe); +int mdp4_overlay_get(struct fb_info *info, struct mdp_overlay *req); +int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req); +int mdp4_overlay_unset(struct fb_info *info, int ndx); +int mdp4_overlay_unset_mixer(int mixer); +int mdp4_overlay_play_wait(struct fb_info *info, + struct msmfb_overlay_data *req); +int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req); +struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(int ptype, int mixer); +void mdp4_overlay_pipe_free(struct mdp4_overlay_pipe *pipe); +void mdp4_overlay_dmap_cfg(struct msm_fb_data_type *mfd, int lcdc); +void mdp4_overlay_dmap_xy(struct mdp4_overlay_pipe *pipe); +void mdp4_overlay_dmae_cfg(struct msm_fb_data_type *mfd, int atv); +void mdp4_overlay_dmae_xy(struct mdp4_overlay_pipe *pipe); +int mdp4_overlay_pipe_staged(int mixer); +void mdp4_lcdc_primary_vsyn(void); +void mdp4_overlay0_done_lcdc(struct mdp_dma_data *dma); +void mdp4_overlay0_done_mddi(struct mdp_dma_data *dma); +void mdp4_dma_s_done_mddi(void); +void mdp4_dma_p_done_mddi(struct mdp_dma_data *dma); +void mdp4_dma_p_done_dsi(struct mdp_dma_data *dma); +void mdp4_dma_p_done_dsi_video(struct mdp_dma_data *dma); +void mdp4_dma_p_done_lcdc(void); +void mdp4_overlay1_done_dtv(void); +void mdp4_overlay1_done_atv(void); +void mdp4_primary_vsync_lcdc(void); +void mdp4_external_vsync_dtv(void); +void mdp4_overlay_lcdc_wait4vsync(struct msm_fb_data_type *mfd); +void mdp4_overlay_lcdc_start(void); +void mdp4_overlay_lcdc_vsync_push(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe); +void mdp4_update_perf_level(u32 perf_level); +void mdp4_set_perf_level(void); +void mdp4_mddi_overlay_dmas_restore(void); + +#ifndef CONFIG_FB_MSM_MIPI_DSI +void mdp4_mddi_dma_busy_wait(struct msm_fb_data_type *mfd); +void mdp4_mddi_overlay_restore(void); +#else +static inline void mdp4_mddi_dma_busy_wait(struct msm_fb_data_type *mfd) +{ + /* empty */ +} +static inline void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd) +{ + /* empty */ +} +static inline void mdp4_mddi_overlay_restore(void) +{ + /* empty */ +} +static inline void mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd) +{ + /*empty*/ +} +static inline void mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd) +{ + /*empty*/ +} +static inline void mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd, + struct msmfb_overlay_blt *req) +{ + /* empty */ +} +static inline void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd, + struct msmfb_overlay_blt *req) +{ + /* empty*/ +} +#endif + +void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe); +void mdp4_rgb_igc_lut_setup(int num); +void mdp4_vg_igc_lut_setup(int num); +void mdp4_mixer_gc_lut_setup(int mixer_num); +void mdp4_fetch_cfg(uint32 clk); +uint32 mdp4_rgb_igc_lut_cvt(uint32 ndx); +void mdp4_vg_qseed_init(int); +int mdp4_overlay_blt(struct fb_info *info, struct msmfb_overlay_blt *req); +int mdp4_overlay_blt_offset(struct fb_info *info, + struct msmfb_overlay_blt *req); + + +#ifdef CONFIG_FB_MSM_MIPI_DSI +int mdp4_dsi_overlay_blt_start(struct msm_fb_data_type *mfd); +int mdp4_dsi_overlay_blt_stop(struct msm_fb_data_type *mfd); +void mdp4_dsi_video_blt_start(struct msm_fb_data_type *mfd); +void mdp4_dsi_video_blt_stop(struct msm_fb_data_type *mfd); +void mdp4_dsi_overlay_blt(struct msm_fb_data_type *mfd, + struct msmfb_overlay_blt *req); +int mdp4_dsi_overlay_blt_offset(struct msm_fb_data_type *mfd, + struct msmfb_overlay_blt *req); + +void mdp4_dsi_video_overlay_blt(struct msm_fb_data_type *mfd, + struct msmfb_overlay_blt *req); +int mdp4_dsi_video_overlay_blt_offset(struct msm_fb_data_type *mfd, + struct msmfb_overlay_blt *req); +void mdp4_dsi_video_base_swap(struct mdp4_overlay_pipe *pipe); + +#ifdef CONFIG_FB_MSM_MDP40 +static inline void mdp3_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd) +{ + /* empty */ +} +#endif +#else +int mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd, + struct msmfb_overlay_blt *req); +void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd, + struct msmfb_overlay_blt *req); +int mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd); +int mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd); +void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd); +static inline int mdp4_dsi_overlay_blt_start(struct msm_fb_data_type *mfd) +{ + return -ENODEV; +} +static inline int mdp4_dsi_overlay_blt_stop(struct msm_fb_data_type *mfd) +{ + return -ENODEV; +} +static inline void mdp4_dsi_video_blt_start(struct msm_fb_data_type *mfd) +{ +} +static inline void mdp4_dsi_video_blt_stop(struct msm_fb_data_type *mfd) +{ +} +static inline void mdp4_dsi_overlay_blt( + struct msm_fb_data_type *mfd, struct msmfb_overlay_blt *req) +{ +} +static inline int mdp4_dsi_overlay_blt_offset( + struct msm_fb_data_type *mfd, struct msmfb_overlay_blt *req) +{ + return -ENODEV; +} +static inline void mdp4_dsi_video_overlay_blt( + struct msm_fb_data_type *mfd, struct msmfb_overlay_blt *req) +{ +} +static inline int mdp4_dsi_video_overlay_blt_offset( + struct msm_fb_data_type *mfd, struct msmfb_overlay_blt *req) +{ + return -ENODEV; +} +static inline void mdp4_dsi_video_base_swap(struct mdp4_overlay_pipe *pipe) +{ + /* empty */ +} +#endif + +void mdp4_lcdc_overlay_blt(struct msm_fb_data_type *mfd, + struct msmfb_overlay_blt *req); +int mdp4_lcdc_overlay_blt_offset(struct msm_fb_data_type *mfd, + struct msmfb_overlay_blt *req); +void mdp4_lcdc_overlay_blt_start(struct msm_fb_data_type *mfd); +void mdp4_lcdc_overlay_blt_stop(struct msm_fb_data_type *mfd); +void mdp4_dtv_overlay_blt_start(struct msm_fb_data_type *mfd); +void mdp4_dtv_overlay_blt_stop(struct msm_fb_data_type *mfd); +void mdp4_overlay_panel_mode(int mixer_num, uint32 mode); +void mdp4_overlay_panel_mode_unset(int mixer_num, uint32 mode); +int mdp4_overlay_mixer_play(int mixer_num); +uint32 mdp4_overlay_panel_list(void); +void mdp4_lcdc_overlay_kickoff(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe); + +void mdp4_mddi_kickoff_video(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe); + +void mdp4_mddi_read_ptr_intr(void); + +void mdp4_dsi_cmd_dma_busy_check(void); + +#ifdef CONFIG_FB_MSM_MIPI_DSI +void mdp4_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd); +void mdp4_dsi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd); +void mdp4_overlay_dsi_video_start(void); +void mdp4_overlay_dsi_video_vsync_push(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe); +void mdp4_dsi_cmd_overlay_restore(void); +void mdp_dsi_cmd_overlay_suspend(struct msm_fb_data_type *mfd); +#else +static inline void mdp4_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd) +{ + /* empty */ +} +static inline void mdp4_dsi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd) +{ + /* empty */ +} +static inline void mdp4_overlay_dsi_video_start(void) +{ + /* empty */ +} +static inline void mdp4_overlay_dsi_video_vsync_push( + struct msm_fb_data_type *mfd, struct mdp4_overlay_pipe *pipe) +{ + /* empty */ +} +static inline void mdp4_dsi_cmd_overlay_restore(void) +{ + /* empty */ +} +#ifdef CONFIG_FB_MSM_MDP40 +static inline void mdp_dsi_cmd_overlay_suspend(struct msm_fb_data_type *mfd) +{ + /* empty */ +} +#endif +#endif /* MIPI_DSI */ + +void mdp4_dsi_cmd_kickoff_ui(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe); +void mdp4_dsi_cmd_kickoff_video(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe); +void mdp4_dsi_cmd_overlay_kickoff(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe); +void mdp4_dsi_cmd_base_swap(struct mdp4_overlay_pipe *pipe); + +void mdp4_overlay_panel_3d(int mixer_num, uint32 panel_3d); +int mdp4_overlay_3d_sbys(struct fb_info *info, struct msmfb_overlay_3d *req); +void mdp4_dsi_cmd_3d_sbys(struct msm_fb_data_type *mfd, + struct msmfb_overlay_3d *r3d); +void mdp4_dsi_video_3d_sbys(struct msm_fb_data_type *mfd, + struct msmfb_overlay_3d *r3d); + +int mdp4_mixer_info(int mixer_num, struct mdp_mixer_info *info); + +void mdp_dmap_vsync_set(int enable); +int mdp_dmap_vsync_get(void); +void mdp_hw_cursor_done(void); +void mdp_hw_cursor_init(void); +int mdp4_mddi_overlay_cursor(struct fb_info *info, struct fb_cursor *cursor); +int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req); +void mdp4_overlay_resource_release(void); +void mdp4_overlay_dsi_video_wait4vsync(struct msm_fb_data_type *mfd); +void mdp4_primary_vsync_dsi_video(void); +uint32_t mdp4_ss_table_value(int8_t param, int8_t index); +void mdp4_overlay_borderfill_stage_down(struct mdp4_overlay_pipe *pipe); + +int mdp4_overlay_writeback_on(struct platform_device *pdev); +int mdp4_overlay_writeback_off(struct platform_device *pdev); +void mdp4_writeback_overlay(struct msm_fb_data_type *mfd); +void mdp4_writeback_kickoff_video(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe); +void mdp4_writeback_dma_busy_wait(struct msm_fb_data_type *mfd); +void mdp4_overlay1_done_writeback(struct mdp_dma_data *dma); + +int mdp4_writeback_start(struct fb_info *info); +int mdp4_writeback_stop(struct fb_info *info); +int mdp4_writeback_dequeue_buffer(struct fb_info *info, + struct msmfb_data *data); +int mdp4_writeback_queue_buffer(struct fb_info *info, + struct msmfb_data *data); +void mdp4_writeback_dma_stop(struct msm_fb_data_type *mfd); +int mdp4_writeback_init(struct fb_info *info); +int mdp4_writeback_terminate(struct fb_info *info); + +uint32_t mdp_block2base(uint32_t block); +int mdp_hist_lut_config(struct mdp_hist_lut_data *data); + +void mdp4_hsic_set(struct mdp4_overlay_pipe *pipe, struct dpp_ctrl *ctrl); +void mdp4_hsic_update(struct mdp4_overlay_pipe *pipe); +int mdp4_csc_config(struct mdp_csc_cfg_data *config); +void mdp4_csc_write(struct mdp_csc_cfg *data, uint32_t base); +int mdp4_csc_enable(struct mdp_csc_cfg_data *config); +int mdp4_pcc_cfg(struct mdp_pcc_cfg_data *cfg_ptr); +int mdp4_argc_cfg(struct mdp_pgc_lut_data *pgc_ptr); +int mdp4_qseed_cfg(struct mdp_qseed_cfg_data *cfg); +u32 mdp4_allocate_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num); +void mdp4_init_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num); +void mdp4_free_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num); + +int mdp4_igc_lut_config(struct mdp_igc_lut_data *cfg); +void mdp4_iommu_unmap(struct mdp4_overlay_pipe *pipe); +void mdp4_iommu_attach(void); +int mdp4_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req, + struct mdp4_overlay_pipe **ppipe); +void mdp4_v4l2_overlay_clear(struct mdp4_overlay_pipe *pipe); +int mdp4_v4l2_overlay_play(struct fb_info *info, struct mdp4_overlay_pipe *pipe, + unsigned long srcp0_addr, unsigned long srcp1_addr, + unsigned long srcp2_addr); + +#endif /* MDP_H */ diff --git a/drivers/video/msm/mdp4_dtv.c b/drivers/video/msm/mdp4_dtv.c new file mode 100644 index 000000000000..7f68bbb3a231 --- /dev/null +++ b/drivers/video/msm/mdp4_dtv.c @@ -0,0 +1,326 @@ +/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_fb.h" +#include "mdp4.h" + +static int dtv_probe(struct platform_device *pdev); +static int dtv_remove(struct platform_device *pdev); + +static int dtv_off(struct platform_device *pdev); +static int dtv_on(struct platform_device *pdev); + +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; + +static struct clk *tv_src_clk; +static struct clk *hdmi_clk; +static struct clk *mdp_tv_clk; + + +static int mdp4_dtv_runtime_suspend(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: suspending...\n"); + return 0; +} + +static int mdp4_dtv_runtime_resume(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: resuming...\n"); + return 0; +} + +static const struct dev_pm_ops mdp4_dtv_dev_pm_ops = { + .runtime_suspend = mdp4_dtv_runtime_suspend, + .runtime_resume = mdp4_dtv_runtime_resume, +}; + +static struct platform_driver dtv_driver = { + .probe = dtv_probe, + .remove = dtv_remove, + .suspend = NULL, + .resume = NULL, + .shutdown = NULL, + .driver = { + .name = "dtv", + .pm = &mdp4_dtv_dev_pm_ops, + }, +}; + +static struct lcdc_platform_data *dtv_pdata; +#ifdef CONFIG_MSM_BUS_SCALING +static uint32_t dtv_bus_scale_handle; +#else +static struct clk *ebi1_clk; +#endif + +static int dtv_off(struct platform_device *pdev) +{ + int ret = 0; + + ret = panel_next_off(pdev); + + pr_info("%s\n", __func__); + + clk_disable_unprepare(hdmi_clk); + if (mdp_tv_clk) + clk_disable_unprepare(mdp_tv_clk); + + if (dtv_pdata && dtv_pdata->lcdc_power_save) + dtv_pdata->lcdc_power_save(0); + + if (dtv_pdata && dtv_pdata->lcdc_gpio_config) + ret = dtv_pdata->lcdc_gpio_config(0); +#ifdef CONFIG_MSM_BUS_SCALING + if (dtv_bus_scale_handle > 0) + msm_bus_scale_client_update_request(dtv_bus_scale_handle, + 0); +#else + if (ebi1_clk) + clk_disable_unprepare(ebi1_clk); +#endif + mdp4_extn_disp = 0; + return ret; +} + +static int dtv_on(struct platform_device *pdev) +{ + int ret = 0; + struct msm_fb_data_type *mfd; + unsigned long panel_pixclock_freq , pm_qos_rate; + + mfd = platform_get_drvdata(pdev); + panel_pixclock_freq = mfd->fbi->var.pixclock; + + if (panel_pixclock_freq > 58000000) + /* pm_qos_rate should be in Khz */ + pm_qos_rate = panel_pixclock_freq / 1000 ; + else + pm_qos_rate = 58000; + mdp4_extn_disp = 1; +#ifdef CONFIG_MSM_BUS_SCALING + if (dtv_bus_scale_handle > 0) + msm_bus_scale_client_update_request(dtv_bus_scale_handle, + 1); +#else + if (ebi1_clk) { + clk_set_rate(ebi1_clk, pm_qos_rate * 1000); + clk_prepare_enable(ebi1_clk); + } +#endif + mfd = platform_get_drvdata(pdev); + + ret = clk_set_rate(tv_src_clk, mfd->fbi->var.pixclock); + if (ret) { + pr_info("%s: clk_set_rate(%d) failed\n", __func__, + mfd->fbi->var.pixclock); + if (mfd->fbi->var.pixclock == 27030000) + mfd->fbi->var.pixclock = 27000000; + ret = clk_set_rate(tv_src_clk, mfd->fbi->var.pixclock); + } + pr_info("%s: tv_src_clk=%dkHz, pm_qos_rate=%ldkHz, [%d]\n", __func__, + mfd->fbi->var.pixclock/1000, pm_qos_rate, ret); + mfd->panel_info.clk_rate = mfd->fbi->var.pixclock; + clk_prepare_enable(hdmi_clk); + clk_reset(hdmi_clk, CLK_RESET_ASSERT); + udelay(20); + clk_reset(hdmi_clk, CLK_RESET_DEASSERT); + + if (mdp_tv_clk) + clk_prepare_enable(mdp_tv_clk); + + if (dtv_pdata && dtv_pdata->lcdc_power_save) + dtv_pdata->lcdc_power_save(1); + if (dtv_pdata && dtv_pdata->lcdc_gpio_config) + ret = dtv_pdata->lcdc_gpio_config(1); + + ret = panel_next_on(pdev); + return ret; +} + +static int dtv_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct fb_info *fbi; + struct platform_device *mdp_dev = NULL; + struct msm_fb_panel_data *pdata = NULL; + int rc; + + if (pdev->id == 0) { + dtv_pdata = pdev->dev.platform_data; +#ifdef CONFIG_MSM_BUS_SCALING + if (!dtv_bus_scale_handle && dtv_pdata && + dtv_pdata->bus_scale_table) { + dtv_bus_scale_handle = + msm_bus_scale_register_client( + dtv_pdata->bus_scale_table); + if (!dtv_bus_scale_handle) { + pr_err("%s not able to get bus scale\n", + __func__); + } + } +#else + ebi1_clk = clk_get(&pdev->dev, "mem_clk"); + if (IS_ERR(ebi1_clk)) { + ebi1_clk = NULL; + pr_warning("%s: Couldn't get ebi1 clock\n", __func__); + } +#endif + tv_src_clk = clk_get(&pdev->dev, "src_clk"); + if (IS_ERR(tv_src_clk)) { + pr_err("error: can't get tv_src_clk!\n"); + return IS_ERR(tv_src_clk); + } + + hdmi_clk = clk_get(&pdev->dev, "hdmi_clk"); + if (IS_ERR(hdmi_clk)) { + pr_err("error: can't get hdmi_clk!\n"); + return IS_ERR(hdmi_clk); + } + + mdp_tv_clk = clk_get(&pdev->dev, "mdp_clk"); + if (IS_ERR(mdp_tv_clk)) + mdp_tv_clk = NULL; + + return 0; + } + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) + return -ENOMEM; + + mdp_dev = platform_device_alloc("mdp", pdev->id); + if (!mdp_dev) + return -ENOMEM; + + /* + * link to the latest pdev + */ + mfd->pdev = mdp_dev; + mfd->dest = DISPLAY_LCDC; + + /* + * alloc panel device data + */ + if (platform_device_add_data + (mdp_dev, pdev->dev.platform_data, + sizeof(struct msm_fb_panel_data))) { + pr_err("dtv_probe: platform_device_add_data failed!\n"); + platform_device_put(mdp_dev); + return -ENOMEM; + } + /* + * data chain + */ + pdata = (struct msm_fb_panel_data *)mdp_dev->dev.platform_data; + pdata->on = dtv_on; + pdata->off = dtv_off; + pdata->next = pdev; + + /* + * get/set panel specific fb info + */ + mfd->panel_info = pdata->panel_info; + if (hdmi_prim_display) + mfd->fb_imgType = MSMFB_DEFAULT_TYPE; + else + mfd->fb_imgType = MDP_RGB_565; + + fbi = mfd->fbi; + fbi->var.pixclock = mfd->panel_info.clk_rate; + fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch; + fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch; + fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch; + fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch; + fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width; + fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width; + + /* + * set driver data + */ + platform_set_drvdata(mdp_dev, mfd); + + /* + * register in mdp driver + */ + rc = platform_device_add(mdp_dev); + if (rc) + goto dtv_probe_err; + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + pdev_list[pdev_list_cnt++] = pdev; + return 0; + +dtv_probe_err: +#ifdef CONFIG_MSM_BUS_SCALING + if (dtv_pdata && dtv_pdata->bus_scale_table && + dtv_bus_scale_handle > 0) + msm_bus_scale_unregister_client(dtv_bus_scale_handle); +#endif + platform_device_put(mdp_dev); + return rc; +} + +static int dtv_remove(struct platform_device *pdev) +{ +#ifdef CONFIG_MSM_BUS_SCALING + if (dtv_pdata && dtv_pdata->bus_scale_table && + dtv_bus_scale_handle > 0) + msm_bus_scale_unregister_client(dtv_bus_scale_handle); +#else + if (ebi1_clk) + clk_put(ebi1_clk); +#endif + pm_runtime_disable(&pdev->dev); + return 0; +} + +static int dtv_register_driver(void) +{ + return platform_driver_register(&dtv_driver); +} + +static int __init dtv_driver_init(void) +{ + return dtv_register_driver(); +} + +module_init(dtv_driver_init); diff --git a/drivers/video/msm/mdp4_hsic.c b/drivers/video/msm/mdp4_hsic.c new file mode 100644 index 000000000000..9b45231d3ae8 --- /dev/null +++ b/drivers/video/msm/mdp4_hsic.c @@ -0,0 +1,534 @@ +/* Copyright (c) 2009-2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include "mdp.h" +#include "mdp4.h" + +/* Definitions */ +#define MDP4_CSC_MV_OFF 0x4400 +#define MDP4_CSC_PRE_BV_OFF 0x4500 +#define MDP4_CSC_POST_BV_OFF 0x4580 +#define MDP4_CSC_PRE_LV_OFF 0x4600 +#define MDP4_CSC_POST_LV_OFF 0x4680 +#define MDP_VG1_BASE (MDP_BASE + MDP4_VIDEO_BASE) + +#define MDP_VG1_CSC_MVn(n) (MDP_VG1_BASE + MDP4_CSC_MV_OFF + 4 * (n)) +#define MDP_VG1_CSC_PRE_LVn(n) (MDP_VG1_BASE + MDP4_CSC_PRE_LV_OFF + 4 * (n)) +#define MDP_VG1_CSC_POST_LVn(n) (MDP_VG1_BASE + MDP4_CSC_POST_LV_OFF + 4 * (n)) +#define MDP_VG1_CSC_PRE_BVn(n) (MDP_VG1_BASE + MDP4_CSC_PRE_BV_OFF + 4 * (n)) +#define MDP_VG1_CSC_POST_BVn(n) (MDP_VG1_BASE + MDP4_CSC_POST_BV_OFF + 4 * (n)) + +#define Q16 (16) +#define Q16_ONE (1 << Q16) + +#define Q16_VALUE(x) ((int32_t)((uint32_t)x << Q16)) +#define Q16_PERCENT_VALUE(x, n) ((int32_t)( \ + div_s64(((int64_t)x * (int64_t)Q16_ONE), n))) + +#define Q16_WHOLE(x) ((int32_t)(x >> 16)) +#define Q16_FRAC(x) ((int32_t)(x & 0xFFFF)) +#define Q16_S1Q16_MUL(x, y) (((x >> 1) * (y >> 1)) >> 14) + +#define Q16_MUL(x, y) ((int32_t)((((int64_t)x) * ((int64_t)y)) >> Q16)) +#define Q16_NEGATE(x) (0 - (x)) + +/* + * HSIC Control min/max values + * These settings are based on the maximum/minimum allowed modifications to + * HSIC controls for layer and display color. Allowing too much variation in + * the CSC block will result in color clipping resulting in unwanted color + * shifts. + */ +#define TRIG_MAX Q16_VALUE(128) +#define CON_SAT_MAX Q16_VALUE(128) +#define INTENSITY_MAX (Q16_VALUE(2047) >> 12) + +#define HUE_MAX Q16_VALUE(100) +#define HUE_MIN Q16_VALUE(-100) +#define HUE_DEF Q16_VALUE(0) + +#define SAT_MAX Q16_VALUE(100) +#define SAT_MIN Q16_VALUE(-100) +#define SAT_DEF CON_SAT_MAX + +#define CON_MAX Q16_VALUE(100) +#define CON_MIN Q16_VALUE(-100) +#define CON_DEF CON_SAT_MAX + +#define INTEN_MAX Q16_VALUE(100) +#define INTEN_MIN Q16_VALUE(-100) +#define INTEN_DEF Q16_VALUE(0) + +enum { + DIRTY, + GENERATED, + CLEAN +}; + +/* local vars*/ +static int32_t csc_matrix_tab[3][3] = { + {0x00012a00, 0x00000000, 0x00019880}, + {0x00012a00, 0xffff9b80, 0xffff3000}, + {0x00012a00, 0x00020480, 0x00000000} +}; + +static int32_t csc_yuv2rgb_conv_tab[3][3] = { + {0x00010000, 0x00000000, 0x000123cb}, + {0x00010000, 0xffff9af9, 0xffff6b5e}, + {0x00010000, 0x00020838, 0x00000000} +}; + +static int32_t csc_rgb2yuv_conv_tab[3][3] = { + {0x00004c8b, 0x00009645, 0x00001d2f}, + {0xffffda56, 0xffffb60e, 0x00006f9d}, + {0x00009d70, 0xffff7c2a, 0xffffe666} +}; + +static uint32_t csc_pre_bv_tab[3] = {0xfffff800, 0xffffc000, 0xffffc000}; +static uint32_t csc_post_bv_tab[3] = {0x00000000, 0x00000000, 0x00000000}; + +static uint32_t csc_pre_lv_tab[6] = {0x00000000, 0x00007f80, 0x00000000, + 0x00007f80, 0x00000000, 0x00007f80}; +static uint32_t csc_post_lv_tab[6] = {0x00000000, 0x00007f80, 0x00000000, + 0x00007f80, 0x00000000, 0x00007f80}; + +/* Lookup table for Sin/Cos lookup - Q16*/ +static const int32_t trig_lut[65] = { + 0x00000000, /* sin((2*M_PI/256) * 0x00);*/ + 0x00000648, /* sin((2*M_PI/256) * 0x01);*/ + 0x00000C90, /* sin((2*M_PI/256) * 0x02);*/ + 0x000012D5, + 0x00001918, + 0x00001F56, + 0x00002590, + 0x00002BC4, + 0x000031F1, + 0x00003817, + 0x00003E34, + 0x00004447, + 0x00004A50, + 0x0000504D, + 0x0000563E, + 0x00005C22, + 0x000061F8, + 0x000067BE, + 0x00006D74, + 0x0000731A, + 0x000078AD, + 0x00007E2F, + 0x0000839C, + 0x000088F6, + 0x00008E3A, + 0x00009368, + 0x00009880, + 0x00009D80, + 0x0000A268, + 0x0000A736, + 0x0000ABEB, + 0x0000B086, + 0x0000B505, + 0x0000B968, + 0x0000BDAF, + 0x0000C1D8, + 0x0000C5E4, + 0x0000C9D1, + 0x0000CD9F, + 0x0000D14D, + 0x0000D4DB, + 0x0000D848, + 0x0000DB94, + 0x0000DEBE, + 0x0000E1C6, + 0x0000E4AA, + 0x0000E768, + 0x0000EA0A, + 0x0000EC83, + 0x0000EED9, + 0x0000F109, + 0x0000F314, + 0x0000F4FA, + 0x0000F6BA, + 0x0000F854, + 0x0000F9C8, + 0x0000FB15, + 0x0000FC3B, + 0x0000FD3B, + 0x0000FE13, + 0x0000FEC4, + 0x0000FF4E, + 0x0000FFB1, + 0x0000FFEC, + 0x00010000, /* sin((2*M_PI/256) * 0x40);*/ +}; + +void trig_values_q16(int32_t deg, int32_t *cos, int32_t *sin) +{ + int32_t angle; + int32_t quad, anglei, anglef; + int32_t v0 = 0, v1 = 0; + int32_t t1, t2; + + /* + * Scale the angle so that 256 is one complete revolution and mask it + * to this domain + * NOTE: 0xB60B == 256/360 + */ + angle = Q16_MUL(deg, 0xB60B) & 0x00FFFFFF; + + /* Obtain a quadrant number, integer, and fractional part */ + quad = angle >> 22; + anglei = (angle >> 16) & 0x3F; + anglef = angle & 0xFFFF; + + /* + * Using the integer part, obtain the lookup table entry and its + * complement. Using the quadrant, swap and negate these as + * necessary. + * (The values and all derivatives of sine and cosine functions + * can be derived from these values) + */ + switch (quad) { + case 0x0: + v0 += trig_lut[anglei]; + v1 += trig_lut[0x40-anglei]; + break; + + case 0x1: + v0 += trig_lut[0x40-anglei]; + v1 -= trig_lut[anglei]; + break; + + case 0x2: + v0 -= trig_lut[anglei]; + v1 -= trig_lut[0x40-anglei]; + break; + + case 0x3: + v0 -= trig_lut[0x40-anglei]; + v1 += trig_lut[anglei]; + break; + } + + /* + * Multiply the fractional part by 2*PI/256 to move it from lookup + * table units to radians, giving us the coefficient for first + * derivatives. + */ + t1 = Q16_S1Q16_MUL(anglef, 0x0648); + + /* + * Square this and divide by 2 to get the coefficient for second + * derivatives + */ + t2 = Q16_S1Q16_MUL(t1, t1) >> 1; + + *sin = v0 + Q16_S1Q16_MUL(v1, t1) - Q16_S1Q16_MUL(v0, t2); + + *cos = v1 - Q16_S1Q16_MUL(v0, t1) - Q16_S1Q16_MUL(v1, t2); +} + +/* Convert input Q16 value to s4.9 */ +int16_t convert_q16_s49(int32_t q16Value) +{ /* Top half is the whole number, Bottom half is fractional portion*/ + int16_t whole = Q16_WHOLE(q16Value); + int32_t fraction = Q16_FRAC(q16Value); + + /* Clamp whole to 3 bits */ + if (whole > 7) + whole = 7; + else if (whole < -7) + whole = -7; + + /* Reduce fraction to 9 bits. */ + fraction = (fraction<<9)>>Q16; + + return (int16_t) ((int16_t)whole<<9) | ((int16_t)fraction); +} + +/* Convert input Q16 value to uint16 */ +int16_t convert_q16_int16(int32_t val) +{ + int32_t rounded; + + if (val >= 0) { + /* Add 0.5 */ + rounded = val + (Q16_ONE>>1); + } else { + /* Subtract 0.5 */ + rounded = val - (Q16_ONE>>1); + } + + /* Truncate rounded value */ + return (int16_t)(rounded>>Q16); +} + +/* + * norm_q16 + * Return a Q16 value represeting a normalized value + * + * value -100% 0% +100% + * |-----------------|----------------| + * ^ ^ ^ + * q16MinValue q16DefaultValue q16MaxValue + * + */ +int32_t norm_q16(int32_t value, int32_t min, int32_t default_val, int32_t max, + int32_t range) +{ + int32_t diff, perc, mul, result; + + if (0 == value) { + result = default_val; + } else if (value > 0) { + /* value is between 0% and +100% represent 1.0 -> QRange Max */ + diff = range; + perc = Q16_PERCENT_VALUE(value, max); + mul = Q16_MUL(perc, diff); + result = default_val + mul; + } else { + /* if (value <= 0) */ + diff = -range; + perc = Q16_PERCENT_VALUE(-value, -min); + mul = Q16_MUL(perc, diff); + result = default_val + mul; + } + return result; +} + +void matrix_mul_3x3(int32_t dest[][3], int32_t a[][3], int32_t b[][3]) +{ + int32_t i, j, k; + int32_t tmp[3][3]; + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + tmp[i][j] = 0; + for (k = 0; k < 3; k++) + tmp[i][j] += Q16_MUL(a[i][k], b[k][j]); + } + } + + /* in case dest = a or b*/ + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) + dest[i][j] = tmp[i][j]; + } +} + +#define CONVERT(x) (x)/*convert_q16_s49((x))*/ +void pr_params(struct mdp4_hsic_regs *regs) +{ + int i; + if (regs) { + for (i = 0; i < NUM_HSIC_PARAM; i++) { + pr_info("\t: hsic->params[%d] = 0x%08x [raw = 0x%08x]\n", + i, CONVERT(regs->params[i]), regs->params[i]); + } + } +} + +void pr_3x3_matrix(int32_t in[][3]) +{ + pr_info("\t[0x%08x\t0x%08x\t0x%08x]\n", CONVERT(in[0][0]), + CONVERT(in[0][1]), CONVERT(in[0][2])); + pr_info("\t[0x%08x\t0x%08x\t0x%08x]\n", CONVERT(in[1][0]), + CONVERT(in[1][1]), CONVERT(in[1][2])); + pr_info("\t[0x%08x\t0x%08x\t0x%08x]\n", CONVERT(in[2][0]), + CONVERT(in[2][1]), CONVERT(in[2][2])); +} + +void _hsic_get(struct mdp4_hsic_regs *regs, int32_t type, int8_t *val) +{ + if (type < 0 || type >= NUM_HSIC_PARAM) + BUG_ON(-EINVAL); + *val = regs->params[type]; + pr_info("%s: getting params[%d] = %d\n", __func__, type, *val); +} + +void _hsic_set(struct mdp4_hsic_regs *regs, int32_t type, int8_t val) +{ + if (type < 0 || type >= NUM_HSIC_PARAM) + BUG_ON(-EINVAL); + + if (regs->params[type] != Q16_VALUE(val)) { + regs->params[type] = Q16_VALUE(val); + regs->dirty = DIRTY; + } +} + +void _hsic_generate_csc_matrix(struct mdp4_overlay_pipe *pipe) +{ + int i, j; + int32_t sin, cos; + + int32_t hue_matrix[3][3]; + int32_t con_sat_matrix[3][3]; + struct mdp4_hsic_regs *regs = &(pipe->hsic_regs); + + memset(con_sat_matrix, 0x0, sizeof(con_sat_matrix)); + memset(hue_matrix, 0x0, sizeof(hue_matrix)); + + /* + * HSIC control require matrix multiplication of these two tables + * [T 0 0][1 0 0] T = Contrast C=Cos(Hue) + * [0 S 0][0 C -N] S = Saturation N=Sin(Hue) + * [0 0 S][0 N C] + */ + + con_sat_matrix[0][0] = norm_q16(regs->params[HSIC_CON], CON_MIN, + CON_DEF, CON_MAX, CON_SAT_MAX); + con_sat_matrix[1][1] = norm_q16(regs->params[HSIC_SAT], SAT_MIN, + SAT_DEF, SAT_MAX, CON_SAT_MAX); + con_sat_matrix[2][2] = con_sat_matrix[1][1]; + + hue_matrix[0][0] = TRIG_MAX; + + trig_values_q16(norm_q16(regs->params[HSIC_HUE], HUE_MIN, HUE_DEF, + HUE_MAX, TRIG_MAX), &cos, &sin); + + cos = Q16_MUL(cos, TRIG_MAX); + sin = Q16_MUL(sin, TRIG_MAX); + + hue_matrix[1][1] = cos; + hue_matrix[2][2] = cos; + hue_matrix[2][1] = sin; + hue_matrix[1][2] = Q16_NEGATE(sin); + + /* Generate YUV CSC matrix */ + matrix_mul_3x3(regs->conv_matrix, con_sat_matrix, hue_matrix); + + if (!(pipe->op_mode & MDP4_OP_SRC_DATA_YCBCR)) { + /* Convert input RGB to YUV then apply CSC matrix */ + pr_info("Pipe %d, has RGB input\n", pipe->pipe_num); + matrix_mul_3x3(regs->conv_matrix, regs->conv_matrix, + csc_rgb2yuv_conv_tab); + } + + /* Normalize the matrix */ + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) + regs->conv_matrix[i][j] = (regs->conv_matrix[i][j]>>14); + } + + /* Multiply above result by current csc table */ + matrix_mul_3x3(regs->conv_matrix, regs->conv_matrix, csc_matrix_tab); + + if (!(pipe->op_mode & MDP4_OP_SRC_DATA_YCBCR)) { + /*HACK:only "works"for src side*/ + /* Convert back to RGB */ + pr_info("Pipe %d, has RGB output\n", pipe->pipe_num); + matrix_mul_3x3(regs->conv_matrix, csc_yuv2rgb_conv_tab, + regs->conv_matrix); + } + + /* Update clamps pre and post. */ + /* TODO: different tables for different color formats? */ + for (i = 0; i < 6; i++) { + regs->pre_limit[i] = csc_pre_lv_tab[i]; + regs->post_limit[i] = csc_post_lv_tab[i]; + } + + /* update bias values, pre and post */ + for (i = 0; i < 3; i++) { + regs->pre_bias[i] = csc_pre_bv_tab[i]; + regs->post_bias[i] = csc_post_bv_tab[i] + + norm_q16(regs->params[HSIC_INT], + INTEN_MIN, INTEN_DEF, INTEN_MAX, INTENSITY_MAX); + } + + regs->dirty = GENERATED; +} + +void _hsic_update_mdp(struct mdp4_overlay_pipe *pipe) +{ + struct mdp4_hsic_regs *regs = &(pipe->hsic_regs); + int i, j, k; + + uint32_t *csc_mv; + uint32_t *pre_lv; + uint32_t *post_lv; + uint32_t *pre_bv; + uint32_t *post_bv; + + switch (pipe->pipe_num) { + case OVERLAY_PIPE_VG2: + csc_mv = (uint32_t *) (MDP_VG1_CSC_MVn(0) + + MDP4_VIDEO_OFF); + pre_lv = (uint32_t *) (MDP_VG1_CSC_PRE_LVn(0) + + MDP4_VIDEO_OFF); + post_lv = (uint32_t *) (MDP_VG1_CSC_POST_LVn(0) + + MDP4_VIDEO_OFF); + pre_bv = (uint32_t *) (MDP_VG1_CSC_PRE_BVn(0) + + MDP4_VIDEO_OFF); + post_bv = (uint32_t *) (MDP_VG1_CSC_POST_BVn(0) + + MDP4_VIDEO_OFF); + break; + case OVERLAY_PIPE_VG1: + default: + csc_mv = (uint32_t *) MDP_VG1_CSC_MVn(0); + pre_lv = (uint32_t *) MDP_VG1_CSC_PRE_LVn(0); + post_lv = (uint32_t *) MDP_VG1_CSC_POST_LVn(0); + pre_bv = (uint32_t *) MDP_VG1_CSC_PRE_BVn(0); + post_bv = (uint32_t *) MDP_VG1_CSC_POST_BVn(0); + break; + } + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + k = (3*i) + j; + MDP_OUTP(csc_mv + k, convert_q16_s49( + regs->conv_matrix[i][j])); + } + } + + for (i = 0; i < 6; i++) { + MDP_OUTP(pre_lv + i, convert_q16_s49(regs->pre_limit[i])); + MDP_OUTP(post_lv + i, convert_q16_s49(regs->post_limit[i])); + } + + for (i = 0; i < 3; i++) { + MDP_OUTP(pre_bv + i, convert_q16_s49(regs->pre_bias[i])); + MDP_OUTP(post_bv + i, convert_q16_s49(regs->post_bias[i])); + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + regs->dirty = CLEAN; +} + +void mdp4_hsic_get(struct mdp4_overlay_pipe *pipe, struct dpp_ctrl *ctrl) +{ + int i; + for (i = 0; i < NUM_HSIC_PARAM; i++) + _hsic_get(&(pipe->hsic_regs), i, &(ctrl->hsic_params[i])); +} + +void mdp4_hsic_set(struct mdp4_overlay_pipe *pipe, struct dpp_ctrl *ctrl) +{ + int i; + for (i = 0; i < NUM_HSIC_PARAM; i++) + _hsic_set(&(pipe->hsic_regs), i, ctrl->hsic_params[i]); + + if (pipe->hsic_regs.dirty == DIRTY) + _hsic_generate_csc_matrix(pipe); +} + +void mdp4_hsic_update(struct mdp4_overlay_pipe *pipe) +{ + if (pipe->hsic_regs.dirty == GENERATED) + _hsic_update_mdp(pipe); +} diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c new file mode 100644 index 000000000000..819afffc4f43 --- /dev/null +++ b/drivers/video/msm/mdp4_overlay.c @@ -0,0 +1,3356 @@ +/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mdp.h" +#include "msm_fb.h" +#include "mdp4.h" + +#define VERSION_KEY_MASK 0xFFFFFF00 + +struct mdp4_overlay_ctrl { + struct mdp4_overlay_pipe plist[OVERLAY_PIPE_MAX]; + struct mdp4_overlay_pipe *stage[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX]; + struct mdp4_overlay_pipe *baselayer[MDP4_MIXER_MAX]; + struct blend_cfg blend[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX]; + uint32 mixer_cfg[MDP4_MIXER_MAX]; + uint32 flush[MDP4_MIXER_MAX]; + uint32 cs_controller; + uint32 hw_version; + uint32 panel_3d; + uint32 panel_mode; + uint32 mixer0_played; + uint32 mixer1_played; + uint32 mixer2_played; +} mdp4_overlay_db = { + .cs_controller = CS_CONTROLLER_0, + .plist = { + { + .pipe_type = OVERLAY_TYPE_RGB, + .pipe_num = OVERLAY_PIPE_RGB1, + .pipe_ndx = 1, + }, + { + .pipe_type = OVERLAY_TYPE_RGB, + .pipe_num = OVERLAY_PIPE_RGB2, + .pipe_ndx = 2, + }, + { + .pipe_type = OVERLAY_TYPE_VIDEO, + .pipe_num = OVERLAY_PIPE_VG1, + .pipe_ndx = 3, + }, + { + .pipe_type = OVERLAY_TYPE_VIDEO, + .pipe_num = OVERLAY_PIPE_VG2, + .pipe_ndx = 4, + }, + { + .pipe_type = OVERLAY_TYPE_BF, + .pipe_num = OVERLAY_PIPE_RGB3, + .pipe_ndx = 5, + .mixer_num = MDP4_MIXER0, + }, + { + .pipe_type = OVERLAY_TYPE_BF, + .pipe_num = OVERLAY_PIPE_VG3, + .pipe_ndx = 6, + .mixer_num = MDP4_MIXER1, + }, + { + .pipe_type = OVERLAY_TYPE_BF, + .pipe_num = OVERLAY_PIPE_VG4, + .pipe_ndx = 7, + .mixer_num = MDP4_MIXER2, + }, + }, +}; + +static struct mdp4_overlay_ctrl *ctrl = &mdp4_overlay_db; +static int new_perf_level; +static struct ion_client *display_iclient; +static struct mdp4_iommu_pipe_info mdp_iommu[MDP4_MIXER_MAX][OVERLAY_PIPE_MAX]; + +int mdp4_overlay_iommu_map_buf(int mem_id, + struct mdp4_overlay_pipe *pipe, unsigned int plane, + unsigned long *start, unsigned long *len, + struct ion_handle **srcp_ihdl) +{ + struct mdp4_iommu_pipe_info *iom_pipe_info; + + if (!display_iclient) + return -EINVAL; + + *srcp_ihdl = ion_import_fd(display_iclient, mem_id); + if (IS_ERR_OR_NULL(*srcp_ihdl)) { + pr_err("ion_import_fd() failed\n"); + return PTR_ERR(*srcp_ihdl); + } + pr_debug("%s(): ion_hdl %p, ion_buf %p\n", __func__, *srcp_ihdl, + ion_share(display_iclient, *srcp_ihdl)); + pr_debug("mixer %u, pipe %u, plane %u\n", pipe->mixer_num, + pipe->pipe_ndx, plane); + if (ion_map_iommu(display_iclient, *srcp_ihdl, + DISPLAY_DOMAIN, GEN_POOL, SZ_4K, 0, start, + len, 0, ION_IOMMU_UNMAP_DELAYED)) { + ion_free(display_iclient, *srcp_ihdl); + pr_err("ion_map_iommu() failed\n"); + return -EINVAL; + } + + iom_pipe_info = &mdp_iommu[pipe->mixer_num][pipe->pipe_ndx - 1]; + if (!iom_pipe_info->ihdl[plane]) { + iom_pipe_info->ihdl[plane] = *srcp_ihdl; + } else { + if (iom_pipe_info->prev_ihdl[plane]) { + ion_unmap_iommu(display_iclient, + iom_pipe_info->prev_ihdl[plane], + DISPLAY_DOMAIN, GEN_POOL); + ion_free(display_iclient, + iom_pipe_info->prev_ihdl[plane]); + pr_debug("Previous: mixer %u, pipe %u, plane %u, " + "prev_ihdl %p\n", pipe->mixer_num, + pipe->pipe_ndx, plane, + iom_pipe_info->prev_ihdl[plane]); + } + + iom_pipe_info->prev_ihdl[plane] = iom_pipe_info->ihdl[plane]; + iom_pipe_info->ihdl[plane] = *srcp_ihdl; + } + pr_debug("mem_id %d, start 0x%lx, len 0x%lx\n", + mem_id, *start, *len); + return 0; +} + +void mdp4_iommu_unmap(struct mdp4_overlay_pipe *pipe) +{ + struct mdp4_iommu_pipe_info *iom_pipe_info; + unsigned char i, j; + + if (!display_iclient) + return; + + for (j = 0; j < OVERLAY_PIPE_MAX; j++) { + iom_pipe_info = &mdp_iommu[pipe->mixer_num][j]; + for (i = 0; i < MDP4_MAX_PLANE; i++) { + if (iom_pipe_info->prev_ihdl[i]) { + pr_debug("%s(): mixer %u, pipe %u, plane %u, " + "prev_ihdl %p\n", __func__, + pipe->mixer_num, j + 1, i, + iom_pipe_info->prev_ihdl[i]); + ion_unmap_iommu(display_iclient, + iom_pipe_info->prev_ihdl[i], + DISPLAY_DOMAIN, GEN_POOL); + ion_free(display_iclient, + iom_pipe_info->prev_ihdl[i]); + iom_pipe_info->prev_ihdl[i] = NULL; + } + + if (iom_pipe_info->mark_unmap) { + if (iom_pipe_info->ihdl[i]) { + if (pipe->mixer_num == MDP4_MIXER1) + mdp4_overlay_dtv_wait4vsync(); + pr_debug("%s(): mixer %u, pipe %u, plane %u, " + "ihdl %p\n", __func__, + pipe->mixer_num, j + 1, i, + iom_pipe_info->ihdl[i]); + ion_unmap_iommu(display_iclient, + iom_pipe_info->ihdl[i], + DISPLAY_DOMAIN, GEN_POOL); + ion_free(display_iclient, + iom_pipe_info->ihdl[i]); + iom_pipe_info->ihdl[i] = NULL; + } + } + } + iom_pipe_info->mark_unmap = 0; + } +} + +int mdp4_overlay_mixer_play(int mixer_num) +{ + if (mixer_num == MDP4_MIXER2) + return ctrl->mixer2_played; + else if (mixer_num == MDP4_MIXER1) + return ctrl->mixer1_played; + else + return ctrl->mixer0_played; +} + +void mdp4_overlay_panel_3d(int mixer_num, uint32 panel_3d) +{ + ctrl->panel_3d = panel_3d; +} + +void mdp4_overlay_panel_mode(int mixer_num, uint32 mode) +{ + ctrl->panel_mode |= mode; +} + +void mdp4_overlay_panel_mode_unset(int mixer_num, uint32 mode) +{ + ctrl->panel_mode &= ~mode; +} + +uint32 mdp4_overlay_panel_list(void) +{ + return ctrl->panel_mode; +} + +void mdp4_overlay_cfg_init(void) +{ + if (ctrl->hw_version == 0) { + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + ctrl->hw_version = inpdw(MDP_BASE + 0x0); /* MDP_HW_VERSION */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + } + + if (ctrl->hw_version >= 0x0402030b) { + /* MDP_LAYERMIXER_IN_CFG_UPDATE_METHOD */ + outpdw(MDP_BASE + 0x100fc, 0x01); + } +} + +void mdp4_overlay_dmae_cfg(struct msm_fb_data_type *mfd, int atv) +{ + uint32 dmae_cfg_reg; + + if (atv) + dmae_cfg_reg = DMA_DEFLKR_EN; + else + dmae_cfg_reg = 0; + + if (mfd->fb_imgType == MDP_BGR_565) + dmae_cfg_reg |= DMA_PACK_PATTERN_BGR; + else + dmae_cfg_reg |= DMA_PACK_PATTERN_RGB; + + + if (mfd->panel_info.bpp == 18) { + dmae_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */ + DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; + } else if (mfd->panel_info.bpp == 16) { + dmae_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */ + DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; + } else { + dmae_cfg_reg |= DMA_DSTC0G_8BITS | /* 888 16BPP */ + DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS; + } + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* dma2 config register */ + MDP_OUTP(MDP_BASE + 0xb0000, dmae_cfg_reg); + if (atv) { + MDP_OUTP(MDP_BASE + 0xb0070, 0xeb0010); + MDP_OUTP(MDP_BASE + 0xb0074, 0xf00010); + MDP_OUTP(MDP_BASE + 0xb0078, 0xf00010); + MDP_OUTP(MDP_BASE + 0xb3000, 0x80); + MDP_OUTP(MDP_BASE + 0xb3010, 0x1800040); + MDP_OUTP(MDP_BASE + 0xb3014, 0x1000080); + MDP_OUTP(MDP_BASE + 0xb4004, 0x67686970); + } else { + mdp_vid_quant_set(); + } + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +#ifdef CONFIG_FB_MSM_HDMI_3D +void unfill_black_screen(void) { return; } +#else +void unfill_black_screen(void) +{ + uint32 temp_src_format; + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + /* + * VG2 Constant Color + */ + temp_src_format = inpdw(MDP_BASE + 0x30050); + MDP_OUTP(MDP_BASE + 0x30050, temp_src_format&(~BIT(22))); + /* + * MDP_OVERLAY_REG_FLUSH + */ + MDP_OUTP(MDP_BASE + 0x18000, BIT(3)); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + return; +} +#endif + +#ifdef CONFIG_FB_MSM_HDMI_3D +void fill_black_screen(void) { return; } +#else +void fill_black_screen(void) +{ + /*Black color*/ + uint32 color = 0x00000000; + uint32 temp_src_format; + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + /* + * VG2 Constant Color + */ + MDP_OUTP(MDP_BASE + 0x31008, color); + /* + * MDP_VG2_SRC_FORMAT + */ + temp_src_format = inpdw(MDP_BASE + 0x30050); + MDP_OUTP(MDP_BASE + 0x30050, temp_src_format | BIT(22)); + /* + * MDP_OVERLAY_REG_FLUSH + */ + MDP_OUTP(MDP_BASE + 0x18000, BIT(3)); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + return; +} +#endif + +void mdp4_overlay_dmae_xy(struct mdp4_overlay_pipe *pipe) +{ + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + MDP_OUTP(MDP_BASE + 0xb0004, + (pipe->src_height << 16 | pipe->src_width)); + if (pipe->blt_addr) { + uint32 off, bpp; +#ifdef BLT_RGB565 + bpp = 2; /* overlay ouput is RGB565 */ +#else + bpp = 3; /* overlay ouput is RGB888 */ +#endif + off = 0; + if (pipe->ov_cnt & 0x01) + off = pipe->src_height * pipe->src_width * bpp; + MDP_OUTP(MDP_BASE + 0xb0008, pipe->blt_addr + off); + /* RGB888, output of overlay blending */ + MDP_OUTP(MDP_BASE + 0xb000c, pipe->src_width * bpp); + } else { + /* dma_e source */ + MDP_OUTP(MDP_BASE + 0xb0008, pipe->srcp0_addr); + MDP_OUTP(MDP_BASE + 0xb000c, pipe->srcp0_ystride); + } + /* dma_e dest */ + MDP_OUTP(MDP_BASE + 0xb0010, (pipe->dst_y << 16 | pipe->dst_x)); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_overlay_dmap_cfg(struct msm_fb_data_type *mfd, int lcdc) +{ + uint32 dma2_cfg_reg; + uint32 mask, curr; + + dma2_cfg_reg = DMA_DITHER_EN; +#ifdef BLT_RGB565 + /* RGB888 is 0 */ + dma2_cfg_reg |= DMA_BUF_FORMAT_RGB565; /* blt only */ +#endif + + if (mfd->fb_imgType == MDP_BGR_565) + dma2_cfg_reg |= DMA_PACK_PATTERN_BGR; + else + dma2_cfg_reg |= DMA_PACK_PATTERN_RGB; + + + if (mfd->panel_info.bpp == 18) { + dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */ + DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; + } else if (mfd->panel_info.bpp == 16) { + dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */ + DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; + } else { + dma2_cfg_reg |= DMA_DSTC0G_8BITS | /* 888 16BPP */ + DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS; + } + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + +#ifndef CONFIG_FB_MSM_LCDC_CHIMEI_WXGA_PANEL + if (lcdc) + dma2_cfg_reg |= DMA_PACK_ALIGN_MSB; +#endif + + /* dma2 config register */ + curr = inpdw(MDP_BASE + 0x90000); + mask = 0x0FFFFFFF; + dma2_cfg_reg = (dma2_cfg_reg & mask) | (curr & ~mask); + MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +/* + * mdp4_overlay_dmap_xy: called form baselayer only + */ +void mdp4_overlay_dmap_xy(struct mdp4_overlay_pipe *pipe) +{ + uint32 off, bpp; + + if (mdp_is_in_isr == FALSE) + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* dma_p source */ + MDP_OUTP(MDP_BASE + 0x90004, + (pipe->src_height << 16 | pipe->src_width)); + if (pipe->blt_addr) { +#ifdef BLT_RGB565 + bpp = 2; /* overlay ouput is RGB565 */ +#else + bpp = 3; /* overlay ouput is RGB888 */ +#endif + off = 0; + if (pipe->dmap_cnt & 0x01) + off = pipe->src_height * pipe->src_width * bpp; + MDP_OUTP(MDP_BASE + 0x90008, pipe->blt_addr + off); + /* RGB888, output of overlay blending */ + MDP_OUTP(MDP_BASE + 0x9000c, pipe->src_width * bpp); + } else { + MDP_OUTP(MDP_BASE + 0x90008, pipe->srcp0_addr); + MDP_OUTP(MDP_BASE + 0x9000c, pipe->srcp0_ystride); + } + + /* dma_p dest */ + MDP_OUTP(MDP_BASE + 0x90010, (pipe->dst_y << 16 | pipe->dst_x)); + + if (mdp_is_in_isr == FALSE) + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +#define MDP4_VG_PHASE_STEP_DEFAULT 0x20000000 +#define MDP4_VG_PHASE_STEP_SHIFT 29 + +static int mdp4_leading_0(uint32 num) +{ + uint32 bit = 0x80000000; + int i; + + for (i = 0; i < 32; i++) { + if (bit & num) + return i; + bit >>= 1; + } + + return i; +} + +static uint32 mdp4_scale_phase_step(int f_num, uint32 src, uint32 dst) +{ + uint32 val, s; + int n; + + n = mdp4_leading_0(src); + if (n > f_num) + n = f_num; + s = src << n; /* maximum to reduce lose of resolution */ + val = s / dst; + if (n < f_num) { + n = f_num - n; + val <<= n; + val |= ((s % dst) << n) / dst; + } + + return val; +} + +static void mdp4_scale_setup(struct mdp4_overlay_pipe *pipe) +{ + pipe->phasex_step = MDP4_VG_PHASE_STEP_DEFAULT; + pipe->phasey_step = MDP4_VG_PHASE_STEP_DEFAULT; + + if (pipe->dst_h && pipe->src_h != pipe->dst_h) { + u32 upscale_max; + upscale_max = (mdp_rev >= MDP_REV_41) ? + MDP4_REV41_OR_LATER_UP_SCALING_MAX : + MDP4_REV40_UP_SCALING_MAX; + if (pipe->dst_h > pipe->src_h * upscale_max) + return; + + pipe->op_mode |= MDP4_OP_SCALEY_EN; + + if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) { + if (pipe->flags & MDP_BACKEND_COMPOSITION && + pipe->alpha_enable && pipe->dst_h > pipe->src_h) + pipe->op_mode |= MDP4_OP_SCALEY_PIXEL_RPT; + else if (pipe->dst_h <= (pipe->src_h / 4)) + pipe->op_mode |= MDP4_OP_SCALEY_MN_PHASE; + else + pipe->op_mode |= MDP4_OP_SCALEY_FIR; + } else { /* RGB pipe */ + pipe->op_mode |= MDP4_OP_SCALE_RGB_ENHANCED | + MDP4_OP_SCALE_RGB_BILINEAR | + MDP4_OP_SCALE_ALPHA_BILINEAR; + } + + pipe->phasey_step = mdp4_scale_phase_step(29, + pipe->src_h, pipe->dst_h); + } + + if (pipe->dst_w && pipe->src_w != pipe->dst_w) { + u32 upscale_max; + upscale_max = (mdp_rev >= MDP_REV_41) ? + MDP4_REV41_OR_LATER_UP_SCALING_MAX : + MDP4_REV40_UP_SCALING_MAX; + + if (pipe->dst_w > pipe->src_w * upscale_max) + return; + pipe->op_mode |= MDP4_OP_SCALEX_EN; + if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) { + if (pipe->flags & MDP_BACKEND_COMPOSITION && + pipe->alpha_enable && pipe->dst_w > pipe->src_w) + pipe->op_mode |= MDP4_OP_SCALEX_PIXEL_RPT; + else if (pipe->dst_w <= (pipe->src_w / 4)) + pipe->op_mode |= MDP4_OP_SCALEX_MN_PHASE; + else + pipe->op_mode |= MDP4_OP_SCALEX_FIR; + } else { /* RGB pipe */ + pipe->op_mode |= MDP4_OP_SCALE_RGB_ENHANCED | + MDP4_OP_SCALE_RGB_BILINEAR | + MDP4_OP_SCALE_ALPHA_BILINEAR; + } + + pipe->phasex_step = mdp4_scale_phase_step(29, + pipe->src_w, pipe->dst_w); + } +} + +void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe) +{ + char *rgb_base; + uint32 src_size, src_xy, dst_size, dst_xy; + uint32 format, pattern; + uint32 curr, mask; + uint32 offset = 0; + int pnum; + + pnum = pipe->pipe_num - OVERLAY_PIPE_RGB1; /* start from 0 */ + rgb_base = MDP_BASE + MDP4_RGB_BASE; + rgb_base += (MDP4_RGB_OFF * pnum); + + src_size = ((pipe->src_h << 16) | pipe->src_w); + src_xy = ((pipe->src_y << 16) | pipe->src_x); + dst_size = ((pipe->dst_h << 16) | pipe->dst_w); + dst_xy = ((pipe->dst_y << 16) | pipe->dst_x); + + if ((pipe->src_x + pipe->src_w) > 0x7FF) { + offset += pipe->src_x * pipe->bpp; + src_xy &= 0xFFFF0000; + } + + if ((pipe->src_y + pipe->src_h) > 0x7FF) { + offset += pipe->src_y * pipe->src_width * pipe->bpp; + src_xy &= 0x0000FFFF; + } + + format = mdp4_overlay_format(pipe); + pattern = mdp4_overlay_unpack_pattern(pipe); + +#ifdef MDP4_IGC_LUT_ENABLE + pipe->op_mode |= MDP4_OP_IGC_LUT_EN; +#endif + + mdp4_scale_setup(pipe); + + /* Ensure proper covert matrix loaded when color space swaps */ + curr = inpdw(rgb_base + 0x0058); + /* Don't touch bits you don't want to configure*/ + mask = 0xFFFEFFFF; + pipe->op_mode = (pipe->op_mode & mask) | (curr & ~mask); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + outpdw(rgb_base + 0x0000, src_size); /* MDP_RGB_SRC_SIZE */ + outpdw(rgb_base + 0x0004, src_xy); /* MDP_RGB_SRC_XY */ + outpdw(rgb_base + 0x0008, dst_size); /* MDP_RGB_DST_SIZE */ + outpdw(rgb_base + 0x000c, dst_xy); /* MDP_RGB_DST_XY */ + + outpdw(rgb_base + 0x0010, pipe->srcp0_addr + offset); + outpdw(rgb_base + 0x0040, pipe->srcp0_ystride); + + outpdw(rgb_base + 0x0050, format);/* MDP_RGB_SRC_FORMAT */ + outpdw(rgb_base + 0x0054, pattern);/* MDP_RGB_SRC_UNPACK_PATTERN */ + if (format & MDP4_FORMAT_SOLID_FILL) { + u32 op_mode = pipe->op_mode; + op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN); + op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN); + outpdw(rgb_base + 0x0058, op_mode);/* MDP_RGB_OP_MODE */ + } else + outpdw(rgb_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */ + outpdw(rgb_base + 0x005c, pipe->phasex_step); + outpdw(rgb_base + 0x0060, pipe->phasey_step); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + mdp4_stat.pipe[pipe->pipe_num]++; +} + + +static void mdp4_overlay_vg_get_src_offset(struct mdp4_overlay_pipe *pipe, + char *vg_base, uint32 *luma_off, uint32 *chroma_off) +{ + uint32 src_xy; + *luma_off = 0; + *chroma_off = 0; + + if (pipe->src_x && (pipe->frame_format == + MDP4_FRAME_FORMAT_LINEAR)) { + src_xy = (pipe->src_y << 16) | pipe->src_x; + src_xy &= 0xffff0000; + outpdw(vg_base + 0x0004, src_xy); /* MDP_RGB_SRC_XY */ + + switch (pipe->src_format) { + case MDP_Y_CR_CB_H2V2: + case MDP_Y_CR_CB_GH2V2: + case MDP_Y_CB_CR_H2V2: + *luma_off = pipe->src_x; + *chroma_off = pipe->src_x/2; + break; + + case MDP_Y_CBCR_H2V2_TILE: + case MDP_Y_CRCB_H2V2_TILE: + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + case MDP_Y_CRCB_H1V1: + case MDP_Y_CBCR_H1V1: + case MDP_Y_CRCB_H2V1: + case MDP_Y_CBCR_H2V1: + *luma_off = pipe->src_x; + *chroma_off = pipe->src_x; + break; + + case MDP_YCRYCB_H2V1: + if (pipe->src_x & 0x1) + pipe->src_x += 1; + *luma_off += pipe->src_x * 2; + break; + + case MDP_ARGB_8888: + case MDP_RGBA_8888: + case MDP_BGRA_8888: + case MDP_RGBX_8888: + case MDP_RGB_565: + case MDP_BGR_565: + case MDP_XRGB_8888: + case MDP_RGB_888: + case MDP_YCBCR_H1V1: + case MDP_YCRCB_H1V1: + *luma_off = pipe->src_x * pipe->bpp; + break; + + default: + pr_err("%s: fmt %u not supported for adjustment\n", + __func__, pipe->src_format); + break; + } + } +} + +void mdp4_overlay_vg_setup(struct mdp4_overlay_pipe *pipe) +{ + char *vg_base; + uint32 frame_size, src_size, src_xy, dst_size, dst_xy; + uint32 format, pattern, luma_offset, chroma_offset; + uint32 mask, curr, addr; + int pnum, ptype; + + pnum = pipe->pipe_num - OVERLAY_PIPE_VG1; /* start from 0 */ + vg_base = MDP_BASE + MDP4_VIDEO_BASE; + vg_base += (MDP4_VIDEO_OFF * pnum); + + frame_size = ((pipe->src_height << 16) | pipe->src_width); + src_size = ((pipe->src_h << 16) | pipe->src_w); + src_xy = ((pipe->src_y << 16) | pipe->src_x); + dst_size = ((pipe->dst_h << 16) | pipe->dst_w); + dst_xy = ((pipe->dst_y << 16) | pipe->dst_x); + + ptype = mdp4_overlay_format2type(pipe->src_format); + format = mdp4_overlay_format(pipe); + pattern = mdp4_overlay_unpack_pattern(pipe); + + /* not RGB use VG pipe, pure VG pipe */ + pipe->op_mode |= MDP4_OP_CSC_EN; + if (ptype != OVERLAY_TYPE_RGB) + pipe->op_mode |= MDP4_OP_SRC_DATA_YCBCR; + +#ifdef MDP4_IGC_LUT_ENABLE + pipe->op_mode |= MDP4_OP_IGC_LUT_EN; +#endif + + mdp4_scale_setup(pipe); + + luma_offset = 0; + chroma_offset = 0; + + if (ptype == OVERLAY_TYPE_RGB) { + if ((pipe->src_y + pipe->src_h) > 0x7FF) { + luma_offset = pipe->src_y * pipe->src_width * pipe->bpp; + src_xy &= 0x0000FFFF; + } + + if ((pipe->src_x + pipe->src_w) > 0x7FF) { + luma_offset += pipe->src_x * pipe->bpp; + src_xy &= 0xFFFF0000; + } + } + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + outpdw(vg_base + 0x0000, src_size); /* MDP_RGB_SRC_SIZE */ + outpdw(vg_base + 0x0004, src_xy); /* MDP_RGB_SRC_XY */ + outpdw(vg_base + 0x0008, dst_size); /* MDP_RGB_DST_SIZE */ + outpdw(vg_base + 0x000c, dst_xy); /* MDP_RGB_DST_XY */ + + if (pipe->frame_format != MDP4_FRAME_FORMAT_LINEAR) + outpdw(vg_base + 0x0048, frame_size); /* TILE frame size */ + + /* + * Adjust src X offset to avoid MDP from overfetching pixels + * present before the offset. This is required for video + * frames coming with unused green pixels along the left margin + */ + /* not RGB use VG pipe, pure VG pipe */ + if (ptype != OVERLAY_TYPE_RGB) { + mdp4_overlay_vg_get_src_offset(pipe, vg_base, &luma_offset, + &chroma_offset); + } + + /* Ensure proper covert matrix loaded when color space swaps */ + curr = inpdw(vg_base + 0x0058); + mask = 0x600; + + if ((curr & mask) != (pipe->op_mode & mask)) { + addr = ((uint32_t)vg_base) + 0x4000; + if (ptype != OVERLAY_TYPE_RGB) + mdp4_csc_write(&(mdp_csc_convert[1]), addr); + else + mdp4_csc_write(&(mdp_csc_convert[0]), addr); + + mask = 0xFFFCFFFF; + } else { + /* Don't touch bits you don't want to configure*/ + mask = 0xFFFCF1FF; + } + pipe->op_mode = (pipe->op_mode & mask) | (curr & ~mask); + + /* luma component plane */ + outpdw(vg_base + 0x0010, pipe->srcp0_addr + luma_offset); + + /* chroma component plane or planar color 1 */ + outpdw(vg_base + 0x0014, pipe->srcp1_addr + chroma_offset); + + /* planar color 2 */ + outpdw(vg_base + 0x0018, pipe->srcp2_addr + chroma_offset); + + outpdw(vg_base + 0x0040, + pipe->srcp1_ystride << 16 | pipe->srcp0_ystride); + + outpdw(vg_base + 0x0044, + pipe->srcp3_ystride << 16 | pipe->srcp2_ystride); + + outpdw(vg_base + 0x0050, format); /* MDP_RGB_SRC_FORMAT */ + outpdw(vg_base + 0x0054, pattern); /* MDP_RGB_SRC_UNPACK_PATTERN */ + if (format & MDP4_FORMAT_SOLID_FILL) { + u32 op_mode = pipe->op_mode; + op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN); + op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN); + outpdw(vg_base + 0x0058, op_mode);/* MDP_RGB_OP_MODE */ + } else + outpdw(vg_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */ + outpdw(vg_base + 0x005c, pipe->phasex_step); + outpdw(vg_base + 0x0060, pipe->phasey_step); + + if (pipe->op_mode & MDP4_OP_DITHER_EN) { + outpdw(vg_base + 0x0068, + pipe->r_bit << 4 | pipe->b_bit << 2 | pipe->g_bit); + } + + if (pipe->flags & MDP_SHARPENING) { + outpdw(vg_base + 0x8200, + mdp4_ss_table_value(pipe->req_data.dpp.sharp_strength, + 0)); + outpdw(vg_base + 0x8204, + mdp4_ss_table_value(pipe->req_data.dpp.sharp_strength, + 1)); + } + + if (mdp_rev > MDP_REV_41) { + /* mdp chip select controller */ + mask = 0; + if (pipe->pipe_num == OVERLAY_PIPE_VG1) + mask = 0x020; /* bit 5 */ + else if (pipe->pipe_num == OVERLAY_PIPE_VG2) + mask = 0x02000; /* bit 13 */ + if (mask) { + if (pipe->op_mode & MDP4_OP_SCALEY_MN_PHASE) + ctrl->cs_controller &= ~mask; + else + ctrl->cs_controller |= mask; + /* NOT double buffered */ + outpdw(MDP_BASE + 0x00c0, ctrl->cs_controller); + } + } + + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + mdp4_stat.pipe[pipe->pipe_num]++; +} + +int mdp4_overlay_format2type(uint32 format) +{ + switch (format) { + case MDP_RGB_565: + case MDP_RGB_888: + case MDP_BGR_565: + case MDP_XRGB_8888: + case MDP_ARGB_8888: + case MDP_RGBA_8888: + case MDP_BGRA_8888: + case MDP_RGBX_8888: + return OVERLAY_TYPE_RGB; + case MDP_YCRYCB_H2V1: + case MDP_Y_CRCB_H2V1: + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V2: + case MDP_Y_CBCR_H2V2: + case MDP_Y_CBCR_H2V2_TILE: + case MDP_Y_CRCB_H2V2_TILE: + case MDP_Y_CR_CB_H2V2: + case MDP_Y_CR_CB_GH2V2: + case MDP_Y_CB_CR_H2V2: + case MDP_Y_CRCB_H1V1: + case MDP_Y_CBCR_H1V1: + case MDP_YCRCB_H1V1: + case MDP_YCBCR_H1V1: + return OVERLAY_TYPE_VIDEO; + case MDP_RGB_BORDERFILL: + return OVERLAY_TYPE_BF; + default: + mdp4_stat.err_format++; + return -ERANGE; + } + +} + +#define C3_ALPHA 3 /* alpha */ +#define C2_R_Cr 2 /* R/Cr */ +#define C1_B_Cb 1 /* B/Cb */ +#define C0_G_Y 0 /* G/luma */ +#define YUV_444_MAX_WIDTH 1280 /* Max width for YUV 444*/ + +int mdp4_overlay_format2pipe(struct mdp4_overlay_pipe *pipe) +{ + switch (pipe->src_format) { + case MDP_RGB_565: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 0; + pipe->r_bit = 1; /* R, 5 bits */ + pipe->b_bit = 1; /* B, 5 bits */ + pipe->g_bit = 2; /* G, 6 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 2; + pipe->element2 = C2_R_Cr; /* R */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->bpp = 2; /* 2 bpp */ + break; + case MDP_RGB_888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 0; + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 2; + pipe->element2 = C1_B_Cb; /* B */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C2_R_Cr; /* R */ + pipe->bpp = 3; /* 3 bpp */ + break; + case MDP_BGR_565: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 0; + pipe->r_bit = 1; /* R, 5 bits */ + pipe->b_bit = 1; /* B, 5 bits */ + pipe->g_bit = 2; /* G, 6 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 2; + pipe->element2 = C1_B_Cb; /* B */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C2_R_Cr; /* R */ + pipe->bpp = 2; /* 2 bpp */ + break; + case MDP_XRGB_8888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 3; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C1_B_Cb; /* B */ + pipe->element2 = C0_G_Y; /* G */ + pipe->element1 = C2_R_Cr; /* R */ + pipe->element0 = C3_ALPHA; /* alpha */ + pipe->bpp = 4; /* 4 bpp */ + break; + case MDP_ARGB_8888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 3; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 1; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C1_B_Cb; /* B */ + pipe->element2 = C0_G_Y; /* G */ + pipe->element1 = C2_R_Cr; /* R */ + pipe->element0 = C3_ALPHA; /* alpha */ + pipe->bpp = 4; /* 4 bpp */ + break; + case MDP_RGBA_8888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 3; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 1; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C3_ALPHA; /* alpha */ + pipe->element2 = C1_B_Cb; /* B */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C2_R_Cr; /* R */ + pipe->bpp = 4; /* 4 bpp */ + break; + case MDP_RGBX_8888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 3; + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C3_ALPHA; /* alpha */ + pipe->element2 = C1_B_Cb; /* B */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C2_R_Cr; /* R */ + pipe->bpp = 4; /* 4 bpp */ + break; + case MDP_BGRA_8888: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 3; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 1; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C3_ALPHA; /* alpha */ + pipe->element2 = C2_R_Cr; /* R */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->bpp = 4; /* 4 bpp */ + break; + case MDP_YCRYCB_H2V1: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 0; /* alpha, 4 bits */ + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 3; + pipe->element3 = C0_G_Y; /* G */ + pipe->element2 = C2_R_Cr; /* R */ + pipe->element1 = C0_G_Y; /* G */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->bpp = 2; /* 2 bpp */ + pipe->chroma_sample = MDP4_CHROMA_H2V1; + break; + case MDP_Y_CRCB_H2V1: + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V2: + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H1V1: + case MDP_Y_CBCR_H1V1: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_PSEUDO_PLANAR; + pipe->a_bit = 0; + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 1; /* 2 */ + if (pipe->src_format == MDP_Y_CRCB_H2V1) { + pipe->element1 = C1_B_Cb; + pipe->element0 = C2_R_Cr; + pipe->chroma_sample = MDP4_CHROMA_H2V1; + } else if (pipe->src_format == MDP_Y_CRCB_H1V1) { + pipe->element1 = C1_B_Cb; + pipe->element0 = C2_R_Cr; + if (pipe->src_width > YUV_444_MAX_WIDTH) + pipe->chroma_sample = MDP4_CHROMA_H1V2; + else + pipe->chroma_sample = MDP4_CHROMA_RGB; + } else if (pipe->src_format == MDP_Y_CBCR_H2V1) { + pipe->element1 = C2_R_Cr; + pipe->element0 = C1_B_Cb; + pipe->chroma_sample = MDP4_CHROMA_H2V1; + } else if (pipe->src_format == MDP_Y_CBCR_H1V1) { + pipe->element1 = C2_R_Cr; + pipe->element0 = C1_B_Cb; + if (pipe->src_width > YUV_444_MAX_WIDTH) + pipe->chroma_sample = MDP4_CHROMA_H1V2; + else + pipe->chroma_sample = MDP4_CHROMA_RGB; + } else if (pipe->src_format == MDP_Y_CRCB_H2V2) { + pipe->element1 = C1_B_Cb; + pipe->element0 = C2_R_Cr; + pipe->chroma_sample = MDP4_CHROMA_420; + } else if (pipe->src_format == MDP_Y_CBCR_H2V2) { + pipe->element1 = C2_R_Cr; + pipe->element0 = C1_B_Cb; + pipe->chroma_sample = MDP4_CHROMA_420; + } + pipe->bpp = 2; /* 2 bpp */ + break; + case MDP_Y_CBCR_H2V2_TILE: + case MDP_Y_CRCB_H2V2_TILE: + pipe->frame_format = MDP4_FRAME_FORMAT_VIDEO_SUPERTILE; + pipe->fetch_plane = OVERLAY_PLANE_PSEUDO_PLANAR; + pipe->a_bit = 0; + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 1; /* 2 */ + if (pipe->src_format == MDP_Y_CRCB_H2V2_TILE) { + pipe->element1 = C1_B_Cb; /* B */ + pipe->element0 = C2_R_Cr; /* R */ + pipe->chroma_sample = MDP4_CHROMA_420; + } else if (pipe->src_format == MDP_Y_CBCR_H2V2_TILE) { + pipe->element1 = C2_R_Cr; /* R */ + pipe->element0 = C1_B_Cb; /* B */ + pipe->chroma_sample = MDP4_CHROMA_420; + } + pipe->bpp = 2; /* 2 bpp */ + break; + case MDP_Y_CR_CB_H2V2: + case MDP_Y_CR_CB_GH2V2: + case MDP_Y_CB_CR_H2V2: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_PLANAR; + pipe->a_bit = 0; + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->chroma_sample = MDP4_CHROMA_420; + pipe->bpp = 2; /* 2 bpp */ + break; + case MDP_YCBCR_H1V1: + case MDP_YCRCB_H1V1: + pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; + pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; + pipe->a_bit = 0; + pipe->r_bit = 3; /* R, 8 bits */ + pipe->b_bit = 3; /* B, 8 bits */ + pipe->g_bit = 3; /* G, 8 bits */ + pipe->alpha_enable = 0; + pipe->unpack_tight = 1; + pipe->unpack_align_msb = 0; + pipe->unpack_count = 2; + pipe->element0 = C0_G_Y; /* G */ + if (pipe->src_format == MDP_YCRCB_H1V1) { + pipe->element1 = C2_R_Cr; /* R */ + pipe->element2 = C1_B_Cb; /* B */ + } else { + pipe->element1 = C1_B_Cb; /* B */ + pipe->element2 = C2_R_Cr; /* R */ + } + pipe->bpp = 3; /* 3 bpp */ + case MDP_RGB_BORDERFILL: + pipe->alpha_enable = 0; + pipe->alpha = 0; + break; + default: + /* not likely */ + mdp4_stat.err_format++; + return -ERANGE; + } + + return 0; +} + +/* + * color_key_convert: output with 12 bits color key + */ +static uint32 color_key_convert(int start, int num, uint32 color) +{ + uint32 data; + + data = (color >> start) & ((1 << num) - 1); + + /* convert to 8 bits */ + if (num == 5) + data = ((data << 3) | (data >> 2)); + else if (num == 6) + data = ((data << 2) | (data >> 4)); + + /* convert 8 bits to 12 bits */ + data = (data << 4) | (data >> 4); + + return data; +} + +void transp_color_key(int format, uint32 transp, + uint32 *c0, uint32 *c1, uint32 *c2) +{ + int b_start, g_start, r_start; + int b_num, g_num, r_num; + + switch (format) { + case MDP_RGB_565: + b_start = 0; + g_start = 5; + r_start = 11; + r_num = 5; + g_num = 6; + b_num = 5; + break; + case MDP_RGB_888: + case MDP_XRGB_8888: + case MDP_ARGB_8888: + case MDP_BGRA_8888: + b_start = 0; + g_start = 8; + r_start = 16; + r_num = 8; + g_num = 8; + b_num = 8; + break; + case MDP_RGBA_8888: + case MDP_RGBX_8888: + b_start = 16; + g_start = 8; + r_start = 0; + r_num = 8; + g_num = 8; + b_num = 8; + break; + case MDP_BGR_565: + b_start = 11; + g_start = 5; + r_start = 0; + r_num = 5; + g_num = 6; + b_num = 5; + break; + case MDP_Y_CB_CR_H2V2: + case MDP_Y_CBCR_H2V2: + case MDP_Y_CBCR_H2V1: + case MDP_YCBCR_H1V1: + b_start = 8; + g_start = 16; + r_start = 0; + r_num = 8; + g_num = 8; + b_num = 8; + break; + case MDP_Y_CR_CB_H2V2: + case MDP_Y_CR_CB_GH2V2: + case MDP_Y_CRCB_H2V2: + case MDP_Y_CRCB_H2V1: + case MDP_Y_CRCB_H1V1: + case MDP_Y_CBCR_H1V1: + case MDP_YCRCB_H1V1: + b_start = 0; + g_start = 16; + r_start = 8; + r_num = 8; + g_num = 8; + b_num = 8; + break; + default: + b_start = 0; + g_start = 8; + r_start = 16; + r_num = 8; + g_num = 8; + b_num = 8; + break; + } + + *c0 = color_key_convert(g_start, g_num, transp); + *c1 = color_key_convert(b_start, b_num, transp); + *c2 = color_key_convert(r_start, r_num, transp); +} + +uint32 mdp4_overlay_format(struct mdp4_overlay_pipe *pipe) +{ + uint32 format; + + format = 0; + + if (pipe->solid_fill) + format |= MDP4_FORMAT_SOLID_FILL; + + if (pipe->unpack_align_msb) + format |= MDP4_FORMAT_UNPACK_ALIGN_MSB; + + if (pipe->unpack_tight) + format |= MDP4_FORMAT_UNPACK_TIGHT; + + if (pipe->alpha_enable) + format |= MDP4_FORMAT_ALPHA_ENABLE; + + if (pipe->flags & MDP_SOURCE_ROTATED_90) + format |= MDP4_FORMAT_90_ROTATED; + format |= (pipe->unpack_count << 13); + format |= ((pipe->bpp - 1) << 9); + format |= (pipe->a_bit << 6); + format |= (pipe->r_bit << 4); + format |= (pipe->b_bit << 2); + format |= pipe->g_bit; + + format |= (pipe->frame_format << 29); + + if (pipe->fetch_plane == OVERLAY_PLANE_PSEUDO_PLANAR || + pipe->fetch_plane == OVERLAY_PLANE_PLANAR) { + /* video/graphic */ + format |= (pipe->fetch_plane << 19); + format |= (pipe->chroma_site << 28); + format |= (pipe->chroma_sample << 26); + } + + return format; +} + +uint32 mdp4_overlay_unpack_pattern(struct mdp4_overlay_pipe *pipe) +{ + return (pipe->element3 << 24) | (pipe->element2 << 16) | + (pipe->element1 << 8) | pipe->element0; +} + +/* + * mdp4_overlayproc_cfg: only be called from base layer + */ +void mdp4_overlayproc_cfg(struct mdp4_overlay_pipe *pipe) +{ + uint32 data, intf; + char *overlay_base; + uint32 curr; + + intf = 0; + if (pipe->mixer_num == MDP4_MIXER2) + overlay_base = MDP_BASE + MDP4_OVERLAYPROC2_BASE; + else if (pipe->mixer_num == MDP4_MIXER1) { + overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */ + intf = inpdw(MDP_BASE + 0x0038); /* MDP_DISP_INTF_SEL */ + intf >>= 4; + intf &= 0x03; + } else + overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ + + if (mdp_is_in_isr == FALSE) + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* + * BLT support both primary and external external + */ + if (pipe->blt_addr) { + int off, bpp; +#ifdef BLT_RGB565 + bpp = 2; /* overlay ouput is RGB565 */ +#else + bpp = 3; /* overlay ouput is RGB888 */ +#endif + data = pipe->src_height; + data <<= 16; + data |= pipe->src_width; + outpdw(overlay_base + 0x0008, data); /* ROI, height + width */ + if (pipe->mixer_num == MDP4_MIXER0 || + pipe->mixer_num == MDP4_MIXER1) { + off = 0; + if (pipe->ov_cnt & 0x01) + off = pipe->src_height * pipe->src_width * bpp; + + outpdw(overlay_base + 0x000c, pipe->blt_addr + off); + /* overlay ouput is RGB888 */ + outpdw(overlay_base + 0x0010, pipe->src_width * bpp); + outpdw(overlay_base + 0x001c, pipe->blt_addr + off); + /* MDDI - BLT + on demand */ + outpdw(overlay_base + 0x0004, 0x08); + + curr = inpdw(overlay_base + 0x0014); + curr &= 0x4; +#ifdef BLT_RGB565 + outpdw(overlay_base + 0x0014, curr | 0x1); /* RGB565 */ +#else + outpdw(overlay_base + 0x0014, curr | 0x0); /* RGB888 */ +#endif + } else if (pipe->mixer_num == MDP4_MIXER2) { + if (ctrl->panel_mode & MDP4_PANEL_WRITEBACK) { + off = 0; + bpp = 1; + if (pipe->ov_cnt & 0x01) + off = pipe->src_height * + pipe->src_width * bpp; + + outpdw(overlay_base + 0x000c, + pipe->blt_addr + off); + /* overlay ouput is RGB888 */ + outpdw(overlay_base + 0x0010, + ((pipe->src_width << 16) | + pipe->src_width)); + outpdw(overlay_base + 0x001c, + pipe->blt_addr + off); + off = pipe->src_height * pipe->src_width; + /* align chroma to 2k address */ + off = (off + 2047) & ~2047; + /* UV plane adress */ + outpdw(overlay_base + 0x0020, + pipe->blt_addr + off); + /* MDDI - BLT + on demand */ + outpdw(overlay_base + 0x0004, 0x08); + /* pseudo planar + writeback */ + curr = inpdw(overlay_base + 0x0014); + curr &= 0x4; + outpdw(overlay_base + 0x0014, curr | 0x012); + /* rgb->yuv */ + outpdw(overlay_base + 0x0200, 0x05); + } + } + } else { + data = pipe->src_height; + data <<= 16; + data |= pipe->src_width; + outpdw(overlay_base + 0x0008, data); /* ROI, height + width */ + outpdw(overlay_base + 0x000c, pipe->srcp0_addr); + outpdw(overlay_base + 0x0010, pipe->srcp0_ystride); + outpdw(overlay_base + 0x0004, 0x01); /* directout */ + } + + if (pipe->mixer_num == MDP4_MIXER1) { + if (intf == TV_INTF) { + curr = inpdw(overlay_base + 0x0014); + curr &= 0x4; + outpdw(overlay_base + 0x0014, 0x02); /* yuv422 */ + /* overlay1 CSC config */ + outpdw(overlay_base + 0x0200, 0x05); /* rgb->yuv */ + } + } + +#ifdef MDP4_IGC_LUT_ENABLE + curr = inpdw(overlay_base + 0x0014); + curr &= ~0x4; + outpdw(overlay_base + 0x0014, curr | 0x4); /* GC_LUT_EN, 888 */ +#endif + + if (mdp_is_in_isr == FALSE) + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +int mdp4_overlay_pipe_staged(int mixer) +{ + uint32 data, mask, i, off; + int p1, p2; + + if (mixer == MDP4_MIXER2) + off = 0x100F0; + else + off = 0x10100; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + data = inpdw(MDP_BASE + off); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + p1 = 0; + p2 = 0; + for (i = 0; i < 8; i++) { + mask = data & 0x0f; + if (mask) { + if (mask <= 4) + p1++; + else + p2++; + } + data >>= 4; + } + + if (mixer) + return p2; + else + return p1; +} + +int mdp4_mixer_info(int mixer_num, struct mdp_mixer_info *info) +{ + + int ndx, cnt; + struct mdp4_overlay_pipe *pipe; + + if (mixer_num > MDP4_MIXER_MAX) + return -ENODEV; + + cnt = 0; + ndx = MDP4_MIXER_STAGE_BASE; + for ( ; ndx < MDP4_MIXER_STAGE_MAX; ndx++) { + pipe = ctrl->stage[mixer_num][ndx]; + if (pipe == NULL) + continue; + info->z_order = pipe->mixer_stage - MDP4_MIXER_STAGE0; + /* z_order == -1, means base layer */ + info->ptype = pipe->pipe_type; + info->pnum = pipe->pipe_num; + info->pndx = pipe->pipe_ndx; + info->mixer_num = pipe->mixer_num; + info++; + cnt++; + } + return cnt; +} + +static void mdp4_mixer_stage_commit(int mixer) +{ + struct mdp4_overlay_pipe *pipe; + int i, num; + u32 data, stage; + int off; + unsigned long flags; + + data = 0; + for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) { + pipe = ctrl->stage[mixer][i]; + if (pipe == NULL) + continue; + pr_debug("%s: mixer=%d ndx=%d stage=%d\n", __func__, + mixer, pipe->pipe_ndx, i); + stage = pipe->mixer_stage; + if (mixer >= MDP4_MIXER1) + stage += 8; + stage <<= (4 * pipe->pipe_num); + data |= stage; + } + + mdp4_mixer_blend_setup(mixer); + + off = 0; + if (data != ctrl->mixer_cfg[mixer]) { + ctrl->mixer_cfg[mixer] = data; + if (mixer >= MDP4_MIXER2) { + /* MDP_LAYERMIXER2_IN_CFG */ + off = 0x100f0; + } else { + /* mixer 0 or 1 */ + num = mixer + 1; + num &= 0x01; + data |= ctrl->mixer_cfg[num]; + off = 0x10100; + } + pr_debug("%s: mixer=%d data=%x flush=%x\n", __func__, + mixer, data, ctrl->flush[mixer]); + } + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + local_irq_save(flags); + if (off) + outpdw(MDP_BASE + off, data); + + if (ctrl->flush[mixer]) { + outpdw(MDP_BASE + 0x18000, ctrl->flush[mixer]); + ctrl->flush[mixer] = 0; + } + local_irq_restore(flags); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + + +void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe) +{ + struct mdp4_overlay_pipe *pp; + int i, mixer; + + mixer = pipe->mixer_num; + + for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) { + pp = ctrl->stage[mixer][i]; + if (pp == pipe) { + ctrl->stage[mixer][i] = NULL; + break; + } + } + + ctrl->stage[mixer][pipe->mixer_stage] = pipe; /* keep it */ + + if (!(pipe->flags & MDP_OV_PLAY_NOWAIT)) { + pr_debug("%s: mixer=%d ndx=%d stage=%d flags=%x\n", + __func__, mixer, pipe->pipe_ndx, + pipe->mixer_stage, pipe->flags); + mdp4_mixer_stage_commit(mixer); + } +} + +void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe) +{ + struct mdp4_overlay_pipe *pp; + int i, mixer; + + mixer = pipe->mixer_num; + + for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) { + pp = ctrl->stage[mixer][i]; + if (pp == pipe) + ctrl->stage[mixer][i] = NULL; /* clear it */ + } + + if (!(pipe->flags & MDP_OV_PLAY_NOWAIT)) { + pr_debug("%s: mixer=%d ndx=%d stage=%d flags=%x\n", + __func__, pipe->mixer_num, pipe->pipe_ndx, + pipe->mixer_stage, pipe->flags); + mdp4_mixer_stage_commit(pipe->mixer_num); + } +} +/* + * mixer0: rgb3: border color at register 0x15004, 0x15008 + * mixer1: vg3: border color at register 0x1D004, 0x1D008 + * mixer2: xxx: border color at register 0x8D004, 0x8D008 + */ +void mdp4_overlay_borderfill_stage_up(struct mdp4_overlay_pipe *pipe) +{ + struct mdp4_overlay_pipe *bspipe; + int ptype, pnum, pndx, mixer; + int format, alpha_enable, alpha; + + if (pipe->pipe_type != OVERLAY_TYPE_BF) + return; + + mixer = pipe->mixer_num; + + if (ctrl->baselayer[mixer]) + return; + + bspipe = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE]; + + /* save original base layer */ + ctrl->baselayer[mixer] = bspipe; + + pipe->alpha = 0; /* make sure bf pipe has alpha 0 */ + ptype = pipe->pipe_type; + pnum = pipe->pipe_num; + pndx = pipe->pipe_ndx; + format = pipe->src_format; + alpha_enable = pipe->alpha_enable; + alpha = pipe->alpha; + *pipe = *bspipe; /* keep base layer configuration */ + pipe->pipe_type = ptype; + pipe->pipe_num = pnum; + pipe->pipe_ndx = pndx; + pipe->src_format = format; + pipe->alpha_enable = alpha_enable; + pipe->alpha = alpha; + + /* free original base layer pipe to be sued as normal pipe */ + bspipe->pipe_used = 0; + + if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) + mdp4_dsi_video_base_swap(pipe); + else if (ctrl->panel_mode & MDP4_PANEL_LCDC) + mdp4_lcdc_base_swap(pipe); + else if (ctrl->panel_mode & MDP4_PANEL_DTV) + mdp4_dtv_base_swap(pipe); + + mdp4_overlay_reg_flush(bspipe, 1); + /* borderfill pipe as base layer */ + mdp4_mixer_stage_up(pipe); +} + +void mdp4_overlay_borderfill_stage_down(struct mdp4_overlay_pipe *pipe) +{ + struct mdp4_overlay_pipe *bspipe; + int ptype, pnum, pndx, mixer; + int format, alpha_enable, alpha; + + if (pipe->pipe_type != OVERLAY_TYPE_BF) + return; + + mixer = pipe->mixer_num; + + /* retrieve original base layer */ + bspipe = ctrl->baselayer[mixer]; + if (bspipe == NULL) { + pr_err("%s: no base layer at mixer=%d\n", + __func__, mixer); + return; + } + + ptype = bspipe->pipe_type; + pnum = bspipe->pipe_num; + pndx = bspipe->pipe_ndx; + format = bspipe->src_format; + alpha_enable = bspipe->alpha_enable; + alpha = bspipe->alpha; + *bspipe = *pipe; /* restore base layer configuration */ + bspipe->pipe_type = ptype; + bspipe->pipe_num = pnum; + bspipe->pipe_ndx = pndx; + bspipe->src_format = format; + bspipe->alpha_enable = alpha_enable; + bspipe->alpha = alpha; + + bspipe->pipe_used++; /* mark base layer pipe used */ + + ctrl->baselayer[mixer] = NULL; + + /* free borderfill pipe */ + pipe->pipe_used = 0; + + mdp4_dsi_video_base_swap(bspipe); + + /* free borderfill pipe */ + mdp4_overlay_reg_flush(pipe, 1); + mdp4_mixer_stage_down(pipe); + mdp4_overlay_pipe_free(pipe); + + /* stage up base layer */ + mdp4_overlay_reg_flush(bspipe, 1); + /* restore original base layer */ + mdp4_mixer_stage_up(bspipe); +} + + +static struct mdp4_overlay_pipe *mdp4_background_layer(int mixer, + struct mdp4_overlay_pipe *sp) +{ + struct mdp4_overlay_pipe *pp; + struct mdp4_overlay_pipe *kp; + int i; + + kp = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE]; + for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) { + pp = ctrl->stage[mixer][i]; + if (pp == NULL) + continue; + if (pp == sp) + break; + + if ((pp->dst_x <= sp->dst_x) && + ((pp->dst_x + pp->dst_w) >= (sp->dst_x + sp->dst_w))) { + if ((pp->dst_y <= sp->dst_y) && + ((pp->dst_y + pp->dst_h) >= + (sp->dst_y + sp->dst_h))) { + kp = pp; + } + } + } + return kp; +} + +static void mdp4_overlay_bg_solidfill(struct blend_cfg *blend) +{ + struct mdp4_overlay_pipe *pipe; + char *base; + u32 op_mode, format; + int pnum, ptype; + + pipe = blend->solidfill_pipe; + if (pipe == NULL) + return; + + if (pipe->pipe_type == OVERLAY_TYPE_BF) + return; + + ptype = mdp4_overlay_format2type(pipe->src_format); + if (ptype == OVERLAY_TYPE_RGB) { + pnum = pipe->pipe_num - OVERLAY_PIPE_RGB1; + base = MDP_BASE + MDP4_RGB_BASE; + base += MDP4_RGB_OFF * pnum; + } else { + pnum = pipe->pipe_num - OVERLAY_PIPE_VG1; + base = MDP_BASE + MDP4_VIDEO_BASE; + base += MDP4_VIDEO_OFF * pnum; + } + + format = inpdw(base + 0x50); + if (blend->solidfill) { + format |= MDP4_FORMAT_SOLID_FILL; + /* + * If solid fill is enabled, flip and scale + * have to be disabled. otherwise, h/w + * underruns. + */ + op_mode = inpdw(base + 0x0058); + op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN); + op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN); + outpdw(base + 0x0058, op_mode); + outpdw(base + 0x1008, 0); /* black */ + } else { + format &= ~MDP4_FORMAT_SOLID_FILL; + blend->solidfill_pipe = NULL; + } + + outpdw(base + 0x50, format); + + mdp4_overlay_reg_flush(pipe, 0); +} + +/* + * D(i+1) = Ks * S + Kd * D(i) + */ +void mdp4_mixer_blend_setup(int mixer) +{ + struct mdp4_overlay_pipe *d_pipe; + struct mdp4_overlay_pipe *s_pipe; + struct blend_cfg *blend; + int i, off, ptype; + int d_alpha, s_alpha; + unsigned char *overlay_base; + uint32 c0, c1, c2; + + + d_pipe = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE]; + if (d_pipe == NULL) { + pr_err("%s: Error: no bg_pipe at mixer=%d\n", __func__, mixer); + return; + } + + blend = &ctrl->blend[mixer][MDP4_MIXER_STAGE0]; + for (i = MDP4_MIXER_STAGE0; i < MDP4_MIXER_STAGE_MAX; i++) { + blend->solidfill = 0; + blend->op = (MDP4_BLEND_FG_ALPHA_FG_CONST | + MDP4_BLEND_BG_ALPHA_BG_CONST); + s_pipe = ctrl->stage[mixer][i]; + if (s_pipe == NULL) { + blend++; + d_pipe = NULL; + d_alpha = 0; + continue; + } + d_pipe = mdp4_background_layer(mixer, s_pipe); + d_alpha = d_pipe->alpha_enable; + s_alpha = s_pipe->alpha_enable; + pr_debug("%s: stage=%d: bg: ndx=%d da=%d dalpha=%x " + "fg: ndx=%d sa=%d salpha=%x is_fg=%d\n", + __func__, i-2, d_pipe->pipe_ndx, d_alpha, d_pipe->alpha, + s_pipe->pipe_ndx, s_alpha, s_pipe->alpha, s_pipe->is_fg); + + /* base on fg's alpha */ + blend->bg_alpha = 0x0ff - s_pipe->alpha; + blend->fg_alpha = s_pipe->alpha; + blend->co3_sel = 1; /* use fg alpha */ + + if (s_pipe->is_fg) { + if (s_pipe->alpha == 0xff) { + blend->solidfill = 1; + blend->solidfill_pipe = d_pipe; + } + } else if (s_alpha) { + blend->op = (MDP4_BLEND_BG_ALPHA_FG_PIXEL | + MDP4_BLEND_BG_INV_ALPHA); + } else if (d_alpha) { + ptype = mdp4_overlay_format2type(s_pipe->src_format); + if (ptype == OVERLAY_TYPE_VIDEO) { + blend->op = (MDP4_BLEND_BG_ALPHA_BG_PIXEL | + MDP4_BLEND_FG_ALPHA_BG_PIXEL | + MDP4_BLEND_FG_INV_ALPHA); + blend->co3_sel = 0; /* use bg alpha */ + } else { + /* s_pipe is rgb without alpha */ + blend->op = (MDP4_BLEND_FG_ALPHA_FG_CONST | + MDP4_BLEND_BG_ALPHA_BG_CONST); + blend->bg_alpha = 0; + } + } + + if (s_pipe->transp != MDP_TRANSP_NOP) { + if (s_pipe->is_fg) { + transp_color_key(s_pipe->src_format, + s_pipe->transp, &c0, &c1, &c2); + /* Fg blocked */ + blend->op |= MDP4_BLEND_FG_TRANSP_EN; + /* lower limit */ + blend->transp_low0 = (c1 << 16 | c0); + blend->transp_low1 = c2; + /* upper limit */ + blend->transp_high0 = (c1 << 16 | c0); + blend->transp_high1 = c2; + } else { + transp_color_key(d_pipe->src_format, + s_pipe->transp, &c0, &c1, &c2); + /* Fg blocked */ + blend->op |= MDP4_BLEND_BG_TRANSP_EN; + blend--; /* one stage back */ + /* lower limit */ + blend->transp_low0 = (c1 << 16 | c0); + blend->transp_low1 = c2; + /* upper limit */ + blend->transp_high0 = (c1 << 16 | c0); + blend->transp_high1 = c2; + blend++; /* back to original stage */ + } + } + blend++; + } + + /* mixer numer, /dev/fb0, /dev/fb1, /dev/fb2 */ + if (mixer == MDP4_MIXER2) + overlay_base = MDP_BASE + MDP4_OVERLAYPROC2_BASE;/* 0x88000 */ + else if (mixer == MDP4_MIXER1) + overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */ + else + overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + blend = &ctrl->blend[mixer][MDP4_MIXER_STAGE_BASE]; + /* lower limit */ + outpdw(overlay_base + 0x180, blend->transp_low0); + outpdw(overlay_base + 0x184, blend->transp_low1); + /* upper limit */ + outpdw(overlay_base + 0x188, blend->transp_high0); + outpdw(overlay_base + 0x18c, blend->transp_high1); + blend++; /* stage0 */ + for (i = MDP4_MIXER_STAGE0; i < MDP4_MIXER_STAGE_MAX; i++) { + off = 20 * i; + off = 0x20 * (i - MDP4_MIXER_STAGE0); + if (i == MDP4_MIXER_STAGE3) + off -= 4; + + if (blend->solidfill_pipe) + mdp4_overlay_bg_solidfill(blend); + + outpdw(overlay_base + off + 0x108, blend->fg_alpha); + outpdw(overlay_base + off + 0x10c, blend->bg_alpha); + outpdw(overlay_base + off + 0x104, blend->op); + outpdw(overlay_base + (off << 5) + 0x1004, blend->co3_sel); + outpdw(overlay_base + off + 0x110, blend->transp_low0);/* low */ + outpdw(overlay_base + off + 0x114, blend->transp_low1);/* low */ + /* upper limit */ + outpdw(overlay_base + off + 0x118, blend->transp_high0); + outpdw(overlay_base + off + 0x11c, blend->transp_high1); + blend++; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all) +{ + int mixer; + uint32 *reg; + + mixer = pipe->mixer_num; + reg = &ctrl->flush[mixer]; + *reg |= (1 << (2 + pipe->pipe_num)); + + if (all) { + if (mixer == MDP4_MIXER0) + *reg |= 0x01; + else + *reg |= 0x02; + } +} + +void mdp4_overlay_flush_piggyback(int m0, int m1) +{ + u32 data; + + data = ctrl->flush[m0] | ctrl->flush[m1]; + ctrl->flush[m0] = data; +} + +void mdp4_overlay_reg_flush_reset(struct mdp4_overlay_pipe *pipe) +{ + int mixer; + + mixer = pipe->mixer_num; + ctrl->flush[mixer] = 0; +} + +struct mdp4_overlay_pipe *mdp4_overlay_stage_pipe(int mixer, int stage) +{ + return ctrl->stage[mixer][stage]; +} + +struct mdp4_overlay_pipe *mdp4_overlay_ndx2pipe(int ndx) +{ + struct mdp4_overlay_pipe *pipe; + + if (ndx <= 0 || ndx > OVERLAY_PIPE_MAX) + return NULL; + + pipe = &ctrl->plist[ndx - 1]; /* ndx start from 1 */ + + if (pipe->pipe_used == 0) + return NULL; + + return pipe; +} + +struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(int ptype, int mixer) +{ + int i; + struct mdp4_overlay_pipe *pipe; + + if (ptype == OVERLAY_TYPE_BF) { + if (!mdp4_overlay_borderfill_supported()) + return NULL; + } + + for (i = 0; i < OVERLAY_PIPE_MAX; i++) { + pipe = &ctrl->plist[i]; + if ((pipe->pipe_used == 0) && ((pipe->pipe_type == ptype) || + (ptype == OVERLAY_TYPE_RGB && + pipe->pipe_type == OVERLAY_TYPE_VIDEO))) { + if (ptype == OVERLAY_TYPE_BF && + mixer != pipe->mixer_num) + continue; + init_completion(&pipe->comp); + init_completion(&pipe->dmas_comp); + pr_debug("%s: pipe=%x ndx=%d num=%d\n", __func__, + (int)pipe, pipe->pipe_ndx, pipe->pipe_num); + return pipe; + } + } + + pr_err("%s: ptype=%d FAILED\n", __func__, ptype); + + return NULL; +} + + +void mdp4_overlay_pipe_free(struct mdp4_overlay_pipe *pipe) +{ + uint32 ptype, num, ndx, mixer; + struct mdp4_iommu_pipe_info *iom_pipe_info; + + pr_debug("%s: pipe=%x ndx=%d\n", __func__, (int)pipe, pipe->pipe_ndx); + + ptype = pipe->pipe_type; + num = pipe->pipe_num; + ndx = pipe->pipe_ndx; + mixer = pipe->mixer_num; + iom_pipe_info = &mdp_iommu[pipe->mixer_num][pipe->pipe_ndx - 1]; + iom_pipe_info->mark_unmap = 1; + + memset(pipe, 0, sizeof(*pipe)); + + pipe->pipe_type = ptype; + pipe->pipe_num = num; + pipe->pipe_ndx = ndx; + pipe->mixer_num = mixer; +} + +static int mdp4_overlay_validate_downscale(struct mdp_overlay *req, + struct msm_fb_data_type *mfd, uint32 perf_level, uint32 pclk_rate) +{ + __u32 panel_clk_khz, mdp_clk_khz; + __u32 num_hsync_pix_clks, mdp_clks_per_hsync, src_wh; + __u32 hsync_period_ps, mdp_period_ps, total_hsync_period_ps; + unsigned long fill_rate_y_dir, fill_rate_x_dir; + unsigned long fillratex100, mdp_pixels_produced; + unsigned long mdp_clk_hz; + + pr_debug("%s: LCDC Mode Downscale validation with MDP Core" + " Clk rate\n", __func__); + pr_debug("src_w %u, src_h %u, dst_w %u, dst_h %u\n", + req->src_rect.w, req->src_rect.h, req->dst_rect.w, + req->dst_rect.h); + + + panel_clk_khz = pclk_rate/1000; + mdp_clk_hz = mdp_perf_level2clk_rate(perf_level); + + if (!mdp_clk_hz || !req->dst_rect.w || !req->dst_rect.h) { + pr_debug("mdp_perf_level2clk_rate returned 0," + "or dst_rect height/width is 0," + "Downscale Validation incomplete\n"); + return 0; + } + + mdp_clk_khz = mdp_clk_hz/1000; + + num_hsync_pix_clks = mfd->panel_info.lcdc.h_back_porch + + mfd->panel_info.lcdc.h_front_porch + + mfd->panel_info.lcdc.h_pulse_width + + mfd->panel_info.xres; + + hsync_period_ps = 1000000000/panel_clk_khz; + mdp_period_ps = 1000000000/mdp_clk_khz; + + total_hsync_period_ps = num_hsync_pix_clks * hsync_period_ps; + mdp_clks_per_hsync = total_hsync_period_ps/mdp_period_ps; + + pr_debug("hsync_period_ps %u, mdp_period_ps %u," + "total_hsync_period_ps %u\n", hsync_period_ps, + mdp_period_ps, total_hsync_period_ps); + + src_wh = req->src_rect.w * req->src_rect.h; + if (src_wh % req->dst_rect.h) + fill_rate_y_dir = (src_wh / req->dst_rect.h) + 1; + else + fill_rate_y_dir = (src_wh / req->dst_rect.h); + + fill_rate_x_dir = (mfd->panel_info.xres - req->dst_rect.w) + + req->src_rect.w; + + if (fill_rate_y_dir >= fill_rate_x_dir) + fillratex100 = 100 * fill_rate_y_dir / mfd->panel_info.xres; + else + fillratex100 = 100 * fill_rate_x_dir / mfd->panel_info.xres; + + pr_debug("mdp_clks_per_hsync %u, fill_rate_y_dir %lu," + "fill_rate_x_dir %lu\n", mdp_clks_per_hsync, + fill_rate_y_dir, fill_rate_x_dir); + + mdp_pixels_produced = 100 * mdp_clks_per_hsync/fillratex100; + pr_debug("fillratex100 %lu, mdp_pixels_produced %lu\n", + fillratex100, mdp_pixels_produced); + if (mdp_pixels_produced <= mfd->panel_info.xres) { + mdp4_stat.err_underflow++; + return -ERANGE; + } + + return 0; +} + +static int mdp4_overlay_req2pipe(struct mdp_overlay *req, int mixer, + struct mdp4_overlay_pipe **ppipe, + struct msm_fb_data_type *mfd) +{ + struct mdp4_overlay_pipe *pipe; + struct mdp4_iommu_pipe_info *iom_pipe_info; + int ret, ptype; + + u32 upscale_max; + upscale_max = (mdp_rev >= MDP_REV_41) ? + MDP4_REV41_OR_LATER_UP_SCALING_MAX : + MDP4_REV40_UP_SCALING_MAX; + + if (mfd == NULL) { + pr_err("%s: mfd == NULL, -ENODEV\n", __func__); + return -ENODEV; + } + + if (mixer >= MDP4_MIXER_MAX) { + pr_err("%s: mixer out of range!\n", __func__); + mdp4_stat.err_mixer++; + return -ERANGE; + } + + if (req->z_order < 0 || req->z_order > 3) { + pr_err("%s: z_order=%d out of range!\n", __func__, + req->z_order); + mdp4_stat.err_zorder++; + return -ERANGE; + } + + if (req->src_rect.h == 0 || req->src_rect.w == 0) { + pr_err("%s: src img of zero size!\n", __func__); + mdp4_stat.err_size++; + return -EINVAL; + } + + if (req->dst_rect.h > (req->src_rect.h * upscale_max)) { + mdp4_stat.err_scale++; + pr_err("%s: scale up, too much (h)!\n", __func__); + return -ERANGE; + } + + if (req->src_rect.h > (req->dst_rect.h * 8)) { /* too little */ + mdp4_stat.err_scale++; + pr_err("%s: scale down, too little (h)!\n", __func__); + return -ERANGE; + } + + if (req->dst_rect.w > (req->src_rect.w * upscale_max)) { + mdp4_stat.err_scale++; + pr_err("%s: scale up, too much (w)!\n", __func__); + return -ERANGE; + } + + if (req->src_rect.w > (req->dst_rect.w * 8)) { /* too little */ + mdp4_stat.err_scale++; + pr_err("%s: scale down, too little (w)!\n", __func__); + return -ERANGE; + } + + if (mdp_hw_revision == MDP4_REVISION_V1) { + /* non integer down saceling ratio smaller than 1/4 + * is not supportted + */ + if (req->src_rect.h > (req->dst_rect.h * 4)) { + if (req->src_rect.h % req->dst_rect.h) { + mdp4_stat.err_scale++; + pr_err("%s: need integer (h)!\n", __func__); + return -ERANGE; + } + } + + if (req->src_rect.w > (req->dst_rect.w * 4)) { + if (req->src_rect.w % req->dst_rect.w) { + mdp4_stat.err_scale++; + pr_err("%s: need integer (w)!\n", __func__); + return -ERANGE; + } + } + } + + if (((req->src_rect.x + req->src_rect.w) > req->src.width) || + ((req->src_rect.y + req->src_rect.h) > req->src.height)) { + mdp4_stat.err_size++; + pr_err("%s invalid src rectangle\n", __func__); + return -ERANGE; + } + + if (ctrl->panel_3d != MDP4_3D_SIDE_BY_SIDE) { + int xres; + int yres; + + xres = mfd->panel_info.xres; + yres = mfd->panel_info.yres; + + if (((req->dst_rect.x + req->dst_rect.w) > xres) || + ((req->dst_rect.y + req->dst_rect.h) > yres)) { + mdp4_stat.err_size++; + pr_err("%s invalid dst rectangle\n", __func__); + return -ERANGE; + } + } + + ptype = mdp4_overlay_format2type(req->src.format); + if (ptype < 0) { + pr_err("%s: mdp4_overlay_format2type!\n", __func__); + return ptype; + } + + if (req->flags & MDP_OV_PIPE_SHARE) + ptype = OVERLAY_TYPE_VIDEO; /* VG pipe supports both RGB+YUV */ + + if (req->id == MSMFB_NEW_REQUEST) /* new request */ + pipe = mdp4_overlay_pipe_alloc(ptype, mixer); + else + pipe = mdp4_overlay_ndx2pipe(req->id); + + if (pipe == NULL) { + pr_err("%s: pipe == NULL!\n", __func__); + return -ENOMEM; + } + + if (!display_iclient && !IS_ERR_OR_NULL(mfd->iclient)) { + display_iclient = mfd->iclient; + pr_debug("%s(): display_iclient %p\n", __func__, + display_iclient); + } + + iom_pipe_info = &mdp_iommu[pipe->mixer_num][pipe->pipe_ndx - 1]; + iom_pipe_info->mark_unmap = 0; + + pipe->src_format = req->src.format; + ret = mdp4_overlay_format2pipe(pipe); + + if (ret < 0) { + pr_err("%s: mdp4_overlay_format2pipe!\n", __func__); + return ret; + } + + /* + * base layer == 1, reserved for frame buffer + * zorder 0 == stage 0 == 2 + * zorder 1 == stage 1 == 3 + * zorder 2 == stage 2 == 4 + */ + if (req->id == MSMFB_NEW_REQUEST) { /* new request */ + pipe->pipe_used++; + pipe->mixer_num = mixer; + pr_debug("%s: zorder=%d pipe ndx=%d num=%d\n", __func__, + req->z_order, pipe->pipe_ndx, pipe->pipe_num); + + } + + pipe->mixer_stage = req->z_order + MDP4_MIXER_STAGE0; + pipe->src_width = req->src.width & 0x1fff; /* source img width */ + pipe->src_height = req->src.height & 0x1fff; /* source img height */ + pipe->src_h = req->src_rect.h & 0x07ff; + pipe->src_w = req->src_rect.w & 0x07ff; + pipe->src_y = req->src_rect.y & 0x07ff; + pipe->src_x = req->src_rect.x & 0x07ff; + pipe->dst_h = req->dst_rect.h & 0x07ff; + pipe->dst_w = req->dst_rect.w & 0x07ff; + pipe->dst_y = req->dst_rect.y & 0x07ff; + pipe->dst_x = req->dst_rect.x & 0x07ff; + + pipe->op_mode = 0; + + if (req->flags & MDP_FLIP_LR) + pipe->op_mode |= MDP4_OP_FLIP_LR; + + if (req->flags & MDP_FLIP_UD) + pipe->op_mode |= MDP4_OP_FLIP_UD; + + if (req->flags & MDP_DITHER) + pipe->op_mode |= MDP4_OP_DITHER_EN; + + if (req->flags & MDP_DEINTERLACE) + pipe->op_mode |= MDP4_OP_DEINT_EN; + + if (req->flags & MDP_DEINTERLACE_ODD) + pipe->op_mode |= MDP4_OP_DEINT_ODD_REF; + + pipe->is_fg = req->is_fg;/* control alpha and color key */ + + pipe->alpha = req->alpha & 0x0ff; + + pipe->transp = req->transp_mask; + + *ppipe = pipe; + + return 0; +} + +static int get_img(struct msmfb_data *img, struct fb_info *info, + struct mdp4_overlay_pipe *pipe, unsigned int plane, + unsigned long *start, unsigned long *len, struct file **srcp_file, + int *p_need, struct ion_handle **srcp_ihdl) +{ + struct file *file; + int put_needed, ret = 0, fb_num; +#ifdef CONFIG_ANDROID_PMEM + unsigned long vstart; +#endif + *p_need = 0; + + if (img->flags & MDP_BLIT_SRC_GEM) { + *srcp_file = NULL; + return kgsl_gem_obj_addr(img->memory_id, (int) img->priv, + start, len); + } + + if (img->flags & MDP_MEMORY_ID_TYPE_FB) { + file = fget_light(img->memory_id, &put_needed); + if (file == NULL) + return -EINVAL; + + if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) { + fb_num = MINOR(file->f_dentry->d_inode->i_rdev); + if (get_fb_phys_info(start, len, fb_num, + DISPLAY_SUBSYSTEM_ID)) { + ret = -1; + } else { + *srcp_file = file; + *p_need = put_needed; + } + } else + ret = -1; + if (ret) + fput_light(file, put_needed); + return ret; + } + +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + return mdp4_overlay_iommu_map_buf(img->memory_id, pipe, plane, + start, len, srcp_ihdl); +#endif +#ifdef CONFIG_ANDROID_PMEM + if (!get_pmem_file(img->memory_id, start, &vstart, + len, srcp_file)) + return 0; + else + return -EINVAL; +#endif +} + +#ifdef CONFIG_FB_MSM_MIPI_DSI +int mdp4_overlay_3d_sbys(struct fb_info *info, struct msmfb_overlay_3d *req) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + int ret = -EPERM; + + if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) + return -EINTR; + + if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) { + mdp4_dsi_cmd_3d_sbys(mfd, req); + ret = 0; + } else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) { + mdp4_dsi_video_3d_sbys(mfd, req); + ret = 0; + } + mutex_unlock(&mfd->dma->ov_mutex); + + return ret; +} +#else +int mdp4_overlay_3d_sbys(struct fb_info *info, struct msmfb_overlay_3d *req) +{ + /* do nothing */ + return -EPERM; +} +#endif + +int mdp4_overlay_blt(struct fb_info *info, struct msmfb_overlay_blt *req) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (mfd == NULL) + return -ENODEV; + + if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) + return -EINTR; + + if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) + mdp4_dsi_overlay_blt(mfd, req); + else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) + mdp4_dsi_video_overlay_blt(mfd, req); + else if (ctrl->panel_mode & MDP4_PANEL_LCDC) + mdp4_lcdc_overlay_blt(mfd, req); + else if (ctrl->panel_mode & MDP4_PANEL_MDDI) + mdp4_mddi_overlay_blt(mfd, req); + + mutex_unlock(&mfd->dma->ov_mutex); + + return 0; +} + +int mdp4_overlay_blt_offset(struct fb_info *info, struct msmfb_overlay_blt *req) +{ + int ret = 0; + + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) + return -EINTR; + + if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) + ret = mdp4_dsi_overlay_blt_offset(mfd, req); + else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) + ret = mdp4_dsi_video_overlay_blt_offset(mfd, req); + else if (ctrl->panel_mode & MDP4_PANEL_LCDC) + ret = mdp4_lcdc_overlay_blt_offset(mfd, req); + else if (ctrl->panel_mode & MDP4_PANEL_MDDI) + mdp4_mddi_overlay_blt_offset(mfd, req); + + mutex_unlock(&mfd->dma->ov_mutex); + + return ret; +} + +int mdp4_overlay_get(struct fb_info *info, struct mdp_overlay *req) +{ + struct mdp4_overlay_pipe *pipe; + + pipe = mdp4_overlay_ndx2pipe(req->id); + if (pipe == NULL) + return -ENODEV; + + *req = pipe->req_data; + + if (mdp4_overlay_borderfill_supported()) + req->flags |= MDP_BORDERFILL_SUPPORTED; + + return 0; +} + +#define OVERLAY_VGA_SIZE 0x04B000 +#define OVERLAY_720P_TILE_SIZE 0x0E6000 +#define OVERLAY_WSVGA_SIZE 0x98000 /* 1024x608, align 600 to 32bit */ + +#define OVERLAY_BUS_SCALE_TABLE_BASE 6 + +static int mdp4_overlay_is_rgb_type(int format) +{ + switch (format) { + case MDP_RGB_565: + case MDP_RGB_888: + case MDP_BGR_565: + case MDP_XRGB_8888: + case MDP_ARGB_8888: + case MDP_RGBA_8888: + case MDP_BGRA_8888: + case MDP_RGBX_8888: + return 1; + default: + return 0; + } +} + +static uint32 mdp4_overlay_get_perf_level(struct mdp_overlay *req, + struct msm_fb_data_type *mfd) +{ + int is_fg = 0, i, cnt; + + if (req->is_fg && ((req->alpha & 0x0ff) == 0xff)) + is_fg = 1; + + if (mdp4_extn_disp) + return OVERLAY_PERF_LEVEL1; + + if (req->flags & (MDP_DEINTERLACE | MDP_BACKEND_COMPOSITION)) + return OVERLAY_PERF_LEVEL1; + + for (i = 0, cnt = 0; i < OVERLAY_PIPE_MAX; i++) { + if (ctrl->plist[i].pipe_used && ++cnt > 2) + return OVERLAY_PERF_LEVEL1; + } + + if (mdp4_overlay_is_rgb_type(req->src.format) && is_fg && + ((req->src.width * req->src.height) <= OVERLAY_WSVGA_SIZE)) + return OVERLAY_PERF_LEVEL4; + else if (mdp4_overlay_is_rgb_type(req->src.format)) + return OVERLAY_PERF_LEVEL1; + + if (req->src.width*req->src.height <= OVERLAY_VGA_SIZE) { + if (mfd->mdp_rev >= MDP_REV_42) + return OVERLAY_PERF_LEVEL4; + else + return OVERLAY_PERF_LEVEL3; + + } else if (req->src.width*req->src.height <= OVERLAY_720P_TILE_SIZE) { + u32 max, min; + max = (req->dst_rect.h > req->dst_rect.w) ? + req->dst_rect.h : req->dst_rect.w; + min = (mfd->panel_info.yres > mfd->panel_info.xres) ? + mfd->panel_info.xres : mfd->panel_info.yres; + if (max > min) /* landscape mode */ + return OVERLAY_PERF_LEVEL3; + else /* potrait mode */ + return OVERLAY_PERF_LEVEL2; + } + else + return OVERLAY_PERF_LEVEL1; +} + +void mdp4_update_perf_level(u32 perf_level) +{ + static int first = 1; + + new_perf_level = perf_level; + + if (first) { + first = 0; + mdp4_set_perf_level(); + } +} + +void mdp4_set_perf_level(void) +{ + static int old_perf_level; + int cur_perf_level; + + if (mdp4_extn_disp) + cur_perf_level = OVERLAY_PERF_LEVEL1; + else + cur_perf_level = new_perf_level; + + if (old_perf_level != cur_perf_level) { + mdp_set_core_clk(cur_perf_level); + old_perf_level = cur_perf_level; + mdp_bus_scale_update_request(OVERLAY_BUS_SCALE_TABLE_BASE + - cur_perf_level); + } +} + +static void mdp4_overlay_update_blt_mode(struct msm_fb_data_type *mfd) +{ + if (mfd->use_ov0_blt == mfd->ov0_blt_state) + return; + + if (mfd->use_ov0_blt) { + if (mfd->panel_info.type == LCDC_PANEL || + mfd->panel_info.type == LVDS_PANEL) + mdp4_lcdc_overlay_blt_start(mfd); + else if (mfd->panel_info.type == MIPI_VIDEO_PANEL) + mdp4_dsi_video_blt_start(mfd); + else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) + mdp4_dsi_overlay_blt_start(mfd); + else if (ctrl->panel_mode & MDP4_PANEL_MDDI) + mdp4_mddi_overlay_blt_start(mfd); + } else { + if (mfd->panel_info.type == LCDC_PANEL || + mfd->panel_info.type == LVDS_PANEL) + mdp4_lcdc_overlay_blt_stop(mfd); + else if (mfd->panel_info.type == MIPI_VIDEO_PANEL) + mdp4_dsi_video_blt_stop(mfd); + else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) + mdp4_dsi_overlay_blt_stop(mfd); + else if (ctrl->panel_mode & MDP4_PANEL_MDDI) + mdp4_mddi_overlay_blt_stop(mfd); + } + mfd->ov0_blt_state = mfd->use_ov0_blt; +} + +static void mdp4_overlay1_update_blt_mode(struct msm_fb_data_type *mfd) +{ + if (mfd->ov1_blt_state == mfd->use_ov1_blt) + return; + if (mfd->use_ov1_blt) { + mdp4_allocate_writeback_buf(mfd, MDP4_MIXER1); + mdp4_dtv_overlay_blt_start(mfd); + pr_debug("%s overlay1 writeback is enabled\n", __func__); + } else { + mdp4_dtv_overlay_blt_stop(mfd); + pr_debug("%s overlay1 writeback is disabled\n", __func__); + } + mfd->ov1_blt_state = mfd->use_ov1_blt; +} + +static u32 mdp4_overlay_blt_enable(struct mdp_overlay *req, + struct msm_fb_data_type *mfd, uint32 perf_level) +{ + u32 clk_rate = mfd->panel_info.clk_rate; + u32 pull_mode = 0, use_blt = 0; + + if (mfd->panel_info.type == MIPI_VIDEO_PANEL) + clk_rate = (&mfd->panel_info.mipi)->dsi_pclk_rate; + + if ((mfd->panel_info.type == LCDC_PANEL) || + (mfd->panel_info.type == MIPI_VIDEO_PANEL) || + (mfd->panel_info.type == DTV_PANEL)) + pull_mode = 1; + + if (pull_mode && (req->src_rect.h > req->dst_rect.h || + req->src_rect.w > req->dst_rect.w)) { + if (mdp4_overlay_validate_downscale(req, mfd, perf_level, + clk_rate)) + use_blt = 1; + } + + if (mfd->panel_info.type == MDDI_PANEL) { + if ((req->src_rect.h/2) >= req->dst_rect.h || + (req->src_rect.w/2) >= req->dst_rect.w) + use_blt = 1; + } + + if (mfd->mdp_rev == MDP_REV_41) { + /* + * writeback (blt) mode to provide work around for + * dsi cmd mode interface hardware bug. + */ + if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) { + if (req->dst_rect.x != 0) + use_blt = 1; + } + if ((mfd->panel_info.xres > 1280) && + (mfd->panel_info.type != DTV_PANEL)) + use_blt = 1; + } + return use_blt; +} + +int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + int ret, mixer, perf_level; + struct mdp4_overlay_pipe *pipe; + + if (mfd == NULL) { + pr_err("%s: mfd == NULL, -ENODEV\n", __func__); + return -ENODEV; + } + + if (info->node != 0 || mfd->cont_splash_done) /* primary */ + if (!mfd->panel_power_on) /* suspended */ + return -EPERM; + + if (req->src.format == MDP_FB_FORMAT) + req->src.format = mfd->fb_imgType; + + if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) { + pr_err("%s: mutex_lock_interruptible, -EINTR\n", __func__); + return -EINTR; + } + + mixer = mfd->panel_info.pdest; /* DISPLAY_1 or DISPLAY_2 */ + + ret = mdp4_overlay_req2pipe(req, mixer, &pipe, mfd); + + if (ret < 0) { + mutex_unlock(&mfd->dma->ov_mutex); + pr_err("%s: mdp4_overlay_req2pipe, ret=%d\n", __func__, ret); + return ret; + } + + perf_level = mdp4_overlay_get_perf_level(req, mfd); + + if (mixer == MDP4_MIXER0) { + u32 use_blt = mdp4_overlay_blt_enable(req, mfd, perf_level); + mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1)); + mfd->use_ov0_blt |= (use_blt << (pipe->pipe_ndx-1)); + } + + /* return id back to user */ + req->id = pipe->pipe_ndx; /* pipe_ndx start from 1 */ + pipe->req_data = *req; /* keep original req */ + + pipe->flags = req->flags; + + if (!IS_ERR_OR_NULL(mfd->iclient)) { + pr_debug("pipe->flags 0x%x\n", pipe->flags); + if (pipe->flags & MDP_SECURE_OVERLAY_SESSION) { + mfd->mem_hid &= ~BIT(ION_IOMMU_HEAP_ID); + mfd->mem_hid |= ION_SECURE; + } else { + mfd->mem_hid |= BIT(ION_IOMMU_HEAP_ID); + mfd->mem_hid &= ~ION_SECURE; + } + } + + if (pipe->flags & MDP_SHARPENING) { + bool test = ((pipe->req_data.dpp.sharp_strength > 0) && + ((req->src_rect.w > req->dst_rect.w) && + (req->src_rect.h > req->dst_rect.h))); + if (test) { + pr_debug("%s: No sharpening while downscaling.\n", + __func__); + pipe->flags &= ~MDP_SHARPENING; + } + } + + /* precompute HSIC matrices */ + if (req->flags & MDP_DPP_HSIC) + mdp4_hsic_set(pipe, &(req->dpp)); + + mdp4_stat.overlay_set[pipe->mixer_num]++; + + if (ctrl->panel_mode & MDP4_PANEL_DTV && + pipe->mixer_num == MDP4_MIXER1) { + u32 use_blt = mdp4_overlay_blt_enable(req, mfd, perf_level); + + if (hdmi_prim_display) { + if (!mdp4_overlay_is_rgb_type(req->src.format) && + pipe->pipe_type == OVERLAY_TYPE_VIDEO && + (req->src_rect.h > req->dst_rect.h || + req->src_rect.w > req->dst_rect.w)) + use_blt = 1; + } + + mdp4_overlay_dtv_set(mfd, pipe); + mfd->use_ov1_blt &= ~(1 << (pipe->pipe_ndx-1)); + mfd->use_ov1_blt |= (use_blt << (pipe->pipe_ndx-1)); + } + + if (new_perf_level != perf_level) { + u32 old_level = new_perf_level; + mdp4_update_perf_level(perf_level); + + /* change clck base on perf level */ + if (pipe->mixer_num == MDP4_MIXER0) { + if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) { + if (old_level > perf_level) + mdp4_set_perf_level(); + } else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) { + mdp4_dsi_cmd_dma_busy_wait(mfd); + mdp4_dsi_blt_dmap_busy_wait(mfd); + mdp4_set_perf_level(); + } else if (ctrl->panel_mode & MDP4_PANEL_LCDC) { + if (old_level > perf_level) + mdp4_set_perf_level(); + } else if (ctrl->panel_mode & MDP4_PANEL_MDDI) { + mdp4_mddi_dma_busy_wait(mfd); + mdp4_mddi_blt_dmap_busy_wait(mfd); + mdp4_set_perf_level(); + } + } else { + if (ctrl->panel_mode & MDP4_PANEL_DTV) { + mdp4_overlay_reg_flush(pipe, 0); + mdp4_overlay_dtv_ov_done_push(mfd, pipe); + } + } + } + mutex_unlock(&mfd->dma->ov_mutex); + + return 0; +} + +int mdp4_overlay_unset_mixer(int mixer) +{ + struct mdp4_overlay_pipe *pipe; + int i, cnt = 0; + + for (i = MDP4_MIXER_STAGE3; i >= MDP4_MIXER_STAGE_BASE; i--) { + pipe = ctrl->stage[mixer][i]; + if (pipe == NULL) + continue; + pipe->flags &= ~MDP_OV_PLAY_NOWAIT; + mdp4_mixer_stage_down(pipe); + mdp4_overlay_pipe_free(pipe); + cnt++; + } + + return cnt; +} + +int mdp4_overlay_unset(struct fb_info *info, int ndx) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct mdp4_overlay_pipe *pipe; + struct dpp_ctrl dpp; + int i; + + if (mfd == NULL) + return -ENODEV; + + if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) + return -EINTR; + + pipe = mdp4_overlay_ndx2pipe(ndx); + + if (pipe == NULL) { + mutex_unlock(&mfd->dma->ov_mutex); + return -ENODEV; + } + + if (pipe->pipe_type == OVERLAY_TYPE_BF) { + mdp4_overlay_borderfill_stage_down(pipe); + mutex_unlock(&mfd->dma->ov_mutex); + return 0; + } + + if (pipe->mixer_num == MDP4_MIXER2) + ctrl->mixer2_played = 0; + else if (pipe->mixer_num == MDP4_MIXER1) + ctrl->mixer1_played = 0; + else { + /* mixer 0 */ + ctrl->mixer0_played = 0; +#ifdef CONFIG_FB_MSM_MIPI_DSI + if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) { + if (mfd->panel_power_on) { + mdp4_dsi_blt_dmap_busy_wait(mfd); + } + } +#else + if (ctrl->panel_mode & MDP4_PANEL_MDDI) { + if (mfd->panel_power_on) + mdp4_mddi_blt_dmap_busy_wait(mfd); + } +#endif + } + + { + mdp4_overlay_reg_flush(pipe, 1); + + if (mfd->use_ov0_blt || pipe->mixer_num == MDP4_MIXER1) { + /* unstage pipe forcedly */ + pipe->flags &= ~MDP_OV_PLAY_NOWAIT; + } + + mdp4_mixer_stage_down(pipe); + + if (pipe->mixer_num == MDP4_MIXER0) { +#ifdef CONFIG_FB_MSM_MIPI_DSI + if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) { + if (mfd->panel_power_on) + mdp4_dsi_cmd_overlay_restore(); + } else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) { + pipe->flags &= ~MDP_OV_PLAY_NOWAIT; + if (mfd->panel_power_on) + mdp4_overlay_dsi_video_vsync_push(mfd, + pipe); + } +#else + if (ctrl->panel_mode & MDP4_PANEL_MDDI) { + if (mfd->panel_power_on) + mdp4_mddi_overlay_restore(); + } +#endif + else if (ctrl->panel_mode & MDP4_PANEL_LCDC) { + pipe->flags &= ~MDP_OV_PLAY_NOWAIT; + if (mfd->panel_power_on) + mdp4_overlay_lcdc_vsync_push(mfd, pipe); + } + mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1)); + mdp4_overlay_update_blt_mode(mfd); + if (!mfd->use_ov0_blt) + mdp4_free_writeback_buf(mfd, MDP4_MIXER0); + } else { /* mixer1, DTV, ATV */ + if (ctrl->panel_mode & MDP4_PANEL_DTV) { + mdp4_overlay_dtv_unset(mfd, pipe); + mfd->use_ov1_blt &= ~(1 << (pipe->pipe_ndx-1)); + mdp4_overlay1_update_blt_mode(mfd); + if (!mfd->use_ov1_blt) + mdp4_free_writeback_buf(mfd, + MDP4_MIXER1); + } + } + } + + /* Reset any HSIC settings to default */ + if (pipe->flags & MDP_DPP_HSIC) { + for (i = 0; i < NUM_HSIC_PARAM; i++) + dpp.hsic_params[i] = 0; + + mdp4_hsic_set(pipe, &dpp); + mdp4_hsic_update(pipe); + } + + mdp4_stat.overlay_unset[pipe->mixer_num]++; + + mdp4_overlay_pipe_free(pipe); + + mutex_unlock(&mfd->dma->ov_mutex); + + return 0; +} + + +struct tile_desc { + uint32 width; /* tile's width */ + uint32 height; /* tile's height */ + uint32 row_tile_w; /* tiles per row's width */ + uint32 row_tile_h; /* tiles per row's height */ +}; + +void tile_samsung(struct tile_desc *tp) +{ + /* + * each row of samsung tile consists of two tiles in height + * and two tiles in width which means width should align to + * 64 x 2 bytes and height should align to 32 x 2 bytes. + * video decoder generate two tiles in width and one tile + * in height which ends up height align to 32 X 1 bytes. + */ + tp->width = 64; /* 64 bytes */ + tp->row_tile_w = 2; /* 2 tiles per row's width */ + tp->height = 32; /* 32 bytes */ + tp->row_tile_h = 1; /* 1 tiles per row's height */ +} + +uint32 tile_mem_size(struct mdp4_overlay_pipe *pipe, struct tile_desc *tp) +{ + uint32 tile_w, tile_h; + uint32 row_num_w, row_num_h; + + + tile_w = tp->width * tp->row_tile_w; + tile_h = tp->height * tp->row_tile_h; + + row_num_w = (pipe->src_width + tile_w - 1) / tile_w; + row_num_h = (pipe->src_height + tile_h - 1) / tile_h; + return ((row_num_w * row_num_h * tile_w * tile_h) + 8191) & ~8191; +} + +int mdp4_overlay_play_wait(struct fb_info *info, struct msmfb_overlay_data *req) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct mdp4_overlay_pipe *pipe; + + if (mfd == NULL) + return -ENODEV; + + if (!mfd->panel_power_on) /* suspended */ + return -EPERM; + + pipe = mdp4_overlay_ndx2pipe(req->id); + + if (!pipe) { + mdp4_stat.err_play++; + return -ENODEV; + } + + if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) + return -EINTR; + + mdp4_mixer_stage_commit(pipe->mixer_num); + + if (mfd->use_ov1_blt) + mdp4_overlay1_update_blt_mode(mfd); + + mdp4_overlay_dtv_wait4vsync(); + mdp4_iommu_unmap(pipe); + + mutex_unlock(&mfd->dma->ov_mutex); + return 0; +} + +int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct msmfb_data *img; + struct mdp4_overlay_pipe *pipe; + ulong start, addr; + ulong len = 0; + struct file *srcp0_file = NULL; + struct file *srcp1_file = NULL, *srcp2_file = NULL; + struct ion_handle *srcp0_ihdl = NULL; + struct ion_handle *srcp1_ihdl = NULL, *srcp2_ihdl = NULL; + int ps0_need, p_need; + uint32_t overlay_version = 0; + int ret = 0; + + if (mfd == NULL) + return -ENODEV; + + if (!mfd->panel_power_on) /* suspended */ + return -EPERM; + + pipe = mdp4_overlay_ndx2pipe(req->id); + if (pipe == NULL) { + mdp4_stat.err_play++; + return -ENODEV; + } + + if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) + return -EINTR; + + if (pipe->pipe_type == OVERLAY_TYPE_BF) { + mdp4_overlay_borderfill_stage_up(pipe); + mutex_unlock(&mfd->dma->ov_mutex); + return 0; + } + + img = &req->data; + get_img(img, info, pipe, 0, &start, &len, &srcp0_file, + &ps0_need, &srcp0_ihdl); + if (len == 0) { + mutex_unlock(&mfd->dma->ov_mutex); + pr_err("%s: pmem Error\n", __func__); + ret = -1; + goto end; + } + + addr = start + img->offset; + pipe->srcp0_addr = addr; + pipe->srcp0_ystride = pipe->src_width * pipe->bpp; + + + pr_debug("%s: mixer=%d ndx=%x addr=%x flags=%x\n", __func__, + pipe->mixer_num, pipe->pipe_ndx, (int)addr, pipe->flags); + + if ((req->version_key & VERSION_KEY_MASK) == 0xF9E8D700) + overlay_version = (req->version_key & ~VERSION_KEY_MASK); + + if (pipe->fetch_plane == OVERLAY_PLANE_PSEUDO_PLANAR) { + if (overlay_version > 0) { + img = &req->plane1_data; + get_img(img, info, pipe, 1, &start, &len, &srcp1_file, + &p_need, &srcp1_ihdl); + if (len == 0) { + mutex_unlock(&mfd->dma->ov_mutex); + pr_err("%s: Error to get plane1\n", __func__); + ret = -EINVAL; + goto end; + } + pipe->srcp1_addr = start + img->offset; + } else if (pipe->frame_format == + MDP4_FRAME_FORMAT_VIDEO_SUPERTILE) { + struct tile_desc tile; + + tile_samsung(&tile); + pipe->srcp1_addr = addr + tile_mem_size(pipe, &tile); + } else { + pipe->srcp1_addr = addr + (pipe->src_width * + pipe->src_height); + } + pipe->srcp0_ystride = pipe->src_width; + if ((pipe->src_format == MDP_Y_CRCB_H1V1) || + (pipe->src_format == MDP_Y_CBCR_H1V1)) { + if (pipe->src_width > YUV_444_MAX_WIDTH) + pipe->srcp1_ystride = pipe->src_width << 2; + else + pipe->srcp1_ystride = pipe->src_width << 1; + } else + pipe->srcp1_ystride = pipe->src_width; + + } else if (pipe->fetch_plane == OVERLAY_PLANE_PLANAR) { + if (overlay_version > 0) { + img = &req->plane1_data; + get_img(img, info, pipe, 1, &start, &len, &srcp1_file, + &p_need, &srcp1_ihdl); + if (len == 0) { + mutex_unlock(&mfd->dma->ov_mutex); + pr_err("%s: Error to get plane1\n", __func__); + ret = -EINVAL; + goto end; + } + pipe->srcp1_addr = start + img->offset; + + img = &req->plane2_data; + get_img(img, info, pipe, 2, &start, &len, &srcp2_file, + &p_need, &srcp2_ihdl); + if (len == 0) { + mutex_unlock(&mfd->dma->ov_mutex); + pr_err("%s: Error to get plane2\n", __func__); + ret = -EINVAL; + goto end; + } + pipe->srcp2_addr = start + img->offset; + } else { + if (pipe->src_format == MDP_Y_CR_CB_GH2V2) { + addr += (ALIGN(pipe->src_width, 16) * + pipe->src_height); + pipe->srcp1_addr = addr; + addr += ((ALIGN((pipe->src_width / 2), 16)) * + (pipe->src_height / 2)); + pipe->srcp2_addr = addr; + } else { + addr += (pipe->src_width * pipe->src_height); + pipe->srcp1_addr = addr; + addr += ((pipe->src_width / 2) * + (pipe->src_height / 2)); + pipe->srcp2_addr = addr; + } + } + /* mdp planar format expects Cb in srcp1 and Cr in p2 */ + if ((pipe->src_format == MDP_Y_CR_CB_H2V2) || + (pipe->src_format == MDP_Y_CR_CB_GH2V2)) + swap(pipe->srcp1_addr, pipe->srcp2_addr); + + if (pipe->src_format == MDP_Y_CR_CB_GH2V2) { + pipe->srcp0_ystride = ALIGN(pipe->src_width, 16); + pipe->srcp1_ystride = ALIGN(pipe->src_width / 2, 16); + pipe->srcp2_ystride = ALIGN(pipe->src_width / 2, 16); + } else { + pipe->srcp0_ystride = pipe->src_width; + pipe->srcp1_ystride = pipe->src_width / 2; + pipe->srcp2_ystride = pipe->src_width / 2; + } + } + + if (mfd->use_ov0_blt) + mdp4_overlay_update_blt_mode(mfd); + + if (mfd->use_ov1_blt) + mdp4_overlay1_update_blt_mode(mfd); + + + if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) { + mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */ + } else { + if (pipe->flags & MDP_SHARPENING) { + pr_debug( + "%s: Sharpening/Smoothing not supported on RGB pipe\n", + __func__); + pipe->flags &= ~MDP_SHARPENING; + } + mdp4_overlay_rgb_setup(pipe); /* rgb pipe */ + } + + mdp4_overlay_reg_flush(pipe, 1); + mdp4_mixer_stage_up(pipe); + + if (pipe->mixer_num == MDP4_MIXER2) { + ctrl->mixer2_played++; +#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL + if (ctrl->panel_mode & MDP4_PANEL_WRITEBACK) { + mdp4_writeback_dma_busy_wait(mfd); + mdp4_writeback_kickoff_video(mfd, pipe); + } +#endif + } else if (pipe->mixer_num == MDP4_MIXER1) { + ctrl->mixer1_played++; + /* enternal interface */ + if (ctrl->panel_mode & MDP4_PANEL_DTV) { + if (pipe->flags & MDP_OV_PLAY_NOWAIT) + mdp4_overlay_flush_piggyback(MDP4_MIXER0, + MDP4_MIXER1); + mdp4_overlay_dtv_start(); + mdp4_overlay_dtv_ov_done_push(mfd, pipe); + if (!mfd->use_ov1_blt) + mdp4_overlay1_update_blt_mode(mfd); + } + } else { + + /* primary interface */ + ctrl->mixer0_played++; + if (ctrl->panel_mode & MDP4_PANEL_LCDC) { + mdp4_overlay_reg_flush(pipe, 0); + mdp4_overlay_lcdc_start(); + mdp4_overlay_lcdc_vsync_push(mfd, pipe); + if (!mfd->use_ov0_blt && + !(pipe->flags & MDP_OV_PLAY_NOWAIT)) + mdp4_overlay_update_blt_mode(mfd); + } +#ifdef CONFIG_FB_MSM_MIPI_DSI + else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) { + mdp4_overlay_reg_flush(pipe, 0); + mdp4_overlay_dsi_video_start(); + mdp4_overlay_dsi_video_vsync_push(mfd, pipe); + if (!mfd->use_ov0_blt && + !(pipe->flags & MDP_OV_PLAY_NOWAIT)) + mdp4_overlay_update_blt_mode(mfd); + } +#endif + else { + mdp4_overlay_reg_flush_reset(pipe); + /* mddi & mipi dsi cmd mode */ + if (pipe->flags & MDP_OV_PLAY_NOWAIT) { + mdp4_stat.overlay_play[pipe->mixer_num]++; + mutex_unlock(&mfd->dma->ov_mutex); + goto end; + } +#ifdef CONFIG_FB_MSM_MIPI_DSI + if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) { + mdp4_iommu_attach(); + mdp4_dsi_cmd_dma_busy_wait(mfd); + mdp4_dsi_cmd_kickoff_video(mfd, pipe); + } +#else + if (ctrl->panel_mode & MDP4_PANEL_MDDI) { + mdp4_mddi_dma_busy_wait(mfd); + mdp4_mddi_kickoff_video(mfd, pipe); + } +#endif + } + } + + /* write out DPP HSIC registers */ + if (pipe->flags & MDP_DPP_HSIC) + mdp4_hsic_update(pipe); + if (!(pipe->flags & MDP_OV_PLAY_NOWAIT)) + mdp4_iommu_unmap(pipe); + mdp4_stat.overlay_play[pipe->mixer_num]++; + mutex_unlock(&mfd->dma->ov_mutex); +end: +#ifdef CONFIG_ANDROID_PMEM + if (srcp0_file) + put_pmem_file(srcp0_file); + if (srcp1_file) + put_pmem_file(srcp1_file); + if (srcp2_file) + put_pmem_file(srcp2_file); +#endif + /* only source may use frame buffer */ + if (img->flags & MDP_MEMORY_ID_TYPE_FB) + fput_light(srcp0_file, ps0_need); + return ret; +} + +static struct { + char *name; + int domain; +} msm_iommu_ctx_names[] = { + /* Display */ + { + .name = "mdp_port0_cb0", + .domain = DISPLAY_DOMAIN, + }, + /* Display */ + { + .name = "mdp_port0_cb1", + .domain = DISPLAY_DOMAIN, + }, + /* Display */ + { + .name = "mdp_port1_cb0", + .domain = DISPLAY_DOMAIN, + }, + /* Display */ + { + .name = "mdp_port1_cb1", + .domain = DISPLAY_DOMAIN, + }, +}; + +static int mdp_iommu_fault_handler(struct iommu_domain *domain, + struct device *dev, unsigned long iova, int flags) +{ + pr_err("MDP IOMMU page fault: iova 0x%lx", iova); + return 0; +} + +void mdp4_iommu_attach(void) +{ + static int done; + struct iommu_domain *domain; + int i; + + if (!done) { + for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) { + int domain_idx; + struct device *ctx = msm_iommu_get_ctx( + msm_iommu_ctx_names[i].name); + + if (!ctx) + continue; + + domain_idx = msm_iommu_ctx_names[i].domain; + + domain = msm_get_iommu_domain(domain_idx); + if (!domain) + continue; + + iommu_set_fault_handler(domain, + mdp_iommu_fault_handler); + if (iommu_attach_device(domain, ctx)) { + WARN(1, "%s: could not attach domain %d to context %s." + " iommu programming will not occur.\n", + __func__, domain_idx, + msm_iommu_ctx_names[i].name); + continue; + } + } + done = 1; + } +} + +int mdp4_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req, + struct mdp4_overlay_pipe **ppipe) +{ + struct mdp4_overlay_pipe *pipe; + int err; + struct msm_fb_data_type *mfb = info->par; + + req->z_order = 0; + req->id = MSMFB_NEW_REQUEST; + req->is_fg = false; + req->alpha = 0xff; + err = mdp4_overlay_req2pipe(req, MDP4_MIXER0, &pipe, mfb); + if (err < 0) { + pr_err("%s:Could not allocate MDP overlay pipe\n", __func__); + return err; + } + + mdp4_mixer_blend_setup(pipe->mixer_num); + *ppipe = pipe; + + return 0; +} + +void mdp4_v4l2_overlay_clear(struct mdp4_overlay_pipe *pipe) +{ + mdp4_mixer_stage_down(pipe); + mdp4_overlay_pipe_free(pipe); +} + +int mdp4_v4l2_overlay_play(struct fb_info *info, struct mdp4_overlay_pipe *pipe, + unsigned long srcp0_addr, unsigned long srcp1_addr, + unsigned long srcp2_addr) +{ + struct msm_fb_data_type *mfd = info->par; + int err; + + if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) + return -EINTR; + + switch (pipe->src_format) { + case MDP_Y_CR_CB_H2V2: + /* YUV420 */ + pipe->srcp0_addr = srcp0_addr; + pipe->srcp0_ystride = pipe->src_width; + /* + * For YUV420, the luma plane is 1 byte per pixel times + * num of pixels in the image Also, the planes are + * switched in MDP, srcp2 is actually first chroma plane + */ + pipe->srcp2_addr = srcp1_addr ? srcp1_addr : + pipe->srcp0_addr + (pipe->src_width * pipe->src_height); + pipe->srcp2_ystride = pipe->src_width/2; + /* + * The chroma planes are half the size of the luma + * planes + */ + pipe->srcp1_addr = srcp2_addr ? srcp2_addr : + pipe->srcp2_addr + + (pipe->src_width * pipe->src_height / 4); + pipe->srcp1_ystride = pipe->src_width/2; + break; + case MDP_Y_CRCB_H2V2: + /* NV12 */ + pipe->srcp0_addr = srcp0_addr; + pipe->srcp0_ystride = pipe->src_width; + pipe->srcp1_addr = srcp1_addr ? srcp1_addr : + pipe->srcp0_addr + + (pipe->src_width * pipe->src_height); + pipe->srcp1_ystride = pipe->src_width; + break; + default: + pr_err("%s: format (%u) is not supported\n", __func__, + pipe->src_format); + err = -EINVAL; + goto done; + } + + pr_debug("%s: pipe ndx=%d stage=%d format=%x\n", __func__, + pipe->pipe_ndx, pipe->mixer_stage, pipe->src_format); + + if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) + mdp4_overlay_vg_setup(pipe); + else + mdp4_overlay_rgb_setup(pipe); + + if (ctrl->panel_mode & MDP4_PANEL_LCDC) + mdp4_overlay_reg_flush(pipe, 1); + + mdp4_mixer_stage_up(pipe); + + if (ctrl->panel_mode & MDP4_PANEL_LCDC) { + mdp4_overlay_lcdc_vsync_push(mfd, pipe); + } else { +#ifdef CONFIG_FB_MSM_MIPI_DSI + if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) { + mdp4_dsi_cmd_dma_busy_wait(mfd); + mdp4_dsi_cmd_kickoff_video(mfd, pipe); + } +#else + if (ctrl->panel_mode & MDP4_PANEL_MDDI) { + mdp4_mddi_dma_busy_wait(mfd); + mdp4_mddi_kickoff_video(mfd, pipe); + } +#endif + } +done: + mutex_unlock(&mfd->dma->ov_mutex); + return err; +} + diff --git a/drivers/video/msm/mdp4_overlay_atv.c b/drivers/video/msm/mdp4_overlay_atv.c new file mode 100644 index 000000000000..a64dd97be957 --- /dev/null +++ b/drivers/video/msm/mdp4_overlay_atv.c @@ -0,0 +1,210 @@ +/* Copyright (c) 2010, 2012 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mdp.h" +#include "msm_fb.h" +#include "mdp4.h" + + +static struct mdp4_overlay_pipe *atv_pipe; + +int mdp4_atv_on(struct platform_device *pdev) +{ + uint8 *buf; + unsigned int buf_offset; + int bpp, ptype; + struct fb_info *fbi; + struct fb_var_screeninfo *var; + struct msm_fb_data_type *mfd; + struct mdp4_overlay_pipe *pipe; + int ret; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + fbi = mfd->fbi; + var = &fbi->var; + + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + buf_offset = calc_fb_offset(mfd, fbi, bpp); + + if (atv_pipe == NULL) { + ptype = mdp4_overlay_format2type(mfd->fb_imgType); + pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER1); + if (pipe == NULL) + return -EBUSY; + pipe->pipe_used++; + pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; + pipe->mixer_num = MDP4_MIXER1; + pipe->src_format = mfd->fb_imgType; + mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_ATV); + mdp4_overlay_format2pipe(pipe); + + atv_pipe = pipe; /* keep it */ + } else { + pipe = atv_pipe; + } + + printk(KERN_INFO "mdp4_atv_overlay: pipe=%x ndx=%d\n", + (int)pipe, pipe->pipe_ndx); + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* Turn the next panel on, get correct resolution + before configuring overlay pipe */ + ret = panel_next_on(pdev); + + pr_info("%s: fbi->var.yres: %d | fbi->var.xres: %d", + __func__, fbi->var.yres, fbi->var.xres); + + /* MDP4 Config */ + pipe->src_height = fbi->var.yres; + pipe->src_width = fbi->var.xres; + pipe->src_h = fbi->var.yres; + pipe->src_w = fbi->var.xres; + pipe->src_y = 0; + pipe->src_x = 0; + if (mfd->map_buffer) { + pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \ + buf_offset; + pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd-> + map_buffer->iova[0], pipe->srcp0_addr); + } else { + pipe->srcp0_addr = (uint32)(buf + buf_offset); + } + + pipe->srcp0_ystride = fbi->fix.line_length; + + mdp4_overlay_dmae_xy(pipe); /* dma_e */ + mdp4_overlay_dmae_cfg(mfd, 1); + + mdp4_overlay_rgb_setup(pipe); + + mdp4_overlayproc_cfg(pipe); + + mdp4_overlay_reg_flush(pipe, 1); + mdp4_mixer_stage_up(pipe); + + if (ret == 0) + mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + return ret; +} + +int mdp4_atv_off(struct platform_device *pdev) +{ + int ret = 0; + + mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + ret = panel_next_off(pdev); + + /* delay to make sure the last frame finishes */ + msleep(100); + + /* dis-engage rgb2 from mixer1 */ + if (atv_pipe) { + mdp4_mixer_stage_down(atv_pipe); + mdp4_iommu_unmap(atv_pipe); + } + + return ret; +} + +/* + * mdp4_overlay1_done_atv: called from isr + */ +void mdp4_overlay1_done_atv() +{ + complete(&atv_pipe->comp); +} + +void mdp4_atv_overlay(struct msm_fb_data_type *mfd) +{ + struct fb_info *fbi = mfd->fbi; + uint8 *buf; + unsigned int buf_offset; + int bpp; + unsigned long flag; + struct mdp4_overlay_pipe *pipe; + + if (!mfd->panel_power_on) + return; + + /* no need to power on cmd block since it's lcdc mode */ + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + buf_offset = calc_fb_offset(mfd, fbi, bpp); + + mutex_lock(&mfd->dma->ov_mutex); + + pipe = atv_pipe; + if (mfd->map_buffer) { + pipe->srcp0_addr = (unsigned int)mfd->map_buffer->iova[0] + \ + buf_offset; + pr_debug("start 0x%lx srcp0_addr 0x%x\n", mfd-> + map_buffer->iova[0], pipe->srcp0_addr); + } else { + pipe->srcp0_addr = (uint32)(buf + buf_offset); + } + mdp4_overlay_rgb_setup(pipe); + mdp4_overlay_reg_flush(pipe, 0); + mdp4_mixer_stage_up(pipe); + + printk(KERN_INFO "mdp4_atv_overlay: pipe=%x ndx=%d\n", + (int)pipe, pipe->pipe_ndx); + + /* enable irq */ + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_enable_irq(MDP_OVERLAY1_TERM); + INIT_COMPLETION(atv_pipe->comp); + mfd->dma->waiting = TRUE; + outp32(MDP_INTR_CLEAR, INTR_OVERLAY1_DONE); + mdp_intr_mask |= INTR_OVERLAY1_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + spin_unlock_irqrestore(&mdp_spin_lock, flag); + wait_for_completion_killable(&atv_pipe->comp); + mdp_disable_irq(MDP_OVERLAY1_TERM); + + /* change mdp clk while mdp is idle` */ + mdp4_set_perf_level(); + + mdp4_stat.kickoff_atv++; + mutex_unlock(&mfd->dma->ov_mutex); +} diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c new file mode 100644 index 000000000000..351e2d059a0d --- /dev/null +++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c @@ -0,0 +1,718 @@ +/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mdp.h" +#include "msm_fb.h" +#include "mdp4.h" +#include "mipi_dsi.h" + +static struct mdp4_overlay_pipe *dsi_pipe; +static struct msm_fb_data_type *dsi_mfd; +static int busy_wait_cnt; +static int dsi_state; +static unsigned long tout_expired; + +#define TOUT_PERIOD HZ /* 1 second */ +#define MS_100 (HZ/10) /* 100 ms */ + +static int vsync_start_y_adjust = 4; + +struct timer_list dsi_clock_timer; + +void mdp4_overlay_dsi_state_set(int state) +{ + unsigned long flag; + + spin_lock_irqsave(&mdp_spin_lock, flag); + dsi_state = state; + spin_unlock_irqrestore(&mdp_spin_lock, flag); +} + +int mdp4_overlay_dsi_state_get(void) +{ + return dsi_state; +} + +static void dsi_clock_tout(unsigned long data) +{ + if (mipi_dsi_clk_on) { + if (dsi_state == ST_DSI_PLAYING) { + mipi_dsi_turn_off_clks(); + mdp4_overlay_dsi_state_set(ST_DSI_CLK_OFF); + } + } +} + +static __u32 msm_fb_line_length(__u32 fb_index, __u32 xres, int bpp) +{ + /* + * The adreno GPU hardware requires that the pitch be aligned to + * 32 pixels for color buffers, so for the cases where the GPU + * is writing directly to fb0, the framebuffer pitch + * also needs to be 32 pixel aligned + */ + + if (fb_index == 0) + return ALIGN(xres, 32) * bpp; + else + return xres * bpp; +} + +void mdp4_mipi_vsync_enable(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe, int which) +{ + uint32 start_y, data, tear_en; + + tear_en = (1 << which); + + if ((mfd->use_mdp_vsync) && (mfd->ibuf.vsync_enable) && + (mfd->panel_info.lcd.vsync_enable)) { + + if (vsync_start_y_adjust <= pipe->dst_y) + start_y = pipe->dst_y - vsync_start_y_adjust; + else + start_y = (mfd->total_lcd_lines - 1) - + (vsync_start_y_adjust - pipe->dst_y); + if (which == 0) + MDP_OUTP(MDP_BASE + 0x210, start_y); /* primary */ + else + MDP_OUTP(MDP_BASE + 0x214, start_y); /* secondary */ + + data = inpdw(MDP_BASE + 0x20c); + data |= tear_en; + MDP_OUTP(MDP_BASE + 0x20c, data); + } else { + data = inpdw(MDP_BASE + 0x20c); + data &= ~tear_en; + MDP_OUTP(MDP_BASE + 0x20c, data); + } +} + +void mdp4_dsi_cmd_base_swap(struct mdp4_overlay_pipe *pipe) +{ + dsi_pipe = pipe; +} + +void mdp4_overlay_update_dsi_cmd(struct msm_fb_data_type *mfd) +{ + MDPIBUF *iBuf = &mfd->ibuf; + uint8 *src; + int ptype; + struct mdp4_overlay_pipe *pipe; + int bpp; + int ret; + + if (mfd->key != MFD_KEY) + return; + + dsi_mfd = mfd; /* keep it */ + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + if (dsi_pipe == NULL) { + ptype = mdp4_overlay_format2type(mfd->fb_imgType); + if (ptype < 0) + printk(KERN_INFO "%s: format2type failed\n", __func__); + pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0); + if (pipe == NULL) + printk(KERN_INFO "%s: pipe_alloc failed\n", __func__); + pipe->pipe_used++; + pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; + pipe->mixer_num = MDP4_MIXER0; + pipe->src_format = mfd->fb_imgType; + mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_DSI_CMD); + ret = mdp4_overlay_format2pipe(pipe); + if (ret < 0) + printk(KERN_INFO "%s: format2type failed\n", __func__); + + init_timer(&dsi_clock_timer); + dsi_clock_timer.function = dsi_clock_tout; + dsi_clock_timer.data = (unsigned long) mfd;; + dsi_clock_timer.expires = 0xffffffff; + add_timer(&dsi_clock_timer); + tout_expired = jiffies; + + dsi_pipe = pipe; /* keep it */ + + mdp4_init_writeback_buf(mfd, MDP4_MIXER0); + pipe->blt_addr = 0; + + } else { + pipe = dsi_pipe; + } + + if (pipe->pipe_used == 0 || + pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) { + pr_err("%s: NOT baselayer\n", __func__); + mutex_unlock(&mfd->dma->ov_mutex); + return; + } + + /* + * configure dsi stream id + * dma_p = 0, dma_s = 1 + */ + MDP_OUTP(MDP_BASE + 0x000a0, 0x10); + /* disable dsi trigger */ + MDP_OUTP(MDP_BASE + 0x000a4, 0x00); + /* whole screen for base layer */ + src = (uint8 *) iBuf->buf; + + + { + struct fb_info *fbi; + + fbi = mfd->fbi; + if (pipe->is_3d) { + bpp = fbi->var.bits_per_pixel / 8; + pipe->src_height = pipe->src_height_3d; + pipe->src_width = pipe->src_width_3d; + pipe->src_h = pipe->src_height_3d; + pipe->src_w = pipe->src_width_3d; + pipe->dst_h = pipe->src_height_3d; + pipe->dst_w = pipe->src_width_3d; + pipe->srcp0_ystride = msm_fb_line_length(0, + pipe->src_width, bpp); + } else { + /* 2D */ + pipe->src_height = fbi->var.yres; + pipe->src_width = fbi->var.xres; + pipe->src_h = fbi->var.yres; + pipe->src_w = fbi->var.xres; + pipe->dst_h = fbi->var.yres; + pipe->dst_w = fbi->var.xres; + pipe->srcp0_ystride = fbi->fix.line_length; + } + pipe->src_y = 0; + pipe->src_x = 0; + pipe->dst_y = 0; + pipe->dst_x = 0; + pipe->srcp0_addr = (uint32)src; + } + + + mdp4_overlay_rgb_setup(pipe); + + mdp4_overlay_reg_flush(pipe, 1); + + mdp4_mixer_stage_up(pipe); + + mdp4_overlayproc_cfg(pipe); + + mdp4_overlay_dmap_xy(pipe); + + mdp4_overlay_dmap_cfg(mfd, 0); + + mdp4_mipi_vsync_enable(mfd, pipe, 0); + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + wmb(); +} + +/* 3D side by side */ +void mdp4_dsi_cmd_3d_sbys(struct msm_fb_data_type *mfd, + struct msmfb_overlay_3d *r3d) +{ + struct fb_info *fbi; + struct mdp4_overlay_pipe *pipe; + int bpp; + uint8 *src = NULL; + + if (dsi_pipe == NULL) + return; + + dsi_pipe->is_3d = r3d->is_3d; + dsi_pipe->src_height_3d = r3d->height; + dsi_pipe->src_width_3d = r3d->width; + + pipe = dsi_pipe; + if (pipe->pipe_used == 0 || + pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) { + pr_err("%s: NOT baselayer\n", __func__); + mutex_unlock(&mfd->dma->ov_mutex); + return; + } + + if (pipe->is_3d) + mdp4_overlay_panel_3d(pipe->mixer_num, MDP4_3D_SIDE_BY_SIDE); + else + mdp4_overlay_panel_3d(pipe->mixer_num, MDP4_3D_NONE); + + if (mfd->panel_power_on) { + mdp4_dsi_cmd_dma_busy_wait(mfd); + mdp4_dsi_blt_dmap_busy_wait(mfd); + } + + fbi = mfd->fbi; + if (pipe->is_3d) { + bpp = fbi->var.bits_per_pixel / 8; + pipe->src_height = pipe->src_height_3d; + pipe->src_width = pipe->src_width_3d; + pipe->src_h = pipe->src_height_3d; + pipe->src_w = pipe->src_width_3d; + pipe->dst_h = pipe->src_height_3d; + pipe->dst_w = pipe->src_width_3d; + pipe->srcp0_ystride = msm_fb_line_length(0, + pipe->src_width, bpp); + } else { + /* 2D */ + pipe->src_height = fbi->var.yres; + pipe->src_width = fbi->var.xres; + pipe->src_h = fbi->var.yres; + pipe->src_w = fbi->var.xres; + pipe->dst_h = fbi->var.yres; + pipe->dst_w = fbi->var.xres; + pipe->srcp0_ystride = fbi->fix.line_length; + } + pipe->src_y = 0; + pipe->src_x = 0; + pipe->dst_y = 0; + pipe->dst_x = 0; + pipe->srcp0_addr = (uint32)src; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + mdp4_overlay_rgb_setup(pipe); + + mdp4_overlay_reg_flush(pipe, 1); + + mdp4_mixer_stage_up(pipe); + + mdp4_overlayproc_cfg(pipe); + + mdp4_overlay_dmap_xy(pipe); + + mdp4_overlay_dmap_cfg(mfd, 0); + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +int mdp4_dsi_overlay_blt_start(struct msm_fb_data_type *mfd) +{ + unsigned long flag; + + pr_debug("%s: blt_end=%d blt_addr=%x pid=%d\n", + __func__, dsi_pipe->blt_end, (int)dsi_pipe->blt_addr, current->pid); + + mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0); + + if (mfd->ov0_wb_buf->phys_addr == 0) { + pr_info("%s: no blt_base assigned\n", __func__); + return -EBUSY; + } + + if (dsi_pipe->blt_addr == 0) { + mdp4_dsi_cmd_dma_busy_wait(mfd); + spin_lock_irqsave(&mdp_spin_lock, flag); + dsi_pipe->blt_end = 0; + dsi_pipe->blt_cnt = 0; + dsi_pipe->ov_cnt = 0; + dsi_pipe->dmap_cnt = 0; + dsi_pipe->blt_addr = mfd->ov0_wb_buf->phys_addr; + mdp4_stat.blt_dsi_cmd++; + spin_unlock_irqrestore(&mdp_spin_lock, flag); + return 0; + } + + return -EBUSY; +} + +int mdp4_dsi_overlay_blt_stop(struct msm_fb_data_type *mfd) +{ + unsigned long flag; + + + pr_debug("%s: blt_end=%d blt_addr=%x\n", + __func__, dsi_pipe->blt_end, (int)dsi_pipe->blt_addr); + + if ((dsi_pipe->blt_end == 0) && dsi_pipe->blt_addr) { + spin_lock_irqsave(&mdp_spin_lock, flag); + dsi_pipe->blt_end = 1; /* mark as end */ + spin_unlock_irqrestore(&mdp_spin_lock, flag); + return 0; + } + + return -EBUSY; +} + +int mdp4_dsi_overlay_blt_offset(struct msm_fb_data_type *mfd, + struct msmfb_overlay_blt *req) +{ + req->offset = 0; + req->width = dsi_pipe->src_width; + req->height = dsi_pipe->src_height; + req->bpp = dsi_pipe->bpp; + + return sizeof(*req); +} + +void mdp4_dsi_overlay_blt(struct msm_fb_data_type *mfd, + struct msmfb_overlay_blt *req) +{ + if (req->enable) + mdp4_dsi_overlay_blt_start(mfd); + else if (req->enable == 0) + mdp4_dsi_overlay_blt_stop(mfd); + +} + +void mdp4_blt_xy_update(struct mdp4_overlay_pipe *pipe) +{ + uint32 off, addr, addr2; + int bpp; + char *overlay_base; + + + if (pipe->blt_addr == 0) + return; + + +#ifdef BLT_RGB565 + bpp = 2; /* overlay ouput is RGB565 */ +#else + bpp = 3; /* overlay ouput is RGB888 */ +#endif + off = 0; + if (pipe->dmap_cnt & 0x01) + off = pipe->src_height * pipe->src_width * bpp; + addr = pipe->blt_addr + off; + + /* dmap */ + MDP_OUTP(MDP_BASE + 0x90008, addr); + + off = 0; + if (pipe->ov_cnt & 0x01) + off = pipe->src_height * pipe->src_width * bpp; + addr2 = pipe->blt_addr + off; + /* overlay 0 */ + overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ + outpdw(overlay_base + 0x000c, addr2); + outpdw(overlay_base + 0x001c, addr2); +} + + +/* + * mdp4_dmap_done_dsi: called from isr + * DAM_P_DONE only used when blt enabled + */ +void mdp4_dma_p_done_dsi(struct mdp_dma_data *dma) +{ + int diff; + + dsi_pipe->dmap_cnt++; + diff = dsi_pipe->ov_cnt - dsi_pipe->dmap_cnt; + pr_debug("%s: ov_cnt=%d dmap_cnt=%d\n", + __func__, dsi_pipe->ov_cnt, dsi_pipe->dmap_cnt); + + if (diff <= 0) { + spin_lock(&mdp_spin_lock); + dma->dmap_busy = FALSE; + complete(&dma->dmap_comp); + spin_unlock(&mdp_spin_lock); + if (dsi_pipe->blt_end) { + dsi_pipe->blt_end = 0; + dsi_pipe->blt_addr = 0; + pr_debug("%s: END, ov_cnt=%d dmap_cnt=%d\n", + __func__, dsi_pipe->ov_cnt, dsi_pipe->dmap_cnt); + mdp_intr_mask &= ~INTR_DMA_P_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + } + mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE); + mdp_disable_irq_nosync(MDP_DMA2_TERM); /* disable intr */ + return; + } + + spin_lock(&mdp_spin_lock); + dma->busy = FALSE; + spin_unlock(&mdp_spin_lock); + complete(&dma->comp); + if (busy_wait_cnt) + busy_wait_cnt--; + + pr_debug("%s: kickoff dmap\n", __func__); + + mdp4_blt_xy_update(dsi_pipe); + /* kick off dmap */ + outpdw(MDP_BASE + 0x000c, 0x0); + mdp4_stat.kickoff_dmap++; + /* trigger dsi cmd engine */ + mipi_dsi_cmd_mdp_start(); + + mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE); +} + + +/* + * mdp4_overlay0_done_dsi_cmd: called from isr + */ +void mdp4_overlay0_done_dsi_cmd(struct mdp_dma_data *dma) +{ + int diff; + + if (dsi_pipe->blt_addr == 0) { + mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE); + spin_lock(&mdp_spin_lock); + dma->busy = FALSE; + spin_unlock(&mdp_spin_lock); + complete(&dma->comp); + if (busy_wait_cnt) + busy_wait_cnt--; + mdp_disable_irq_nosync(MDP_OVERLAY0_TERM); + return; + } + + /* blt enabled */ + if (dsi_pipe->blt_end == 0) + dsi_pipe->ov_cnt++; + + pr_debug("%s: ov_cnt=%d dmap_cnt=%d\n", + __func__, dsi_pipe->ov_cnt, dsi_pipe->dmap_cnt); + + if (dsi_pipe->blt_cnt == 0) { + /* first kickoff since blt enabled */ + mdp_intr_mask |= INTR_DMA_P_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + } + dsi_pipe->blt_cnt++; + + diff = dsi_pipe->ov_cnt - dsi_pipe->dmap_cnt; + if (diff >= 2) { + mdp_disable_irq_nosync(MDP_OVERLAY0_TERM); + return; + } + + spin_lock(&mdp_spin_lock); + dma->busy = FALSE; + dma->dmap_busy = TRUE; + spin_unlock(&mdp_spin_lock); + complete(&dma->comp); + if (busy_wait_cnt) + busy_wait_cnt--; + + pr_debug("%s: kickoff dmap\n", __func__); + + mdp4_blt_xy_update(dsi_pipe); + mdp_enable_irq(MDP_DMA2_TERM); /* enable intr */ + /* kick off dmap */ + outpdw(MDP_BASE + 0x000c, 0x0); + mdp4_stat.kickoff_dmap++; + /* trigger dsi cmd engine */ + mipi_dsi_cmd_mdp_start(); + mdp_disable_irq_nosync(MDP_OVERLAY0_TERM); +} + +void mdp4_dsi_cmd_overlay_restore(void) +{ + /* mutex holded by caller */ + if (dsi_mfd && dsi_pipe) { + mdp4_dsi_cmd_dma_busy_wait(dsi_mfd); + mipi_dsi_mdp_busy_wait(dsi_mfd); + mdp4_overlay_update_dsi_cmd(dsi_mfd); + + if (dsi_pipe->blt_addr) + mdp4_dsi_blt_dmap_busy_wait(dsi_mfd); + mdp4_dsi_cmd_overlay_kickoff(dsi_mfd, dsi_pipe); + } +} + +void mdp4_dsi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd) +{ + unsigned long flag; + int need_wait = 0; + + spin_lock_irqsave(&mdp_spin_lock, flag); + if (mfd->dma->dmap_busy == TRUE) { + INIT_COMPLETION(mfd->dma->dmap_comp); + need_wait++; + } + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + if (need_wait) { + /* wait until DMA finishes the current job */ + wait_for_completion(&mfd->dma->dmap_comp); + } +} + +/* + * mdp4_dsi_cmd_dma_busy_wait: check dsi link activity + * dsi link is a shared resource and it can only be used + * while it is in idle state. + * ov_mutex need to be acquired before call this function. + */ +void mdp4_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd) +{ + unsigned long flag; + int need_wait = 0; + + + + if (dsi_clock_timer.function) { + if (time_after(jiffies, tout_expired)) { + tout_expired = jiffies + TOUT_PERIOD; + mod_timer(&dsi_clock_timer, tout_expired); + tout_expired -= MS_100; + } + } + + pr_debug("%s: start pid=%d dsi_clk_on=%d\n", + __func__, current->pid, mipi_dsi_clk_on); + + /* satrt dsi clock if necessary */ + if (mipi_dsi_clk_on == 0) { + local_bh_disable(); + mipi_dsi_turn_on_clks(); + local_bh_enable(); + } + + spin_lock_irqsave(&mdp_spin_lock, flag); + if (mfd->dma->busy == TRUE) { + if (busy_wait_cnt == 0) + INIT_COMPLETION(mfd->dma->comp); + busy_wait_cnt++; + need_wait++; + } + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + if (need_wait) { + /* wait until DMA finishes the current job */ + pr_debug("%s: pending pid=%d dsi_clk_on=%d\n", + __func__, current->pid, mipi_dsi_clk_on); + wait_for_completion(&mfd->dma->comp); + } + pr_debug("%s: done pid=%d dsi_clk_on=%d\n", + __func__, current->pid, mipi_dsi_clk_on); +} + +void mdp4_dsi_cmd_kickoff_video(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + /* + * a video kickoff may happen before UI kickoff after + * blt enabled. mdp4_overlay_update_dsi_cmd() need + * to be called before kickoff. + * vice versa for blt disabled. + */ + if (dsi_pipe->blt_addr && dsi_pipe->blt_cnt == 0) + mdp4_overlay_update_dsi_cmd(mfd); /* first time */ + else if (dsi_pipe->blt_addr == 0 && dsi_pipe->blt_cnt) { + mdp4_overlay_update_dsi_cmd(mfd); /* last time */ + dsi_pipe->blt_cnt = 0; + } + + pr_debug("%s: blt_addr=%d blt_cnt=%d\n", + __func__, (int)dsi_pipe->blt_addr, dsi_pipe->blt_cnt); + + if (dsi_pipe->blt_addr) + mdp4_dsi_blt_dmap_busy_wait(dsi_mfd); + + mdp4_dsi_cmd_overlay_kickoff(mfd, pipe); +} + +void mdp4_dsi_cmd_kickoff_ui(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + + pr_debug("%s: pid=%d\n", __func__, current->pid); + mdp4_dsi_cmd_overlay_kickoff(mfd, pipe); +} + + +void mdp4_dsi_cmd_overlay_kickoff(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + unsigned long flag; + + + /* change mdp clk */ + mdp4_set_perf_level(); + + mipi_dsi_mdp_busy_wait(mfd); + + if (dsi_pipe->blt_addr == 0) + mipi_dsi_cmd_mdp_start(); + + mdp4_overlay_dsi_state_set(ST_DSI_PLAYING); + + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_enable_irq(MDP_OVERLAY0_TERM); + mfd->dma->busy = TRUE; + if (dsi_pipe->blt_addr) + mfd->dma->dmap_busy = TRUE; + /* start OVERLAY pipe */ + spin_unlock_irqrestore(&mdp_spin_lock, flag); + mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd); + mdp4_stat.kickoff_ov0++; +} + +void mdp_dsi_cmd_overlay_suspend(struct msm_fb_data_type *mfd) +{ + /* dis-engage rgb0 from mixer0 */ + if (dsi_pipe) { + if (mfd->ref_cnt == 0) { + /* adb stop */ + if (dsi_pipe->pipe_type == OVERLAY_TYPE_BF) + mdp4_overlay_borderfill_stage_down(dsi_pipe); + + /* dsi_pipe == rgb1 */ + mdp4_overlay_unset_mixer(dsi_pipe->mixer_num); + dsi_pipe = NULL; + } else { + mdp4_mixer_stage_down(dsi_pipe); + mdp4_iommu_unmap(dsi_pipe); + } + } +} + +void mdp4_dsi_cmd_overlay(struct msm_fb_data_type *mfd) +{ + mutex_lock(&mfd->dma->ov_mutex); + + if (mfd && mfd->panel_power_on) { + mdp4_dsi_cmd_dma_busy_wait(mfd); + + if (dsi_pipe && dsi_pipe->blt_addr) + mdp4_dsi_blt_dmap_busy_wait(mfd); + + mdp4_overlay_update_dsi_cmd(mfd); + + mdp4_iommu_attach(); + mdp4_dsi_cmd_kickoff_ui(mfd, dsi_pipe); + mdp4_iommu_unmap(dsi_pipe); + /* signal if pan function is waiting for the update completion */ + if (mfd->pan_waiting) { + mfd->pan_waiting = FALSE; + complete(&mfd->pan_comp); + } + } + mutex_unlock(&mfd->dma->ov_mutex); +} diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c new file mode 100644 index 000000000000..e9befef1522e --- /dev/null +++ b/drivers/video/msm/mdp4_overlay_dsi_video.c @@ -0,0 +1,729 @@ +/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mdp.h" +#include "msm_fb.h" +#include "mdp4.h" +#include "mipi_dsi.h" + +#include + +#define DSI_VIDEO_BASE 0xE0000 + +static int first_pixel_start_x; +static int first_pixel_start_y; +static int dsi_video_enabled; + +static struct mdp4_overlay_pipe *dsi_pipe; +static struct completion dsi_video_comp; +static int blt_cfg_changed; + +static cmd_fxn_t display_on; + +static __u32 msm_fb_line_length(__u32 fb_index, __u32 xres, int bpp) +{ + /* + * The adreno GPU hardware requires that the pitch be aligned to + * 32 pixels for color buffers, so for the cases where the GPU + * is writing directly to fb0, the framebuffer pitch + * also needs to be 32 pixel aligned + */ + + if (fb_index == 0) + return ALIGN(xres, 32) * bpp; + else + return xres * bpp; +} + +void mdp4_dsi_video_fxn_register(cmd_fxn_t fxn) +{ + display_on = fxn; +} + +static void mdp4_overlay_dsi_video_wait4event(struct msm_fb_data_type *mfd, + int intr_done); + +void mdp4_dsi_video_base_swap(struct mdp4_overlay_pipe *pipe) +{ + dsi_pipe = pipe; +} + +int mdp4_dsi_video_on(struct platform_device *pdev) +{ + int dsi_width; + int dsi_height; + int dsi_bpp; + int dsi_border_clr; + int dsi_underflow_clr; + int dsi_hsync_skew; + + int hsync_period; + int hsync_ctrl; + int vsync_period; + int display_hctl; + int display_v_start; + int display_v_end; + int active_hctl; + int active_h_start; + int active_h_end; + int active_v_start; + int active_v_end; + int ctrl_polarity; + int h_back_porch; + int h_front_porch; + int v_back_porch; + int v_front_porch; + int hsync_pulse_width; + int vsync_pulse_width; + int hsync_polarity; + int vsync_polarity; + int data_en_polarity; + int hsync_start_x; + int hsync_end_x; + uint8 *buf; + unsigned int buf_offset; + int bpp, ptype; + struct fb_info *fbi; + struct fb_var_screeninfo *var; + struct msm_fb_data_type *mfd; + struct mdp4_overlay_pipe *pipe; + int ret; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + fbi = mfd->fbi; + var = &fbi->var; + + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + buf_offset = calc_fb_offset(mfd, fbi, bpp); + + if (dsi_pipe == NULL) { + ptype = mdp4_overlay_format2type(mfd->fb_imgType); + if (ptype < 0) + printk(KERN_INFO "%s: format2type failed\n", __func__); + pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0); + if (pipe == NULL) { + printk(KERN_INFO "%s: pipe_alloc failed\n", __func__); + return -EBUSY; + } + pipe->pipe_used++; + pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; + pipe->mixer_num = MDP4_MIXER0; + pipe->src_format = mfd->fb_imgType; + mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_DSI_VIDEO); + ret = mdp4_overlay_format2pipe(pipe); + if (ret < 0) + printk(KERN_INFO "%s: format2type failed\n", __func__); + + dsi_pipe = pipe; /* keep it */ + init_completion(&dsi_video_comp); + + mdp4_init_writeback_buf(mfd, MDP4_MIXER0); + pipe->blt_addr = 0; + + } else { + pipe = dsi_pipe; + } + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + if (!(mfd->cont_splash_done)) { + mfd->cont_splash_done = 1; + mdp_pipe_ctrl(MDP_CMD_BLOCK, + MDP_BLOCK_POWER_OFF, FALSE); + mdp4_overlay_dsi_video_wait4event(mfd, INTR_DMA_P_DONE); + /* disable timing generator */ + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0); + mipi_dsi_controller_cfg(0); + } + + if (is_mdp4_hw_reset()) { + mdp4_hw_init(); + outpdw(MDP_BASE + 0x0038, mdp4_display_intf); + } + + pipe->src_height = fbi->var.yres; + pipe->src_width = fbi->var.xres; + pipe->src_h = fbi->var.yres; + pipe->src_w = fbi->var.xres; + pipe->src_y = 0; + pipe->src_x = 0; + pipe->srcp0_ystride = fbi->fix.line_length; + pipe->bpp = bpp; + + if (mfd->display_iova) + pipe->srcp0_addr = mfd->display_iova + buf_offset; + else + pipe->srcp0_addr = (uint32)(buf + buf_offset); + + pipe->dst_h = fbi->var.yres; + pipe->dst_w = fbi->var.xres; + + mdp4_overlay_dmap_xy(pipe); /* dma_p */ + mdp4_overlay_dmap_cfg(mfd, 1); + mdp4_overlay_rgb_setup(pipe); + mdp4_overlay_reg_flush(pipe, 1); + mdp4_mixer_stage_up(pipe); + + mdp4_overlayproc_cfg(pipe); + + /* + * DSI timing setting + */ + h_back_porch = var->left_margin; + h_front_porch = var->right_margin; + v_back_porch = var->upper_margin; + v_front_porch = var->lower_margin; + hsync_pulse_width = var->hsync_len; + vsync_pulse_width = var->vsync_len; + dsi_border_clr = mfd->panel_info.lcdc.border_clr; + dsi_underflow_clr = mfd->panel_info.lcdc.underflow_clr; + dsi_hsync_skew = mfd->panel_info.lcdc.hsync_skew; + dsi_width = mfd->panel_info.xres + + mfd->panel_info.lcdc.xres_pad; + dsi_height = mfd->panel_info.yres + + mfd->panel_info.lcdc.yres_pad; + dsi_bpp = mfd->panel_info.bpp; + + hsync_period = hsync_pulse_width + h_back_porch + dsi_width + + h_front_porch; + hsync_ctrl = (hsync_period << 16) | hsync_pulse_width; + hsync_start_x = h_back_porch + hsync_pulse_width; + hsync_end_x = hsync_period - h_front_porch - 1; + display_hctl = (hsync_end_x << 16) | hsync_start_x; + + vsync_period = + (vsync_pulse_width + v_back_porch + dsi_height + v_front_porch); + display_v_start = ((vsync_pulse_width + v_back_porch) * hsync_period) + + dsi_hsync_skew; + display_v_end = + ((vsync_period - v_front_porch) * hsync_period) + dsi_hsync_skew - 1; + + if (dsi_width != var->xres) { + active_h_start = hsync_start_x + first_pixel_start_x; + active_h_end = active_h_start + var->xres - 1; + active_hctl = + ACTIVE_START_X_EN | (active_h_end << 16) | active_h_start; + } else { + active_hctl = 0; + } + + if (dsi_height != var->yres) { + active_v_start = + display_v_start + first_pixel_start_y * hsync_period; + active_v_end = active_v_start + (var->yres) * hsync_period - 1; + active_v_start |= ACTIVE_START_Y_EN; + } else { + active_v_start = 0; + active_v_end = 0; + } + + dsi_underflow_clr |= 0x80000000; /* enable recovery */ + hsync_polarity = 0; + vsync_polarity = 0; + data_en_polarity = 0; + + ctrl_polarity = + (data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity); + + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x4, hsync_ctrl); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x8, vsync_period * hsync_period); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0xc, + vsync_pulse_width * hsync_period); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x10, display_hctl); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x14, display_v_start); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x18, display_v_end); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x1c, active_hctl); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x20, active_v_start); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x24, active_v_end); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x28, dsi_border_clr); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x2c, dsi_underflow_clr); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x30, dsi_hsync_skew); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x38, ctrl_polarity); + mdp4_overlay_reg_flush(pipe, 1); + mdp4_mixer_stage_up(pipe); + + mdp_histogram_ctrl_all(TRUE); + + ret = panel_next_on(pdev); + if (ret == 0) { + if (display_on != NULL) { + msleep(50); + display_on(pdev); + } + } + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + return ret; +} + +int mdp4_dsi_video_off(struct platform_device *pdev) +{ + int ret = 0; + struct msm_fb_data_type *mfd; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0); + dsi_video_enabled = 0; + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + mdp_histogram_ctrl_all(FALSE); + ret = panel_next_off(pdev); + + /* delay to make sure the last frame finishes */ + msleep(20); + + /* dis-engage rgb0 from mixer0 */ + if (dsi_pipe) { + if (mfd->ref_cnt == 0) { + /* adb stop */ + if (dsi_pipe->pipe_type == OVERLAY_TYPE_BF) + mdp4_overlay_borderfill_stage_down(dsi_pipe); + + /* dsi_pipe == rgb1 */ + mdp4_overlay_unset_mixer(dsi_pipe->mixer_num); + dsi_pipe = NULL; + } else { + mdp4_mixer_stage_down(dsi_pipe); + mdp4_iommu_unmap(dsi_pipe); + } + } + + return ret; +} + +/* 3D side by side */ +void mdp4_dsi_video_3d_sbys(struct msm_fb_data_type *mfd, + struct msmfb_overlay_3d *r3d) +{ + struct fb_info *fbi; + struct mdp4_overlay_pipe *pipe; + unsigned int buf_offset; + int bpp; + uint8 *buf = NULL; + + if (dsi_pipe == NULL) + return; + + dsi_pipe->is_3d = r3d->is_3d; + dsi_pipe->src_height_3d = r3d->height; + dsi_pipe->src_width_3d = r3d->width; + + pipe = dsi_pipe; + + if (pipe->is_3d) + mdp4_overlay_panel_3d(pipe->mixer_num, MDP4_3D_SIDE_BY_SIDE); + else + mdp4_overlay_panel_3d(pipe->mixer_num, MDP4_3D_NONE); + + fbi = mfd->fbi; + + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + buf_offset = calc_fb_offset(mfd, fbi, bpp); + + if (pipe->is_3d) { + pipe->src_height = pipe->src_height_3d; + pipe->src_width = pipe->src_width_3d; + pipe->src_h = pipe->src_height_3d; + pipe->src_w = pipe->src_width_3d; + pipe->dst_h = pipe->src_height_3d; + pipe->dst_w = pipe->src_width_3d; + pipe->srcp0_ystride = msm_fb_line_length(0, + pipe->src_width, bpp); + } else { + /* 2D */ + pipe->src_height = fbi->var.yres; + pipe->src_width = fbi->var.xres; + pipe->src_h = fbi->var.yres; + pipe->src_w = fbi->var.xres; + pipe->dst_h = fbi->var.yres; + pipe->dst_w = fbi->var.xres; + pipe->srcp0_ystride = fbi->fix.line_length; + } + + pipe->src_y = 0; + pipe->src_x = 0; + pipe->dst_y = 0; + pipe->dst_x = 0; + + if (mfd->display_iova) + pipe->srcp0_addr = mfd->display_iova + buf_offset; + else + pipe->srcp0_addr = (uint32)(buf + buf_offset); + + mdp4_overlay_rgb_setup(pipe); + + mdp4_overlayproc_cfg(pipe); + + mdp4_overlay_dmap_xy(pipe); + + mdp4_overlay_dmap_cfg(mfd, 1); + + mdp4_overlay_reg_flush(pipe, 1); + mdp4_mixer_stage_up(pipe); + + mb(); + + /* wait for vsycn */ + mdp4_overlay_dsi_video_vsync_push(mfd, pipe); +} + +static void mdp4_dsi_video_blt_ov_update(struct mdp4_overlay_pipe *pipe) +{ + uint32 off, addr; + int bpp; + char *overlay_base; + + + if (pipe->blt_addr == 0) + return; + + +#ifdef BLT_RGB565 + bpp = 2; /* overlay ouput is RGB565 */ +#else + bpp = 3; /* overlay ouput is RGB888 */ +#endif + off = 0; + if (pipe->ov_cnt & 0x01) + off = pipe->src_height * pipe->src_width * bpp; + addr = pipe->blt_addr + off; + + /* overlay 0 */ + overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ + outpdw(overlay_base + 0x000c, addr); + outpdw(overlay_base + 0x001c, addr); +} + +static void mdp4_dsi_video_blt_dmap_update(struct mdp4_overlay_pipe *pipe) +{ + uint32 off, addr; + int bpp; + + if (pipe->blt_addr == 0) + return; + + +#ifdef BLT_RGB565 + bpp = 2; /* overlay ouput is RGB565 */ +#else + bpp = 3; /* overlay ouput is RGB888 */ +#endif + off = 0; + if (pipe->dmap_cnt & 0x01) + off = pipe->src_height * pipe->src_width * bpp; + addr = pipe->blt_addr + off; + + /* dmap */ + MDP_OUTP(MDP_BASE + 0x90008, addr); +} + +/* + * mdp4_overlay_dsi_video_wait4event: + * INTR_DMA_P_DONE and INTR_PRIMARY_VSYNC event only + * no INTR_OVERLAY0_DONE event allowed. + */ +static void mdp4_overlay_dsi_video_wait4event(struct msm_fb_data_type *mfd, + int intr_done) +{ + unsigned long flag; + unsigned int data; + + data = inpdw(MDP_BASE + DSI_VIDEO_BASE); + data &= 0x01; + if (data == 0) /* timing generator disabled */ + return; + + spin_lock_irqsave(&mdp_spin_lock, flag); + INIT_COMPLETION(dsi_video_comp); + mfd->dma->waiting = TRUE; + outp32(MDP_INTR_CLEAR, intr_done); + mdp_intr_mask |= intr_done; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + mdp_enable_irq(MDP_DMA2_TERM); /* enable intr */ + spin_unlock_irqrestore(&mdp_spin_lock, flag); + wait_for_completion(&dsi_video_comp); + mdp_disable_irq(MDP_DMA2_TERM); +} + +static void mdp4_overlay_dsi_video_dma_busy_wait(struct msm_fb_data_type *mfd) +{ + unsigned long flag; + int need_wait = 0; + + pr_debug("%s: start pid=%d\n", __func__, current->pid); + + spin_lock_irqsave(&mdp_spin_lock, flag); + if (mfd->dma->busy == TRUE) { + INIT_COMPLETION(mfd->dma->comp); + need_wait++; + } + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + if (need_wait) { + /* wait until DMA finishes the current job */ + pr_debug("%s: pending pid=%d\n", __func__, current->pid); + wait_for_completion(&mfd->dma->comp); + } + pr_debug("%s: done pid=%d\n", __func__, current->pid); +} + +void mdp4_overlay_dsi_video_start(void) +{ + if (!dsi_video_enabled) { + /* enable DSI block */ + mdp4_iommu_attach(); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 1); + mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + dsi_video_enabled = 1; + } +} + +void mdp4_overlay_dsi_video_vsync_push(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + unsigned long flag; + + if (pipe->flags & MDP_OV_PLAY_NOWAIT) + return; + + if (dsi_pipe->blt_addr) { + mdp4_overlay_dsi_video_dma_busy_wait(mfd); + + mdp4_dsi_video_blt_ov_update(dsi_pipe); + dsi_pipe->ov_cnt++; + + spin_lock_irqsave(&mdp_spin_lock, flag); + outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE); + mdp_intr_mask |= INTR_OVERLAY0_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + mdp_enable_irq(MDP_OVERLAY0_TERM); + mfd->dma->busy = TRUE; + mb(); /* make sure all registers updated */ + spin_unlock_irqrestore(&mdp_spin_lock, flag); + outpdw(MDP_BASE + 0x0004, 0); /* kickoff overlay engine */ + mdp4_stat.kickoff_ov0++; + mb(); + mdp4_overlay_dsi_video_wait4event(mfd, INTR_DMA_P_DONE); + } else { + mdp4_overlay_dsi_video_wait4event(mfd, INTR_PRIMARY_VSYNC); + } + + mdp4_set_perf_level(); +} + +/* + * mdp4_primary_vsync_dsi_video: called from isr + */ +void mdp4_primary_vsync_dsi_video(void) +{ + complete_all(&dsi_video_comp); +} + + /* + * mdp4_dma_p_done_dsi_video: called from isr + */ +void mdp4_dma_p_done_dsi_video(struct mdp_dma_data *dma) +{ + if (blt_cfg_changed) { + mdp_is_in_isr = TRUE; + mdp4_overlayproc_cfg(dsi_pipe); + mdp4_overlay_dmap_xy(dsi_pipe); + mdp_is_in_isr = FALSE; + if (dsi_pipe->blt_addr) { + mdp4_dsi_video_blt_ov_update(dsi_pipe); + dsi_pipe->ov_cnt++; + outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE); + mdp_intr_mask |= INTR_OVERLAY0_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + dma->busy = TRUE; + mdp_enable_irq(MDP_OVERLAY0_TERM); + /* kickoff overlay engine */ + outpdw(MDP_BASE + 0x0004, 0); + } + blt_cfg_changed = 0; + } + complete_all(&dsi_video_comp); +} + +/* + * mdp4_overlay1_done_dsi: called from isr + */ +void mdp4_overlay0_done_dsi_video(struct mdp_dma_data *dma) +{ + spin_lock(&mdp_spin_lock); + dma->busy = FALSE; + if (dsi_pipe->blt_addr == 0) { + spin_unlock(&mdp_spin_lock); + return; + } + mdp4_dsi_video_blt_dmap_update(dsi_pipe); + dsi_pipe->dmap_cnt++; + mdp_disable_irq_nosync(MDP_OVERLAY0_TERM); + spin_unlock(&mdp_spin_lock); + complete(&dma->comp); +} + +/* + * make sure the MIPI_DSI_WRITEBACK_SIZE defined at boardfile + * has enough space h * w * 3 * 2 + */ +static void mdp4_dsi_video_do_blt(struct msm_fb_data_type *mfd, int enable) +{ + unsigned long flag; + int data; + int change = 0; + + mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0); + + if (mfd->ov0_wb_buf->phys_addr == 0) { + pr_info("%s: no blt_base assigned\n", __func__); + return; + } + + spin_lock_irqsave(&mdp_spin_lock, flag); + if (enable && dsi_pipe->blt_addr == 0) { + dsi_pipe->blt_addr = mfd->ov0_wb_buf->phys_addr; + dsi_pipe->blt_cnt = 0; + dsi_pipe->ov_cnt = 0; + dsi_pipe->dmap_cnt = 0; + mdp4_stat.blt_dsi_video++; + change++; + } else if (enable == 0 && dsi_pipe->blt_addr) { + dsi_pipe->blt_addr = 0; + change++; + } + + if (!change) { + spin_unlock_irqrestore(&mdp_spin_lock, flag); + return; + } + + pr_debug("%s: enable=%d blt_addr=%x\n", __func__, + enable, (int)dsi_pipe->blt_addr); + blt_cfg_changed = 1; + + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + /* + * may need mutex here to sync with whom dsiable + * timing generator + */ + data = inpdw(MDP_BASE + DSI_VIDEO_BASE); + data &= 0x01; + if (data) { /* timing generator enabled */ + mdp4_overlay_dsi_video_wait4event(mfd, INTR_DMA_P_DONE); + mdp4_overlay_dsi_video_wait4event(mfd, INTR_PRIMARY_VSYNC); + } + + +} + +int mdp4_dsi_video_overlay_blt_offset(struct msm_fb_data_type *mfd, + struct msmfb_overlay_blt *req) +{ + req->offset = 0; + req->width = dsi_pipe->src_width; + req->height = dsi_pipe->src_height; + req->bpp = dsi_pipe->bpp; + + return sizeof(*req); +} + +void mdp4_dsi_video_overlay_blt(struct msm_fb_data_type *mfd, + struct msmfb_overlay_blt *req) +{ + mdp4_dsi_video_do_blt(mfd, req->enable); +} + +void mdp4_dsi_video_blt_start(struct msm_fb_data_type *mfd) +{ + mdp4_dsi_video_do_blt(mfd, 1); +} + +void mdp4_dsi_video_blt_stop(struct msm_fb_data_type *mfd) +{ + mdp4_dsi_video_do_blt(mfd, 0); +} + +void mdp4_dsi_video_overlay(struct msm_fb_data_type *mfd) +{ + struct fb_info *fbi = mfd->fbi; + uint8 *buf; + unsigned int buf_offset; + int bpp; + struct mdp4_overlay_pipe *pipe; + + if (!mfd->panel_power_on) + return; + + /* no need to power on cmd block since it's dsi video mode */ + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + buf_offset = calc_fb_offset(mfd, fbi, bpp); + + mutex_lock(&mfd->dma->ov_mutex); + + pipe = dsi_pipe; + if (pipe->pipe_used == 0 || + pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) { + pr_err("%s: NOT baselayer\n", __func__); + mutex_unlock(&mfd->dma->ov_mutex); + return; + } + + if (mfd->display_iova) + pipe->srcp0_addr = mfd->display_iova + buf_offset; + else + pipe->srcp0_addr = (uint32)(buf + buf_offset); + + mdp4_overlay_rgb_setup(pipe); + mdp4_overlay_reg_flush(pipe, 1); + mdp4_mixer_stage_up(pipe); + mdp4_overlay_dsi_video_start(); + mdp4_overlay_dsi_video_vsync_push(mfd, pipe); + mdp4_iommu_unmap(pipe); + mutex_unlock(&mfd->dma->ov_mutex); +} diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c new file mode 100644 index 000000000000..534daa487e33 --- /dev/null +++ b/drivers/video/msm/mdp4_overlay_dtv.c @@ -0,0 +1,728 @@ +/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mdp.h" +#include "msm_fb.h" +#include "mdp4.h" + +#define DTV_BASE 0xD0000 + +/*#define DEBUG*/ +#ifdef DEBUG +static void __mdp_outp(uint32 port, uint32 value) +{ + uint32 in_val; + + outpdw(port, value); + in_val = inpdw(port); + printk(KERN_INFO "MDP-DTV[%04x] => %08x [%08x]\n", + port-(uint32)(MDP_BASE + DTV_BASE), value, in_val); +} + +#undef MDP_OUTP +#define MDP_OUTP(port, value) __mdp_outp((uint32)(port), (value)) +#endif + +static int first_pixel_start_x; +static int first_pixel_start_y; +static int dtv_enabled; + +static struct mdp4_overlay_pipe *dtv_pipe; +static DECLARE_COMPLETION(dtv_comp); + +void mdp4_dtv_base_swap(struct mdp4_overlay_pipe *pipe) +{ + if (hdmi_prim_display) + dtv_pipe = pipe; +} + +static int mdp4_dtv_start(struct msm_fb_data_type *mfd) +{ + int dtv_width; + int dtv_height; + int dtv_bpp; + int dtv_border_clr; + int dtv_underflow_clr; + int dtv_hsync_skew; + + int hsync_period; + int hsync_ctrl; + int vsync_period; + int display_hctl; + int display_v_start; + int display_v_end; + int active_hctl; + int active_h_start; + int active_h_end; + int active_v_start; + int active_v_end; + int ctrl_polarity; + int h_back_porch; + int h_front_porch; + int v_back_porch; + int v_front_porch; + int hsync_pulse_width; + int vsync_pulse_width; + int hsync_polarity; + int vsync_polarity; + int data_en_polarity; + int hsync_start_x; + int hsync_end_x; + struct fb_info *fbi; + struct fb_var_screeninfo *var; + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (dtv_pipe == NULL) + return -EINVAL; + + fbi = mfd->fbi; + var = &fbi->var; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + if (hdmi_prim_display) { + if (is_mdp4_hw_reset()) { + mdp4_hw_init(); + outpdw(MDP_BASE + 0x0038, mdp4_display_intf); + } + } + mdp4_overlay_dmae_cfg(mfd, 0); + + /* + * DTV timing setting + */ + h_back_porch = var->left_margin; + h_front_porch = var->right_margin; + v_back_porch = var->upper_margin; + v_front_porch = var->lower_margin; + hsync_pulse_width = var->hsync_len; + vsync_pulse_width = var->vsync_len; + dtv_border_clr = mfd->panel_info.lcdc.border_clr; + dtv_underflow_clr = mfd->panel_info.lcdc.underflow_clr; + dtv_hsync_skew = mfd->panel_info.lcdc.hsync_skew; + + pr_info("%s: \n", __func__, + var->reserved[3], var->xres, var->yres, + var->right_margin, var->hsync_len, var->left_margin, + var->lower_margin, var->vsync_len, var->upper_margin, + var->pixclock/1000/1000); + + dtv_width = var->xres; + dtv_height = var->yres; + dtv_bpp = mfd->panel_info.bpp; + + hsync_period = + hsync_pulse_width + h_back_porch + dtv_width + h_front_porch; + hsync_ctrl = (hsync_period << 16) | hsync_pulse_width; + hsync_start_x = hsync_pulse_width + h_back_porch; + hsync_end_x = hsync_period - h_front_porch - 1; + display_hctl = (hsync_end_x << 16) | hsync_start_x; + + vsync_period = + (vsync_pulse_width + v_back_porch + dtv_height + + v_front_porch) * hsync_period; + display_v_start = + (vsync_pulse_width + v_back_porch) * hsync_period + dtv_hsync_skew; + display_v_end = + vsync_period - (v_front_porch * hsync_period) + dtv_hsync_skew - 1; + + if (dtv_width != var->xres) { + active_h_start = hsync_start_x + first_pixel_start_x; + active_h_end = active_h_start + var->xres - 1; + active_hctl = + ACTIVE_START_X_EN | (active_h_end << 16) | active_h_start; + } else { + active_hctl = 0; + } + + if (dtv_height != var->yres) { + active_v_start = + display_v_start + first_pixel_start_y * hsync_period; + active_v_end = active_v_start + (var->yres) * hsync_period - 1; + active_v_start |= ACTIVE_START_Y_EN; + } else { + active_v_start = 0; + active_v_end = 0; + } + + dtv_underflow_clr |= 0x80000000; /* enable recovery */ + hsync_polarity = fbi->var.yres >= 720 ? 0 : 1; + vsync_polarity = fbi->var.yres >= 720 ? 0 : 1; + data_en_polarity = 0; + + ctrl_polarity = + (data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity); + + + MDP_OUTP(MDP_BASE + DTV_BASE + 0x4, hsync_ctrl); + MDP_OUTP(MDP_BASE + DTV_BASE + 0x8, vsync_period); + MDP_OUTP(MDP_BASE + DTV_BASE + 0xc, vsync_pulse_width * hsync_period); + MDP_OUTP(MDP_BASE + DTV_BASE + 0x18, display_hctl); + MDP_OUTP(MDP_BASE + DTV_BASE + 0x1c, display_v_start); + MDP_OUTP(MDP_BASE + DTV_BASE + 0x20, display_v_end); + MDP_OUTP(MDP_BASE + DTV_BASE + 0x40, dtv_border_clr); + MDP_OUTP(MDP_BASE + DTV_BASE + 0x44, dtv_underflow_clr); + MDP_OUTP(MDP_BASE + DTV_BASE + 0x48, dtv_hsync_skew); + MDP_OUTP(MDP_BASE + DTV_BASE + 0x50, ctrl_polarity); + MDP_OUTP(MDP_BASE + DTV_BASE + 0x2c, active_hctl); + MDP_OUTP(MDP_BASE + DTV_BASE + 0x30, active_v_start); + MDP_OUTP(MDP_BASE + DTV_BASE + 0x38, active_v_end); + + /* Test pattern 8 x 8 pixel */ + /* MDP_OUTP(MDP_BASE + DTV_BASE + 0x4C, 0x80000808); */ + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + return 0; +} + +static int mdp4_dtv_stop(struct msm_fb_data_type *mfd) +{ + if (dtv_pipe == NULL) + return -EINVAL; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + msleep(20); + MDP_OUTP(MDP_BASE + DTV_BASE, 0); + dtv_enabled = 0; + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + return 0; +} + +int mdp4_dtv_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + int ret = 0; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + mdp_footswitch_ctrl(TRUE); + mdp4_overlay_panel_mode(MDP4_MIXER1, MDP4_PANEL_DTV); + + /* Allocate dtv_pipe at dtv_on*/ + if (dtv_pipe == NULL) { + if (mdp4_overlay_dtv_set(mfd, NULL)) { + pr_warn("%s: dtv_pipe is NULL, dtv_set failed\n", + __func__); + return -EINVAL; + } + } + + ret = panel_next_on(pdev); + if (ret != 0) + dev_warn(&pdev->dev, "mdp4_overlay_dtv: panel_next_on failed"); + + dev_info(&pdev->dev, "mdp4_overlay_dtv: on"); + + return ret; +} + +int mdp4_dtv_off(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + int ret = 0; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if (dtv_pipe != NULL) { + mdp4_dtv_stop(mfd); + if (hdmi_prim_display && mfd->ref_cnt == 0) { + /* adb stop */ + if (dtv_pipe->pipe_type == OVERLAY_TYPE_BF) + mdp4_overlay_borderfill_stage_down(dtv_pipe); + + /* dtv_pipe == rgb1 */ + mdp4_overlay_unset_mixer(dtv_pipe->mixer_num); + dtv_pipe = NULL; + } else { + mdp4_mixer_stage_down(dtv_pipe); + mdp4_overlay_pipe_free(dtv_pipe); + mdp4_iommu_unmap(dtv_pipe); + dtv_pipe = NULL; + } + } + mdp4_overlay_panel_mode_unset(MDP4_MIXER1, MDP4_PANEL_DTV); + + ret = panel_next_off(pdev); + mdp_footswitch_ctrl(FALSE); + + dev_info(&pdev->dev, "mdp4_overlay_dtv: off"); + return ret; +} + +static void mdp4_overlay_dtv_alloc_pipe(struct msm_fb_data_type *mfd, + int32 ptype) +{ + int ret = 0; + struct fb_info *fbi = mfd->fbi; + struct mdp4_overlay_pipe *pipe; + + if (dtv_pipe != NULL) + return; + + pr_debug("%s: ptype=%d\n", __func__, ptype); + + pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER1); + if (pipe == NULL) { + pr_err("%s: pipe_alloc failed\n", __func__); + return; + } + pipe->pipe_used++; + pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; + pipe->mixer_num = MDP4_MIXER1; + + if (ptype == OVERLAY_TYPE_BF) { + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + /* LSP_BORDER_COLOR */ + MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5004, + ((0x0 & 0xFFF) << 16) | /* 12-bit B */ + (0x0 & 0xFFF)); /* 12-bit G */ + /* MSP_BORDER_COLOR */ + MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5008, + (0x0 & 0xFFF)); /* 12-bit R */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + } else { + switch (mfd->ibuf.bpp) { + case 2: + pipe->src_format = MDP_RGB_565; + break; + case 3: + pipe->src_format = MDP_RGB_888; + break; + case 4: + default: + if (hdmi_prim_display) + pipe->src_format = MSMFB_DEFAULT_TYPE; + else + pipe->src_format = MDP_ARGB_8888; + break; + } + } + + pipe->src_height = fbi->var.yres; + pipe->src_width = fbi->var.xres; + pipe->src_h = fbi->var.yres; + pipe->src_w = fbi->var.xres; + pipe->src_y = 0; + pipe->src_x = 0; + pipe->srcp0_ystride = fbi->fix.line_length; + + ret = mdp4_overlay_format2pipe(pipe); + if (ret < 0) + pr_warn("%s: format2type failed\n", __func__); + + mdp4_overlay_dmae_xy(pipe); /* dma_e */ + mdp4_overlayproc_cfg(pipe); + + if (pipe->pipe_type == OVERLAY_TYPE_RGB) { + pipe->srcp0_addr = (uint32) mfd->ibuf.buf; + mdp4_overlay_rgb_setup(pipe); + } + + mdp4_overlay_reg_flush(pipe, 1); + mdp4_mixer_stage_up(pipe); + + dtv_pipe = pipe; /* keep it */ +} + +int mdp4_overlay_dtv_set(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + if (dtv_pipe != NULL) + return 0; + + if (pipe != NULL && pipe->mixer_stage == MDP4_MIXER_STAGE_BASE && + pipe->pipe_type == OVERLAY_TYPE_RGB) + dtv_pipe = pipe; /* keep it */ + else if (!hdmi_prim_display && mdp4_overlay_borderfill_supported()) + mdp4_overlay_dtv_alloc_pipe(mfd, OVERLAY_TYPE_BF); + else + mdp4_overlay_dtv_alloc_pipe(mfd, OVERLAY_TYPE_RGB); + if (dtv_pipe == NULL) + return -ENODEV; + + mdp4_init_writeback_buf(mfd, MDP4_MIXER1); + dtv_pipe->blt_addr = 0; + + return mdp4_dtv_start(mfd); +} + +int mdp4_overlay_dtv_unset(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + int result = 0; + + if (dtv_pipe == NULL) + return result; + + pipe->flags &= ~MDP_OV_PLAY_NOWAIT; + mdp4_overlay_reg_flush(pipe, 0); + mdp4_overlay_dtv_ov_done_push(mfd, pipe); + + if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE && + pipe->pipe_type == OVERLAY_TYPE_RGB) { + result = mdp4_dtv_stop(mfd); + dtv_pipe = NULL; + } + return result; +} + +static void mdp4_dtv_blt_ov_update(struct mdp4_overlay_pipe *pipe) +{ + uint32 off, addr; + int bpp; + char *overlay_base; + + if (pipe->blt_addr == 0) + return; +#ifdef BLT_RGB565 + bpp = 2; /* overlay ouput is RGB565 */ +#else + bpp = 3; /* overlay ouput is RGB888 */ +#endif + off = (pipe->ov_cnt & 0x01) ? + pipe->src_height * pipe->src_width * bpp : 0; + + addr = pipe->blt_addr + off; + pr_debug("%s overlay addr 0x%x\n", __func__, addr); + /* overlay 1 */ + overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */ + outpdw(overlay_base + 0x000c, addr); + outpdw(overlay_base + 0x001c, addr); +} + +static inline void mdp4_dtv_blt_dmae_update(struct mdp4_overlay_pipe *pipe) +{ + uint32 off, addr; + int bpp; + + if (pipe->blt_addr == 0) + return; + +#ifdef BLT_RGB565 + bpp = 2; /* overlay ouput is RGB565 */ +#else + bpp = 3; /* overlay ouput is RGB888 */ +#endif + off = (pipe->dmae_cnt & 0x01) ? + pipe->src_height * pipe->src_width * bpp : 0; + addr = pipe->blt_addr + off; + MDP_OUTP(MDP_BASE + 0xb0008, addr); +} + +static inline void mdp4_overlay_dtv_ov_kick_start(void) +{ + outpdw(MDP_BASE + 0x0008, 0); +} + +static void mdp4_overlay_dtv_ov_start(struct msm_fb_data_type *mfd) +{ + unsigned long flag; + + /* enable irq */ + if (mfd->ov_start) + return; + + if (!dtv_pipe) { + pr_debug("%s: no mixer1 base layer pipe allocated!\n", + __func__); + return; + } + + if (dtv_pipe->blt_addr) { + mdp4_dtv_blt_ov_update(dtv_pipe); + dtv_pipe->ov_cnt++; + mdp4_overlay_dtv_ov_kick_start(); + } + + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_enable_irq(MDP_OVERLAY1_TERM); + INIT_COMPLETION(dtv_pipe->comp); + mfd->dma->waiting = TRUE; + outp32(MDP_INTR_CLEAR, INTR_OVERLAY1_DONE); + mdp_intr_mask |= INTR_OVERLAY1_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + spin_unlock_irqrestore(&mdp_spin_lock, flag); + mfd->ov_start = true; +} + +static void mdp4_overlay_dtv_wait4dmae(struct msm_fb_data_type *mfd) +{ + unsigned long flag; + + if (!dtv_pipe) { + pr_debug("%s: no mixer1 base layer pipe allocated!\n", + __func__); + return; + } + /* enable irq */ + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_enable_irq(MDP_DMA_E_TERM); + INIT_COMPLETION(dtv_pipe->comp); + mfd->dma->waiting = TRUE; + outp32(MDP_INTR_CLEAR, INTR_DMA_E_DONE); + mdp_intr_mask |= INTR_DMA_E_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + spin_unlock_irqrestore(&mdp_spin_lock, flag); + wait_for_completion_killable(&dtv_pipe->comp); + mdp_disable_irq(MDP_DMA_E_TERM); +} + +static void mdp4_overlay_dtv_wait4_ov_done(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + u32 data = inpdw(MDP_BASE + DTV_BASE); + + if (mfd->ov_start) + mfd->ov_start = false; + else + return; + if (!(data & 0x1) || (pipe == NULL)) + return; + if (!dtv_pipe) { + pr_debug("%s: no mixer1 base layer pipe allocated!\n", + __func__); + return; + } + + wait_for_completion_timeout(&dtv_pipe->comp, + msecs_to_jiffies(VSYNC_PERIOD*2)); + mdp_disable_irq(MDP_OVERLAY1_TERM); + + if (dtv_pipe->blt_addr) + mdp4_overlay_dtv_wait4dmae(mfd); +} + +void mdp4_overlay_dtv_start(void) +{ + if (!dtv_enabled) { + mdp4_iommu_attach(); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + /* enable DTV block */ + MDP_OUTP(MDP_BASE + DTV_BASE, 1); + mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + dtv_enabled = 1; + } +} + +void mdp4_overlay_dtv_ov_done_push(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + mdp4_overlay_dtv_ov_start(mfd); + if (pipe->flags & MDP_OV_PLAY_NOWAIT) + return; + + mdp4_overlay_dtv_wait4_ov_done(mfd, pipe); + + /* change mdp clk while mdp is idle` */ + mdp4_set_perf_level(); +} + +void mdp4_overlay_dtv_wait_for_ov(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + mdp4_overlay_dtv_wait4_ov_done(mfd, pipe); + mdp4_set_perf_level(); +} + +void mdp4_dma_e_done_dtv() +{ + if (!dtv_pipe) + return; + + complete(&dtv_pipe->comp); +} + +void mdp4_external_vsync_dtv() +{ + + complete_all(&dtv_comp); +} + +/* + * mdp4_overlay1_done_dtv: called from isr + */ +void mdp4_overlay1_done_dtv() +{ + if (!dtv_pipe) + return; + if (dtv_pipe->blt_addr) { + mdp4_dtv_blt_dmae_update(dtv_pipe); + dtv_pipe->dmae_cnt++; + } + complete_all(&dtv_pipe->comp); +} + +void mdp4_dtv_set_black_screen(void) +{ + char *rgb_base; + /*Black color*/ + uint32 color = 0x00000000; + uint32 temp_src_format; + + if (!dtv_pipe || !hdmi_prim_display) { + pr_err("dtv_pipe/hdmi as primary are not" + " configured yet\n"); + return; + } + rgb_base = MDP_BASE + MDP4_RGB_BASE; + rgb_base += (MDP4_RGB_OFF * dtv_pipe->pipe_num); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + /* + * RGB Constant Color + */ + MDP_OUTP(rgb_base + 0x1008, color); + /* + * MDP_RGB_SRC_FORMAT + */ + temp_src_format = inpdw(rgb_base + 0x0050); + MDP_OUTP(rgb_base + 0x0050, temp_src_format | BIT(22)); + mdp4_overlay_reg_flush(dtv_pipe, 1); + mdp4_mixer_stage_up(dtv_pipe); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_overlay_dtv_wait4vsync(void) +{ + unsigned long flag; + + if (!dtv_enabled) + return; + + /* enable irq */ + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_enable_irq(MDP_DMA_E_TERM); + INIT_COMPLETION(dtv_comp); + outp32(MDP_INTR_CLEAR, INTR_EXTERNAL_VSYNC); + mdp_intr_mask |= INTR_EXTERNAL_VSYNC; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + spin_unlock_irqrestore(&mdp_spin_lock, flag); + wait_for_completion_killable(&dtv_comp); + mdp_disable_irq(MDP_DMA_E_TERM); +} + +static void mdp4_dtv_do_blt(struct msm_fb_data_type *mfd, int enable) +{ + unsigned long flag; + int change = 0; + + if (!mfd->ov1_wb_buf->phys_addr) { + pr_debug("%s: no writeback buf assigned\n", __func__); + return; + } + + if (!dtv_pipe) { + pr_debug("%s: no mixer1 base layer pipe allocated!\n", + __func__); + return; + } + + spin_lock_irqsave(&mdp_spin_lock, flag); + if (enable && dtv_pipe->blt_addr == 0) { + dtv_pipe->blt_addr = mfd->ov1_wb_buf->phys_addr; + change++; + dtv_pipe->ov_cnt = 0; + dtv_pipe->dmae_cnt = 0; + } else if (enable == 0 && dtv_pipe->blt_addr) { + dtv_pipe->blt_addr = 0; + change++; + } + pr_debug("%s: blt_addr=%x\n", __func__, (int)dtv_pipe->blt_addr); + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + if (!change) + return; + + mdp4_overlay_dtv_wait4dmae(mfd); + + MDP_OUTP(MDP_BASE + DTV_BASE, 0); /* stop dtv */ + msleep(20); + mdp4_overlayproc_cfg(dtv_pipe); + mdp4_overlay_dmae_xy(dtv_pipe); + MDP_OUTP(MDP_BASE + DTV_BASE, 1); /* start dtv */ +} + +void mdp4_dtv_overlay_blt_start(struct msm_fb_data_type *mfd) +{ + mdp4_dtv_do_blt(mfd, 1); +} + +void mdp4_dtv_overlay_blt_stop(struct msm_fb_data_type *mfd) +{ + mdp4_dtv_do_blt(mfd, 0); +} + +void mdp4_dtv_overlay(struct msm_fb_data_type *mfd) +{ + struct mdp4_overlay_pipe *pipe; + if (!mfd->panel_power_on) + return; + if (!dtv_pipe) { + pr_debug("%s: no mixer1 base layer pipe allocated!\n", + __func__); + return; + } + mutex_lock(&mfd->dma->ov_mutex); + pipe = dtv_pipe; + + if (hdmi_prim_display && (pipe->pipe_used == 0 || + pipe->mixer_stage != MDP4_MIXER_STAGE_BASE)) { + pr_err("%s: NOT baselayer\n", __func__); + mutex_unlock(&mfd->dma->ov_mutex); + return; + } + + if (pipe->pipe_type == OVERLAY_TYPE_RGB) { + pipe->srcp0_addr = (uint32) mfd->ibuf.buf; + mdp4_overlay_rgb_setup(pipe); + } + mdp4_overlay_reg_flush(pipe, 1); + mdp4_mixer_stage_up(pipe); + mdp4_overlay_dtv_start(); + mdp4_overlay_dtv_ov_done_push(mfd, pipe); + mdp4_iommu_unmap(pipe); + mutex_unlock(&mfd->dma->ov_mutex); +} diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c new file mode 100644 index 000000000000..6620d0231f9c --- /dev/null +++ b/drivers/video/msm/mdp4_overlay_lcdc.c @@ -0,0 +1,621 @@ +/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "mdp.h" +#include "msm_fb.h" +#include "mdp4.h" + +#ifdef CONFIG_FB_MSM_MDP40 +#define LCDC_BASE 0xC0000 +#else +#define LCDC_BASE 0xE0000 +#endif + +int first_pixel_start_x; +int first_pixel_start_y; +static int lcdc_enabled; + +static struct mdp4_overlay_pipe *lcdc_pipe; +static struct completion lcdc_comp; + +void mdp4_lcdc_base_swap(struct mdp4_overlay_pipe *pipe) +{ + lcdc_pipe = pipe; +} + +int mdp_lcdc_on(struct platform_device *pdev) +{ + int lcdc_width; + int lcdc_height; + int lcdc_bpp; + int lcdc_border_clr; + int lcdc_underflow_clr; + int lcdc_hsync_skew; + + int hsync_period; + int hsync_ctrl; + int vsync_period; + int display_hctl; + int display_v_start; + int display_v_end; + int active_hctl; + int active_h_start; + int active_h_end; + int active_v_start; + int active_v_end; + int ctrl_polarity; + int h_back_porch; + int h_front_porch; + int v_back_porch; + int v_front_porch; + int hsync_pulse_width; + int vsync_pulse_width; + int hsync_polarity; + int vsync_polarity; + int data_en_polarity; + int hsync_start_x; + int hsync_end_x; + uint8 *buf; + unsigned int buf_offset; + int bpp, ptype; + struct fb_info *fbi; + struct fb_var_screeninfo *var; + struct msm_fb_data_type *mfd; + struct mdp4_overlay_pipe *pipe; + int ret; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + fbi = mfd->fbi; + var = &fbi->var; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + if (is_mdp4_hw_reset()) { + mdp4_hw_init(); + outpdw(MDP_BASE + 0x0038, mdp4_display_intf); + } + + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + buf_offset = calc_fb_offset(mfd, fbi, bpp); + + if (lcdc_pipe == NULL) { + ptype = mdp4_overlay_format2type(mfd->fb_imgType); + if (ptype < 0) + printk(KERN_INFO "%s: format2type failed\n", __func__); + pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0); + if (pipe == NULL) + printk(KERN_INFO "%s: pipe_alloc failed\n", __func__); + pipe->pipe_used++; + pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; + pipe->mixer_num = MDP4_MIXER0; + pipe->src_format = mfd->fb_imgType; + mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_LCDC); + ret = mdp4_overlay_format2pipe(pipe); + if (ret < 0) + printk(KERN_INFO "%s: format2pipe failed\n", __func__); + lcdc_pipe = pipe; /* keep it */ + init_completion(&lcdc_comp); + + mdp4_init_writeback_buf(mfd, MDP4_MIXER0); + pipe->blt_addr = 0; + + } else { + pipe = lcdc_pipe; + } + + pipe->src_height = fbi->var.yres; + pipe->src_width = fbi->var.xres; + pipe->src_h = fbi->var.yres; + pipe->src_w = fbi->var.xres; + pipe->src_y = 0; + pipe->src_x = 0; + + if (mfd->display_iova) + pipe->srcp0_addr = mfd->display_iova + buf_offset; + else + pipe->srcp0_addr = (uint32)(buf + buf_offset); + + pipe->srcp0_ystride = fbi->fix.line_length; + pipe->bpp = bpp; + + mdp4_overlay_dmap_xy(pipe); + mdp4_overlay_dmap_cfg(mfd, 1); + + mdp4_overlay_rgb_setup(pipe); + mdp4_overlay_reg_flush(pipe, 1); + mdp4_mixer_stage_up(pipe); + + mdp4_overlayproc_cfg(pipe); + + /* + * LCDC timing setting + */ + h_back_porch = var->left_margin; + h_front_porch = var->right_margin; + v_back_porch = var->upper_margin; + v_front_porch = var->lower_margin; + hsync_pulse_width = var->hsync_len; + vsync_pulse_width = var->vsync_len; + lcdc_border_clr = mfd->panel_info.lcdc.border_clr; + lcdc_underflow_clr = mfd->panel_info.lcdc.underflow_clr; + lcdc_hsync_skew = mfd->panel_info.lcdc.hsync_skew; + + lcdc_width = var->xres + mfd->panel_info.lcdc.xres_pad; + lcdc_height = var->yres + mfd->panel_info.lcdc.yres_pad; + lcdc_bpp = mfd->panel_info.bpp; + + hsync_period = + hsync_pulse_width + h_back_porch + lcdc_width + h_front_porch; + hsync_ctrl = (hsync_period << 16) | hsync_pulse_width; + hsync_start_x = hsync_pulse_width + h_back_porch; + hsync_end_x = hsync_period - h_front_porch - 1; + display_hctl = (hsync_end_x << 16) | hsync_start_x; + + vsync_period = + (vsync_pulse_width + v_back_porch + lcdc_height + + v_front_porch) * hsync_period; + display_v_start = + (vsync_pulse_width + v_back_porch) * hsync_period + lcdc_hsync_skew; + display_v_end = + vsync_period - (v_front_porch * hsync_period) + lcdc_hsync_skew - 1; + + if (lcdc_width != var->xres) { + active_h_start = hsync_start_x + first_pixel_start_x; + active_h_end = active_h_start + var->xres - 1; + active_hctl = + ACTIVE_START_X_EN | (active_h_end << 16) | active_h_start; + } else { + active_hctl = 0; + } + + if (lcdc_height != var->yres) { + active_v_start = + display_v_start + first_pixel_start_y * hsync_period; + active_v_end = active_v_start + (var->yres) * hsync_period - 1; + active_v_start |= ACTIVE_START_Y_EN; + } else { + active_v_start = 0; + active_v_end = 0; + } + + +#ifdef CONFIG_FB_MSM_MDP40 + hsync_polarity = 1; + vsync_polarity = 1; + lcdc_underflow_clr |= 0x80000000; /* enable recovery */ +#else + hsync_polarity = 0; + vsync_polarity = 0; +#endif + data_en_polarity = 0; + + ctrl_polarity = + (data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity); + + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x4, hsync_ctrl); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x8, vsync_period); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0xc, vsync_pulse_width * hsync_period); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x10, display_hctl); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x14, display_v_start); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x18, display_v_end); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x28, lcdc_border_clr); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x2c, lcdc_underflow_clr); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x30, lcdc_hsync_skew); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x38, ctrl_polarity); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x1c, active_hctl); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x20, active_v_start); + MDP_OUTP(MDP_BASE + LCDC_BASE + 0x24, active_v_end); + + mdp4_overlay_reg_flush(pipe, 1); + mdp4_mixer_stage_up(pipe); + +#ifdef CONFIG_MSM_BUS_SCALING + mdp_bus_scale_update_request(2); +#endif + mdp_histogram_ctrl_all(TRUE); + + ret = panel_next_on(pdev); + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + return ret; +} + +int mdp_lcdc_off(struct platform_device *pdev) +{ + int ret = 0; + struct msm_fb_data_type *mfd; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + mutex_lock(&mfd->dma->ov_mutex); + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + MDP_OUTP(MDP_BASE + LCDC_BASE, 0); + lcdc_enabled = 0; + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + mdp_histogram_ctrl_all(FALSE); + ret = panel_next_off(pdev); + + mutex_unlock(&mfd->dma->ov_mutex); + + /* delay to make sure the last frame finishes */ + msleep(20); + + /* dis-engage rgb0 from mixer0 */ + if (lcdc_pipe) { + if (mfd->ref_cnt == 0) { + /* adb stop */ + if (lcdc_pipe->pipe_type == OVERLAY_TYPE_BF) + mdp4_overlay_borderfill_stage_down(lcdc_pipe); + + /* lcdc_pipe == rgb1 */ + mdp4_overlay_unset_mixer(lcdc_pipe->mixer_num); + lcdc_pipe = NULL; + } else { + mdp4_mixer_stage_down(lcdc_pipe); + mdp4_iommu_unmap(lcdc_pipe); + } + } + +#ifdef CONFIG_MSM_BUS_SCALING + mdp_bus_scale_update_request(0); +#endif + + return ret; +} + +static void mdp4_lcdc_blt_ov_update(struct mdp4_overlay_pipe *pipe) +{ + uint32 off, addr; + int bpp; + char *overlay_base; + + + if (pipe->blt_addr == 0) + return; + + +#ifdef BLT_RGB565 + bpp = 2; /* overlay ouput is RGB565 */ +#else + bpp = 3; /* overlay ouput is RGB888 */ +#endif + off = 0; + if (pipe->ov_cnt & 0x01) + off = pipe->src_height * pipe->src_width * bpp; + addr = pipe->blt_addr + off; + + /* overlay 0 */ + overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ + outpdw(overlay_base + 0x000c, addr); + outpdw(overlay_base + 0x001c, addr); +} + +static void mdp4_lcdc_blt_dmap_update(struct mdp4_overlay_pipe *pipe) +{ + uint32 off, addr; + int bpp; + + if (pipe->blt_addr == 0) + return; + + +#ifdef BLT_RGB565 + bpp = 2; /* overlay ouput is RGB565 */ +#else + bpp = 3; /* overlay ouput is RGB888 */ +#endif + off = 0; + if (pipe->dmap_cnt & 0x01) + off = pipe->src_height * pipe->src_width * bpp; + addr = pipe->blt_addr + off; + + /* dmap */ + MDP_OUTP(MDP_BASE + 0x90008, addr); +} + +/* + * mdp4_overlay_lcdc_wait4event: + * INTR_DMA_P_DONE and INTR_PRIMARY_VSYNC event only + * no INTR_OVERLAY0_DONE event allowed. + */ +static void mdp4_overlay_lcdc_wait4event(struct msm_fb_data_type *mfd, + int intr_done) +{ + unsigned long flag; + unsigned int data; + + data = inpdw(MDP_BASE + LCDC_BASE); + data &= 0x01; + if (data == 0) /* timing generator disabled */ + return; + + spin_lock_irqsave(&mdp_spin_lock, flag); + INIT_COMPLETION(lcdc_comp); + mfd->dma->waiting = TRUE; + outp32(MDP_INTR_CLEAR, intr_done); + mdp_intr_mask |= intr_done; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + mdp_enable_irq(MDP_DMA2_TERM); /* enable intr */ + spin_unlock_irqrestore(&mdp_spin_lock, flag); + wait_for_completion(&lcdc_comp); + mdp_disable_irq(MDP_DMA2_TERM); +} + +static void mdp4_overlay_lcdc_dma_busy_wait(struct msm_fb_data_type *mfd) +{ + unsigned long flag; + int need_wait = 0; + + pr_debug("%s: start pid=%d\n", __func__, current->pid); + + spin_lock_irqsave(&mdp_spin_lock, flag); + if (mfd->dma->busy == TRUE) { + INIT_COMPLETION(mfd->dma->comp); + need_wait++; + } + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + if (need_wait) { + /* wait until DMA finishes the current job */ + pr_debug("%s: pending pid=%d\n", __func__, current->pid); + wait_for_completion(&mfd->dma->comp); + } + pr_debug("%s: done pid=%d\n", __func__, current->pid); +} + +void mdp4_overlay_lcdc_start(void) +{ + if (!lcdc_enabled) { + /* enable LCDC block */ + mdp4_iommu_attach(); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + MDP_OUTP(MDP_BASE + LCDC_BASE, 1); + mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + lcdc_enabled = 1; + } +} + +void mdp4_overlay_lcdc_vsync_push(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + unsigned long flag; + + if (pipe->flags & MDP_OV_PLAY_NOWAIT) + return; + + if (lcdc_pipe->blt_addr) { + mdp4_overlay_lcdc_dma_busy_wait(mfd); + + mdp4_lcdc_blt_ov_update(lcdc_pipe); + lcdc_pipe->ov_cnt++; + + spin_lock_irqsave(&mdp_spin_lock, flag); + outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE); + mdp_intr_mask |= INTR_OVERLAY0_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + mdp_enable_irq(MDP_OVERLAY0_TERM); + mfd->dma->busy = TRUE; + mb(); /* make sure all registers updated */ + spin_unlock_irqrestore(&mdp_spin_lock, flag); + outpdw(MDP_BASE + 0x0004, 0); /* kickoff overlay engine */ + mdp4_stat.kickoff_ov0++; + mb(); + mdp4_overlay_lcdc_wait4event(mfd, INTR_DMA_P_DONE); + } else { + mdp4_overlay_lcdc_wait4event(mfd, INTR_PRIMARY_VSYNC); + } + mdp4_set_perf_level(); +} + +/* + * mdp4_primary_vsync_lcdc: called from isr + */ +void mdp4_primary_vsync_lcdc(void) +{ + complete_all(&lcdc_comp); +} + +/* + * mdp4_dma_p_done_lcdc: called from isr + */ +void mdp4_dma_p_done_lcdc(void) +{ + complete_all(&lcdc_comp); +} + +/* + * mdp4_overlay0_done_lcdc: called from isr + */ +void mdp4_overlay0_done_lcdc(struct mdp_dma_data *dma) +{ + spin_lock(&mdp_spin_lock); + dma->busy = FALSE; + if (lcdc_pipe->blt_addr == 0) { + spin_unlock(&mdp_spin_lock); + return; + } + mdp4_lcdc_blt_dmap_update(lcdc_pipe); + lcdc_pipe->dmap_cnt++; + mdp_disable_irq_nosync(MDP_OVERLAY0_TERM); + spin_unlock(&mdp_spin_lock); + complete(&dma->comp); +} + +static void mdp4_overlay_lcdc_prefill(struct msm_fb_data_type *mfd) +{ + unsigned long flag; + + if (lcdc_pipe->blt_addr) { + mdp4_overlay_lcdc_dma_busy_wait(mfd); + + mdp4_lcdc_blt_ov_update(lcdc_pipe); + lcdc_pipe->ov_cnt++; + + spin_lock_irqsave(&mdp_spin_lock, flag); + outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE); + mdp_intr_mask |= INTR_OVERLAY0_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + mdp_enable_irq(MDP_OVERLAY0_TERM); + mfd->dma->busy = TRUE; + mb(); /* make sure all registers updated */ + spin_unlock_irqrestore(&mdp_spin_lock, flag); + outpdw(MDP_BASE + 0x0004, 0); /* kickoff overlay engine */ + mdp4_stat.kickoff_ov0++; + mb(); + } +} +/* + * make sure the WRITEBACK_SIZE defined at boardfile + * has enough space h * w * 3 * 2 + */ +static void mdp4_lcdc_do_blt(struct msm_fb_data_type *mfd, int enable) +{ + unsigned long flag; + int change = 0; + + mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0); + + if (!mfd->ov0_wb_buf->phys_addr) { + pr_debug("%s: no blt_base assigned\n", __func__); + return; + } + + spin_lock_irqsave(&mdp_spin_lock, flag); + if (enable && lcdc_pipe->blt_addr == 0) { + lcdc_pipe->blt_addr = mfd->ov0_wb_buf->phys_addr; + change++; + lcdc_pipe->blt_cnt = 0; + lcdc_pipe->ov_cnt = 0; + lcdc_pipe->dmap_cnt = 0; + mdp4_stat.blt_lcdc++; + } else if (enable == 0 && lcdc_pipe->blt_addr) { + lcdc_pipe->blt_addr = 0; + change++; + } + pr_info("%s: blt_addr=%x\n", __func__, (int)lcdc_pipe->blt_addr); + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + if (!change) + return; + + mdp4_overlay_lcdc_wait4event(mfd, INTR_DMA_P_DONE); + MDP_OUTP(MDP_BASE + LCDC_BASE, 0); /* stop lcdc */ + msleep(20); + mdp4_overlayproc_cfg(lcdc_pipe); + mdp4_overlay_dmap_xy(lcdc_pipe); + if (lcdc_pipe->blt_addr) { + mdp4_overlay_lcdc_prefill(mfd); + mdp4_overlay_lcdc_prefill(mfd); + } + MDP_OUTP(MDP_BASE + LCDC_BASE, 1); /* start lcdc */ +} + +int mdp4_lcdc_overlay_blt_offset(struct msm_fb_data_type *mfd, + struct msmfb_overlay_blt *req) +{ + req->offset = 0; + req->width = lcdc_pipe->src_width; + req->height = lcdc_pipe->src_height; + req->bpp = lcdc_pipe->bpp; + + return sizeof(*req); +} + +void mdp4_lcdc_overlay_blt(struct msm_fb_data_type *mfd, + struct msmfb_overlay_blt *req) +{ + mdp4_lcdc_do_blt(mfd, req->enable); +} + +void mdp4_lcdc_overlay_blt_start(struct msm_fb_data_type *mfd) +{ + mdp4_lcdc_do_blt(mfd, 1); +} + +void mdp4_lcdc_overlay_blt_stop(struct msm_fb_data_type *mfd) +{ + mdp4_lcdc_do_blt(mfd, 0); +} + +void mdp4_lcdc_overlay(struct msm_fb_data_type *mfd) +{ + struct fb_info *fbi = mfd->fbi; + uint8 *buf; + unsigned int buf_offset; + int bpp; + struct mdp4_overlay_pipe *pipe; + + if (!mfd->panel_power_on) + return; + + /* no need to power on cmd block since it's lcdc mode */ + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + buf_offset = calc_fb_offset(mfd, fbi, bpp); + + mutex_lock(&mfd->dma->ov_mutex); + + pipe = lcdc_pipe; + if (pipe->pipe_used == 0 || + pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) { + pr_err("%s: NOT baselayer\n", __func__); + mutex_unlock(&mfd->dma->ov_mutex); + return; + } + + if (mfd->display_iova) + pipe->srcp0_addr = mfd->display_iova + buf_offset; + else + pipe->srcp0_addr = (uint32)(buf + buf_offset); + + mdp4_overlay_rgb_setup(pipe); + mdp4_overlay_reg_flush(pipe, 1); + mdp4_mixer_stage_up(pipe); + mdp4_overlay_lcdc_start(); + mdp4_overlay_lcdc_vsync_push(mfd, pipe); + mdp4_iommu_unmap(pipe); + mutex_unlock(&mfd->dma->ov_mutex); +} diff --git a/drivers/video/msm/mdp4_overlay_mddi.c b/drivers/video/msm/mdp4_overlay_mddi.c new file mode 100644 index 000000000000..e11bea8c9415 --- /dev/null +++ b/drivers/video/msm/mdp4_overlay_mddi.c @@ -0,0 +1,726 @@ +/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "mdp.h" +#include "msm_fb.h" +#include "mdp4.h" + +static struct mdp4_overlay_pipe *mddi_pipe; +static struct msm_fb_data_type *mddi_mfd; +static int busy_wait_cnt; + +static int vsync_start_y_adjust = 4; + +static int dmap_vsync_enable; + +void mdp_dmap_vsync_set(int enable) +{ + dmap_vsync_enable = enable; +} + +int mdp_dmap_vsync_get(void) +{ + return dmap_vsync_enable; +} + +void mdp4_mddi_vsync_enable(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe, int which) +{ + uint32 start_y, data, tear_en; + + tear_en = (1 << which); + + if ((mfd->use_mdp_vsync) && (mfd->ibuf.vsync_enable) && + (mfd->panel_info.lcd.vsync_enable)) { + + if (mdp_hw_revision < MDP4_REVISION_V2_1) { + /* need dmas dmap switch */ + if (which == 0 && dmap_vsync_enable == 0 && + mfd->panel_info.lcd.rev < 2) /* dma_p */ + return; + } + + if (vsync_start_y_adjust <= pipe->dst_y) + start_y = pipe->dst_y - vsync_start_y_adjust; + else + start_y = (mfd->total_lcd_lines - 1) - + (vsync_start_y_adjust - pipe->dst_y); + if (which == 0) + MDP_OUTP(MDP_BASE + 0x210, start_y); /* primary */ + else + MDP_OUTP(MDP_BASE + 0x214, start_y); /* secondary */ + + data = inpdw(MDP_BASE + 0x20c); + data |= tear_en; + MDP_OUTP(MDP_BASE + 0x20c, data); + } else { + data = inpdw(MDP_BASE + 0x20c); + data &= ~tear_en; + MDP_OUTP(MDP_BASE + 0x20c, data); + } +} + +#define WHOLESCREEN + +void mdp4_overlay_update_lcd(struct msm_fb_data_type *mfd) +{ + MDPIBUF *iBuf = &mfd->ibuf; + uint8 *src; + int ptype; + uint32 mddi_ld_param; + uint16 mddi_vdo_packet_reg; + struct mdp4_overlay_pipe *pipe; + int ret; + + if (mfd->key != MFD_KEY) + return; + + mddi_mfd = mfd; /* keep it */ + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + if (mddi_pipe == NULL) { + ptype = mdp4_overlay_format2type(mfd->fb_imgType); + if (ptype < 0) + printk(KERN_INFO "%s: format2type failed\n", __func__); + pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER0); + if (pipe == NULL) + printk(KERN_INFO "%s: pipe_alloc failed\n", __func__); + pipe->pipe_used++; + pipe->mixer_num = MDP4_MIXER0; + pipe->src_format = mfd->fb_imgType; + mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_MDDI); + ret = mdp4_overlay_format2pipe(pipe); + if (ret < 0) + printk(KERN_INFO "%s: format2type failed\n", __func__); + + mddi_pipe = pipe; /* keep it */ + mddi_ld_param = 0; + mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt; + + if (mdp_hw_revision == MDP4_REVISION_V2_1) { + uint32 data; + + data = inpdw(MDP_BASE + 0x0028); + data &= ~0x0300; /* bit 8, 9, MASTER4 */ + if (mfd->fbi->var.xres == 540) /* qHD, 540x960 */ + data |= 0x0200; + else + data |= 0x0100; + + MDP_OUTP(MDP_BASE + 0x00028, data); + } + + if (mfd->panel_info.type == MDDI_PANEL) { + if (mfd->panel_info.pdest == DISPLAY_1) + mddi_ld_param = 0; + else + mddi_ld_param = 1; + } else { + mddi_ld_param = 2; + } + + MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param); + + if (mfd->panel_info.bpp == 24) + MDP_OUTP(MDP_BASE + 0x00094, + (MDDI_VDO_PACKET_DESC_24 << 16) | mddi_vdo_packet_reg); + else if (mfd->panel_info.bpp == 16) + MDP_OUTP(MDP_BASE + 0x00094, + (MDDI_VDO_PACKET_DESC_16 << 16) | mddi_vdo_packet_reg); + else + MDP_OUTP(MDP_BASE + 0x00094, + (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg); + + MDP_OUTP(MDP_BASE + 0x00098, 0x01); + mdp4_init_writeback_buf(mfd, MDP4_MIXER0); + pipe->blt_addr = 0; + } else { + pipe = mddi_pipe; + } + + /* 0 for dma_p, client_id = 0 */ + MDP_OUTP(MDP_BASE + 0x00090, 0); + + + src = (uint8 *) iBuf->buf; + +#ifdef WHOLESCREEN + + { + struct fb_info *fbi; + + fbi = mfd->fbi; + pipe->src_height = fbi->var.yres; + pipe->src_width = fbi->var.xres; + pipe->src_h = fbi->var.yres; + pipe->src_w = fbi->var.xres; + pipe->src_y = 0; + pipe->src_x = 0; + pipe->dst_h = fbi->var.yres; + pipe->dst_w = fbi->var.xres; + pipe->dst_y = 0; + pipe->dst_x = 0; + pipe->srcp0_addr = (uint32)src; + pipe->srcp0_ystride = fbi->fix.line_length; + } + +#else + if (mdp4_overlay_active(MDP4_MIXER0)) { + struct fb_info *fbi; + + fbi = mfd->fbi; + pipe->src_height = fbi->var.yres; + pipe->src_width = fbi->var.xres; + pipe->src_h = fbi->var.yres; + pipe->src_w = fbi->var.xres; + pipe->src_y = 0; + pipe->src_x = 0; + pipe->dst_h = fbi->var.yres; + pipe->dst_w = fbi->var.xres; + pipe->dst_y = 0; + pipe->dst_x = 0; + pipe->srcp0_addr = (uint32) src; + pipe->srcp0_ystride = fbi->fix.line_length; + } else { + /* starting input address */ + src += (iBuf->dma_x + iBuf->dma_y * iBuf->ibuf_width) + * iBuf->bpp; + + pipe->src_height = iBuf->dma_h; + pipe->src_width = iBuf->dma_w; + pipe->src_h = iBuf->dma_h; + pipe->src_w = iBuf->dma_w; + pipe->src_y = 0; + pipe->src_x = 0; + pipe->dst_h = iBuf->dma_h; + pipe->dst_w = iBuf->dma_w; + pipe->dst_y = iBuf->dma_y; + pipe->dst_x = iBuf->dma_x; + pipe->srcp0_addr = (uint32) src; + pipe->srcp0_ystride = iBuf->ibuf_width * iBuf->bpp; + } +#endif + + pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; + + mdp4_overlay_rgb_setup(pipe); + + mdp4_mixer_stage_up(pipe); + + mdp4_overlayproc_cfg(pipe); + + mdp4_overlay_dmap_xy(pipe); + + mdp4_overlay_dmap_cfg(mfd, 0); + + mdp4_mddi_vsync_enable(mfd, pipe, 0); + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +int mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd) +{ + unsigned long flag; + + pr_debug("%s: blt_end=%d blt_addr=%x pid=%d\n", + __func__, mddi_pipe->blt_end, (int)mddi_pipe->blt_addr, current->pid); + + mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0); + + if (mfd->ov0_wb_buf->phys_addr == 0) { + pr_info("%s: no blt_base assigned\n", __func__); + return -EBUSY; + } + + if (mddi_pipe->blt_addr == 0) { + mdp4_mddi_dma_busy_wait(mfd); + spin_lock_irqsave(&mdp_spin_lock, flag); + mddi_pipe->blt_end = 0; + mddi_pipe->blt_cnt = 0; + mddi_pipe->ov_cnt = 0; + mddi_pipe->dmap_cnt = 0; + mddi_pipe->blt_addr = mfd->ov0_wb_buf->phys_addr; + mdp4_stat.blt_mddi++; + spin_unlock_irqrestore(&mdp_spin_lock, flag); + return 0; +} + + return -EBUSY; +} + +int mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd) +{ + unsigned long flag; + + pr_debug("%s: blt_end=%d blt_addr=%x\n", + __func__, mddi_pipe->blt_end, (int)mddi_pipe->blt_addr); + + if ((mddi_pipe->blt_end == 0) && mddi_pipe->blt_addr) { + spin_lock_irqsave(&mdp_spin_lock, flag); + mddi_pipe->blt_end = 1; /* mark as end */ + spin_unlock_irqrestore(&mdp_spin_lock, flag); + return 0; + } + + return -EBUSY; +} + +int mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd, + struct msmfb_overlay_blt *req) +{ + req->offset = 0; + req->width = mddi_pipe->src_width; + req->height = mddi_pipe->src_height; + req->bpp = mddi_pipe->bpp; + + return sizeof(*req); +} + +void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd, + struct msmfb_overlay_blt *req) +{ + if (req->enable) + mdp4_mddi_overlay_blt_start(mfd); + else if (req->enable == 0) + mdp4_mddi_overlay_blt_stop(mfd); + +} + +void mdp4_blt_xy_update(struct mdp4_overlay_pipe *pipe) +{ + uint32 off, addr, addr2; + int bpp; + char *overlay_base; + + if (pipe->blt_addr == 0) + return; + + +#ifdef BLT_RGB565 + bpp = 2; /* overlay ouput is RGB565 */ +#else + bpp = 3; /* overlay ouput is RGB888 */ +#endif + off = 0; + if (pipe->dmap_cnt & 0x01) + off = pipe->src_height * pipe->src_width * bpp; + + addr = pipe->blt_addr + off; + + /* dmap */ + MDP_OUTP(MDP_BASE + 0x90008, addr); + + off = 0; + if (pipe->ov_cnt & 0x01) + off = pipe->src_height * pipe->src_width * bpp; + addr2 = pipe->blt_addr + off; + /* overlay 0 */ + overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ + outpdw(overlay_base + 0x000c, addr2); + outpdw(overlay_base + 0x001c, addr2); +} + +/* + * mdp4_dmap_done_mddi: called from isr + */ +void mdp4_dma_p_done_mddi(struct mdp_dma_data *dma) +{ + int diff; + + mddi_pipe->dmap_cnt++; + diff = mddi_pipe->ov_cnt - mddi_pipe->dmap_cnt; + pr_debug("%s: ov_cnt=%d dmap_cnt=%d\n", + __func__, mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt); + + if (diff <= 0) { + spin_lock(&mdp_spin_lock); + dma->dmap_busy = FALSE; + complete(&dma->dmap_comp); + spin_unlock(&mdp_spin_lock); + + if (mddi_pipe->blt_end) { + mddi_pipe->blt_end = 0; + mddi_pipe->blt_addr = 0; + pr_debug("%s: END, ov_cnt=%d dmap_cnt=%d\n", __func__, + mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt); + mdp_intr_mask &= ~INTR_DMA_P_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + } + + mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE); + mdp_disable_irq_nosync(MDP_DMA2_TERM); /* disable intr */ + return; + } + + spin_lock(&mdp_spin_lock); + dma->busy = FALSE; + spin_unlock(&mdp_spin_lock); + complete(&dma->comp); + if (busy_wait_cnt) + busy_wait_cnt--; + + pr_debug("%s: kickoff dmap\n", __func__); + + mdp4_blt_xy_update(mddi_pipe); + /* kick off dmap */ + outpdw(MDP_BASE + 0x000c, 0x0); + mdp4_stat.kickoff_dmap++; + mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE); +} + +/* + * mdp4_overlay0_done_mddi: called from isr + */ +void mdp4_overlay0_done_mddi(struct mdp_dma_data *dma) +{ + int diff; + + if (mddi_pipe->blt_addr == 0) { + mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE); + spin_lock(&mdp_spin_lock); + dma->busy = FALSE; + spin_unlock(&mdp_spin_lock); + complete(&dma->comp); + + if (busy_wait_cnt) + busy_wait_cnt--; + mdp_disable_irq_nosync(MDP_OVERLAY0_TERM); + + return; + } + + /* blt enabled */ + if (mddi_pipe->blt_end == 0) + mddi_pipe->ov_cnt++; + + pr_debug("%s: ov_cnt=%d dmap_cnt=%d\n", + __func__, mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt); + + if (mddi_pipe->blt_cnt == 0) { + /* first kickoff since blt enabled */ + mdp_intr_mask |= INTR_DMA_P_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + } + + mddi_pipe->blt_cnt++; + + diff = mddi_pipe->ov_cnt - mddi_pipe->dmap_cnt; + if (diff >= 2) { + mdp_disable_irq_nosync(MDP_OVERLAY0_TERM); + return; + } + + spin_lock(&mdp_spin_lock); + dma->busy = FALSE; + dma->dmap_busy = TRUE; + spin_unlock(&mdp_spin_lock); + complete(&dma->comp); + + if (busy_wait_cnt) + busy_wait_cnt--; + + pr_debug("%s: kickoff dmap\n", __func__); + + mdp4_blt_xy_update(mddi_pipe); + mdp_enable_irq(MDP_DMA2_TERM); /* enable intr */ + /* kick off dmap */ + outpdw(MDP_BASE + 0x000c, 0x0); + mdp4_stat.kickoff_dmap++; + mdp_disable_irq_nosync(MDP_OVERLAY0_TERM); +} + +void mdp4_mddi_overlay_restore(void) +{ + if (mddi_mfd == NULL) + return; + + pr_debug("%s: resotre, pid=%d\n", __func__, current->pid); + + if (mddi_mfd->panel_power_on == 0) + return; + if (mddi_mfd && mddi_pipe) { + mdp4_mddi_dma_busy_wait(mddi_mfd); + mdp4_overlay_update_lcd(mddi_mfd); + + if (mddi_pipe->blt_addr) + mdp4_mddi_blt_dmap_busy_wait(mddi_mfd); + mdp4_mddi_overlay_kickoff(mddi_mfd, mddi_pipe); + mddi_mfd->dma_update_flag = 1; + } + if (mdp_hw_revision < MDP4_REVISION_V2_1) /* need dmas dmap switch */ + mdp4_mddi_overlay_dmas_restore(); +} + +void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd) +{ + unsigned long flag; + int need_wait = 0; + + spin_lock_irqsave(&mdp_spin_lock, flag); + if (mfd->dma->dmap_busy == TRUE) { + INIT_COMPLETION(mfd->dma->dmap_comp); + need_wait++; + } + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + if (need_wait) { + /* wait until DMA finishes the current job */ + wait_for_completion(&mfd->dma->dmap_comp); + } +} + +/* + * mdp4_mddi_cmd_dma_busy_wait: check mddi link activity + * mddi link is a shared resource and it can only be used + * while it is in idle state. + * ov_mutex need to be acquired before call this function. + */ +void mdp4_mddi_dma_busy_wait(struct msm_fb_data_type *mfd) +{ + unsigned long flag; + int need_wait = 0; + + pr_debug("%s: START, pid=%d\n", __func__, current->pid); + spin_lock_irqsave(&mdp_spin_lock, flag); + if (mfd->dma->busy == TRUE) { + if (busy_wait_cnt == 0) + INIT_COMPLETION(mfd->dma->comp); + busy_wait_cnt++; + need_wait++; + } + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + + if (need_wait) { + /* wait until DMA finishes the current job */ + pr_debug("%s: PENDING, pid=%d\n", __func__, current->pid); + wait_for_completion(&mfd->dma->comp); + } + pr_debug("%s: DONE, pid=%d\n", __func__, current->pid); +} + +void mdp4_mddi_kickoff_video(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + /* + * a video kickoff may happen before UI kickoff after + * blt enabled. mdp4_overlay_update_lcd() need + * to be called before kickoff. + * vice versa for blt disabled. + */ + if (mddi_pipe->blt_addr && mddi_pipe->blt_cnt == 0) + mdp4_overlay_update_lcd(mfd); /* first time */ + else if (mddi_pipe->blt_addr == 0 && mddi_pipe->blt_cnt) { + mdp4_overlay_update_lcd(mfd); /* last time */ + mddi_pipe->blt_cnt = 0; + } + + pr_debug("%s: blt_addr=%d blt_cnt=%d\n", + __func__, (int)mddi_pipe->blt_addr, mddi_pipe->blt_cnt); + + if (mddi_pipe->blt_addr) + mdp4_mddi_blt_dmap_busy_wait(mddi_mfd); + mdp4_mddi_overlay_kickoff(mfd, pipe); +} + +void mdp4_mddi_kickoff_ui(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + pr_debug("%s: pid=%d\n", __func__, current->pid); + mdp4_mddi_overlay_kickoff(mfd, pipe); +} + + +void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + unsigned long flag; + /* change mdp clk while mdp is idle` */ + mdp4_set_perf_level(); + + mdp_enable_irq(MDP_OVERLAY0_TERM); + spin_lock_irqsave(&mdp_spin_lock, flag); + mfd->dma->busy = TRUE; + if (mddi_pipe->blt_addr) + mfd->dma->dmap_busy = TRUE; + spin_unlock_irqrestore(&mdp_spin_lock, flag); + /* start OVERLAY pipe */ + mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd); + mdp4_stat.kickoff_ov0++; +} + +void mdp4_dma_s_update_lcd(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + MDPIBUF *iBuf = &mfd->ibuf; + uint32 outBpp = iBuf->bpp; + uint16 mddi_vdo_packet_reg; + uint32 dma_s_cfg_reg; + + dma_s_cfg_reg = 0; + + if (mfd->fb_imgType == MDP_RGBA_8888) + dma_s_cfg_reg |= DMA_PACK_PATTERN_BGR; /* on purpose */ + else if (mfd->fb_imgType == MDP_BGR_565) + dma_s_cfg_reg |= DMA_PACK_PATTERN_BGR; + else + dma_s_cfg_reg |= DMA_PACK_PATTERN_RGB; + + if (outBpp == 4) + dma_s_cfg_reg |= (1 << 26); /* xRGB8888 */ + else if (outBpp == 2) + dma_s_cfg_reg |= DMA_IBUF_FORMAT_RGB565; + + dma_s_cfg_reg |= DMA_DITHER_EN; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + /* PIXELSIZE */ + MDP_OUTP(MDP_BASE + 0xa0004, (pipe->dst_h << 16 | pipe->dst_w)); + MDP_OUTP(MDP_BASE + 0xa0008, pipe->srcp0_addr); /* ibuf address */ + MDP_OUTP(MDP_BASE + 0xa000c, pipe->srcp0_ystride);/* ystride */ + + if (mfd->panel_info.bpp == 24) { + dma_s_cfg_reg |= DMA_DSTC0G_8BITS | /* 666 18BPP */ + DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS; + } else if (mfd->panel_info.bpp == 18) { + dma_s_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */ + DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; + } else { + dma_s_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */ + DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; + } + + MDP_OUTP(MDP_BASE + 0xa0010, (pipe->dst_y << 16) | pipe->dst_x); + + /* 1 for dma_s, client_id = 0 */ + MDP_OUTP(MDP_BASE + 0x00090, 1); + + mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt; + + if (mfd->panel_info.bpp == 24) + MDP_OUTP(MDP_BASE + 0x00094, + (MDDI_VDO_PACKET_DESC_24 << 16) | mddi_vdo_packet_reg); + else if (mfd->panel_info.bpp == 16) + MDP_OUTP(MDP_BASE + 0x00094, + (MDDI_VDO_PACKET_DESC_16 << 16) | mddi_vdo_packet_reg); + else + MDP_OUTP(MDP_BASE + 0x00094, + (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg); + + MDP_OUTP(MDP_BASE + 0x00098, 0x01); + + MDP_OUTP(MDP_BASE + 0xa0000, dma_s_cfg_reg); + + mdp4_mddi_vsync_enable(mfd, pipe, 1); + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_mddi_dma_s_kickoff(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + /* change mdp clk while mdp is idle` */ + mdp4_set_perf_level(); + + mdp_enable_irq(MDP_DMA_S_TERM); + + if (mddi_pipe->blt_addr == 0) + mfd->dma->busy = TRUE; + + mfd->ibuf_flushed = TRUE; + /* start dma_s pipe */ + mdp_pipe_kickoff(MDP_DMA_S_TERM, mfd); + mdp4_stat.kickoff_dmas++; + + /* wait until DMA finishes the current job */ + wait_for_completion(&mfd->dma->comp); + mdp_disable_irq(MDP_DMA_S_TERM); +} + +void mdp4_mddi_overlay_dmas_restore(void) +{ + /* mutex held by caller */ + if (mddi_mfd && mddi_pipe) { + mdp4_mddi_dma_busy_wait(mddi_mfd); + mdp4_dma_s_update_lcd(mddi_mfd, mddi_pipe); + mdp4_mddi_dma_s_kickoff(mddi_mfd, mddi_pipe); + mddi_mfd->dma_update_flag = 1; + } +} + +void mdp4_mddi_overlay(struct msm_fb_data_type *mfd) +{ + mutex_lock(&mfd->dma->ov_mutex); + + if (mfd && mfd->panel_power_on) { + mdp4_mddi_dma_busy_wait(mfd); + + if (mddi_pipe && mddi_pipe->blt_addr) + mdp4_mddi_blt_dmap_busy_wait(mfd); + + mdp4_overlay_update_lcd(mfd); + + if (mdp_hw_revision < MDP4_REVISION_V2_1) { + /* dmas dmap switch */ + if (mdp4_overlay_mixer_play(mddi_pipe->mixer_num) + == 0) { + mdp4_dma_s_update_lcd(mfd, mddi_pipe); + mdp4_mddi_dma_s_kickoff(mfd, mddi_pipe); + } else + mdp4_mddi_kickoff_ui(mfd, mddi_pipe); + } else /* no dams dmap switch */ + mdp4_mddi_kickoff_ui(mfd, mddi_pipe); + + /* signal if pan function is waiting for the update completion */ + if (mfd->pan_waiting) { + mfd->pan_waiting = FALSE; + complete(&mfd->pan_comp); + } + } + mutex_unlock(&mfd->dma->ov_mutex); +} + +int mdp4_mddi_overlay_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct msm_fb_data_type *mfd = info->par; + mutex_lock(&mfd->dma->ov_mutex); + if (mfd && mfd->panel_power_on) { + mdp4_mddi_dma_busy_wait(mfd); + mdp_hw_cursor_update(info, cursor); + } + mutex_unlock(&mfd->dma->ov_mutex); + return 0; +} diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c new file mode 100644 index 000000000000..3ff360159a2c --- /dev/null +++ b/drivers/video/msm/mdp4_overlay_writeback.c @@ -0,0 +1,596 @@ +/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "mdp.h" +#include "msm_fb.h" +#include "mdp4.h" +enum { + WB_OPEN, + WB_START, + WB_STOPING, + WB_STOP +}; +enum { + REGISTERED, + IN_FREE_QUEUE, + IN_BUSY_QUEUE, + WITH_CLIENT +}; + +static struct mdp4_overlay_pipe *writeback_pipe; +static struct msm_fb_data_type *writeback_mfd; +static int busy_wait_cnt; + +int mdp4_overlay_writeback_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct fb_info *fbi; + uint8 *buf; + struct mdp4_overlay_pipe *pipe; + int bpp; + int ret; + uint32 data; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + writeback_mfd = mfd; /* keep it */ + + fbi = mfd->fbi; + + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + buf += fbi->var.xoffset * bpp + + fbi->var.yoffset * fbi->fix.line_length; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + if (writeback_pipe == NULL) { + pipe = mdp4_overlay_pipe_alloc(OVERLAY_TYPE_BF, MDP4_MIXER2); + if (pipe == NULL) + pr_info("%s: pipe_alloc failed\n", __func__); + pipe->pipe_used++; + pipe->mixer_stage = MDP4_MIXER_STAGE_BASE; + pipe->mixer_num = MDP4_MIXER2; + pipe->src_format = MDP_ARGB_8888; + mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_WRITEBACK); + ret = mdp4_overlay_format2pipe(pipe); + if (ret < 0) + pr_info("%s: format2type failed\n", __func__); + + writeback_pipe = pipe; /* keep it */ + + } else { + pipe = writeback_pipe; + } + ret = panel_next_on(pdev); + + /* MDP_LAYERMIXER_WB_MUX_SEL to use mixer1 axi for mixer2 writeback */ + if (hdmi_prim_display) + data = 0x01; + else + data = 0x02; + outpdw(MDP_BASE + 0x100F4, data); + + MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5004, + ((0x0 & 0xFFF) << 16) | /* 12-bit B */ + (0x0 & 0xFFF)); /* 12-bit G */ + /* MSP_BORDER_COLOR */ + MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5008, + (0x0 & 0xFFF)); /* 12-bit R */ + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + return ret; +} + +int mdp4_overlay_writeback_off(struct platform_device *pdev) +{ + int ret; + struct msm_fb_data_type *mfd = + (struct msm_fb_data_type *)platform_get_drvdata(pdev); + if (mfd && writeback_pipe) { + mdp4_writeback_dma_busy_wait(mfd); + mdp4_overlay_pipe_free(writeback_pipe); + mdp4_overlay_panel_mode_unset(writeback_pipe->mixer_num, + MDP4_PANEL_WRITEBACK); + writeback_pipe = NULL; + } + ret = panel_next_off(pdev); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + /* MDP_LAYERMIXER_WB_MUX_SEL to restore to default cfg*/ + outpdw(MDP_BASE + 0x100F4, 0x0); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + return ret; +} +int mdp4_overlay_writeback_update(struct msm_fb_data_type *mfd) +{ + struct fb_info *fbi; + uint8 *buf; + unsigned int buf_offset; + struct mdp4_overlay_pipe *pipe; + int bpp; + + if (mfd->key != MFD_KEY) + return -ENODEV; + + if (!writeback_pipe) + return -EINVAL; + + fbi = mfd->fbi; + + pipe = writeback_pipe; + + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + buf_offset = fbi->var.xoffset * bpp + + fbi->var.yoffset * fbi->fix.line_length; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + pipe->src_height = fbi->var.yres; + pipe->src_width = fbi->var.xres; + pipe->src_h = fbi->var.yres; + pipe->src_w = fbi->var.xres; + pipe->dst_h = fbi->var.yres; + pipe->dst_w = fbi->var.xres; + pipe->srcp0_ystride = fbi->fix.line_length; + pipe->src_y = 0; + pipe->src_x = 0; + pipe->dst_y = 0; + pipe->dst_x = 0; + + if (mfd->display_iova) + pipe->srcp0_addr = mfd->display_iova + buf_offset; + else + pipe->srcp0_addr = (uint32)(buf + buf_offset); + + mdp4_mixer_stage_up(pipe); + + mdp4_overlayproc_cfg(pipe); + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + wmb(); + return 0; +} +void mdp4_writeback_dma_busy_wait(struct msm_fb_data_type *mfd) +{ + unsigned long flag; + int need_wait = 0; + + spin_lock_irqsave(&mdp_spin_lock, flag); + if (mfd->dma->busy == TRUE) { + if (busy_wait_cnt == 0) + INIT_COMPLETION(mfd->dma->comp); + busy_wait_cnt = 1; + need_wait++; + } + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + if (need_wait) { + /* wait until DMA finishes the current job */ + pr_debug("%s: pending pid=%d\n", + __func__, current->pid); + wait_for_completion(&mfd->dma->comp); + } +} + +void mdp4_overlay1_done_writeback(struct mdp_dma_data *dma) +{ + spin_lock(&mdp_spin_lock); + dma->busy = FALSE; + if (busy_wait_cnt) + busy_wait_cnt = 0; + mdp_disable_irq_nosync(MDP_OVERLAY2_TERM); + spin_unlock(&mdp_spin_lock); + complete_all(&dma->comp); + pr_debug("%s ovdone interrupt\n", __func__); + +} +void mdp4_writeback_overlay_kickoff(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + unsigned long flag; + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_enable_irq(MDP_OVERLAY2_TERM); + + mfd->dma->busy = TRUE; + outp32(MDP_INTR_CLEAR, INTR_OVERLAY2_DONE); + mdp_intr_mask |= INTR_OVERLAY2_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + + wmb(); /* make sure all registers updated */ + spin_unlock_irqrestore(&mdp_spin_lock, flag); + /* start OVERLAY pipe */ + mdp_pipe_kickoff(MDP_OVERLAY2_TERM, mfd); + wmb(); + pr_debug("%s: before ov done interrupt\n", __func__); +} +void mdp4_writeback_dma_stop(struct msm_fb_data_type *mfd) +{ + /* mutex holded by caller */ + if (mfd && writeback_pipe) { + mdp4_writeback_dma_busy_wait(mfd); + mdp4_overlay_writeback_update(mfd); + + mdp4_writeback_overlay_kickoff(mfd, writeback_pipe); + } +} + +void mdp4_writeback_kickoff_video(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + struct msmfb_writeback_data_list *node = NULL; + mutex_lock(&mfd->unregister_mutex); + mutex_lock(&mfd->writeback_mutex); + if (!list_empty(&mfd->writeback_free_queue) + && mfd->writeback_state != WB_STOPING + && mfd->writeback_state != WB_STOP) { + node = list_first_entry(&mfd->writeback_free_queue, + struct msmfb_writeback_data_list, active_entry); + } + if (node) { + list_del(&(node->active_entry)); + node->state = IN_BUSY_QUEUE; + mfd->writeback_active_cnt++; + } + mutex_unlock(&mfd->writeback_mutex); + + writeback_pipe->blt_addr = (ulong) (node ? node->addr : NULL); + + if (!writeback_pipe->blt_addr) { + pr_err("%s: no writeback buffer 0x%x, %p\n", __func__, + (unsigned int)writeback_pipe->blt_addr, node); + mutex_unlock(&mfd->unregister_mutex); + return; + } + + if (writeback_pipe->blt_cnt == 0) + mdp4_overlay_writeback_update(mfd); + + pr_debug("%s: pid=%d\n", __func__, current->pid); + + mdp4_writeback_overlay_kickoff(mfd, pipe); + + mutex_lock(&mfd->writeback_mutex); + list_add_tail(&node->active_entry, &mfd->writeback_busy_queue); + mutex_unlock(&mfd->writeback_mutex); + mfd->writeback_active_cnt--; + mutex_unlock(&mfd->unregister_mutex); + wake_up(&mfd->wait_q); +} + +void mdp4_writeback_kickoff_ui(struct msm_fb_data_type *mfd, + struct mdp4_overlay_pipe *pipe) +{ + + pr_debug("%s: pid=%d\n", __func__, current->pid); + mdp4_writeback_overlay_kickoff(mfd, pipe); +} + +void mdp4_writeback_overlay(struct msm_fb_data_type *mfd) +{ + int ret = 0; + struct msmfb_writeback_data_list *node = NULL; + + mutex_lock(&mfd->unregister_mutex); + mutex_lock(&mfd->writeback_mutex); + if (!list_empty(&mfd->writeback_free_queue) + && mfd->writeback_state != WB_STOPING + && mfd->writeback_state != WB_STOP) { + node = list_first_entry(&mfd->writeback_free_queue, + struct msmfb_writeback_data_list, active_entry); + } + if (node) { + list_del(&(node->active_entry)); + node->state = IN_BUSY_QUEUE; + mfd->writeback_active_cnt++; + } + mutex_unlock(&mfd->writeback_mutex); + + writeback_pipe->blt_addr = (ulong) (node ? node->addr : NULL); + + mutex_lock(&mfd->dma->ov_mutex); + pr_debug("%s in writeback\n", __func__); + if (writeback_pipe && !writeback_pipe->blt_addr) { + pr_err("%s: no writeback buffer 0x%x\n", __func__, + (unsigned int)writeback_pipe->blt_addr); + ret = mdp4_overlay_writeback_update(mfd); + if (ret) + pr_err("%s: update failed writeback pipe NULL\n", + __func__); + goto fail_no_blt_addr; + } + + if (mfd && mfd->panel_power_on) { + pr_debug("%s in before busy wait\n", __func__); + mdp4_writeback_dma_busy_wait(mfd); + + pr_debug("%s in before update\n", __func__); + ret = mdp4_overlay_writeback_update(mfd); + if (ret) { + pr_err("%s: update failed writeback pipe NULL\n", + __func__); + goto fail_no_blt_addr; + } + + pr_debug("%s: in writeback pan display 0x%x\n", __func__, + (unsigned int)writeback_pipe->blt_addr); + mdp4_writeback_kickoff_ui(mfd, writeback_pipe); + mdp4_iommu_unmap(writeback_pipe); + + /* signal if pan function is waiting for the + * update completion */ + if (mfd->pan_waiting) { + mfd->pan_waiting = FALSE; + complete(&mfd->pan_comp); + } + } + + mutex_lock(&mfd->writeback_mutex); + list_add_tail(&node->active_entry, &mfd->writeback_busy_queue); + mfd->writeback_active_cnt--; + mutex_unlock(&mfd->writeback_mutex); + wake_up(&mfd->wait_q); +fail_no_blt_addr: + /*NOTE: This api was removed + mdp4_overlay_resource_release();*/ + mutex_unlock(&mfd->dma->ov_mutex); + mutex_unlock(&mfd->unregister_mutex); +} +static int mdp4_overlay_writeback_register_buffer( + struct msm_fb_data_type *mfd, struct msmfb_writeback_data_list *node) +{ + if (!node) { + pr_err("Cannot register a NULL node\n"); + return -EINVAL; + } + node->state = REGISTERED; + list_add_tail(&node->registered_entry, &mfd->writeback_register_queue); + return 0; +} +static struct msmfb_writeback_data_list *get_if_registered( + struct msm_fb_data_type *mfd, struct msmfb_data *data) +{ + struct msmfb_writeback_data_list *temp; + bool found = false; + if (!list_empty(&mfd->writeback_register_queue)) { + list_for_each_entry(temp, + &mfd->writeback_register_queue, + registered_entry) { + if (temp && temp->buf_info.iova == data->iova) { + found = true; + break; + } + } + } + if (!found) { + temp = kzalloc(sizeof(struct msmfb_writeback_data_list), + GFP_KERNEL); + if (temp == NULL) { + pr_err("%s: out of memory\n", __func__); + goto register_alloc_fail; + } + + if (data->iova) + temp->addr = (void *)(data->iova + data->offset); +#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION + else { + struct ion_handle *srcp_ihdl; + ulong len; + srcp_ihdl = ion_import_fd(mfd->iclient, + data->memory_id); + if (IS_ERR_OR_NULL(srcp_ihdl)) { + pr_err("%s: ion import fd failed\n", __func__); + goto register_ion_fail; + } + if (ion_phys(mfd->iclient, + srcp_ihdl, + (ulong *)&temp->addr, + (size_t *)&len)) { + pr_err("%s: unable to get ion phys\n", + __func__); + goto register_ion_fail; + } + temp->addr += data->offset; + } +#else + else { + pr_err("%s: only support ion memory\n", __func__); + goto register_ion_fail; + } +#endif + memcpy(&temp->buf_info, data, sizeof(struct msmfb_data)); + if (mdp4_overlay_writeback_register_buffer(mfd, temp)) { + pr_err("%s: error registering node\n", __func__); + goto register_ion_fail; + } + } + return temp; + register_ion_fail: + kfree(temp); + register_alloc_fail: + return NULL; +} +int mdp4_writeback_start( + struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + mutex_lock(&mfd->writeback_mutex); + mfd->writeback_state = WB_START; + mutex_unlock(&mfd->writeback_mutex); + wake_up(&mfd->wait_q); + return 0; +} + +int mdp4_writeback_queue_buffer(struct fb_info *info, struct msmfb_data *data) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct msmfb_writeback_data_list *node = NULL; + int rv = 0; + + mutex_lock(&mfd->writeback_mutex); + node = get_if_registered(mfd, data); + if (!node || node->state == IN_BUSY_QUEUE || + node->state == IN_FREE_QUEUE) { + pr_err("memory not registered or Buffer already with us\n"); + rv = -EINVAL; + goto exit; + } + + list_add_tail(&node->active_entry, &mfd->writeback_free_queue); + node->state = IN_FREE_QUEUE; + +exit: + mutex_unlock(&mfd->writeback_mutex); + return rv; +} +static int is_buffer_ready(struct msm_fb_data_type *mfd) +{ + int rc; + mutex_lock(&mfd->writeback_mutex); + rc = !list_empty(&mfd->writeback_busy_queue) || + (mfd->writeback_state == WB_STOPING); + mutex_unlock(&mfd->writeback_mutex); + return rc; +} +int mdp4_writeback_dequeue_buffer(struct fb_info *info, struct msmfb_data *data) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct msmfb_writeback_data_list *node = NULL; + int rc = 0; + + rc = wait_event_interruptible(mfd->wait_q, is_buffer_ready(mfd)); + if (rc) { + pr_err("failed to get dequeued buffer\n"); + return -ENOBUFS; + } + mutex_lock(&mfd->writeback_mutex); + if (mfd->writeback_state == WB_STOPING) { + mfd->writeback_state = WB_STOP; + mutex_unlock(&mfd->writeback_mutex); + return -ENOBUFS; + } else if (!list_empty(&mfd->writeback_busy_queue)) { + node = list_first_entry(&mfd->writeback_busy_queue, + struct msmfb_writeback_data_list, active_entry); + } + if (node) { + list_del(&node->active_entry); + node->state = WITH_CLIENT; + memcpy(data, &node->buf_info, sizeof(struct msmfb_data)); + } else { + pr_err("node is NULL. Somebody else dequeued?\n"); + rc = -ENOBUFS; + } + mutex_unlock(&mfd->writeback_mutex); + return rc; +} + +static bool is_writeback_inactive(struct msm_fb_data_type *mfd) +{ + bool active; + mutex_lock(&mfd->writeback_mutex); + active = !mfd->writeback_active_cnt; + mutex_unlock(&mfd->writeback_mutex); + return active; +} +int mdp4_writeback_stop(struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + mutex_lock(&mfd->writeback_mutex); + mfd->writeback_state = WB_STOPING; + mutex_unlock(&mfd->writeback_mutex); + /* Wait for all pending writebacks to finish */ + wait_event_interruptible(mfd->wait_q, is_writeback_inactive(mfd)); + + /* Wake up dequeue thread in case of no UI update*/ + wake_up(&mfd->wait_q); + + return 0; +} +int mdp4_writeback_init(struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + mutex_init(&mfd->writeback_mutex); + mutex_init(&mfd->unregister_mutex); + INIT_LIST_HEAD(&mfd->writeback_free_queue); + INIT_LIST_HEAD(&mfd->writeback_busy_queue); + INIT_LIST_HEAD(&mfd->writeback_register_queue); + mfd->writeback_state = WB_OPEN; + init_waitqueue_head(&mfd->wait_q); + return 0; +} +int mdp4_writeback_terminate(struct fb_info *info) +{ + struct list_head *ptr, *next; + struct msmfb_writeback_data_list *temp; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + int rc = 0; + + mutex_lock(&mfd->unregister_mutex); + mutex_lock(&mfd->writeback_mutex); + + if (mfd->writeback_state != WB_STOPING && + mfd->writeback_state != WB_STOP) { + pr_err("%s called without stopping\n", __func__); + rc = -EPERM; + goto terminate_err; + + } + + if (!list_empty(&mfd->writeback_register_queue)) { + list_for_each_safe(ptr, next, + &mfd->writeback_register_queue) { + temp = list_entry(ptr, + struct msmfb_writeback_data_list, + registered_entry); + list_del(&temp->registered_entry); + kfree(temp); + } + } + INIT_LIST_HEAD(&mfd->writeback_register_queue); + INIT_LIST_HEAD(&mfd->writeback_busy_queue); + INIT_LIST_HEAD(&mfd->writeback_free_queue); + + +terminate_err: + mutex_unlock(&mfd->writeback_mutex); + mutex_unlock(&mfd->unregister_mutex); + return rc; +} diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c new file mode 100644 index 000000000000..f0f90d43d159 --- /dev/null +++ b/drivers/video/msm/mdp4_util.c @@ -0,0 +1,3306 @@ +/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mdp.h" +#include "msm_fb.h" +#include "mdp4.h" + +struct mdp4_statistic mdp4_stat; + +unsigned is_mdp4_hw_reset(void) +{ + unsigned hw_reset = 0; + + /* Only revisions > v2.1 may be reset or powered off/on at runtime */ + if (mdp_hw_revision > MDP4_REVISION_V2_1) { + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + hw_reset = !inpdw(MDP_BASE + 0x003c); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + } + + return hw_reset; +} + +void mdp4_sw_reset(ulong bits) +{ + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + bits &= 0x1f; /* 5 bits */ + outpdw(MDP_BASE + 0x001c, bits); /* MDP_SW_RESET */ + + while (inpdw(MDP_BASE + 0x001c) & bits) /* self clear when complete */ + ; + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + MSM_FB_DEBUG("mdp4_sw_reset: 0x%x\n", (int)bits); +} + +void mdp4_overlay_cfg(int overlayer, int blt_mode, int refresh, int direct_out) +{ + ulong bits = 0; + + if (blt_mode) + bits |= (1 << 3); + refresh &= 0x03; /* 2 bites */ + bits |= (refresh << 1); + direct_out &= 0x01; + bits |= direct_out; + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + + if (overlayer == MDP4_MIXER0) + outpdw(MDP_BASE + 0x10004, bits); /* MDP_OVERLAY0_CFG */ + else if (overlayer == MDP4_MIXER1) + outpdw(MDP_BASE + 0x18004, bits); /* MDP_OVERLAY1_CFG */ + + MSM_FB_DEBUG("mdp4_overlay_cfg: 0x%x\n", + (int)inpdw(MDP_BASE + 0x10004)); + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_display_intf_sel(int output, ulong intf) +{ + ulong bits, mask, data; + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + bits = inpdw(MDP_BASE + 0x0038); /* MDP_DISP_INTF_SEL */ + + if (intf == DSI_VIDEO_INTF) { + data = 0x40; /* bit 6 */ + intf = MDDI_LCDC_INTF; + if (output == SECONDARY_INTF_SEL) { + MSM_FB_INFO("%s: Illegal INTF selected, output=%d \ + intf=%d\n", __func__, output, (int)intf); + } + } else if (intf == DSI_CMD_INTF) { + data = 0x80; /* bit 7 */ + intf = MDDI_INTF; + if (output == EXTERNAL_INTF_SEL) { + MSM_FB_INFO("%s: Illegal INTF selected, output=%d \ + intf=%d\n", __func__, output, (int)intf); + } + } else + data = 0; + + mask = 0x03; /* 2 bits */ + intf &= 0x03; /* 2 bits */ + + switch (output) { + case EXTERNAL_INTF_SEL: + intf <<= 4; + mask <<= 4; + break; + case SECONDARY_INTF_SEL: + intf &= 0x02; /* only MDDI and EBI2 support */ + intf <<= 2; + mask <<= 2; + break; + default: + break; + } + + intf |= data; + mask |= data; + + bits &= ~mask; + bits |= intf; + + outpdw(MDP_BASE + 0x0038, bits); /* MDP_DISP_INTF_SEL */ + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + MSM_FB_DEBUG("mdp4_display_intf_sel: 0x%x\n", (int)inpdw(MDP_BASE + 0x0038)); +} + +unsigned long mdp4_display_status(void) +{ + ulong status; + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + status = inpdw(MDP_BASE + 0x0018) & 0x3ff; /* MDP_DISPLAY_STATUS */ + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + return status; +} + +void mdp4_ebi2_lcd_setup(int lcd, ulong base, int ystride) +{ + /* always use memory map */ + ystride &= 0x01fff; /* 13 bits */ + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + if (lcd == EBI2_LCD0) { + outpdw(MDP_BASE + 0x0060, base);/* MDP_EBI2_LCD0 */ + outpdw(MDP_BASE + 0x0068, ystride);/* MDP_EBI2_LCD0_YSTRIDE */ + } else { + outpdw(MDP_BASE + 0x0064, base);/* MDP_EBI2_LCD1 */ + outpdw(MDP_BASE + 0x006c, ystride);/* MDP_EBI2_LCD1_YSTRIDE */ + } + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_mddi_setup(int mddi, unsigned long id) +{ + ulong bits; + + if (mddi == MDDI_EXTERNAL_SET) + bits = 0x02; + else if (mddi == MDDI_SECONDARY_SET) + bits = 0x01; + else + bits = 0; /* PRIMARY_SET */ + + id <<= 16; + + bits |= id; + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + outpdw(MDP_BASE + 0x0090, bits); /* MDP_MDDI_PARAM_WR_SEL */ + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req) +{ + + /* not implemented yet */ + return -1; +} + +void mdp4_fetch_cfg(uint32 core_clk) +{ + uint32 dmap_data, vg_data; + char *base; + int i; + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + if (mdp_rev >= MDP_REV_41 || core_clk >= 90000000) { /* 90 Mhz */ + dmap_data = 0x47; /* 16 bytes-burst x 8 req */ + vg_data = 0x47; /* 16 bytes-burs x 8 req */ + } else { + dmap_data = 0x27; /* 8 bytes-burst x 8 req */ + vg_data = 0x43; /* 16 bytes-burst x 4 req */ + } + + MSM_FB_DEBUG("mdp4_fetch_cfg: dmap=%x vg=%x\n", + dmap_data, vg_data); + + /* dma_p fetch config */ + outpdw(MDP_BASE + 0x91004, dmap_data); + /* dma_e fetch config */ + outpdw(MDP_BASE + 0xB1004, dmap_data); + + /* + * set up two vg pipes and two rgb pipes + */ + base = MDP_BASE + MDP4_VIDEO_BASE; + for (i = 0; i < 4; i++) { + outpdw(base + 0x1004, vg_data); + base += MDP4_VIDEO_OFF; + } + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_hw_init(void) +{ + ulong bits; + uint32 clk_rate; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + mdp4_update_perf_level(OVERLAY_PERF_LEVEL4); + +#ifdef MDP4_ERROR + /* + * Issue software reset on DMA_P will casue DMA_P dma engine stall + * on LCDC mode. However DMA_P does not stall at MDDI mode. + * This need further investigation. + */ + mdp4_sw_reset(0x17); +#endif + + if (mdp_rev > MDP_REV_41) { + /* mdp chip select controller */ + outpdw(MDP_BASE + 0x00c0, CS_CONTROLLER_0); + outpdw(MDP_BASE + 0x00c4, CS_CONTROLLER_1); + } + + mdp4_clear_lcdc(); + + mdp4_mixer_blend_init(0); + mdp4_mixer_blend_init(1); + mdp4_vg_qseed_init(0); + mdp4_vg_qseed_init(1); + + mdp4_vg_csc_setup(0); + mdp4_vg_csc_setup(1); + mdp4_mixer_csc_setup(1); + mdp4_mixer_csc_setup(2); + mdp4_dmap_csc_setup(); + + if (mdp_rev <= MDP_REV_41) { + mdp4_mixer_gc_lut_setup(0); + mdp4_mixer_gc_lut_setup(1); + } + + mdp4_vg_igc_lut_setup(0); + mdp4_vg_igc_lut_setup(1); + + mdp4_rgb_igc_lut_setup(0); + mdp4_rgb_igc_lut_setup(1); + + outp32(MDP_EBI2_PORTMAP_MODE, 0x3); + + /* system interrupts */ + + bits = mdp_intr_mask; + outpdw(MDP_BASE + 0x0050, bits);/* enable specififed interrupts */ + + /* For the max read pending cmd config below, if the MDP clock */ + /* is less than the AXI clock, then we must use 3 pending */ + /* pending requests. Otherwise, we should use 8 pending requests. */ + /* In the future we should do this detection automatically. */ + + /* max read pending cmd config */ + outpdw(MDP_BASE + 0x004c, 0x02222); /* 3 pending requests */ + +#ifndef CONFIG_FB_MSM_OVERLAY + /* both REFRESH_MODE and DIRECT_OUT are ignored at BLT mode */ + mdp4_overlay_cfg(MDP4_MIXER0, OVERLAY_MODE_BLT, 0, 0); + mdp4_overlay_cfg(MDP4_MIXER1, OVERLAY_MODE_BLT, 0, 0); +#endif + + clk_rate = mdp_get_core_clk(); + mdp4_fetch_cfg(clk_rate); + + mdp4_overlay_cfg_init(); + + /* Mark hardware as initialized. Only revisions > v2.1 have a register + * for tracking core reset status. */ + if (mdp_hw_revision > MDP4_REVISION_V2_1) + outpdw(MDP_BASE + 0x003c, 1); + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + + +void mdp4_clear_lcdc(void) +{ + uint32 bits; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + bits = inpdw(MDP_BASE + 0xc0000); + if (bits & 0x01) { /* enabled already */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + return; + } + + outpdw(MDP_BASE + 0xc0004, 0); /* vsync ctrl out */ + outpdw(MDP_BASE + 0xc0008, 0); /* vsync period */ + outpdw(MDP_BASE + 0xc000c, 0); /* vsync pusle width */ + outpdw(MDP_BASE + 0xc0010, 0); /* lcdc display HCTL */ + outpdw(MDP_BASE + 0xc0014, 0); /* lcdc display v start */ + outpdw(MDP_BASE + 0xc0018, 0); /* lcdc display v end */ + outpdw(MDP_BASE + 0xc001c, 0); /* lcdc active hctl */ + outpdw(MDP_BASE + 0xc0020, 0); /* lcdc active v start */ + outpdw(MDP_BASE + 0xc0024, 0); /* lcdc active v end */ + outpdw(MDP_BASE + 0xc0028, 0); /* lcdc board color */ + outpdw(MDP_BASE + 0xc002c, 0); /* lcdc underflow ctrl */ + outpdw(MDP_BASE + 0xc0030, 0); /* lcdc hsync skew */ + outpdw(MDP_BASE + 0xc0034, 0); /* lcdc test ctl */ + outpdw(MDP_BASE + 0xc0038, 0); /* lcdc ctl polarity */ + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +irqreturn_t mdp4_isr(int irq, void *ptr) +{ + uint32 isr, mask, panel; + struct mdp_dma_data *dma; + struct mdp_hist_mgmt *mgmt = NULL; + char *base_addr; + int i, ret; + + mdp_is_in_isr = TRUE; + + /* complete all the reads before reading the interrupt + * status register - eliminate effects of speculative + * reads by the cpu + */ + rmb(); + isr = inpdw(MDP_INTR_STATUS); + if (isr == 0) + goto out; + + mdp4_stat.intr_tot++; + mask = inpdw(MDP_INTR_ENABLE); + outpdw(MDP_INTR_CLEAR, isr); + + if (isr & INTR_PRIMARY_INTF_UDERRUN) { + pr_debug("%s: UNDERRUN -- primary\n", __func__); + mdp4_stat.intr_underrun_p++; + /* When underun occurs mdp clear the histogram registers + that are set before in hw_init so restore them back so + that histogram works.*/ + for (i = 0; i < MDP_HIST_MGMT_MAX; i++) { + mgmt = mdp_hist_mgmt_array[i]; + if (!mgmt) + continue; + base_addr = MDP_BASE + mgmt->base; + MDP_OUTP(base_addr + 0x010, 1); + outpdw(base_addr + 0x01c, INTR_HIST_DONE | + INTR_HIST_RESET_SEQ_DONE); + mgmt->mdp_is_hist_valid = FALSE; + __mdp_histogram_reset(mgmt); + } + } + + if (isr & INTR_EXTERNAL_INTF_UDERRUN) { + pr_debug("%s: UNDERRUN -- external\n", __func__); + mdp4_stat.intr_underrun_e++; + } + + isr &= mask; + + if (isr == 0) + goto out; + + panel = mdp4_overlay_panel_list(); + if (isr & INTR_PRIMARY_VSYNC) { + mdp4_stat.intr_vsync_p++; + dma = &dma2_data; + spin_lock(&mdp_spin_lock); + mdp_intr_mask &= ~INTR_PRIMARY_VSYNC; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + dma->waiting = FALSE; + if (panel & MDP4_PANEL_LCDC) + mdp4_primary_vsync_lcdc(); +#ifdef CONFIG_FB_MSM_MIPI_DSI + else if (panel & MDP4_PANEL_DSI_VIDEO) + mdp4_primary_vsync_dsi_video(); +#endif + spin_unlock(&mdp_spin_lock); + } +#ifdef CONFIG_FB_MSM_DTV + if (isr & INTR_EXTERNAL_VSYNC) { + mdp4_stat.intr_vsync_e++; + dma = &dma_e_data; + spin_lock(&mdp_spin_lock); + mdp_intr_mask &= ~INTR_EXTERNAL_VSYNC; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + dma->waiting = FALSE; + if (panel & MDP4_PANEL_DTV) + mdp4_external_vsync_dtv(); + spin_unlock(&mdp_spin_lock); + } +#endif + +#ifdef CONFIG_FB_MSM_OVERLAY + if (isr & INTR_OVERLAY0_DONE) { + mdp4_stat.intr_overlay0++; + dma = &dma2_data; + if (panel & (MDP4_PANEL_LCDC | MDP4_PANEL_DSI_VIDEO)) { + /* disable LCDC interrupt */ + spin_lock(&mdp_spin_lock); + mdp_intr_mask &= ~INTR_OVERLAY0_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + dma->waiting = FALSE; + spin_unlock(&mdp_spin_lock); + if (panel & MDP4_PANEL_LCDC) + mdp4_overlay0_done_lcdc(dma); +#ifdef CONFIG_FB_MSM_MIPI_DSI + else if (panel & MDP4_PANEL_DSI_VIDEO) + mdp4_overlay0_done_dsi_video(dma); +#endif + } else { /* MDDI, DSI_CMD */ +#ifdef CONFIG_FB_MSM_MIPI_DSI + if (panel & MDP4_PANEL_DSI_CMD) + mdp4_overlay0_done_dsi_cmd(dma); +#else + if (panel & MDP4_PANEL_MDDI) + mdp4_overlay0_done_mddi(dma); +#endif + } + mdp_hw_cursor_done(); + } + if (isr & INTR_OVERLAY1_DONE) { + mdp4_stat.intr_overlay1++; + /* disable DTV interrupt */ + dma = &dma_e_data; + spin_lock(&mdp_spin_lock); + mdp_intr_mask &= ~INTR_OVERLAY1_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + dma->waiting = FALSE; + spin_unlock(&mdp_spin_lock); +#if defined(CONFIG_FB_MSM_DTV) + if (panel & MDP4_PANEL_DTV) + mdp4_overlay1_done_dtv(); +#endif +#if defined(CONFIG_FB_MSM_TVOUT) + if (panel & MDP4_PANEL_ATV) + mdp4_overlay1_done_atv(); +#endif + } +#if defined(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) + if (isr & INTR_OVERLAY2_DONE) { + mdp4_stat.intr_overlay2++; + /* disable DTV interrupt */ + dma = &dma_wb_data; + spin_lock(&mdp_spin_lock); + mdp_intr_mask &= ~INTR_OVERLAY2_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + dma->waiting = FALSE; + spin_unlock(&mdp_spin_lock); + if (panel & MDP4_PANEL_WRITEBACK) + mdp4_overlay1_done_writeback(dma); + } +#endif +#endif /* OVERLAY */ + + if (isr & INTR_DMA_P_DONE) { + mdp4_stat.intr_dma_p++; + dma = &dma2_data; + if (panel & MDP4_PANEL_LCDC) { + /* disable LCDC interrupt */ + spin_lock(&mdp_spin_lock); + mdp_intr_mask &= ~INTR_DMA_P_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + dma->waiting = FALSE; + mdp4_dma_p_done_lcdc(); + spin_unlock(&mdp_spin_lock); + } +#ifdef CONFIG_FB_MSM_OVERLAY +#ifdef CONFIG_FB_MSM_MIPI_DSI + else if (panel & MDP4_PANEL_DSI_VIDEO) { + /* disable LCDC interrupt */ + spin_lock(&mdp_spin_lock); + mdp_intr_mask &= ~INTR_DMA_P_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + dma->waiting = FALSE; + mdp4_dma_p_done_dsi_video(dma); + spin_unlock(&mdp_spin_lock); + } else if (panel & MDP4_PANEL_DSI_CMD) { + mdp4_dma_p_done_dsi(dma); + } +#else + else { /* MDDI */ + mdp4_dma_p_done_mddi(dma); + mdp_pipe_ctrl(MDP_DMA2_BLOCK, + MDP_BLOCK_POWER_OFF, TRUE); + complete(&dma->comp); + } +#endif +#else + else { + spin_lock(&mdp_spin_lock); + dma->busy = FALSE; + spin_unlock(&mdp_spin_lock); + complete(&dma->comp); + } +#endif + } + if (isr & INTR_DMA_S_DONE) { + mdp4_stat.intr_dma_s++; +#if defined(CONFIG_FB_MSM_OVERLAY) && defined(CONFIG_FB_MSM_MDDI) + dma = &dma2_data; +#else + dma = &dma_s_data; +#endif + + dma->busy = FALSE; + mdp_pipe_ctrl(MDP_DMA_S_BLOCK, + MDP_BLOCK_POWER_OFF, TRUE); + complete(&dma->comp); + } + if (isr & INTR_DMA_E_DONE) { + mdp4_stat.intr_dma_e++; + dma = &dma_e_data; + spin_lock(&mdp_spin_lock); + mdp_intr_mask &= ~INTR_DMA_E_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + dma->busy = FALSE; + mdp4_dma_e_done_dtv(); + if (dma->waiting) { + dma->waiting = FALSE; + complete(&dma->comp); + } + spin_unlock(&mdp_spin_lock); + } + if (isr & INTR_DMA_P_HISTOGRAM) { + mdp4_stat.intr_histogram++; + ret = mdp_histogram_block2mgmt(MDP_BLOCK_DMA_P, &mgmt); + if (!ret) + mdp_histogram_handle_isr(mgmt); + } + if (isr & INTR_DMA_S_HISTOGRAM) { + mdp4_stat.intr_histogram++; + ret = mdp_histogram_block2mgmt(MDP_BLOCK_DMA_S, &mgmt); + if (!ret) + mdp_histogram_handle_isr(mgmt); + } + if (isr & INTR_VG1_HISTOGRAM) { + mdp4_stat.intr_histogram++; + ret = mdp_histogram_block2mgmt(MDP_BLOCK_VG_1, &mgmt); + if (!ret) + mdp_histogram_handle_isr(mgmt); + } + if (isr & INTR_VG2_HISTOGRAM) { + mdp4_stat.intr_histogram++; + ret = mdp_histogram_block2mgmt(MDP_BLOCK_VG_2, &mgmt); + if (!ret) + mdp_histogram_handle_isr(mgmt); + } + +out: + mdp_is_in_isr = FALSE; + + return IRQ_HANDLED; +} + + +/* + * QSEED tables + */ + +static uint32 vg_qseed_table0[] = { + 0x5556aaff, 0x00000000, 0x00000000, 0x00000000 +}; + +static uint32 vg_qseed_table1[] = { + 0x00000000, 0x20000000, +}; + +static uint32 vg_qseed_table2[] = { + 0x02000000, 0x00000000, 0x01ff0ff9, 0x00000008, + 0x01fb0ff2, 0x00000013, 0x01f50fed, 0x0ffe0020, + 0x01ed0fe8, 0x0ffd002e, 0x01e30fe4, 0x0ffb003e, + 0x01d80fe1, 0x0ff9004e, 0x01cb0fde, 0x0ff70060, + 0x01bc0fdc, 0x0ff40074, 0x01ac0fdb, 0x0ff20087, + 0x019a0fdb, 0x0fef009c, 0x01870fdb, 0x0fed00b1, + 0x01740fdb, 0x0fea00c7, 0x01600fdc, 0x0fe700dd, + 0x014b0fdd, 0x0fe500f3, 0x01350fdf, 0x0fe30109, + 0x01200fe0, 0x0fe00120, 0x01090fe3, 0x0fdf0135, + 0x00f30fe5, 0x0fdd014b, 0x00dd0fe7, 0x0fdc0160, + 0x00c70fea, 0x0fdb0174, 0x00b10fed, 0x0fdb0187, + 0x009c0fef, 0x0fdb019a, 0x00870ff2, 0x0fdb01ac, + 0x00740ff4, 0x0fdc01bc, 0x00600ff7, 0x0fde01cb, + 0x004e0ff9, 0x0fe101d8, 0x003e0ffb, 0x0fe401e3, + 0x002e0ffd, 0x0fe801ed, 0x00200ffe, 0x0fed01f5, + 0x00130000, 0x0ff201fb, 0x00080000, 0x0ff901ff, + + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + + 0x02000000, 0x00000000, 0x01fc0ff9, 0x0ffe000d, + 0x01f60ff3, 0x0ffb001c, 0x01ef0fed, 0x0ff9002b, + 0x01e60fe8, 0x0ff6003c, 0x01dc0fe4, 0x0ff3004d, + 0x01d00fe0, 0x0ff1005f, 0x01c30fde, 0x0fee0071, + 0x01b50fdb, 0x0feb0085, 0x01a70fd9, 0x0fe80098, + 0x01960fd8, 0x0fe600ac, 0x01850fd7, 0x0fe300c1, + 0x01730fd7, 0x0fe100d5, 0x01610fd7, 0x0fdf00e9, + 0x014e0fd8, 0x0fdd00fd, 0x013b0fd8, 0x0fdb0112, + 0x01250fda, 0x0fda0127, 0x01120fdb, 0x0fd8013b, + 0x00fd0fdd, 0x0fd8014e, 0x00e90fdf, 0x0fd70161, + 0x00d50fe1, 0x0fd70173, 0x00c10fe3, 0x0fd70185, + 0x00ac0fe6, 0x0fd80196, 0x00980fe8, 0x0fd901a7, + 0x00850feb, 0x0fdb01b5, 0x00710fee, 0x0fde01c3, + 0x005f0ff1, 0x0fe001d0, 0x004d0ff3, 0x0fe401dc, + 0x003c0ff6, 0x0fe801e6, 0x002b0ff9, 0x0fed01ef, + 0x001c0ffb, 0x0ff301f6, 0x000d0ffe, 0x0ff901fc, + + 0x020f0034, 0x0f7a0043, 0x01e80023, 0x0fa8004d, + 0x01d30016, 0x0fbe0059, 0x01c6000a, 0x0fc90067, + 0x01bd0000, 0x0fce0075, 0x01b50ff7, 0x0fcf0085, + 0x01ae0fee, 0x0fcf0095, 0x01a70fe6, 0x0fcd00a6, + 0x019d0fe0, 0x0fcb00b8, 0x01940fd9, 0x0fc900ca, + 0x01890fd4, 0x0fc700dc, 0x017d0fcf, 0x0fc600ee, + 0x01700fcc, 0x0fc40100, 0x01620fc9, 0x0fc40111, + 0x01540fc6, 0x0fc30123, 0x01430fc5, 0x0fc40134, + 0x01340fc4, 0x0fc50143, 0x01230fc3, 0x0fc60154, + 0x01110fc4, 0x0fc90162, 0x01000fc4, 0x0fcc0170, + 0x00ee0fc6, 0x0fcf017d, 0x00dc0fc7, 0x0fd40189, + 0x00ca0fc9, 0x0fd90194, 0x00b80fcb, 0x0fe0019d, + 0x00a60fcd, 0x0fe601a7, 0x00950fcf, 0x0fee01ae, + 0x00850fcf, 0x0ff701b5, 0x00750fce, 0x000001bd, + 0x00670fc9, 0x000a01c6, 0x00590fbe, 0x001601d3, + 0x004d0fa8, 0x002301e8, 0x00430f7a, 0x0034020f, + + 0x015c005e, 0x0fde0068, 0x015c0054, 0x0fdd0073, + 0x015b004b, 0x0fdc007e, 0x015a0042, 0x0fdb0089, + 0x01590039, 0x0fda0094, 0x01560030, 0x0fda00a0, + 0x01530028, 0x0fda00ab, 0x014f0020, 0x0fda00b7, + 0x014a0019, 0x0fdb00c2, 0x01450011, 0x0fdc00ce, + 0x013e000b, 0x0fde00d9, 0x01390004, 0x0fdf00e4, + 0x01310ffe, 0x0fe200ef, 0x01290ff9, 0x0fe400fa, + 0x01200ff4, 0x0fe80104, 0x01180fef, 0x0feb010e, + 0x010e0feb, 0x0fef0118, 0x01040fe8, 0x0ff40120, + 0x00fa0fe4, 0x0ff90129, 0x00ef0fe2, 0x0ffe0131, + 0x00e40fdf, 0x00040139, 0x00d90fde, 0x000b013e, + 0x00ce0fdc, 0x00110145, 0x00c20fdb, 0x0019014a, + 0x00b70fda, 0x0020014f, 0x00ab0fda, 0x00280153, + 0x00a00fda, 0x00300156, 0x00940fda, 0x00390159, + 0x00890fdb, 0x0042015a, 0x007e0fdc, 0x004b015b, + 0x00730fdd, 0x0054015c, 0x00680fde, 0x005e015c, + + 0x01300068, 0x0ff80070, 0x01300060, 0x0ff80078, + 0x012f0059, 0x0ff80080, 0x012d0052, 0x0ff80089, + 0x012b004b, 0x0ff90091, 0x01290044, 0x0ff9009a, + 0x0126003d, 0x0ffa00a3, 0x01220037, 0x0ffb00ac, + 0x011f0031, 0x0ffc00b4, 0x011a002b, 0x0ffe00bd, + 0x01150026, 0x000000c5, 0x010f0021, 0x000200ce, + 0x010a001c, 0x000400d6, 0x01030018, 0x000600df, + 0x00fd0014, 0x000900e6, 0x00f60010, 0x000c00ee, + 0x00ee000c, 0x001000f6, 0x00e60009, 0x001400fd, + 0x00df0006, 0x00180103, 0x00d60004, 0x001c010a, + 0x00ce0002, 0x0021010f, 0x00c50000, 0x00260115, + 0x00bd0ffe, 0x002b011a, 0x00b40ffc, 0x0031011f, + 0x00ac0ffb, 0x00370122, 0x00a30ffa, 0x003d0126, + 0x009a0ff9, 0x00440129, 0x00910ff9, 0x004b012b, + 0x00890ff8, 0x0052012d, 0x00800ff8, 0x0059012f, + 0x00780ff8, 0x00600130, 0x00700ff8, 0x00680130, + + 0x01050079, 0x0003007f, 0x01040073, 0x00030086, + 0x0103006d, 0x0004008c, 0x01030066, 0x00050092, + 0x01010060, 0x00060099, 0x0100005a, 0x0007009f, + 0x00fe0054, 0x000900a5, 0x00fa004f, 0x000b00ac, + 0x00f80049, 0x000d00b2, 0x00f50044, 0x000f00b8, + 0x00f2003f, 0x001200bd, 0x00ef0039, 0x001500c3, + 0x00ea0035, 0x001800c9, 0x00e60030, 0x001c00ce, + 0x00e3002b, 0x001f00d3, 0x00dd0027, 0x002300d9, + 0x00d90023, 0x002700dd, 0x00d3001f, 0x002b00e3, + 0x00ce001c, 0x003000e6, 0x00c90018, 0x003500ea, + 0x00c30015, 0x003900ef, 0x00bd0012, 0x003f00f2, + 0x00b8000f, 0x004400f5, 0x00b2000d, 0x004900f8, + 0x00ac000b, 0x004f00fa, 0x00a50009, 0x005400fe, + 0x009f0007, 0x005a0100, 0x00990006, 0x00600101, + 0x00920005, 0x00660103, 0x008c0004, 0x006d0103, + 0x00860003, 0x00730104, 0x007f0003, 0x00790105, + + 0x00cf0088, 0x001d008c, 0x00ce0084, 0x0020008e, + 0x00cd0080, 0x00210092, 0x00cd007b, 0x00240094, + 0x00ca0077, 0x00270098, 0x00c90073, 0x0029009b, + 0x00c8006f, 0x002c009d, 0x00c6006b, 0x002f00a0, + 0x00c50067, 0x003200a2, 0x00c30062, 0x003600a5, + 0x00c0005f, 0x003900a8, 0x00c0005b, 0x003b00aa, + 0x00be0057, 0x003e00ad, 0x00ba0054, 0x004200b0, + 0x00b90050, 0x004500b2, 0x00b7004c, 0x004900b4, + 0x00b40049, 0x004c00b7, 0x00b20045, 0x005000b9, + 0x00b00042, 0x005400ba, 0x00ad003e, 0x005700be, + 0x00aa003b, 0x005b00c0, 0x00a80039, 0x005f00c0, + 0x00a50036, 0x006200c3, 0x00a20032, 0x006700c5, + 0x00a0002f, 0x006b00c6, 0x009d002c, 0x006f00c8, + 0x009b0029, 0x007300c9, 0x00980027, 0x007700ca, + 0x00940024, 0x007b00cd, 0x00920021, 0x008000cd, + 0x008e0020, 0x008400ce, 0x008c001d, 0x008800cf, + + 0x008e0083, 0x006b0084, 0x008d0083, 0x006c0084, + 0x008d0082, 0x006d0084, 0x008d0081, 0x006d0085, + 0x008d0080, 0x006e0085, 0x008c007f, 0x006f0086, + 0x008b007f, 0x00700086, 0x008b007e, 0x00710086, + 0x008b007d, 0x00720086, 0x008a007d, 0x00730086, + 0x008a007c, 0x00730087, 0x008a007b, 0x00740087, + 0x0089007b, 0x00750087, 0x008a0079, 0x00750088, + 0x008a0078, 0x00760088, 0x008a0077, 0x00770088, + 0x00880077, 0x0077008a, 0x00880076, 0x0078008a, + 0x00880075, 0x0079008a, 0x00870075, 0x007b0089, + 0x00870074, 0x007b008a, 0x00870073, 0x007c008a, + 0x00860073, 0x007d008a, 0x00860072, 0x007d008b, + 0x00860071, 0x007e008b, 0x00860070, 0x007f008b, + 0x0086006f, 0x007f008c, 0x0085006e, 0x0080008d, + 0x0085006d, 0x0081008d, 0x0084006d, 0x0082008d, + 0x0084006c, 0x0083008d, 0x0084006b, 0x0083008e, + + 0x023c0fe2, 0x00000fe2, 0x023a0fdb, 0x00000feb, + 0x02360fd3, 0x0fff0ff8, 0x022e0fcf, 0x0ffc0007, + 0x02250fca, 0x0ffa0017, 0x021a0fc6, 0x0ff70029, + 0x020c0fc4, 0x0ff4003c, 0x01fd0fc1, 0x0ff10051, + 0x01eb0fc0, 0x0fed0068, 0x01d80fc0, 0x0fe9007f, + 0x01c30fc1, 0x0fe50097, 0x01ac0fc2, 0x0fe200b0, + 0x01960fc3, 0x0fdd00ca, 0x017e0fc5, 0x0fd900e4, + 0x01650fc8, 0x0fd500fe, 0x014b0fcb, 0x0fd20118, + 0x01330fcd, 0x0fcd0133, 0x01180fd2, 0x0fcb014b, + 0x00fe0fd5, 0x0fc80165, 0x00e40fd9, 0x0fc5017e, + 0x00ca0fdd, 0x0fc30196, 0x00b00fe2, 0x0fc201ac, + 0x00970fe5, 0x0fc101c3, 0x007f0fe9, 0x0fc001d8, + 0x00680fed, 0x0fc001eb, 0x00510ff1, 0x0fc101fd, + 0x003c0ff4, 0x0fc4020c, 0x00290ff7, 0x0fc6021a, + 0x00170ffa, 0x0fca0225, 0x00070ffc, 0x0fcf022e, + 0x0ff80fff, 0x0fd30236, 0x0feb0000, 0x0fdb023a, + + 0x02780fc4, 0x00000fc4, 0x02770fbc, 0x0fff0fce, + 0x02710fb5, 0x0ffe0fdc, 0x02690fb0, 0x0ffa0fed, + 0x025f0fab, 0x0ff70fff, 0x02500fa8, 0x0ff30015, + 0x02410fa6, 0x0fef002a, 0x022f0fa4, 0x0feb0042, + 0x021a0fa4, 0x0fe5005d, 0x02040fa5, 0x0fe10076, + 0x01eb0fa7, 0x0fdb0093, 0x01d20fa9, 0x0fd600af, + 0x01b80fab, 0x0fd000cd, 0x019d0faf, 0x0fca00ea, + 0x01810fb2, 0x0fc50108, 0x01620fb7, 0x0fc10126, + 0x01440fbb, 0x0fbb0146, 0x01260fc1, 0x0fb70162, + 0x01080fc5, 0x0fb20181, 0x00ea0fca, 0x0faf019d, + 0x00cd0fd0, 0x0fab01b8, 0x00af0fd6, 0x0fa901d2, + 0x00930fdb, 0x0fa701eb, 0x00760fe1, 0x0fa50204, + 0x005d0fe5, 0x0fa4021a, 0x00420feb, 0x0fa4022f, + 0x002a0fef, 0x0fa60241, 0x00150ff3, 0x0fa80250, + 0x0fff0ff7, 0x0fab025f, 0x0fed0ffa, 0x0fb00269, + 0x0fdc0ffe, 0x0fb50271, 0x0fce0fff, 0x0fbc0277, + + 0x02a00fb0, 0x00000fb0, 0x029e0fa8, 0x0fff0fbb, + 0x02980fa1, 0x0ffd0fca, 0x028f0f9c, 0x0ff90fdc, + 0x02840f97, 0x0ff50ff0, 0x02740f94, 0x0ff10007, + 0x02640f92, 0x0fec001e, 0x02500f91, 0x0fe70038, + 0x023a0f91, 0x0fe00055, 0x02220f92, 0x0fdb0071, + 0x02080f95, 0x0fd4008f, 0x01ec0f98, 0x0fce00ae, + 0x01cf0f9b, 0x0fc700cf, 0x01b10f9f, 0x0fc100ef, + 0x01920fa4, 0x0fbb010f, 0x01710faa, 0x0fb50130, + 0x01520fae, 0x0fae0152, 0x01300fb5, 0x0faa0171, + 0x010f0fbb, 0x0fa40192, 0x00ef0fc1, 0x0f9f01b1, + 0x00cf0fc7, 0x0f9b01cf, 0x00ae0fce, 0x0f9801ec, + 0x008f0fd4, 0x0f950208, 0x00710fdb, 0x0f920222, + 0x00550fe0, 0x0f91023a, 0x00380fe7, 0x0f910250, + 0x001e0fec, 0x0f920264, 0x00070ff1, 0x0f940274, + 0x0ff00ff5, 0x0f970284, 0x0fdc0ff9, 0x0f9c028f, + 0x0fca0ffd, 0x0fa10298, 0x0fbb0fff, 0x0fa8029e, + + 0x02c80f9c, 0x00000f9c, 0x02c70f94, 0x0ffe0fa7, + 0x02c10f8c, 0x0ffc0fb7, 0x02b70f87, 0x0ff70fcb, + 0x02aa0f83, 0x0ff30fe0, 0x02990f80, 0x0fee0ff9, + 0x02870f7f, 0x0fe80012, 0x02720f7e, 0x0fe2002e, + 0x025a0f7e, 0x0fdb004d, 0x02400f80, 0x0fd5006b, + 0x02230f84, 0x0fcd008c, 0x02050f87, 0x0fc700ad, + 0x01e60f8b, 0x0fbf00d0, 0x01c60f90, 0x0fb700f3, + 0x01a30f96, 0x0fb00117, 0x01800f9c, 0x0faa013a, + 0x015d0fa2, 0x0fa2015f, 0x013a0faa, 0x0f9c0180, + 0x01170fb0, 0x0f9601a3, 0x00f30fb7, 0x0f9001c6, + 0x00d00fbf, 0x0f8b01e6, 0x00ad0fc7, 0x0f870205, + 0x008c0fcd, 0x0f840223, 0x006b0fd5, 0x0f800240, + 0x004d0fdb, 0x0f7e025a, 0x002e0fe2, 0x0f7e0272, + 0x00120fe8, 0x0f7f0287, 0x0ff90fee, 0x0f800299, + 0x0fe00ff3, 0x0f8302aa, 0x0fcb0ff7, 0x0f8702b7, + 0x0fb70ffc, 0x0f8c02c1, 0x0fa70ffe, 0x0f9402c7, + + 0x02f00f88, 0x00000f88, 0x02ee0f80, 0x0ffe0f94, + 0x02e70f78, 0x0ffc0fa5, 0x02dd0f73, 0x0ff60fba, + 0x02ce0f6f, 0x0ff20fd1, 0x02be0f6c, 0x0feb0feb, + 0x02aa0f6b, 0x0fe50006, 0x02940f6a, 0x0fde0024, + 0x02790f6c, 0x0fd60045, 0x025e0f6e, 0x0fcf0065, + 0x023f0f72, 0x0fc60089, 0x021d0f77, 0x0fbf00ad, + 0x01fd0f7b, 0x0fb600d2, 0x01da0f81, 0x0fad00f8, + 0x01b50f87, 0x0fa6011e, 0x018f0f8f, 0x0f9e0144, + 0x016b0f95, 0x0f95016b, 0x01440f9e, 0x0f8f018f, + 0x011e0fa6, 0x0f8701b5, 0x00f80fad, 0x0f8101da, + 0x00d20fb6, 0x0f7b01fd, 0x00ad0fbf, 0x0f77021d, + 0x00890fc6, 0x0f72023f, 0x00650fcf, 0x0f6e025e, + 0x00450fd6, 0x0f6c0279, 0x00240fde, 0x0f6a0294, + 0x00060fe5, 0x0f6b02aa, 0x0feb0feb, 0x0f6c02be, + 0x0fd10ff2, 0x0f6f02ce, 0x0fba0ff6, 0x0f7302dd, + 0x0fa50ffc, 0x0f7802e7, 0x0f940ffe, 0x0f8002ee, + + 0x03180f74, 0x00000f74, 0x03160f6b, 0x0ffe0f81, + 0x030e0f64, 0x0ffb0f93, 0x03030f5f, 0x0ff50fa9, + 0x02f40f5b, 0x0ff00fc1, 0x02e20f58, 0x0fe90fdd, + 0x02cd0f57, 0x0fe20ffa, 0x02b60f57, 0x0fda0019, + 0x02990f59, 0x0fd1003d, 0x027b0f5c, 0x0fc90060, + 0x02590f61, 0x0fc00086, 0x02370f66, 0x0fb700ac, + 0x02130f6b, 0x0fae00d4, 0x01ee0f72, 0x0fa400fc, + 0x01c70f79, 0x0f9b0125, 0x019f0f81, 0x0f93014d, + 0x01760f89, 0x0f890178, 0x014d0f93, 0x0f81019f, + 0x01250f9b, 0x0f7901c7, 0x00fc0fa4, 0x0f7201ee, + 0x00d40fae, 0x0f6b0213, 0x00ac0fb7, 0x0f660237, + 0x00860fc0, 0x0f610259, 0x00600fc9, 0x0f5c027b, + 0x003d0fd1, 0x0f590299, 0x00190fda, 0x0f5702b6, + 0x0ffa0fe2, 0x0f5702cd, 0x0fdd0fe9, 0x0f5802e2, + 0x0fc10ff0, 0x0f5b02f4, 0x0fa90ff5, 0x0f5f0303, + 0x0f930ffb, 0x0f64030e, 0x0f810ffe, 0x0f6b0316, + + 0x03400f60, 0x00000f60, 0x033e0f57, 0x0ffe0f6d, + 0x03370f4f, 0x0ffa0f80, 0x032a0f4b, 0x0ff30f98, + 0x031a0f46, 0x0fee0fb2, 0x03070f44, 0x0fe60fcf, + 0x02f10f44, 0x0fde0fed, 0x02d70f44, 0x0fd6000f, + 0x02b80f46, 0x0fcc0036, 0x02990f4a, 0x0fc3005a, + 0x02750f4f, 0x0fb90083, 0x02500f55, 0x0fb000ab, + 0x022a0f5b, 0x0fa500d6, 0x02020f63, 0x0f9a0101, + 0x01d80f6b, 0x0f91012c, 0x01ae0f74, 0x0f870157, + 0x01840f7c, 0x0f7c0184, 0x01570f87, 0x0f7401ae, + 0x012c0f91, 0x0f6b01d8, 0x01010f9a, 0x0f630202, + 0x00d60fa5, 0x0f5b022a, 0x00ab0fb0, 0x0f550250, + 0x00830fb9, 0x0f4f0275, 0x005a0fc3, 0x0f4a0299, + 0x00360fcc, 0x0f4602b8, 0x000f0fd6, 0x0f4402d7, + 0x0fed0fde, 0x0f4402f1, 0x0fcf0fe6, 0x0f440307, + 0x0fb20fee, 0x0f46031a, 0x0f980ff3, 0x0f4b032a, + 0x0f800ffa, 0x0f4f0337, 0x0f6d0ffe, 0x0f57033e, + + 0x02000000, 0x00000000, 0x01ff0ff9, 0x00000008, + 0x01fb0ff2, 0x00000013, 0x01f50fed, 0x0ffe0020, + 0x01ed0fe8, 0x0ffd002e, 0x01e30fe4, 0x0ffb003e, + 0x01d80fe1, 0x0ff9004e, 0x01cb0fde, 0x0ff70060, + 0x01bc0fdc, 0x0ff40074, 0x01ac0fdb, 0x0ff20087, + 0x019a0fdb, 0x0fef009c, 0x01870fdb, 0x0fed00b1, + 0x01740fdb, 0x0fea00c7, 0x01600fdc, 0x0fe700dd, + 0x014b0fdd, 0x0fe500f3, 0x01350fdf, 0x0fe30109, + 0x01200fe0, 0x0fe00120, 0x01090fe3, 0x0fdf0135, + 0x00f30fe5, 0x0fdd014b, 0x00dd0fe7, 0x0fdc0160, + 0x00c70fea, 0x0fdb0174, 0x00b10fed, 0x0fdb0187, + 0x009c0fef, 0x0fdb019a, 0x00870ff2, 0x0fdb01ac, + 0x00740ff4, 0x0fdc01bc, 0x00600ff7, 0x0fde01cb, + 0x004e0ff9, 0x0fe101d8, 0x003e0ffb, 0x0fe401e3, + 0x002e0ffd, 0x0fe801ed, 0x00200ffe, 0x0fed01f5, + 0x00130000, 0x0ff201fb, 0x00080000, 0x0ff901ff, + + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + 0x02000000, 0x00000000, 0x02000000, 0x00000000, + + 0x02000000, 0x00000000, 0x01fc0ff9, 0x0ffe000d, + 0x01f60ff3, 0x0ffb001c, 0x01ef0fed, 0x0ff9002b, + 0x01e60fe8, 0x0ff6003c, 0x01dc0fe4, 0x0ff3004d, + 0x01d00fe0, 0x0ff1005f, 0x01c30fde, 0x0fee0071, + 0x01b50fdb, 0x0feb0085, 0x01a70fd9, 0x0fe80098, + 0x01960fd8, 0x0fe600ac, 0x01850fd7, 0x0fe300c1, + 0x01730fd7, 0x0fe100d5, 0x01610fd7, 0x0fdf00e9, + 0x014e0fd8, 0x0fdd00fd, 0x013b0fd8, 0x0fdb0112, + 0x01250fda, 0x0fda0127, 0x01120fdb, 0x0fd8013b, + 0x00fd0fdd, 0x0fd8014e, 0x00e90fdf, 0x0fd70161, + 0x00d50fe1, 0x0fd70173, 0x00c10fe3, 0x0fd70185, + 0x00ac0fe6, 0x0fd80196, 0x00980fe8, 0x0fd901a7, + 0x00850feb, 0x0fdb01b5, 0x00710fee, 0x0fde01c3, + 0x005f0ff1, 0x0fe001d0, 0x004d0ff3, 0x0fe401dc, + 0x003c0ff6, 0x0fe801e6, 0x002b0ff9, 0x0fed01ef, + 0x001c0ffb, 0x0ff301f6, 0x000d0ffe, 0x0ff901fc, + + 0x020f0034, 0x0f7a0043, 0x01e80023, 0x0fa8004d, + 0x01d30016, 0x0fbe0059, 0x01c6000a, 0x0fc90067, + 0x01bd0000, 0x0fce0075, 0x01b50ff7, 0x0fcf0085, + 0x01ae0fee, 0x0fcf0095, 0x01a70fe6, 0x0fcd00a6, + 0x019d0fe0, 0x0fcb00b8, 0x01940fd9, 0x0fc900ca, + 0x01890fd4, 0x0fc700dc, 0x017d0fcf, 0x0fc600ee, + 0x01700fcc, 0x0fc40100, 0x01620fc9, 0x0fc40111, + 0x01540fc6, 0x0fc30123, 0x01430fc5, 0x0fc40134, + 0x01340fc4, 0x0fc50143, 0x01230fc3, 0x0fc60154, + 0x01110fc4, 0x0fc90162, 0x01000fc4, 0x0fcc0170, + 0x00ee0fc6, 0x0fcf017d, 0x00dc0fc7, 0x0fd40189, + 0x00ca0fc9, 0x0fd90194, 0x00b80fcb, 0x0fe0019d, + 0x00a60fcd, 0x0fe601a7, 0x00950fcf, 0x0fee01ae, + 0x00850fcf, 0x0ff701b5, 0x00750fce, 0x000001bd, + 0x00670fc9, 0x000a01c6, 0x00590fbe, 0x001601d3, + 0x004d0fa8, 0x002301e8, 0x00430f7a, 0x0034020f, + + 0x015c005e, 0x0fde0068, 0x015c0054, 0x0fdd0073, + 0x015b004b, 0x0fdc007e, 0x015a0042, 0x0fdb0089, + 0x01590039, 0x0fda0094, 0x01560030, 0x0fda00a0, + 0x01530028, 0x0fda00ab, 0x014f0020, 0x0fda00b7, + 0x014a0019, 0x0fdb00c2, 0x01450011, 0x0fdc00ce, + 0x013e000b, 0x0fde00d9, 0x01390004, 0x0fdf00e4, + 0x01310ffe, 0x0fe200ef, 0x01290ff9, 0x0fe400fa, + 0x01200ff4, 0x0fe80104, 0x01180fef, 0x0feb010e, + 0x010e0feb, 0x0fef0118, 0x01040fe8, 0x0ff40120, + 0x00fa0fe4, 0x0ff90129, 0x00ef0fe2, 0x0ffe0131, + 0x00e40fdf, 0x00040139, 0x00d90fde, 0x000b013e, + 0x00ce0fdc, 0x00110145, 0x00c20fdb, 0x0019014a, + 0x00b70fda, 0x0020014f, 0x00ab0fda, 0x00280153, + 0x00a00fda, 0x00300156, 0x00940fda, 0x00390159, + 0x00890fdb, 0x0042015a, 0x007e0fdc, 0x004b015b, + 0x00730fdd, 0x0054015c, 0x00680fde, 0x005e015c, + + 0x01300068, 0x0ff80070, 0x01300060, 0x0ff80078, + 0x012f0059, 0x0ff80080, 0x012d0052, 0x0ff80089, + 0x012b004b, 0x0ff90091, 0x01290044, 0x0ff9009a, + 0x0126003d, 0x0ffa00a3, 0x01220037, 0x0ffb00ac, + 0x011f0031, 0x0ffc00b4, 0x011a002b, 0x0ffe00bd, + 0x01150026, 0x000000c5, 0x010f0021, 0x000200ce, + 0x010a001c, 0x000400d6, 0x01030018, 0x000600df, + 0x00fd0014, 0x000900e6, 0x00f60010, 0x000c00ee, + 0x00ee000c, 0x001000f6, 0x00e60009, 0x001400fd, + 0x00df0006, 0x00180103, 0x00d60004, 0x001c010a, + 0x00ce0002, 0x0021010f, 0x00c50000, 0x00260115, + 0x00bd0ffe, 0x002b011a, 0x00b40ffc, 0x0031011f, + 0x00ac0ffb, 0x00370122, 0x00a30ffa, 0x003d0126, + 0x009a0ff9, 0x00440129, 0x00910ff9, 0x004b012b, + 0x00890ff8, 0x0052012d, 0x00800ff8, 0x0059012f, + 0x00780ff8, 0x00600130, 0x00700ff8, 0x00680130, + + 0x01050079, 0x0003007f, 0x01040073, 0x00030086, + 0x0103006d, 0x0004008c, 0x01030066, 0x00050092, + 0x01010060, 0x00060099, 0x0100005a, 0x0007009f, + 0x00fe0054, 0x000900a5, 0x00fa004f, 0x000b00ac, + 0x00f80049, 0x000d00b2, 0x00f50044, 0x000f00b8, + 0x00f2003f, 0x001200bd, 0x00ef0039, 0x001500c3, + 0x00ea0035, 0x001800c9, 0x00e60030, 0x001c00ce, + 0x00e3002b, 0x001f00d3, 0x00dd0027, 0x002300d9, + 0x00d90023, 0x002700dd, 0x00d3001f, 0x002b00e3, + 0x00ce001c, 0x003000e6, 0x00c90018, 0x003500ea, + 0x00c30015, 0x003900ef, 0x00bd0012, 0x003f00f2, + 0x00b8000f, 0x004400f5, 0x00b2000d, 0x004900f8, + 0x00ac000b, 0x004f00fa, 0x00a50009, 0x005400fe, + 0x009f0007, 0x005a0100, 0x00990006, 0x00600101, + 0x00920005, 0x00660103, 0x008c0004, 0x006d0103, + 0x00860003, 0x00730104, 0x007f0003, 0x00790105, + + 0x00cf0088, 0x001d008c, 0x00ce0084, 0x0020008e, + 0x00cd0080, 0x00210092, 0x00cd007b, 0x00240094, + 0x00ca0077, 0x00270098, 0x00c90073, 0x0029009b, + 0x00c8006f, 0x002c009d, 0x00c6006b, 0x002f00a0, + 0x00c50067, 0x003200a2, 0x00c30062, 0x003600a5, + 0x00c0005f, 0x003900a8, 0x00c0005b, 0x003b00aa, + 0x00be0057, 0x003e00ad, 0x00ba0054, 0x004200b0, + 0x00b90050, 0x004500b2, 0x00b7004c, 0x004900b4, + 0x00b40049, 0x004c00b7, 0x00b20045, 0x005000b9, + 0x00b00042, 0x005400ba, 0x00ad003e, 0x005700be, + 0x00aa003b, 0x005b00c0, 0x00a80039, 0x005f00c0, + 0x00a50036, 0x006200c3, 0x00a20032, 0x006700c5, + 0x00a0002f, 0x006b00c6, 0x009d002c, 0x006f00c8, + 0x009b0029, 0x007300c9, 0x00980027, 0x007700ca, + 0x00940024, 0x007b00cd, 0x00920021, 0x008000cd, + 0x008e0020, 0x008400ce, 0x008c001d, 0x008800cf, + + 0x008e0083, 0x006b0084, 0x008d0083, 0x006c0084, + 0x008d0082, 0x006d0084, 0x008d0081, 0x006d0085, + 0x008d0080, 0x006e0085, 0x008c007f, 0x006f0086, + 0x008b007f, 0x00700086, 0x008b007e, 0x00710086, + 0x008b007d, 0x00720086, 0x008a007d, 0x00730086, + 0x008a007c, 0x00730087, 0x008a007b, 0x00740087, + 0x0089007b, 0x00750087, 0x008a0079, 0x00750088, + 0x008a0078, 0x00760088, 0x008a0077, 0x00770088, + 0x00880077, 0x0077008a, 0x00880076, 0x0078008a, + 0x00880075, 0x0079008a, 0x00870075, 0x007b0089, + 0x00870074, 0x007b008a, 0x00870073, 0x007c008a, + 0x00860073, 0x007d008a, 0x00860072, 0x007d008b, + 0x00860071, 0x007e008b, 0x00860070, 0x007f008b, + 0x0086006f, 0x007f008c, 0x0085006e, 0x0080008d, + 0x0085006d, 0x0081008d, 0x0084006d, 0x0082008d, + 0x0084006c, 0x0083008d, 0x0084006b, 0x0083008e, + + 0x023c0fe2, 0x00000fe2, 0x023a0fdb, 0x00000feb, + 0x02360fd3, 0x0fff0ff8, 0x022e0fcf, 0x0ffc0007, + 0x02250fca, 0x0ffa0017, 0x021a0fc6, 0x0ff70029, + 0x020c0fc4, 0x0ff4003c, 0x01fd0fc1, 0x0ff10051, + 0x01eb0fc0, 0x0fed0068, 0x01d80fc0, 0x0fe9007f, + 0x01c30fc1, 0x0fe50097, 0x01ac0fc2, 0x0fe200b0, + 0x01960fc3, 0x0fdd00ca, 0x017e0fc5, 0x0fd900e4, + 0x01650fc8, 0x0fd500fe, 0x014b0fcb, 0x0fd20118, + 0x01330fcd, 0x0fcd0133, 0x01180fd2, 0x0fcb014b, + 0x00fe0fd5, 0x0fc80165, 0x00e40fd9, 0x0fc5017e, + 0x00ca0fdd, 0x0fc30196, 0x00b00fe2, 0x0fc201ac, + 0x00970fe5, 0x0fc101c3, 0x007f0fe9, 0x0fc001d8, + 0x00680fed, 0x0fc001eb, 0x00510ff1, 0x0fc101fd, + 0x003c0ff4, 0x0fc4020c, 0x00290ff7, 0x0fc6021a, + 0x00170ffa, 0x0fca0225, 0x00070ffc, 0x0fcf022e, + 0x0ff80fff, 0x0fd30236, 0x0feb0000, 0x0fdb023a, + + 0x02780fc4, 0x00000fc4, 0x02770fbc, 0x0fff0fce, + 0x02710fb5, 0x0ffe0fdc, 0x02690fb0, 0x0ffa0fed, + 0x025f0fab, 0x0ff70fff, 0x02500fa8, 0x0ff30015, + 0x02410fa6, 0x0fef002a, 0x022f0fa4, 0x0feb0042, + 0x021a0fa4, 0x0fe5005d, 0x02040fa5, 0x0fe10076, + 0x01eb0fa7, 0x0fdb0093, 0x01d20fa9, 0x0fd600af, + 0x01b80fab, 0x0fd000cd, 0x019d0faf, 0x0fca00ea, + 0x01810fb2, 0x0fc50108, 0x01620fb7, 0x0fc10126, + 0x01440fbb, 0x0fbb0146, 0x01260fc1, 0x0fb70162, + 0x01080fc5, 0x0fb20181, 0x00ea0fca, 0x0faf019d, + 0x00cd0fd0, 0x0fab01b8, 0x00af0fd6, 0x0fa901d2, + 0x00930fdb, 0x0fa701eb, 0x00760fe1, 0x0fa50204, + 0x005d0fe5, 0x0fa4021a, 0x00420feb, 0x0fa4022f, + 0x002a0fef, 0x0fa60241, 0x00150ff3, 0x0fa80250, + 0x0fff0ff7, 0x0fab025f, 0x0fed0ffa, 0x0fb00269, + 0x0fdc0ffe, 0x0fb50271, 0x0fce0fff, 0x0fbc0277, + + 0x02a00fb0, 0x00000fb0, 0x029e0fa8, 0x0fff0fbb, + 0x02980fa1, 0x0ffd0fca, 0x028f0f9c, 0x0ff90fdc, + 0x02840f97, 0x0ff50ff0, 0x02740f94, 0x0ff10007, + 0x02640f92, 0x0fec001e, 0x02500f91, 0x0fe70038, + 0x023a0f91, 0x0fe00055, 0x02220f92, 0x0fdb0071, + 0x02080f95, 0x0fd4008f, 0x01ec0f98, 0x0fce00ae, + 0x01cf0f9b, 0x0fc700cf, 0x01b10f9f, 0x0fc100ef, + 0x01920fa4, 0x0fbb010f, 0x01710faa, 0x0fb50130, + 0x01520fae, 0x0fae0152, 0x01300fb5, 0x0faa0171, + 0x010f0fbb, 0x0fa40192, 0x00ef0fc1, 0x0f9f01b1, + 0x00cf0fc7, 0x0f9b01cf, 0x00ae0fce, 0x0f9801ec, + 0x008f0fd4, 0x0f950208, 0x00710fdb, 0x0f920222, + 0x00550fe0, 0x0f91023a, 0x00380fe7, 0x0f910250, + 0x001e0fec, 0x0f920264, 0x00070ff1, 0x0f940274, + 0x0ff00ff5, 0x0f970284, 0x0fdc0ff9, 0x0f9c028f, + 0x0fca0ffd, 0x0fa10298, 0x0fbb0fff, 0x0fa8029e, + + 0x02c80f9c, 0x00000f9c, 0x02c70f94, 0x0ffe0fa7, + 0x02c10f8c, 0x0ffc0fb7, 0x02b70f87, 0x0ff70fcb, + 0x02aa0f83, 0x0ff30fe0, 0x02990f80, 0x0fee0ff9, + 0x02870f7f, 0x0fe80012, 0x02720f7e, 0x0fe2002e, + 0x025a0f7e, 0x0fdb004d, 0x02400f80, 0x0fd5006b, + 0x02230f84, 0x0fcd008c, 0x02050f87, 0x0fc700ad, + 0x01e60f8b, 0x0fbf00d0, 0x01c60f90, 0x0fb700f3, + 0x01a30f96, 0x0fb00117, 0x01800f9c, 0x0faa013a, + 0x015d0fa2, 0x0fa2015f, 0x013a0faa, 0x0f9c0180, + 0x01170fb0, 0x0f9601a3, 0x00f30fb7, 0x0f9001c6, + 0x00d00fbf, 0x0f8b01e6, 0x00ad0fc7, 0x0f870205, + 0x008c0fcd, 0x0f840223, 0x006b0fd5, 0x0f800240, + 0x004d0fdb, 0x0f7e025a, 0x002e0fe2, 0x0f7e0272, + 0x00120fe8, 0x0f7f0287, 0x0ff90fee, 0x0f800299, + 0x0fe00ff3, 0x0f8302aa, 0x0fcb0ff7, 0x0f8702b7, + 0x0fb70ffc, 0x0f8c02c1, 0x0fa70ffe, 0x0f9402c7, + + 0x02f00f88, 0x00000f88, 0x02ee0f80, 0x0ffe0f94, + 0x02e70f78, 0x0ffc0fa5, 0x02dd0f73, 0x0ff60fba, + 0x02ce0f6f, 0x0ff20fd1, 0x02be0f6c, 0x0feb0feb, + 0x02aa0f6b, 0x0fe50006, 0x02940f6a, 0x0fde0024, + 0x02790f6c, 0x0fd60045, 0x025e0f6e, 0x0fcf0065, + 0x023f0f72, 0x0fc60089, 0x021d0f77, 0x0fbf00ad, + 0x01fd0f7b, 0x0fb600d2, 0x01da0f81, 0x0fad00f8, + 0x01b50f87, 0x0fa6011e, 0x018f0f8f, 0x0f9e0144, + 0x016b0f95, 0x0f95016b, 0x01440f9e, 0x0f8f018f, + 0x011e0fa6, 0x0f8701b5, 0x00f80fad, 0x0f8101da, + 0x00d20fb6, 0x0f7b01fd, 0x00ad0fbf, 0x0f77021d, + 0x00890fc6, 0x0f72023f, 0x00650fcf, 0x0f6e025e, + 0x00450fd6, 0x0f6c0279, 0x00240fde, 0x0f6a0294, + 0x00060fe5, 0x0f6b02aa, 0x0feb0feb, 0x0f6c02be, + 0x0fd10ff2, 0x0f6f02ce, 0x0fba0ff6, 0x0f7302dd, + 0x0fa50ffc, 0x0f7802e7, 0x0f940ffe, 0x0f8002ee, + + 0x03180f74, 0x00000f74, 0x03160f6b, 0x0ffe0f81, + 0x030e0f64, 0x0ffb0f93, 0x03030f5f, 0x0ff50fa9, + 0x02f40f5b, 0x0ff00fc1, 0x02e20f58, 0x0fe90fdd, + 0x02cd0f57, 0x0fe20ffa, 0x02b60f57, 0x0fda0019, + 0x02990f59, 0x0fd1003d, 0x027b0f5c, 0x0fc90060, + 0x02590f61, 0x0fc00086, 0x02370f66, 0x0fb700ac, + 0x02130f6b, 0x0fae00d4, 0x01ee0f72, 0x0fa400fc, + 0x01c70f79, 0x0f9b0125, 0x019f0f81, 0x0f93014d, + 0x01760f89, 0x0f890178, 0x014d0f93, 0x0f81019f, + 0x01250f9b, 0x0f7901c7, 0x00fc0fa4, 0x0f7201ee, + 0x00d40fae, 0x0f6b0213, 0x00ac0fb7, 0x0f660237, + 0x00860fc0, 0x0f610259, 0x00600fc9, 0x0f5c027b, + 0x003d0fd1, 0x0f590299, 0x00190fda, 0x0f5702b6, + 0x0ffa0fe2, 0x0f5702cd, 0x0fdd0fe9, 0x0f5802e2, + 0x0fc10ff0, 0x0f5b02f4, 0x0fa90ff5, 0x0f5f0303, + 0x0f930ffb, 0x0f64030e, 0x0f810ffe, 0x0f6b0316, + + 0x03400f60, 0x00000f60, 0x033e0f57, 0x0ffe0f6d, + 0x03370f4f, 0x0ffa0f80, 0x032a0f4b, 0x0ff30f98, + 0x031a0f46, 0x0fee0fb2, 0x03070f44, 0x0fe60fcf, + 0x02f10f44, 0x0fde0fed, 0x02d70f44, 0x0fd6000f, + 0x02b80f46, 0x0fcc0036, 0x02990f4a, 0x0fc3005a, + 0x02750f4f, 0x0fb90083, 0x02500f55, 0x0fb000ab, + 0x022a0f5b, 0x0fa500d6, 0x02020f63, 0x0f9a0101, + 0x01d80f6b, 0x0f91012c, 0x01ae0f74, 0x0f870157, + 0x01840f7c, 0x0f7c0184, 0x01570f87, 0x0f7401ae, + 0x012c0f91, 0x0f6b01d8, 0x01010f9a, 0x0f630202, + 0x00d60fa5, 0x0f5b022a, 0x00ab0fb0, 0x0f550250, + 0x00830fb9, 0x0f4f0275, 0x005a0fc3, 0x0f4a0299, + 0x00360fcc, 0x0f4602b8, 0x000f0fd6, 0x0f4402d7, + 0x0fed0fde, 0x0f4402f1, 0x0fcf0fe6, 0x0f440307, + 0x0fb20fee, 0x0f46031a, 0x0f980ff3, 0x0f4b032a, + 0x0f800ffa, 0x0f4f0337, 0x0f6d0ffe, 0x0f57033e +}; + + +#define MDP4_QSEED_TABLE0_OFF 0x8100 +#define MDP4_QSEED_TABLE1_OFF 0x8200 +#define MDP4_QSEED_TABLE2_OFF 0x9000 + +void mdp4_vg_qseed_init(int vp_num) +{ + uint32 *off; + int i, voff; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + voff = MDP4_VIDEO_OFF * vp_num; + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_QSEED_TABLE0_OFF); + for (i = 0; i < (sizeof(vg_qseed_table0) / sizeof(uint32)); i++) { + outpdw(off, vg_qseed_table0[i]); + off++; + /* This code is added to workaround the 1K Boundary AXI + Interleave operations from Scorpion that can potentially + corrupt the QSEED table. The idea is to complete the prevous + to the buffer before making the next write when address is + 1KB aligned to ensure the write has been committed prior to + next instruction write that can go out from the secondary AXI + port.This happens also because of the expected write sequence + from QSEED table, where LSP has to be written first then the + MSP to trigger both to write out to SRAM, if this has not been + the expectation, then corruption wouldn't have happened.*/ + + if (!((uint32)off & 0x3FF)) + wmb(); + } + + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_QSEED_TABLE1_OFF); + for (i = 0; i < (sizeof(vg_qseed_table1) / sizeof(uint32)); i++) { + outpdw(off, vg_qseed_table1[i]); + off++; + if (!((uint32)off & 0x3FF)) + wmb(); + } + + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_QSEED_TABLE2_OFF); + for (i = 0; i < (sizeof(vg_qseed_table2) / sizeof(uint32)); i++) { + outpdw(off, vg_qseed_table2[i]); + off++; + if (!((uint32)off & 0x3FF)) + wmb(); + } + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + +} + +void mdp4_mixer_blend_init(mixer_num) +{ + unsigned char *overlay_base; + int off; + + if (mixer_num) /* mixer number, /dev/fb0, /dev/fb1 */ + overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */ + else + overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* stage 0 to stage 2 */ + off = 0; + outpdw(overlay_base + off + 0x104, 0x010); + outpdw(overlay_base + off + 0x108, 0xff);/* FG */ + outpdw(overlay_base + off + 0x10c, 0x00);/* BG */ + + off += 0x20; + outpdw(overlay_base + off + 0x104, 0x010); + outpdw(overlay_base + off + 0x108, 0xff);/* FG */ + outpdw(overlay_base + off + 0x10c, 0x00);/* BG */ + + off += 0x20; + outpdw(overlay_base + off + 0x104, 0x010); + outpdw(overlay_base + off + 0x108, 0xff);/* FG */ + outpdw(overlay_base + off + 0x10c, 0x00);/* BG */ + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +struct mdp_csc_cfg mdp_csc_convert[4] = { + { /*RGB2RGB*/ + 0, + { + 0x0200, 0x0000, 0x0000, + 0x0000, 0x0200, 0x0000, + 0x0000, 0x0000, 0x0200, + }, + { 0x0, 0x0, 0x0, }, + { 0x0, 0x0, 0x0, }, + { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, }, + { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, }, + }, + { /*YUV2RGB*/ + 0, + { + 0x0254, 0x0000, 0x0331, + 0x0254, 0xff37, 0xfe60, + 0x0254, 0x0409, 0x0000, + }, + { 0xfff0, 0xff80, 0xff80, }, + { 0x0, 0x0, 0x0, }, + { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, }, + { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, }, + }, + { /*RGB2YUV*/ + 0, + { + 0x0083, 0x0102, 0x0032, + 0x1fb5, 0x1f6c, 0x00e1, + 0x00e1, 0x1f45, 0x1fdc + }, + { 0x0, 0x0, 0x0, }, + { 0x0010, 0x0080, 0x0080, }, + { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, }, + { 0x0010, 0x00eb, 0x0010, 0x00f0, 0x0010, 0x00f0, }, + }, + { /*YUV2YUV ???*/ + 0, + { + 0x0200, 0x0000, 0x0000, + 0x0000, 0x0200, 0x0000, + 0x0000, 0x0000, 0x0200, + }, + { 0x0, 0x0, 0x0, }, + { 0x0, 0x0, 0x0, }, + { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, }, + { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, }, + }, +}; + +struct mdp_csc_cfg csc_matrix[3] = { + { + (MDP_CSC_FLAG_YUV_OUT), + { + 0x0254, 0x0000, 0x0331, + 0x0254, 0xff37, 0xfe60, + 0x0254, 0x0409, 0x0000, + }, + { + 0xfff0, 0xff80, 0xff80, + }, + { + 0, 0, 0, + }, + { + 0, 0xff, 0, 0xff, 0, 0xff, + }, + { + 0, 0xff, 0, 0xff, 0, 0xff, + }, + }, + { + (MDP_CSC_FLAG_YUV_OUT), + { + 0x0254, 0x0000, 0x0331, + 0x0254, 0xff37, 0xfe60, + 0x0254, 0x0409, 0x0000, + }, + { + 0xfff0, 0xff80, 0xff80, + }, + { + 0, 0, 0, + }, + { + 0, 0xff, 0, 0xff, 0, 0xff, + }, + { + 0, 0xff, 0, 0xff, 0, 0xff, + }, + }, + { + (0), + { + 0x0200, 0x0000, 0x0000, + 0x0000, 0x0200, 0x0000, + 0x0000, 0x0000, 0x0200, + }, + { + 0x0, 0x0, 0x0, + }, + { + 0, 0, 0, + }, + { + 0, 0xff, 0, 0xff, 0, 0xff, + }, + { + 0, 0xff, 0, 0xff, 0, 0xff, + }, + }, +}; + + + +#define MDP4_CSC_MV_OFF 0x4400 +#define MDP4_CSC_PRE_BV_OFF 0x4500 +#define MDP4_CSC_POST_BV_OFF 0x4580 +#define MDP4_CSC_PRE_LV_OFF 0x4600 +#define MDP4_CSC_POST_LV_OFF 0x4680 + +void mdp4_vg_csc_mv_setup(int vp_num) +{ + uint32 *off; + int i, voff; + + voff = MDP4_VIDEO_OFF * vp_num; + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_CSC_MV_OFF); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < 9; i++) { + outpdw(off, csc_matrix[vp_num].csc_mv[i]); + off++; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_vg_csc_pre_bv_setup(int vp_num) +{ + uint32 *off; + int i, voff; + + voff = MDP4_VIDEO_OFF * vp_num; + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_CSC_PRE_BV_OFF); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < 3; i++) { + outpdw(off, csc_matrix[vp_num].csc_pre_bv[i]); + off++; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_vg_csc_post_bv_setup(int vp_num) +{ + uint32 *off; + int i, voff; + + voff = MDP4_VIDEO_OFF * vp_num; + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_CSC_POST_BV_OFF); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < 3; i++) { + outpdw(off, csc_matrix[vp_num].csc_post_bv[i]); + off++; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_vg_csc_pre_lv_setup(int vp_num) +{ + uint32 *off; + int i, voff; + + voff = MDP4_VIDEO_OFF * vp_num; + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_CSC_PRE_LV_OFF); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < 6; i++) { + outpdw(off, csc_matrix[vp_num].csc_pre_lv[i]); + off++; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_vg_csc_post_lv_setup(int vp_num) +{ + uint32 *off; + int i, voff; + + voff = MDP4_VIDEO_OFF * vp_num; + off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff + + MDP4_CSC_POST_LV_OFF); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < 6; i++) { + outpdw(off, csc_matrix[vp_num].csc_post_lv[i]); + off++; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_vg_csc_convert_setup(int vp_num) +{ + struct mdp_csc_cfg_data cfg; + + switch (vp_num) { + case 0: + cfg.block = MDP_BLOCK_VG_1; + break; + case 1: + cfg.block = MDP_BLOCK_VG_2; + break; + default: + pr_err("%s - invalid vp_num = %d", __func__, vp_num); + return; + } + cfg.csc_data = csc_matrix[vp_num]; + mdp4_csc_enable(&cfg); +} + +void mdp4_vg_csc_setup(int vp_num) +{ + /* yuv2rgb */ + mdp4_vg_csc_mv_setup(vp_num); + mdp4_vg_csc_pre_bv_setup(vp_num); + mdp4_vg_csc_post_bv_setup(vp_num); + mdp4_vg_csc_pre_lv_setup(vp_num); + mdp4_vg_csc_post_lv_setup(vp_num); + mdp4_vg_csc_convert_setup(vp_num); +} +void mdp4_vg_csc_update(struct mdp_csc *p) +{ + struct mdp4_overlay_pipe *pipe; + int vp_num; + + pipe = mdp4_overlay_ndx2pipe(p->id); + if (pipe == NULL) { + pr_err("%s: p->id = %d Error\n", __func__, p->id); + return; + } + + vp_num = pipe->pipe_num - OVERLAY_PIPE_VG1; + + if (vp_num == 0 || vp_num == 1) { + memcpy(csc_matrix[vp_num].csc_mv, p->csc_mv, sizeof(p->csc_mv)); + memcpy(csc_matrix[vp_num].csc_pre_bv, p->csc_pre_bv, + sizeof(p->csc_pre_bv)); + memcpy(csc_matrix[vp_num].csc_post_bv, p->csc_post_bv, + sizeof(p->csc_post_bv)); + memcpy(csc_matrix[vp_num].csc_pre_lv, p->csc_pre_lv, + sizeof(p->csc_pre_lv)); + memcpy(csc_matrix[vp_num].csc_post_lv, p->csc_post_lv, + sizeof(p->csc_post_lv)); + mdp4_vg_csc_setup(vp_num); + } +} +static uint32 csc_rgb2yuv_matrix_tab[9] = { + 0x0083, 0x0102, 0x0032, + 0x1fb5, 0x1f6c, 0x00e1, + 0x00e1, 0x1f45, 0x1fdc +}; + +static uint32 csc_rgb2yuv_pre_bv_tab[3] = {0, 0, 0}; + +static uint32 csc_rgb2yuv_post_bv_tab[3] = {0x0010, 0x0080, 0x0080}; + +static uint32 csc_rgb2yuv_pre_lv_tab[6] = { + 0x00, 0xff, 0x00, + 0xff, 0x00, 0xff +}; + +static uint32 csc_rgb2yuv_post_lv_tab[6] = { + 0x0010, 0x00eb, 0x0010, + 0x00f0, 0x0010, 0x00f0 +}; + +void mdp4_mixer_csc_mv_setup(uint32 mixer) +{ + uint32 *off; + int i; + + if (mixer == MDP4_MIXER1) + off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2400); + else + off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2400); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < 9; i++) { + outpdw(off, csc_rgb2yuv_matrix_tab[i]); + off++; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_mixer_csc_pre_bv_setup(uint32 mixer) +{ + uint32 *off; + int i; + + if (mixer == MDP4_MIXER1) + off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2500); + else + off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2500); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < 3; i++) { + outpdw(off, csc_rgb2yuv_pre_bv_tab[i]); + off++; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_mixer_csc_post_bv_setup(uint32 mixer) +{ + uint32 *off; + int i; + + if (mixer == MDP4_MIXER1) + off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2580); + else + off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2580); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < 3; i++) { + outpdw(off, csc_rgb2yuv_post_bv_tab[i]); + off++; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_mixer_csc_pre_lv_setup(uint32 mixer) +{ + uint32 *off; + int i; + + if (mixer == MDP4_MIXER1) + off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2600); + else + off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2600); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < 6; i++) { + outpdw(off, csc_rgb2yuv_pre_lv_tab[i]); + off++; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_mixer_csc_post_lv_setup(uint32 mixer) +{ + uint32 *off; + int i; + + if (mixer == MDP4_MIXER1) + off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2680); + else + off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2680); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < 6; i++) { + outpdw(off, csc_rgb2yuv_post_lv_tab[i]); + off++; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_mixer_csc_setup(uint32 mixer) +{ + if (mixer >= MDP4_MIXER1) { + /* rgb2yuv */ + mdp4_mixer_csc_mv_setup(mixer); + mdp4_mixer_csc_pre_bv_setup(mixer); + mdp4_mixer_csc_post_bv_setup(mixer); + mdp4_mixer_csc_pre_lv_setup(mixer); + mdp4_mixer_csc_post_lv_setup(mixer); + } +} + +#define DMA_P_BASE 0x90000 +void mdp4_dmap_csc_mv_setup(void) +{ + uint32 *off; + int i; + + off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3400); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < 9; i++) { + outpdw(off, csc_matrix[2].csc_mv[i]); + off++; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_dmap_csc_pre_bv_setup(void) +{ + uint32 *off; + int i; + + off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3500); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < 3; i++) { + outpdw(off, csc_matrix[2].csc_pre_bv[i]); + off++; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_dmap_csc_post_bv_setup(void) +{ + uint32 *off; + int i; + + off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3580); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < 3; i++) { + outpdw(off, csc_matrix[2].csc_post_bv[i]); + off++; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_dmap_csc_pre_lv_setup(void) +{ + uint32 *off; + int i; + + off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3600); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < 6; i++) { + outpdw(off, csc_matrix[2].csc_pre_lv[i]); + off++; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_dmap_csc_post_lv_setup(void) +{ + uint32 *off; + int i; + + off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3680); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < 6; i++) { + outpdw(off, csc_matrix[2].csc_post_lv[i]); + off++; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +void mdp4_dmap_csc_setup(void) +{ + mdp4_dmap_csc_mv_setup(); + mdp4_dmap_csc_pre_bv_setup(); + mdp4_dmap_csc_post_bv_setup(); + mdp4_dmap_csc_pre_lv_setup(); + mdp4_dmap_csc_post_lv_setup(); +} + +char gc_lut[] = { + 0x0, 0x1, 0x2, 0x2, 0x3, 0x4, 0x5, 0x6, + 0x6, 0x7, 0x8, 0x9, 0xA, 0xA, 0xB, 0xC, + 0xD, 0xD, 0xE, 0xF, 0xF, 0x10, 0x10, 0x11, + 0x12, 0x12, 0x13, 0x13, 0x14, 0x14, 0x15, 0x15, + 0x16, 0x16, 0x17, 0x17, 0x17, 0x18, 0x18, 0x19, + 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1C, + 0x1C, 0x1D, 0x1D, 0x1D, 0x1E, 0x1E, 0x1E, 0x1F, + 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, + 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x24, + 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, + 0x26, 0x26, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, + 0x28, 0x29, 0x29, 0x29, 0x29, 0x2A, 0x2A, 0x2A, + 0x2A, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2C, 0x2C, + 0x2C, 0x2C, 0x2D, 0x2D, 0x2D, 0x2D, 0x2E, 0x2E, + 0x2E, 0x2E, 0x2E, 0x2F, 0x2F, 0x2F, 0x2F, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, + 0x3A, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3C, + 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3D, 0x3D, 0x3D, + 0x3D, 0x3D, 0x3D, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, + 0x3E, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, + 0x43, 0x43, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47, + 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, + 0x49, 0x49, 0x49, 0x49, 0x49, 0x4A, 0x4A, 0x4A, + 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4B, 0x4B, 0x4B, + 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4C, 0x4C, 0x4C, + 0x4C, 0x4C, 0x4C, 0x4C, 0x4D, 0x4D, 0x4D, 0x4D, + 0x4D, 0x4D, 0x4D, 0x4D, 0x4E, 0x4E, 0x4E, 0x4E, + 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4F, 0x4F, 0x4F, + 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52, + 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x53, 0x53, + 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, + 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, + 0x56, 0x56, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, + 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, + 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5A, 0x5A, + 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, + 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, + 0x5B, 0x5B, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, + 0x5C, 0x5C, 0x5C, 0x5C, 0x5D, 0x5D, 0x5D, 0x5D, + 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5E, 0x5E, + 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, + 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, + 0x5F, 0x5F, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, + 0x60, 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, + 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x62, + 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, + 0x62, 0x62, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x64, 0x64, 0x64, + 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, + 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, + 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, + 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, + 0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, + 0x68, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, + 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, + 0x69, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, + 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6B, 0x6B, 0x6B, + 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, + 0x6B, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, + 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6D, 0x6D, 0x6D, + 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, + 0x6D, 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, + 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 0x6F, 0x6F, 0x6F, + 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, + 0x6F, 0x6F, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x71, 0x71, + 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, + 0x71, 0x71, 0x71, 0x72, 0x72, 0x72, 0x72, 0x72, + 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, + 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, + 0x73, 0x73, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, + 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, + 0x74, 0x74, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, + 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, + 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, + 0x76, 0x76, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, + 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x7A, 0x7A, + 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, + 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7B, + 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, + 0x7B, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, + 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, + 0x7C, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, + 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, + 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, + 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, + 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, + 0x8A, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, + 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, + 0x8B, 0x8B, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, + 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, + 0x8C, 0x8C, 0x8C, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, + 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, + 0x8D, 0x8D, 0x8D, 0x8D, 0x8E, 0x8E, 0x8E, 0x8E, + 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, + 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8F, 0x8F, 0x8F, + 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, + 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, + 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9B, 0x9B, 0x9B, + 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, + 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, + 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, + 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, + 0x9C, 0x9C, 0x9C, 0x9C, 0x9D, 0x9D, 0x9D, 0x9D, + 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, + 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9E, + 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, + 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, + 0x9E, 0x9E, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, + 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, + 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, + 0xA0, 0xA0, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, + 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, + 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA2, 0xA2, + 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, + 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, + 0xA2, 0xA2, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, + 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, + 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA4, 0xA4, + 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, + 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, + 0xA4, 0xA4, 0xA4, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, + 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, + 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, + 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, + 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, + 0xA6, 0xA6, 0xA6, 0xA6, 0xA7, 0xA7, 0xA7, 0xA7, + 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, + 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, + 0xA7, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, + 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, + 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA9, + 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, + 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, + 0xA9, 0xA9, 0xA9, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, + 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, + 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAC, + 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, + 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, + 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAD, 0xAD, 0xAD, + 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, + 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, + 0xAD, 0xAD, 0xAD, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, + 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, + 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, + 0xAE, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, + 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, + 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xB0, + 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, + 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, + 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB1, 0xB1, + 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, + 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, + 0xB1, 0xB1, 0xB1, 0xB1, 0xB2, 0xB2, 0xB2, 0xB2, + 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, + 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, + 0xB2, 0xB2, 0xB2, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, + 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, + 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, + 0xB3, 0xB3, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, + 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, + 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, + 0xB4, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, + 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, + 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, + 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, + 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, + 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, + 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, + 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, + 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB8, + 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, + 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, + 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB9, + 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, + 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, + 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xBA, + 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, + 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, + 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBB, + 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, + 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, + 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, + 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, + 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, + 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, + 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, + 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, + 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, + 0xBD, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, + 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, + 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, + 0xBE, 0xBE, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, + 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, + 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, + 0xBF, 0xBF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC1, 0xC1, 0xC1, 0xC1, + 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, + 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, + 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC2, 0xC2, 0xC2, + 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, + 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, + 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, + 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, + 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, + 0xC4, 0xC4, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, + 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, + 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, + 0xC5, 0xC5, 0xC5, 0xC5, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, + 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC7, 0xC7, + 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, + 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, + 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, + 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, + 0xC8, 0xC8, 0xC8, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, + 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, + 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, + 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xCA, 0xCA, + 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, + 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, + 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, + 0xCA, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, + 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, + 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, + 0xCB, 0xCB, 0xCB, 0xCB, 0xCC, 0xCC, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCD, + 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, + 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, + 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, + 0xCD, 0xCD, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, + 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, + 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, + 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCF, 0xCF, + 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, + 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, + 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, + 0xCF, 0xCF, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, + 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, + 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, + 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD1, 0xD1, 0xD1, + 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, + 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, + 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, + 0xD1, 0xD1, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, + 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, + 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, + 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD3, 0xD3, + 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, + 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, + 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, + 0xD3, 0xD3, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, + 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, + 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, + 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD5, + 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, + 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, + 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, + 0xD5, 0xD5, 0xD5, 0xD5, 0xD6, 0xD6, 0xD6, 0xD6, + 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, + 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, + 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, + 0xD6, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, + 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, + 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, + 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD8, 0xD8, + 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, + 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, + 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, + 0xD8, 0xD8, 0xD8, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, + 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, + 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, + 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, + 0xD9, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, + 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, + 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, + 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDB, 0xDB, + 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, + 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, + 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, + 0xDB, 0xDB, 0xDB, 0xDB, 0xDC, 0xDC, 0xDC, 0xDC, + 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, + 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, + 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, + 0xDC, 0xDC, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, + 0xDD, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, + 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, + 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, + 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDF, + 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, + 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, + 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, + 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xE0, 0xE0, + 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, + 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, + 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, + 0xE0, 0xE0, 0xE0, 0xE0, 0xE1, 0xE1, 0xE1, 0xE1, + 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, + 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, + 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, + 0xE1, 0xE1, 0xE1, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, + 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, + 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, + 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, + 0xE2, 0xE2, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, + 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, + 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, + 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, + 0xE3, 0xE3, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, + 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, + 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, + 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, + 0xE4, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, + 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, + 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, + 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, + 0xE5, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, + 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, + 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, + 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, + 0xE6, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, + 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, + 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, + 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, + 0xE7, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, + 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, + 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, + 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, + 0xE8, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, + 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, + 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, + 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, + 0xE9, 0xE9, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, + 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, + 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, + 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, + 0xEA, 0xEA, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, + 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, + 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, + 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, + 0xEB, 0xEB, 0xEB, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, + 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, + 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, + 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, + 0xEC, 0xEC, 0xEC, 0xEC, 0xED, 0xED, 0xED, 0xED, + 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, + 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, + 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, + 0xED, 0xED, 0xED, 0xED, 0xED, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEF, 0xEF, + 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, + 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, + 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, + 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, + 0xF1, 0xF1, 0xF1, 0xF1, 0xF2, 0xF2, 0xF2, 0xF2, + 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, + 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, + 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, + 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF3, 0xF3, + 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, + 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, + 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, + 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, + 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, + 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, + 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, + 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, + 0xF4, 0xF4, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, + 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF6, 0xF6, 0xF6, + 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, + 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, + 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, + 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, + 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, + 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, + 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, + 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, + 0xF7, 0xF7, 0xF7, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, + 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, + 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, + 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, + 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF9, 0xF9, + 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, + 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, + 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, + 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, + 0xF9, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, + 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, + 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, + 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, + 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, + 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, + 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, + 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, + 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, + 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, + 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, 0xFD, + 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, + 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, + 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, + 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, + 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +void mdp4_mixer_gc_lut_setup(int mixer_num) +{ + unsigned char *base; + uint32 data; + char val; + int i, off; + + if (mixer_num) /* mixer number, /dev/fb0, /dev/fb1 */ + base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */ + else + base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ + + base += 0x4000; /* GC_LUT offset */ + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + off = 0; + for (i = 0; i < 4096; i++) { + val = gc_lut[i]; + data = (val << 16 | val << 8 | val); /* R, B, and G are same */ + outpdw(base + off, data); + off += 4; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +uint32 igc_video_lut[] = { /* non linear */ + 0x0, 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x9, + 0xA, 0xB, 0xC, 0xE, 0xF, 0x10, 0x12, 0x14, + 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F, 0x21, 0x23, + 0x25, 0x28, 0x2A, 0x2D, 0x30, 0x32, 0x35, 0x38, + 0x3B, 0x3E, 0x42, 0x45, 0x48, 0x4C, 0x4F, 0x53, + 0x57, 0x5B, 0x5F, 0x63, 0x67, 0x6B, 0x70, 0x74, + 0x79, 0x7E, 0x83, 0x88, 0x8D, 0x92, 0x97, 0x9C, + 0xA2, 0xA8, 0xAD, 0xB3, 0xB9, 0xBF, 0xC5, 0xCC, + 0xD2, 0xD8, 0xDF, 0xE6, 0xED, 0xF4, 0xFB, 0x102, + 0x109, 0x111, 0x118, 0x120, 0x128, 0x130, 0x138, 0x140, + 0x149, 0x151, 0x15A, 0x162, 0x16B, 0x174, 0x17D, 0x186, + 0x190, 0x199, 0x1A3, 0x1AC, 0x1B6, 0x1C0, 0x1CA, 0x1D5, + 0x1DF, 0x1EA, 0x1F4, 0x1FF, 0x20A, 0x215, 0x220, 0x22B, + 0x237, 0x242, 0x24E, 0x25A, 0x266, 0x272, 0x27F, 0x28B, + 0x298, 0x2A4, 0x2B1, 0x2BE, 0x2CB, 0x2D8, 0x2E6, 0x2F3, + 0x301, 0x30F, 0x31D, 0x32B, 0x339, 0x348, 0x356, 0x365, + 0x374, 0x383, 0x392, 0x3A1, 0x3B1, 0x3C0, 0x3D0, 0x3E0, + 0x3F0, 0x400, 0x411, 0x421, 0x432, 0x443, 0x454, 0x465, + 0x476, 0x487, 0x499, 0x4AB, 0x4BD, 0x4CF, 0x4E1, 0x4F3, + 0x506, 0x518, 0x52B, 0x53E, 0x551, 0x565, 0x578, 0x58C, + 0x5A0, 0x5B3, 0x5C8, 0x5DC, 0x5F0, 0x605, 0x61A, 0x62E, + 0x643, 0x659, 0x66E, 0x684, 0x699, 0x6AF, 0x6C5, 0x6DB, + 0x6F2, 0x708, 0x71F, 0x736, 0x74D, 0x764, 0x77C, 0x793, + 0x7AB, 0x7C3, 0x7DB, 0x7F3, 0x80B, 0x824, 0x83D, 0x855, + 0x86F, 0x888, 0x8A1, 0x8BB, 0x8D4, 0x8EE, 0x908, 0x923, + 0x93D, 0x958, 0x973, 0x98E, 0x9A9, 0x9C4, 0x9DF, 0x9FB, + 0xA17, 0xA33, 0xA4F, 0xA6C, 0xA88, 0xAA5, 0xAC2, 0xADF, + 0xAFC, 0xB19, 0xB37, 0xB55, 0xB73, 0xB91, 0xBAF, 0xBCE, + 0xBEC, 0xC0B, 0xC2A, 0xC4A, 0xC69, 0xC89, 0xCA8, 0xCC8, + 0xCE8, 0xD09, 0xD29, 0xD4A, 0xD6B, 0xD8C, 0xDAD, 0xDCF, + 0xDF0, 0xE12, 0xE34, 0xE56, 0xE79, 0xE9B, 0xEBE, 0xEE1, + 0xF04, 0xF27, 0xF4B, 0xF6E, 0xF92, 0xFB6, 0xFDB, 0xFFF, +}; + +void mdp4_vg_igc_lut_setup(int vp_num) +{ + unsigned char *base; + int i, voff, off; + uint32 data, val; + + voff = MDP4_VIDEO_OFF * vp_num; + base = MDP_BASE + MDP4_VIDEO_BASE + voff + 0x5000; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + off = 0; + for (i = 0; i < 256; i++) { + val = igc_video_lut[i]; + data = (val << 16 | val); /* color 0 and 1 */ + outpdw(base + off, data); + outpdw(base + off + 0x800, val); /* color 2 */ + off += 4; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +uint32 igc_rgb_lut[] = { /* linear */ + 0x0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, + 0x80, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1, + 0x101, 0x111, 0x121, 0x131, 0x141, 0x151, 0x161, 0x171, + 0x181, 0x191, 0x1A2, 0x1B2, 0x1C2, 0x1D2, 0x1E2, 0x1F2, + 0x202, 0x212, 0x222, 0x232, 0x242, 0x252, 0x262, 0x272, + 0x282, 0x292, 0x2A2, 0x2B3, 0x2C3, 0x2D3, 0x2E3, 0x2F3, + 0x303, 0x313, 0x323, 0x333, 0x343, 0x353, 0x363, 0x373, + 0x383, 0x393, 0x3A3, 0x3B3, 0x3C4, 0x3D4, 0x3E4, 0x3F4, + 0x404, 0x414, 0x424, 0x434, 0x444, 0x454, 0x464, 0x474, + 0x484, 0x494, 0x4A4, 0x4B4, 0x4C4, 0x4D5, 0x4E5, 0x4F5, + 0x505, 0x515, 0x525, 0x535, 0x545, 0x555, 0x565, 0x575, + 0x585, 0x595, 0x5A5, 0x5B5, 0x5C5, 0x5D5, 0x5E6, 0x5F6, + 0x606, 0x616, 0x626, 0x636, 0x646, 0x656, 0x666, 0x676, + 0x686, 0x696, 0x6A6, 0x6B6, 0x6C6, 0x6D6, 0x6E6, 0x6F7, + 0x707, 0x717, 0x727, 0x737, 0x747, 0x757, 0x767, 0x777, + 0x787, 0x797, 0x7A7, 0x7B7, 0x7C7, 0x7D7, 0x7E7, 0x7F7, + 0x808, 0x818, 0x828, 0x838, 0x848, 0x858, 0x868, 0x878, + 0x888, 0x898, 0x8A8, 0x8B8, 0x8C8, 0x8D8, 0x8E8, 0x8F8, + 0x908, 0x919, 0x929, 0x939, 0x949, 0x959, 0x969, 0x979, + 0x989, 0x999, 0x9A9, 0x9B9, 0x9C9, 0x9D9, 0x9E9, 0x9F9, + 0xA09, 0xA19, 0xA2A, 0xA3A, 0xA4A, 0xA5A, 0xA6A, 0xA7A, + 0xA8A, 0xA9A, 0xAAA, 0xABA, 0xACA, 0xADA, 0xAEA, 0xAFA, + 0xB0A, 0xB1A, 0xB2A, 0xB3B, 0xB4B, 0xB5B, 0xB6B, 0xB7B, + 0xB8B, 0xB9B, 0xBAB, 0xBBB, 0xBCB, 0xBDB, 0xBEB, 0xBFB, + 0xC0B, 0xC1B, 0xC2B, 0xC3B, 0xC4C, 0xC5C, 0xC6C, 0xC7C, + 0xC8C, 0xC9C, 0xCAC, 0xCBC, 0xCCC, 0xCDC, 0xCEC, 0xCFC, + 0xD0C, 0xD1C, 0xD2C, 0xD3C, 0xD4C, 0xD5D, 0xD6D, 0xD7D, + 0xD8D, 0xD9D, 0xDAD, 0xDBD, 0xDCD, 0xDDD, 0xDED, 0xDFD, + 0xE0D, 0xE1D, 0xE2D, 0xE3D, 0xE4D, 0xE5D, 0xE6E, 0xE7E, + 0xE8E, 0xE9E, 0xEAE, 0xEBE, 0xECE, 0xEDE, 0xEEE, 0xEFE, + 0xF0E, 0xF1E, 0xF2E, 0xF3E, 0xF4E, 0xF5E, 0xF6E, 0xF7F, + 0xF8F, 0xF9F, 0xFAF, 0xFBF, 0xFCF, 0xFDF, 0xFEF, 0xFFF, +}; + +void mdp4_rgb_igc_lut_setup(int num) +{ + unsigned char *base; + int i, voff, off; + uint32 data, val; + + voff = MDP4_RGB_OFF * num; + base = MDP_BASE + MDP4_RGB_BASE + voff + 0x5000; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + off = 0; + for (i = 0; i < 256; i++) { + val = igc_rgb_lut[i]; + data = (val << 16 | val); /* color 0 and 1 */ + outpdw(base + off, data); + outpdw(base + off + 0x800, val); /* color 2 */ + off += 4; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +uint32 mdp4_rgb_igc_lut_cvt(uint32 ndx) +{ + return igc_rgb_lut[ndx & 0x0ff]; +} + +uint32_t mdp4_ss_table_value(int8_t value, int8_t index) +{ + uint32_t out = 0x0; + int8_t level = -1; + uint32_t mask = 0xffffffff; + + if (value < 0) { + if (value == -128) + value = 127; + else + value = -value; + out = 0x11111111; + } else { + out = 0x88888888; + mask = 0x0fffffff; + } + + if (value == 0) + level = 0; + else { + while (value > 0 && level < 7) { + level++; + value -= 16; + } + } + + if (level == 0) { + if (index == 0) + out = 0x0; + else + out = 0x20000000; + } else { + out += (0x11111111 * level); + if (index == 1) + out &= mask; + } + + return out; +} + +static uint32_t mdp4_csc_block2base(uint32_t block) +{ + uint32_t base = 0x0; + switch (block) { + case MDP_BLOCK_OVERLAY_1: + base = 0x1A000; + break; + case MDP_BLOCK_OVERLAY_2: + base = (mdp_rev >= MDP_REV_44) ? 0x8A000 : 0x0; + break; + case MDP_BLOCK_VG_1: + base = 0x24000; + break; + case MDP_BLOCK_VG_2: + base = 0x34000; + break; + case MDP_BLOCK_DMA_P: + base = 0x93000; + break; + case MDP_BLOCK_DMA_S: + base = (mdp_rev >= MDP_REV_42) ? 0xA3000 : 0x0; + default: + break; + } + return base; +} + +int mdp4_csc_enable(struct mdp_csc_cfg_data *config) +{ + uint32_t output, base, temp, mask; + + switch (config->block) { + case MDP_BLOCK_DMA_P: + base = 0x90070; + output = (config->csc_data.flags << 3) & (0x08); + temp = (config->csc_data.flags << 10) & (0x1800); + output |= temp; + mask = 0x08 | 0x1800; + break; + case MDP_BLOCK_DMA_S: + base = 0xA0028; + output = (config->csc_data.flags << 3) & (0x08); + temp = (config->csc_data.flags << 10) & (0x1800); + output |= temp; + mask = 0x08 | 0x1800; + break; + case MDP_BLOCK_VG_1: + base = 0x20058; + output = (config->csc_data.flags << 11) & (0x800); + temp = (config->csc_data.flags << 8) & (0x600); + output |= temp; + mask = 0x800 | 0x600; + break; + case MDP_BLOCK_VG_2: + base = 0x30058; + output = (config->csc_data.flags << 11) & (0x800); + temp = (config->csc_data.flags << 8) & (0x600); + output |= temp; + mask = 0x800 | 0x600; + break; + case MDP_BLOCK_OVERLAY_1: + base = 0x18200; + output = config->csc_data.flags; + mask = 0x07; + break; + case MDP_BLOCK_OVERLAY_2: + base = 0x88200; + output = config->csc_data.flags; + mask = 0x07; + break; + default: + pr_err("%s - CSC block does not exist on MDP_BLOCK = %d\n", + __func__, config->block); + return -EINVAL; + } + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + temp = inpdw(MDP_BASE + base) & ~mask; + output |= temp; + outpdw(MDP_BASE + base, output); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + return 0; +} + +#define CSC_MV_OFF 0x400 +#define CSC_BV_OFF 0x500 +#define CSC_LV_OFF 0x600 +#define CSC_POST_OFF 0x80 + +void mdp4_csc_write(struct mdp_csc_cfg *data, uint32_t base) +{ + int i; + uint32_t *off; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + off = (uint32_t *) ((uint32_t) base + CSC_MV_OFF); + for (i = 0; i < 9; i++) { + outpdw(off, data->csc_mv[i]); + off++; + } + + off = (uint32_t *) ((uint32_t) base + CSC_BV_OFF); + for (i = 0; i < 3; i++) { + outpdw(off, data->csc_pre_bv[i]); + outpdw((uint32_t *)((uint32_t)off + CSC_POST_OFF), + data->csc_post_bv[i]); + off++; + } + + off = (uint32_t *) ((uint32_t) base + CSC_LV_OFF); + for (i = 0; i < 6; i++) { + outpdw(off, data->csc_pre_lv[i]); + outpdw((uint32_t *)((uint32_t)off + CSC_POST_OFF), + data->csc_post_lv[i]); + off++; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +int mdp4_csc_config(struct mdp_csc_cfg_data *config) +{ + int ret = 0; + uint32_t base; + + base = mdp4_csc_block2base(config->block); + if (!base) { + pr_warn("%s: Block type %d isn't supported by CSC.\n", + __func__, config->block); + return -EINVAL; + } + + mdp4_csc_write(&config->csc_data, (uint32_t) (MDP_BASE + base)); + + ret = mdp4_csc_enable(config); + + return ret; +} + +void mdp4_init_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num) +{ + struct mdp_buf_type *buf; + + if (mix_num == MDP4_MIXER0) + buf = mfd->ov0_wb_buf; + else + buf = mfd->ov1_wb_buf; + + buf->ihdl = NULL; + buf->phys_addr = 0; +} + +u32 mdp4_allocate_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num) +{ + struct mdp_buf_type *buf; + ion_phys_addr_t addr; + size_t buffer_size; + unsigned long len; + + if (mix_num == MDP4_MIXER0) + buf = mfd->ov0_wb_buf; + else + buf = mfd->ov1_wb_buf; + + if (buf->phys_addr || !IS_ERR_OR_NULL(buf->ihdl)) + return 0; + + if (!buf->size) { + pr_err("%s:%d In valid size\n", __func__, __LINE__); + return -EINVAL; + } + + buffer_size = roundup(mfd->panel_info.xres * \ + mfd->panel_info.yres * 3 * 2, SZ_4K); + + if (!IS_ERR_OR_NULL(mfd->iclient)) { + pr_info("%s:%d ion based allocation mfd->mem_hid 0x%x\n", + __func__, __LINE__, mfd->mem_hid); + buf->ihdl = ion_alloc(mfd->iclient, buffer_size, SZ_4K, + mfd->mem_hid); + if (!IS_ERR_OR_NULL(buf->ihdl)) { + if (ion_map_iommu(mfd->iclient, buf->ihdl, + DISPLAY_DOMAIN, GEN_POOL, SZ_4K, 0, &addr, + &len, 0, 0)) { + pr_err("ion_map_iommu() failed\n"); + return -ENOMEM; + } + } else { + pr_err("%s:%d: ion_alloc failed\n", __func__, + __LINE__); + return -ENOMEM; + } + } else { + addr = allocate_contiguous_memory_nomap(buffer_size, + mfd->mem_hid, 4); + } + if (addr) { + pr_info("allocating %d bytes at %x for mdp writeback\n", + buffer_size, (u32) addr); + buf->phys_addr = addr; + return 0; + } else { + pr_err("%s cannot allocate memory for mdp writeback!\n", + __func__); + return -ENOMEM; + } +} + +void mdp4_free_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num) +{ + struct mdp_buf_type *buf; + + if (mix_num == MDP4_MIXER0) + buf = mfd->ov0_wb_buf; + else + buf = mfd->ov1_wb_buf; + + if (!IS_ERR_OR_NULL(mfd->iclient)) { + if (!IS_ERR_OR_NULL(buf->ihdl)) { + ion_unmap_iommu(mfd->iclient, buf->ihdl, + DISPLAY_DOMAIN, GEN_POOL); + ion_free(mfd->iclient, buf->ihdl); + pr_debug("%s:%d free writeback imem\n", __func__, + __LINE__); + buf->ihdl = NULL; + } + } else { + if (buf->phys_addr) { + free_contiguous_memory_by_paddr(buf->phys_addr); + pr_debug("%s:%d free writeback pmem\n", __func__, + __LINE__); + } + } + buf->phys_addr = 0; +} + +static int mdp4_update_pcc_regs(uint32_t offset, + struct mdp_pcc_cfg_data *cfg_ptr) +{ + int ret = -1; + + if (offset && cfg_ptr) { + + outpdw(offset, cfg_ptr->r.c); + outpdw(offset + 0x30, cfg_ptr->g.c); + outpdw(offset + 0x60, cfg_ptr->b.c); + offset += 4; + + outpdw(offset, cfg_ptr->r.r); + outpdw(offset + 0x30, cfg_ptr->g.r); + outpdw(offset + 0x60, cfg_ptr->b.r); + offset += 4; + + outpdw(offset, cfg_ptr->r.g); + outpdw(offset + 0x30, cfg_ptr->g.g); + outpdw(offset + 0x60, cfg_ptr->b.g); + offset += 4; + + outpdw(offset, cfg_ptr->r.b); + outpdw(offset + 0x30, cfg_ptr->g.b); + outpdw(offset + 0x60, cfg_ptr->b.b); + offset += 4; + + outpdw(offset, cfg_ptr->r.rr); + outpdw(offset + 0x30, cfg_ptr->g.rr); + outpdw(offset + 0x60, cfg_ptr->b.rr); + offset += 4; + + outpdw(offset, cfg_ptr->r.gg); + outpdw(offset + 0x30, cfg_ptr->g.gg); + outpdw(offset + 0x60, cfg_ptr->b.gg); + offset += 4; + + outpdw(offset, cfg_ptr->r.bb); + outpdw(offset + 0x30, cfg_ptr->g.bb); + outpdw(offset + 0x60, cfg_ptr->b.bb); + offset += 4; + + outpdw(offset, cfg_ptr->r.rg); + outpdw(offset + 0x30, cfg_ptr->g.rg); + outpdw(offset + 0x60, cfg_ptr->b.rg); + offset += 4; + + outpdw(offset, cfg_ptr->r.gb); + outpdw(offset + 0x30, cfg_ptr->g.gb); + outpdw(offset + 0x60, cfg_ptr->b.gb); + offset += 4; + + outpdw(offset, cfg_ptr->r.rb); + outpdw(offset + 0x30, cfg_ptr->g.rb); + outpdw(offset + 0x60, cfg_ptr->b.rb); + offset += 4; + + outpdw(offset, cfg_ptr->r.rgb_0); + outpdw(offset + 0x30, cfg_ptr->g.rgb_0); + outpdw(offset + 0x60, cfg_ptr->b.rgb_0); + offset += 4; + + outpdw(offset, cfg_ptr->r.rgb_1); + outpdw(offset + 0x30, cfg_ptr->g.rgb_1); + outpdw(offset + 0x60, cfg_ptr->b.rgb_1); + + ret = 0; + } + + return ret; +} + +static int mdp4_read_pcc_regs(uint32_t offset, + struct mdp_pcc_cfg_data *cfg_ptr) +{ + int ret = -1; + + if (offset && cfg_ptr) { + cfg_ptr->r.c = inpdw(offset); + cfg_ptr->g.c = inpdw(offset + 0x30); + cfg_ptr->b.c = inpdw(offset + 0x60); + offset += 4; + + cfg_ptr->r.r = inpdw(offset); + cfg_ptr->g.r = inpdw(offset + 0x30); + cfg_ptr->b.r = inpdw(offset + 0x60); + offset += 4; + + cfg_ptr->r.g = inpdw(offset); + cfg_ptr->g.g = inpdw(offset + 0x30); + cfg_ptr->b.g = inpdw(offset + 0x60); + offset += 4; + + cfg_ptr->r.b = inpdw(offset); + cfg_ptr->g.b = inpdw(offset + 0x30); + cfg_ptr->b.b = inpdw(offset + 0x60); + offset += 4; + + cfg_ptr->r.rr = inpdw(offset); + cfg_ptr->g.rr = inpdw(offset + 0x30); + cfg_ptr->b.rr = inpdw(offset + 0x60); + offset += 4; + + cfg_ptr->r.gg = inpdw(offset); + cfg_ptr->g.gg = inpdw(offset + 0x30); + cfg_ptr->b.gg = inpdw(offset + 0x60); + offset += 4; + + cfg_ptr->r.bb = inpdw(offset); + cfg_ptr->g.bb = inpdw(offset + 0x30); + cfg_ptr->b.bb = inpdw(offset + 0x60); + offset += 4; + + cfg_ptr->r.rg = inpdw(offset); + cfg_ptr->g.rg = inpdw(offset + 0x30); + cfg_ptr->b.rg = inpdw(offset + 0x60); + offset += 4; + + cfg_ptr->r.gb = inpdw(offset); + cfg_ptr->g.gb = inpdw(offset + 0x30); + cfg_ptr->b.gb = inpdw(offset + 0x60); + offset += 4; + + cfg_ptr->r.rb = inpdw(offset); + cfg_ptr->g.rb = inpdw(offset + 0x30); + cfg_ptr->b.rb = inpdw(offset + 0x60); + offset += 4; + + cfg_ptr->r.rgb_0 = inpdw(offset); + cfg_ptr->g.rgb_0 = inpdw(offset + 0x30); + cfg_ptr->b.rgb_0 = inpdw(offset + 0x60); + offset += 4; + + cfg_ptr->r.rgb_1 = inpdw(offset); + cfg_ptr->g.rgb_1 = inpdw(offset + 0x30); + cfg_ptr->b.rgb_1 = inpdw(offset + 0x60); + + ret = 0; + } + + return ret; +} + + +#define MDP_PCC_OFFSET 0xA000 +#define MDP_DMA_GC_OFFSET 0x8800 +#define MDP_LM_GC_OFFSET 0x4800 + +#define MDP_DMA_P_OP_MODE_OFFSET 0x70 +#define MDP_DMA_S_OP_MODE_OFFSET 0x28 +#define MDP_LM_OP_MODE_OFFSET 0x14 + +#define DMA_PCC_R2_OFFSET 0x100 + +#define MDP_GC_COLOR_OFFSET 0x100 +#define MDP_GC_PARMS_OFFSET 0x80 + +#define MDP_AR_GC_MAX_STAGES 16 + +static uint32_t mdp_pp_block2pcc(uint32_t block) +{ + uint32_t valid = 0; + + switch (block) { + case MDP_BLOCK_DMA_P: + case MDP_BLOCK_DMA_S: + valid = (mdp_rev >= MDP_REV_42) ? 1 : 0; + break; + + default: + break; + } + + return valid; +} + +int mdp4_pcc_cfg(struct mdp_pcc_cfg_data *cfg_ptr) +{ + int ret = -1; + uint32_t pcc_offset = 0, mdp_cfg_offset = 0; + uint32_t mdp_dma_op_mode = 0; + uint32_t blockbase; + + if (!mdp_pp_block2pcc(cfg_ptr->block)) + return ret; + + blockbase = mdp_block2base(cfg_ptr->block); + if (!blockbase) + return ret; + + blockbase += (uint32_t) MDP_BASE; + + switch (cfg_ptr->block) { + case MDP_BLOCK_DMA_P: + case MDP_BLOCK_DMA_S: + pcc_offset = blockbase + MDP_PCC_OFFSET; + mdp_cfg_offset = blockbase; + mdp_dma_op_mode = blockbase + + (MDP_BLOCK_DMA_P == cfg_ptr->block ? + MDP_DMA_P_OP_MODE_OFFSET + : MDP_DMA_S_OP_MODE_OFFSET); + break; + + default: + break; + } + + if (0x8 & cfg_ptr->ops) + pcc_offset += DMA_PCC_R2_OFFSET; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + switch ((0x6 & cfg_ptr->ops)>>1) { + case 0x1: + ret = mdp4_read_pcc_regs(pcc_offset, cfg_ptr); + break; + + case 0x2: + ret = mdp4_update_pcc_regs(pcc_offset, cfg_ptr); + break; + + default: + break; + } + + if (0x8 & cfg_ptr->ops) + outpdw(mdp_dma_op_mode, + ((inpdw(mdp_dma_op_mode) & ~(0x1<<10)) | + ((0x8 & cfg_ptr->ops)<<10))); + + outpdw(mdp_cfg_offset, + ((inpdw(mdp_cfg_offset) & ~(0x1<<29)) | + ((cfg_ptr->ops & 0x1)<<29))); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + return ret; +} + +static uint32_t mdp_pp_block2argc(uint32_t block) +{ + uint32_t valid = 0; + + switch (block) { + case MDP_BLOCK_DMA_P: + case MDP_BLOCK_DMA_S: + case MDP_BLOCK_OVERLAY_0: + case MDP_BLOCK_OVERLAY_1: + valid = (mdp_rev >= MDP_REV_42) ? 1 : 0; + break; + + case MDP_BLOCK_OVERLAY_2: + valid = (mdp_rev >= MDP_REV_44) ? 1 : 0; + break; + + default: + break; + } + + return valid; +} + +static int update_ar_gc_lut(uint32_t *offset, struct mdp_pgc_lut_data *lut_data) +{ + int count = 0; + + uint32_t *c0_offset = offset; + uint32_t *c0_params_offset = (uint32_t *)((uint32_t)c0_offset + + MDP_GC_PARMS_OFFSET); + + uint32_t *c1_offset = (uint32_t *)((uint32_t)offset + + MDP_GC_COLOR_OFFSET); + + uint32_t *c1_params_offset = (uint32_t *)((uint32_t)c1_offset + + MDP_GC_PARMS_OFFSET); + + uint32_t *c2_offset = (uint32_t *)((uint32_t)offset + + 2*MDP_GC_COLOR_OFFSET); + + uint32_t *c2_params_offset = (uint32_t *)((uint32_t)c2_offset + +MDP_GC_PARMS_OFFSET); + + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (count = 0; count < MDP_AR_GC_MAX_STAGES; count++) { + if (count < lut_data->num_r_stages) { + outpdw(c0_offset+count, + ((0xfff & lut_data->r_data[count].x_start) + | 0x10000)); + + outpdw(c0_params_offset+count, + ((0x7fff & lut_data->r_data[count].slope) + | ((0xffff + & lut_data->r_data[count].offset) + << 16))); + } else + outpdw(c0_offset+count, 0); + + if (count < lut_data->num_b_stages) { + outpdw(c1_offset+count, + ((0xfff & lut_data->b_data[count].x_start) + | 0x10000)); + + outpdw(c1_params_offset+count, + ((0x7fff & lut_data->b_data[count].slope) + | ((0xffff + & lut_data->b_data[count].offset) + << 16))); + } else + outpdw(c1_offset+count, 0); + + if (count < lut_data->num_g_stages) { + outpdw(c2_offset+count, + ((0xfff & lut_data->g_data[count].x_start) + | 0x10000)); + + outpdw(c2_params_offset+count, + ((0x7fff & lut_data->g_data[count].slope) + | ((0xffff + & lut_data->g_data[count].offset) + << 16))); + } else + outpdw(c2_offset+count, 0); + } + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + return 0; +} + +static int mdp4_argc_process_write_req(uint32_t *offset, + struct mdp_pgc_lut_data *pgc_ptr) +{ + int ret = -1; + struct mdp_ar_gc_lut_data r[MDP_AR_GC_MAX_STAGES]; + struct mdp_ar_gc_lut_data g[MDP_AR_GC_MAX_STAGES]; + struct mdp_ar_gc_lut_data b[MDP_AR_GC_MAX_STAGES]; + + ret = copy_from_user(&r[0], pgc_ptr->r_data, + pgc_ptr->num_r_stages * sizeof(struct mdp_ar_gc_lut_data)); + + if (!ret) { + ret = copy_from_user(&g[0], + pgc_ptr->g_data, + pgc_ptr->num_g_stages + * sizeof(struct mdp_ar_gc_lut_data)); + if (!ret) + ret = copy_from_user(&b[0], + pgc_ptr->b_data, + pgc_ptr->num_b_stages + * sizeof(struct mdp_ar_gc_lut_data)); + } + + if (ret) + return ret; + + pgc_ptr->r_data = &r[0]; + pgc_ptr->g_data = &g[0]; + pgc_ptr->b_data = &b[0]; + + ret = update_ar_gc_lut(offset, pgc_ptr); + return ret; +} + +int mdp4_argc_cfg(struct mdp_pgc_lut_data *pgc_ptr) +{ + int ret = -1; + uint32_t *offset = 0, *pgc_enable_offset = 0, lshift_bits = 0; + uint32_t blockbase; + + if (!mdp_pp_block2argc(pgc_ptr->block)) + return ret; + + blockbase = mdp_block2base(pgc_ptr->block); + if (!blockbase) + return ret; + + blockbase += (uint32_t) MDP_BASE; + ret = 0; + + switch (pgc_ptr->block) { + case MDP_BLOCK_DMA_P: + case MDP_BLOCK_DMA_S: + offset = (uint32_t *)(blockbase + MDP_DMA_GC_OFFSET); + pgc_enable_offset = (uint32_t *) blockbase; + lshift_bits = 28; + break; + + case MDP_BLOCK_OVERLAY_0: + case MDP_BLOCK_OVERLAY_1: + case MDP_BLOCK_OVERLAY_2: + offset = (uint32_t *)(blockbase + MDP_LM_GC_OFFSET); + pgc_enable_offset = (uint32_t *)(blockbase + + MDP_LM_OP_MODE_OFFSET); + lshift_bits = 2; + break; + + default: + ret = -1; + break; + } + + if (!ret) { + + switch ((0x6 & pgc_ptr->flags)>>1) { + case 0x1: + ret = -ENOTTY; + break; + + case 0x2: + ret = mdp4_argc_process_write_req(offset, pgc_ptr); + break; + + default: + break; + } + + if (!ret) { + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + outpdw(pgc_enable_offset, (inpdw(pgc_enable_offset) & + ~(0x1<flags) << lshift_bits)); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, + FALSE); + } + } + + return ret; +} + +static uint32_t mdp4_pp_block2igc(uint32_t block) +{ + uint32_t valid = 0; + switch (block) { + case MDP_BLOCK_VG_1: + valid = 0x1; + break; + case MDP_BLOCK_VG_2: + valid = 0x1; + break; + case MDP_BLOCK_RGB_1: + valid = 0x1; + break; + case MDP_BLOCK_RGB_2: + valid = 0x1; + break; + case MDP_BLOCK_DMA_P: + valid = (mdp_rev >= MDP_REV_40) ? 1 : 0; + break; + case MDP_BLOCK_DMA_S: + valid = (mdp_rev >= MDP_REV_40) ? 1 : 0; + break; + default: + break; + } + return valid; +} + +static int mdp4_igc_lut_write(struct mdp_igc_lut_data *cfg, uint32_t en_off, + uint32_t lut_off) +{ + int i; + uint32_t base, *off_low, *off_high; + uint32_t low[cfg->len]; + uint32_t high[cfg->len]; + + base = mdp_block2base(cfg->block); + + if (cfg->len != 256) + return -EINVAL; + + off_low = (uint32_t *)(MDP_BASE + base + lut_off); + off_high = (uint32_t *)(MDP_BASE + base + lut_off + 0x800); + if (copy_from_user(&low, cfg->c0_c1_data, cfg->len * sizeof(uint32_t))) + return -EFAULT; + if (copy_from_user(&high, cfg->c2_data, cfg->len * sizeof(uint32_t))) + return -EFAULT; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + for (i = 0; i < cfg->len; i++) { + MDP_OUTP(off_low++, low[i]); + /*low address write should occur before high address write*/ + wmb(); + MDP_OUTP(off_high++, high[i]); + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + return 0; +} + +static int mdp4_igc_lut_ctrl(struct mdp_igc_lut_data *cfg) +{ + uint32_t mask, out; + uint32_t base = mdp_block2base(cfg->block); + int8_t shift = 0; + + switch (cfg->block) { + case MDP_BLOCK_DMA_P: + case MDP_BLOCK_DMA_S: + base = base; + shift = 30; + break; + case MDP_BLOCK_VG_1: + case MDP_BLOCK_VG_2: + case MDP_BLOCK_RGB_1: + case MDP_BLOCK_RGB_2: + base += 0x58; + shift = 16; + break; + default: + return -EINVAL; + + } + out = 1<ops & 0x1)<block) { + case MDP_BLOCK_DMA_P: + case MDP_BLOCK_DMA_S: + ret = mdp4_igc_lut_write(cfg, 0x00, 0x9000); + break; + case MDP_BLOCK_VG_1: + case MDP_BLOCK_VG_2: + case MDP_BLOCK_RGB_1: + case MDP_BLOCK_RGB_2: + ret = mdp4_igc_lut_write(cfg, 0x58, 0x5000); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +int mdp4_igc_lut_config(struct mdp_igc_lut_data *cfg) +{ + int ret = 0; + + if (!mdp4_pp_block2igc(cfg->block)) { + ret = -ENOTTY; + goto error; + } + + switch ((cfg->ops & 0x6) >> 1) { + case 0x1: + pr_info("%s: IGC LUT read not supported\n", __func__); + break; + case 0x2: + ret = mdp4_igc_lut_write_cfg(cfg); + if (ret) + goto error; + break; + default: + break; + } + + ret = mdp4_igc_lut_ctrl(cfg); + +error: + return ret; +} + +#define QSEED_TABLE_1_COUNT 2 +#define QSEED_TABLE_2_COUNT 1024 + +static uint32_t mdp4_pp_block2qseed(uint32_t block) +{ + uint32_t valid = 0; + switch (block) { + case MDP_BLOCK_VG_1: + case MDP_BLOCK_VG_2: + valid = 0x1; + break; + default: + break; + } + return valid; +} + +static int mdp4_qseed_write_cfg(struct mdp_qseed_cfg_data *cfg) +{ + int i, ret = 0; + uint32_t base = (uint32_t) (MDP_BASE + mdp_block2base(cfg->block)); + uint32_t *values; + + if ((cfg->table_num != 1) && (cfg->table_num != 2)) { + ret = -ENOTTY; + goto error; + } + + if (((cfg->table_num == 1) && (cfg->len != QSEED_TABLE_1_COUNT)) || + ((cfg->table_num == 2) && (cfg->len != QSEED_TABLE_2_COUNT))) { + ret = -EINVAL; + goto error; + } + + values = kmalloc(cfg->len * sizeof(uint32_t), GFP_KERNEL); + if (!values) { + ret = -ENOMEM; + goto error; + } + + ret = copy_from_user(values, cfg->data, sizeof(uint32_t) * cfg->len); + + base += (cfg->table_num == 1) ? MDP4_QSEED_TABLE1_OFF : + MDP4_QSEED_TABLE2_OFF; + for (i = 0; i < cfg->len; i++) { + MDP_OUTP(base , values[i]); + base += sizeof(uint32_t); + } + + kfree(values); +error: + return ret; +} + +int mdp4_qseed_cfg(struct mdp_qseed_cfg_data *cfg) +{ + int ret = 0; + + if (!mdp4_pp_block2qseed(cfg->block)) { + ret = -ENOTTY; + goto error; + } + + if (cfg->table_num != 1) { + ret = -ENOTTY; + pr_info("%s: Only QSEED table1 supported.\n", __func__); + goto error; + } + + switch ((cfg->ops & 0x6) >> 1) { + case 0x1: + pr_info("%s: QSEED read not supported\n", __func__); + ret = -ENOTTY; + break; + case 0x2: + ret = mdp4_qseed_write_cfg(cfg); + if (ret) + goto error; + break; + default: + break; + } + +error: + return ret; +} diff --git a/drivers/video/msm/mdp4_wfd_writeback.c b/drivers/video/msm/mdp4_wfd_writeback.c new file mode 100644 index 000000000000..d96fc7d6f42d --- /dev/null +++ b/drivers/video/msm/mdp4_wfd_writeback.c @@ -0,0 +1,102 @@ +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mdp4_wfd_writeback_util.h" +#include "msm_fb.h" + +static int writeback_on(struct platform_device *pdev) +{ + return 0; +} +static int writeback_off(struct platform_device *pdev) +{ + return 0; +} +static int writeback_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct platform_device *mdp_dev = NULL; + struct msm_fb_panel_data *pdata = NULL; + int rc = 0; + + WRITEBACK_MSG_ERR("Inside writeback_probe\n"); + mfd = platform_get_drvdata(pdev); + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + mdp_dev = platform_device_alloc("mdp", pdev->id); + if (!mdp_dev) + return -ENOMEM; + /* + * link to the latest pdev + */ + mfd->pdev = mdp_dev; + mfd->dest = DISPLAY_LCD; + + if (platform_device_add_data + (mdp_dev, pdev->dev.platform_data, + sizeof(struct msm_fb_panel_data))) { + pr_err("writeback_probe: " + "platform_device_add_data failed!\n"); + platform_device_put(mdp_dev); + return -ENOMEM; + } + pdata = (struct msm_fb_panel_data *)mdp_dev->dev.platform_data; + pdata->on = writeback_on; + pdata->off = writeback_off; + pdata->next = pdev; + + /* + * get/set panel specific fb info + */ + mfd->panel_info = pdata->panel_info; + + mfd->fb_imgType = MDP_RGB_565; + + platform_set_drvdata(mdp_dev, mfd); + + rc = platform_device_add(mdp_dev); + if (rc) { + WRITEBACK_MSG_ERR("failed to add device"); + platform_device_put(mdp_dev); + return rc; + } + return rc; +} + +static struct platform_driver writeback_driver = { + .probe = writeback_probe, + .driver = { + .name = "writeback", + }, +}; + +static int __init writeback_driver_init(void) +{ + int rc = 0; + WRITEBACK_MSG_ERR("Inside writeback_driver_init\n"); + rc = platform_driver_register(&writeback_driver); + return rc; +} + +module_init(writeback_driver_init); diff --git a/drivers/video/msm/mdp4_wfd_writeback_panel.c b/drivers/video/msm/mdp4_wfd_writeback_panel.c new file mode 100644 index 000000000000..454556fbba6b --- /dev/null +++ b/drivers/video/msm/mdp4_wfd_writeback_panel.c @@ -0,0 +1,83 @@ +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mdp4_wfd_writeback_util.h" +#include "msm_fb.h" + +static int writeback_panel_probe(struct platform_device *pdev) +{ + int rc = 0; + if (pdev->id == 0) + return 0; + + if (!msm_fb_add_device(pdev)) { + WRITEBACK_MSG_ERR("Failed to add fd device\n"); + rc = -ENOMEM; + } + return rc; +} +static struct msm_fb_panel_data writeback_msm_panel_data = { + .panel_info = { + .type = WRITEBACK_PANEL, + .xres = 1280, + .yres = 720, + .pdest = DISPLAY_3, + .wait_cycle = 0, + .bpp = 24, + .fb_num = 1, + .clk_rate = 74250000, + }, +}; + +static struct platform_device writeback_panel_device = { + .name = "writeback_panel", + .id = 1, + .dev.platform_data = &writeback_msm_panel_data, +}; +static struct platform_driver writeback_panel_driver = { + .probe = writeback_panel_probe, + .driver = { + .name = "writeback_panel" + } +}; + +static int __init writeback_panel_init(void) +{ + int rc = 0; + rc = platform_driver_register(&writeback_panel_driver); + if (rc) { + WRITEBACK_MSG_ERR("Failed to register platform driver\n"); + goto fail_driver_registration; + } + rc = platform_device_register(&writeback_panel_device); + if (rc) { + WRITEBACK_MSG_ERR("Failed to register " + "writeback_panel_device\n"); + goto fail_device_registration; + } + return rc; +fail_device_registration: + platform_driver_unregister(&writeback_panel_driver); +fail_driver_registration: + return rc; +} + +module_init(writeback_panel_init); diff --git a/drivers/video/msm/mdp4_wfd_writeback_util.h b/drivers/video/msm/mdp4_wfd_writeback_util.h new file mode 100644 index 000000000000..582d198b2d56 --- /dev/null +++ b/drivers/video/msm/mdp4_wfd_writeback_util.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _WRITEBACK_UTIL_H_ +#define _WRITEBACK_UTIL_H_ + +#define DEBUG + +#ifdef DEBUG + #define WRITEBACK_MSG_INFO(fmt...) pr_info(fmt) + #define WRITEBACK_MSG_WARN(fmt...) pr_warning(fmt) +#else + #define WRITEBACK_MSG_INFO(fmt...) + #define WRITEBACK_MSG_WARN(fmt...) +#endif + #define WRITEBACK_MSG_ERR(fmt...) pr_err(fmt) + #define WRITEBACK_MSG_CRIT(fmt...) pr_crit(fmt) +#endif diff --git a/drivers/video/msm/mdp_csc_table.h b/drivers/video/msm/mdp_csc_table.h new file mode 100644 index 000000000000..a0f72c0ebd4f --- /dev/null +++ b/drivers/video/msm/mdp_csc_table.h @@ -0,0 +1,641 @@ +/* drivers/video/msm/mdp_csc_table.h + * + * Copyright (C) 2007 QUALCOMM Incorporated + * Copyright (C) 2007 Google Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +static struct { + uint32_t reg; + uint32_t val; +} csc_matrix_config_table[] = { + /* RGB -> YUV primary forward matrix (set1). */ + { MDP_CSC_PFMVn(0), 0x83 }, + { MDP_CSC_PFMVn(1), 0x102 }, + { MDP_CSC_PFMVn(2), 0x32 }, + { MDP_CSC_PFMVn(3), 0xffffffb5 }, + { MDP_CSC_PFMVn(4), 0xffffff6c }, + { MDP_CSC_PFMVn(5), 0xe1 }, + { MDP_CSC_PFMVn(6), 0xe1 }, + { MDP_CSC_PFMVn(7), 0xffffff45 }, + { MDP_CSC_PFMVn(8), 0xffffffdc }, + + /* YUV -> RGB primary reverse matrix (set2) */ + { MDP_CSC_PRMVn(0), 0x254 }, + { MDP_CSC_PRMVn(1), 0x0 }, + { MDP_CSC_PRMVn(2), 0x331 }, + { MDP_CSC_PRMVn(3), 0x254 }, + { MDP_CSC_PRMVn(4), 0xffffff38 }, + { MDP_CSC_PRMVn(5), 0xfffffe61 }, + { MDP_CSC_PRMVn(6), 0x254 }, + { MDP_CSC_PRMVn(7), 0x409 }, + { MDP_CSC_PRMVn(8), 0x0 }, + +#ifndef CONFIG_MSM_MDP31 + /* For MDP 2.2/3.0 */ + + /* primary limit vector */ + { MDP_CSC_PLVn(0), 0x10 }, + { MDP_CSC_PLVn(1), 0xeb }, + { MDP_CSC_PLVn(2), 0x10 }, + { MDP_CSC_PLVn(3), 0xf0 }, + + /* primary bias vector */ + { MDP_CSC_PBVn(0), 0x10 }, + { MDP_CSC_PBVn(1), 0x80 }, + { MDP_CSC_PBVn(2), 0x80 }, + +#else /* CONFIG_MSM_MDP31 */ + + /* limit vectors configuration */ + /* rgb -> yuv (set1) pre-limit vector */ + { MDP_PPP_CSC_PRE_LV1n(0), 0x10 }, + { MDP_PPP_CSC_PRE_LV1n(1), 0xeb }, + { MDP_PPP_CSC_PRE_LV1n(2), 0x10 }, + { MDP_PPP_CSC_PRE_LV1n(3), 0xf0 }, + { MDP_PPP_CSC_PRE_LV1n(4), 0x10 }, + { MDP_PPP_CSC_PRE_LV1n(5), 0xf0 }, + + /* rgb -> yuv (set1) post-limit vector */ + { MDP_PPP_CSC_POST_LV1n(0), 0x0 }, + { MDP_PPP_CSC_POST_LV1n(1), 0xff }, + { MDP_PPP_CSC_POST_LV1n(2), 0x0 }, + { MDP_PPP_CSC_POST_LV1n(3), 0xff }, + { MDP_PPP_CSC_POST_LV1n(4), 0x0 }, + { MDP_PPP_CSC_POST_LV1n(5), 0xff }, + + /* yuv -> rgb (set2) pre-limit vector */ + { MDP_PPP_CSC_PRE_LV2n(0), 0x0 }, + { MDP_PPP_CSC_PRE_LV2n(1), 0xff }, + { MDP_PPP_CSC_PRE_LV2n(2), 0x0 }, + { MDP_PPP_CSC_PRE_LV2n(3), 0xff }, + { MDP_PPP_CSC_PRE_LV2n(4), 0x0 }, + { MDP_PPP_CSC_PRE_LV2n(5), 0xff }, + + /* yuv -> rgb (set2) post-limit vector */ + { MDP_PPP_CSC_POST_LV2n(0), 0x10 }, + { MDP_PPP_CSC_POST_LV2n(1), 0xeb }, + { MDP_PPP_CSC_POST_LV2n(2), 0x10 }, + { MDP_PPP_CSC_POST_LV2n(3), 0xf0 }, + { MDP_PPP_CSC_POST_LV2n(4), 0x10 }, + { MDP_PPP_CSC_POST_LV2n(5), 0xf0 }, + + /* bias vectors configuration */ + + /* XXX: why is set2 used for rgb->yuv, but set1 */ + /* used for yuv -> rgb??!? Seems to be the reverse of the + * other vectors. */ + + /* RGB -> YUV pre-bias vector... */ + { MDP_PPP_CSC_PRE_BV2n(0), 0 }, + { MDP_PPP_CSC_PRE_BV2n(1), 0 }, + { MDP_PPP_CSC_PRE_BV2n(2), 0 }, + + /* RGB -> YUV post-bias vector */ + { MDP_PPP_CSC_POST_BV2n(0), 0x10 }, + { MDP_PPP_CSC_POST_BV2n(1), 0x80 }, + { MDP_PPP_CSC_POST_BV2n(2), 0x80 }, + + /* YUV -> RGB pre-bias vector... */ + { MDP_PPP_CSC_PRE_BV1n(0), 0x1f0 }, + { MDP_PPP_CSC_PRE_BV1n(1), 0x180 }, + { MDP_PPP_CSC_PRE_BV1n(2), 0x180 }, + + /* YUV -> RGB post-bias vector */ + { MDP_PPP_CSC_POST_BV1n(0), 0 }, + { MDP_PPP_CSC_POST_BV1n(1), 0 }, + { MDP_PPP_CSC_POST_BV1n(2), 0 }, + + /* luma filter coefficients */ + { MDP_PPP_DEINT_COEFFn(0), 0x3e0 }, + { MDP_PPP_DEINT_COEFFn(1), 0x360 }, + { MDP_PPP_DEINT_COEFFn(2), 0x120 }, + { MDP_PPP_DEINT_COEFFn(3), 0x140 }, +#endif +}; + +static struct { + uint32_t reg; + uint32_t val; +} csc_color_lut[] = { + { 0x40800, 0x0 }, + { 0x40804, 0x151515 }, + { 0x40808, 0x1d1d1d }, + { 0x4080c, 0x232323 }, + { 0x40810, 0x272727 }, + { 0x40814, 0x2b2b2b }, + { 0x40818, 0x2f2f2f }, + { 0x4081c, 0x333333 }, + { 0x40820, 0x363636 }, + { 0x40824, 0x393939 }, + { 0x40828, 0x3b3b3b }, + { 0x4082c, 0x3e3e3e }, + { 0x40830, 0x404040 }, + { 0x40834, 0x434343 }, + { 0x40838, 0x454545 }, + { 0x4083c, 0x474747 }, + { 0x40840, 0x494949 }, + { 0x40844, 0x4b4b4b }, + { 0x40848, 0x4d4d4d }, + { 0x4084c, 0x4f4f4f }, + { 0x40850, 0x515151 }, + { 0x40854, 0x535353 }, + { 0x40858, 0x555555 }, + { 0x4085c, 0x565656 }, + { 0x40860, 0x585858 }, + { 0x40864, 0x5a5a5a }, + { 0x40868, 0x5b5b5b }, + { 0x4086c, 0x5d5d5d }, + { 0x40870, 0x5e5e5e }, + { 0x40874, 0x606060 }, + { 0x40878, 0x616161 }, + { 0x4087c, 0x636363 }, + { 0x40880, 0x646464 }, + { 0x40884, 0x666666 }, + { 0x40888, 0x676767 }, + { 0x4088c, 0x686868 }, + { 0x40890, 0x6a6a6a }, + { 0x40894, 0x6b6b6b }, + { 0x40898, 0x6c6c6c }, + { 0x4089c, 0x6e6e6e }, + { 0x408a0, 0x6f6f6f }, + { 0x408a4, 0x707070 }, + { 0x408a8, 0x717171 }, + { 0x408ac, 0x727272 }, + { 0x408b0, 0x747474 }, + { 0x408b4, 0x757575 }, + { 0x408b8, 0x767676 }, + { 0x408bc, 0x777777 }, + { 0x408c0, 0x787878 }, + { 0x408c4, 0x797979 }, + { 0x408c8, 0x7a7a7a }, + { 0x408cc, 0x7c7c7c }, + { 0x408d0, 0x7d7d7d }, + { 0x408d4, 0x7e7e7e }, + { 0x408d8, 0x7f7f7f }, + { 0x408dc, 0x808080 }, + { 0x408e0, 0x818181 }, + { 0x408e4, 0x828282 }, + { 0x408e8, 0x838383 }, + { 0x408ec, 0x848484 }, + { 0x408f0, 0x858585 }, + { 0x408f4, 0x868686 }, + { 0x408f8, 0x878787 }, + { 0x408fc, 0x888888 }, + { 0x40900, 0x898989 }, + { 0x40904, 0x8a8a8a }, + { 0x40908, 0x8b8b8b }, + { 0x4090c, 0x8c8c8c }, + { 0x40910, 0x8d8d8d }, + { 0x40914, 0x8e8e8e }, + { 0x40918, 0x8f8f8f }, + { 0x4091c, 0x8f8f8f }, + { 0x40920, 0x909090 }, + { 0x40924, 0x919191 }, + { 0x40928, 0x929292 }, + { 0x4092c, 0x939393 }, + { 0x40930, 0x949494 }, + { 0x40934, 0x959595 }, + { 0x40938, 0x969696 }, + { 0x4093c, 0x969696 }, + { 0x40940, 0x979797 }, + { 0x40944, 0x989898 }, + { 0x40948, 0x999999 }, + { 0x4094c, 0x9a9a9a }, + { 0x40950, 0x9b9b9b }, + { 0x40954, 0x9c9c9c }, + { 0x40958, 0x9c9c9c }, + { 0x4095c, 0x9d9d9d }, + { 0x40960, 0x9e9e9e }, + { 0x40964, 0x9f9f9f }, + { 0x40968, 0xa0a0a0 }, + { 0x4096c, 0xa0a0a0 }, + { 0x40970, 0xa1a1a1 }, + { 0x40974, 0xa2a2a2 }, + { 0x40978, 0xa3a3a3 }, + { 0x4097c, 0xa4a4a4 }, + { 0x40980, 0xa4a4a4 }, + { 0x40984, 0xa5a5a5 }, + { 0x40988, 0xa6a6a6 }, + { 0x4098c, 0xa7a7a7 }, + { 0x40990, 0xa7a7a7 }, + { 0x40994, 0xa8a8a8 }, + { 0x40998, 0xa9a9a9 }, + { 0x4099c, 0xaaaaaa }, + { 0x409a0, 0xaaaaaa }, + { 0x409a4, 0xababab }, + { 0x409a8, 0xacacac }, + { 0x409ac, 0xadadad }, + { 0x409b0, 0xadadad }, + { 0x409b4, 0xaeaeae }, + { 0x409b8, 0xafafaf }, + { 0x409bc, 0xafafaf }, + { 0x409c0, 0xb0b0b0 }, + { 0x409c4, 0xb1b1b1 }, + { 0x409c8, 0xb2b2b2 }, + { 0x409cc, 0xb2b2b2 }, + { 0x409d0, 0xb3b3b3 }, + { 0x409d4, 0xb4b4b4 }, + { 0x409d8, 0xb4b4b4 }, + { 0x409dc, 0xb5b5b5 }, + { 0x409e0, 0xb6b6b6 }, + { 0x409e4, 0xb6b6b6 }, + { 0x409e8, 0xb7b7b7 }, + { 0x409ec, 0xb8b8b8 }, + { 0x409f0, 0xb8b8b8 }, + { 0x409f4, 0xb9b9b9 }, + { 0x409f8, 0xbababa }, + { 0x409fc, 0xbababa }, + { 0x40a00, 0xbbbbbb }, + { 0x40a04, 0xbcbcbc }, + { 0x40a08, 0xbcbcbc }, + { 0x40a0c, 0xbdbdbd }, + { 0x40a10, 0xbebebe }, + { 0x40a14, 0xbebebe }, + { 0x40a18, 0xbfbfbf }, + { 0x40a1c, 0xc0c0c0 }, + { 0x40a20, 0xc0c0c0 }, + { 0x40a24, 0xc1c1c1 }, + { 0x40a28, 0xc1c1c1 }, + { 0x40a2c, 0xc2c2c2 }, + { 0x40a30, 0xc3c3c3 }, + { 0x40a34, 0xc3c3c3 }, + { 0x40a38, 0xc4c4c4 }, + { 0x40a3c, 0xc5c5c5 }, + { 0x40a40, 0xc5c5c5 }, + { 0x40a44, 0xc6c6c6 }, + { 0x40a48, 0xc6c6c6 }, + { 0x40a4c, 0xc7c7c7 }, + { 0x40a50, 0xc8c8c8 }, + { 0x40a54, 0xc8c8c8 }, + { 0x40a58, 0xc9c9c9 }, + { 0x40a5c, 0xc9c9c9 }, + { 0x40a60, 0xcacaca }, + { 0x40a64, 0xcbcbcb }, + { 0x40a68, 0xcbcbcb }, + { 0x40a6c, 0xcccccc }, + { 0x40a70, 0xcccccc }, + { 0x40a74, 0xcdcdcd }, + { 0x40a78, 0xcecece }, + { 0x40a7c, 0xcecece }, + { 0x40a80, 0xcfcfcf }, + { 0x40a84, 0xcfcfcf }, + { 0x40a88, 0xd0d0d0 }, + { 0x40a8c, 0xd0d0d0 }, + { 0x40a90, 0xd1d1d1 }, + { 0x40a94, 0xd2d2d2 }, + { 0x40a98, 0xd2d2d2 }, + { 0x40a9c, 0xd3d3d3 }, + { 0x40aa0, 0xd3d3d3 }, + { 0x40aa4, 0xd4d4d4 }, + { 0x40aa8, 0xd4d4d4 }, + { 0x40aac, 0xd5d5d5 }, + { 0x40ab0, 0xd6d6d6 }, + { 0x40ab4, 0xd6d6d6 }, + { 0x40ab8, 0xd7d7d7 }, + { 0x40abc, 0xd7d7d7 }, + { 0x40ac0, 0xd8d8d8 }, + { 0x40ac4, 0xd8d8d8 }, + { 0x40ac8, 0xd9d9d9 }, + { 0x40acc, 0xd9d9d9 }, + { 0x40ad0, 0xdadada }, + { 0x40ad4, 0xdbdbdb }, + { 0x40ad8, 0xdbdbdb }, + { 0x40adc, 0xdcdcdc }, + { 0x40ae0, 0xdcdcdc }, + { 0x40ae4, 0xdddddd }, + { 0x40ae8, 0xdddddd }, + { 0x40aec, 0xdedede }, + { 0x40af0, 0xdedede }, + { 0x40af4, 0xdfdfdf }, + { 0x40af8, 0xdfdfdf }, + { 0x40afc, 0xe0e0e0 }, + { 0x40b00, 0xe0e0e0 }, + { 0x40b04, 0xe1e1e1 }, + { 0x40b08, 0xe1e1e1 }, + { 0x40b0c, 0xe2e2e2 }, + { 0x40b10, 0xe3e3e3 }, + { 0x40b14, 0xe3e3e3 }, + { 0x40b18, 0xe4e4e4 }, + { 0x40b1c, 0xe4e4e4 }, + { 0x40b20, 0xe5e5e5 }, + { 0x40b24, 0xe5e5e5 }, + { 0x40b28, 0xe6e6e6 }, + { 0x40b2c, 0xe6e6e6 }, + { 0x40b30, 0xe7e7e7 }, + { 0x40b34, 0xe7e7e7 }, + { 0x40b38, 0xe8e8e8 }, + { 0x40b3c, 0xe8e8e8 }, + { 0x40b40, 0xe9e9e9 }, + { 0x40b44, 0xe9e9e9 }, + { 0x40b48, 0xeaeaea }, + { 0x40b4c, 0xeaeaea }, + { 0x40b50, 0xebebeb }, + { 0x40b54, 0xebebeb }, + { 0x40b58, 0xececec }, + { 0x40b5c, 0xececec }, + { 0x40b60, 0xededed }, + { 0x40b64, 0xededed }, + { 0x40b68, 0xeeeeee }, + { 0x40b6c, 0xeeeeee }, + { 0x40b70, 0xefefef }, + { 0x40b74, 0xefefef }, + { 0x40b78, 0xf0f0f0 }, + { 0x40b7c, 0xf0f0f0 }, + { 0x40b80, 0xf1f1f1 }, + { 0x40b84, 0xf1f1f1 }, + { 0x40b88, 0xf2f2f2 }, + { 0x40b8c, 0xf2f2f2 }, + { 0x40b90, 0xf2f2f2 }, + { 0x40b94, 0xf3f3f3 }, + { 0x40b98, 0xf3f3f3 }, + { 0x40b9c, 0xf4f4f4 }, + { 0x40ba0, 0xf4f4f4 }, + { 0x40ba4, 0xf5f5f5 }, + { 0x40ba8, 0xf5f5f5 }, + { 0x40bac, 0xf6f6f6 }, + { 0x40bb0, 0xf6f6f6 }, + { 0x40bb4, 0xf7f7f7 }, + { 0x40bb8, 0xf7f7f7 }, + { 0x40bbc, 0xf8f8f8 }, + { 0x40bc0, 0xf8f8f8 }, + { 0x40bc4, 0xf9f9f9 }, + { 0x40bc8, 0xf9f9f9 }, + { 0x40bcc, 0xfafafa }, + { 0x40bd0, 0xfafafa }, + { 0x40bd4, 0xfafafa }, + { 0x40bd8, 0xfbfbfb }, + { 0x40bdc, 0xfbfbfb }, + { 0x40be0, 0xfcfcfc }, + { 0x40be4, 0xfcfcfc }, + { 0x40be8, 0xfdfdfd }, + { 0x40bec, 0xfdfdfd }, + { 0x40bf0, 0xfefefe }, + { 0x40bf4, 0xfefefe }, + { 0x40bf8, 0xffffff }, + { 0x40bfc, 0xffffff }, + { 0x40c00, 0x0 }, + { 0x40c04, 0x0 }, + { 0x40c08, 0x0 }, + { 0x40c0c, 0x0 }, + { 0x40c10, 0x0 }, + { 0x40c14, 0x0 }, + { 0x40c18, 0x0 }, + { 0x40c1c, 0x0 }, + { 0x40c20, 0x0 }, + { 0x40c24, 0x0 }, + { 0x40c28, 0x0 }, + { 0x40c2c, 0x0 }, + { 0x40c30, 0x0 }, + { 0x40c34, 0x0 }, + { 0x40c38, 0x0 }, + { 0x40c3c, 0x0 }, + { 0x40c40, 0x10101 }, + { 0x40c44, 0x10101 }, + { 0x40c48, 0x10101 }, + { 0x40c4c, 0x10101 }, + { 0x40c50, 0x10101 }, + { 0x40c54, 0x10101 }, + { 0x40c58, 0x10101 }, + { 0x40c5c, 0x10101 }, + { 0x40c60, 0x10101 }, + { 0x40c64, 0x10101 }, + { 0x40c68, 0x20202 }, + { 0x40c6c, 0x20202 }, + { 0x40c70, 0x20202 }, + { 0x40c74, 0x20202 }, + { 0x40c78, 0x20202 }, + { 0x40c7c, 0x20202 }, + { 0x40c80, 0x30303 }, + { 0x40c84, 0x30303 }, + { 0x40c88, 0x30303 }, + { 0x40c8c, 0x30303 }, + { 0x40c90, 0x30303 }, + { 0x40c94, 0x40404 }, + { 0x40c98, 0x40404 }, + { 0x40c9c, 0x40404 }, + { 0x40ca0, 0x40404 }, + { 0x40ca4, 0x40404 }, + { 0x40ca8, 0x50505 }, + { 0x40cac, 0x50505 }, + { 0x40cb0, 0x50505 }, + { 0x40cb4, 0x50505 }, + { 0x40cb8, 0x60606 }, + { 0x40cbc, 0x60606 }, + { 0x40cc0, 0x60606 }, + { 0x40cc4, 0x70707 }, + { 0x40cc8, 0x70707 }, + { 0x40ccc, 0x70707 }, + { 0x40cd0, 0x70707 }, + { 0x40cd4, 0x80808 }, + { 0x40cd8, 0x80808 }, + { 0x40cdc, 0x80808 }, + { 0x40ce0, 0x90909 }, + { 0x40ce4, 0x90909 }, + { 0x40ce8, 0xa0a0a }, + { 0x40cec, 0xa0a0a }, + { 0x40cf0, 0xa0a0a }, + { 0x40cf4, 0xb0b0b }, + { 0x40cf8, 0xb0b0b }, + { 0x40cfc, 0xb0b0b }, + { 0x40d00, 0xc0c0c }, + { 0x40d04, 0xc0c0c }, + { 0x40d08, 0xd0d0d }, + { 0x40d0c, 0xd0d0d }, + { 0x40d10, 0xe0e0e }, + { 0x40d14, 0xe0e0e }, + { 0x40d18, 0xe0e0e }, + { 0x40d1c, 0xf0f0f }, + { 0x40d20, 0xf0f0f }, + { 0x40d24, 0x101010 }, + { 0x40d28, 0x101010 }, + { 0x40d2c, 0x111111 }, + { 0x40d30, 0x111111 }, + { 0x40d34, 0x121212 }, + { 0x40d38, 0x121212 }, + { 0x40d3c, 0x131313 }, + { 0x40d40, 0x131313 }, + { 0x40d44, 0x141414 }, + { 0x40d48, 0x151515 }, + { 0x40d4c, 0x151515 }, + { 0x40d50, 0x161616 }, + { 0x40d54, 0x161616 }, + { 0x40d58, 0x171717 }, + { 0x40d5c, 0x171717 }, + { 0x40d60, 0x181818 }, + { 0x40d64, 0x191919 }, + { 0x40d68, 0x191919 }, + { 0x40d6c, 0x1a1a1a }, + { 0x40d70, 0x1b1b1b }, + { 0x40d74, 0x1b1b1b }, + { 0x40d78, 0x1c1c1c }, + { 0x40d7c, 0x1c1c1c }, + { 0x40d80, 0x1d1d1d }, + { 0x40d84, 0x1e1e1e }, + { 0x40d88, 0x1f1f1f }, + { 0x40d8c, 0x1f1f1f }, + { 0x40d90, 0x202020 }, + { 0x40d94, 0x212121 }, + { 0x40d98, 0x212121 }, + { 0x40d9c, 0x222222 }, + { 0x40da0, 0x232323 }, + { 0x40da4, 0x242424 }, + { 0x40da8, 0x242424 }, + { 0x40dac, 0x252525 }, + { 0x40db0, 0x262626 }, + { 0x40db4, 0x272727 }, + { 0x40db8, 0x272727 }, + { 0x40dbc, 0x282828 }, + { 0x40dc0, 0x292929 }, + { 0x40dc4, 0x2a2a2a }, + { 0x40dc8, 0x2b2b2b }, + { 0x40dcc, 0x2c2c2c }, + { 0x40dd0, 0x2c2c2c }, + { 0x40dd4, 0x2d2d2d }, + { 0x40dd8, 0x2e2e2e }, + { 0x40ddc, 0x2f2f2f }, + { 0x40de0, 0x303030 }, + { 0x40de4, 0x313131 }, + { 0x40de8, 0x323232 }, + { 0x40dec, 0x333333 }, + { 0x40df0, 0x333333 }, + { 0x40df4, 0x343434 }, + { 0x40df8, 0x353535 }, + { 0x40dfc, 0x363636 }, + { 0x40e00, 0x373737 }, + { 0x40e04, 0x383838 }, + { 0x40e08, 0x393939 }, + { 0x40e0c, 0x3a3a3a }, + { 0x40e10, 0x3b3b3b }, + { 0x40e14, 0x3c3c3c }, + { 0x40e18, 0x3d3d3d }, + { 0x40e1c, 0x3e3e3e }, + { 0x40e20, 0x3f3f3f }, + { 0x40e24, 0x404040 }, + { 0x40e28, 0x414141 }, + { 0x40e2c, 0x424242 }, + { 0x40e30, 0x434343 }, + { 0x40e34, 0x444444 }, + { 0x40e38, 0x464646 }, + { 0x40e3c, 0x474747 }, + { 0x40e40, 0x484848 }, + { 0x40e44, 0x494949 }, + { 0x40e48, 0x4a4a4a }, + { 0x40e4c, 0x4b4b4b }, + { 0x40e50, 0x4c4c4c }, + { 0x40e54, 0x4d4d4d }, + { 0x40e58, 0x4f4f4f }, + { 0x40e5c, 0x505050 }, + { 0x40e60, 0x515151 }, + { 0x40e64, 0x525252 }, + { 0x40e68, 0x535353 }, + { 0x40e6c, 0x545454 }, + { 0x40e70, 0x565656 }, + { 0x40e74, 0x575757 }, + { 0x40e78, 0x585858 }, + { 0x40e7c, 0x595959 }, + { 0x40e80, 0x5b5b5b }, + { 0x40e84, 0x5c5c5c }, + { 0x40e88, 0x5d5d5d }, + { 0x40e8c, 0x5e5e5e }, + { 0x40e90, 0x606060 }, + { 0x40e94, 0x616161 }, + { 0x40e98, 0x626262 }, + { 0x40e9c, 0x646464 }, + { 0x40ea0, 0x656565 }, + { 0x40ea4, 0x666666 }, + { 0x40ea8, 0x686868 }, + { 0x40eac, 0x696969 }, + { 0x40eb0, 0x6a6a6a }, + { 0x40eb4, 0x6c6c6c }, + { 0x40eb8, 0x6d6d6d }, + { 0x40ebc, 0x6f6f6f }, + { 0x40ec0, 0x707070 }, + { 0x40ec4, 0x717171 }, + { 0x40ec8, 0x737373 }, + { 0x40ecc, 0x747474 }, + { 0x40ed0, 0x767676 }, + { 0x40ed4, 0x777777 }, + { 0x40ed8, 0x797979 }, + { 0x40edc, 0x7a7a7a }, + { 0x40ee0, 0x7c7c7c }, + { 0x40ee4, 0x7d7d7d }, + { 0x40ee8, 0x7f7f7f }, + { 0x40eec, 0x808080 }, + { 0x40ef0, 0x828282 }, + { 0x40ef4, 0x838383 }, + { 0x40ef8, 0x858585 }, + { 0x40efc, 0x868686 }, + { 0x40f00, 0x888888 }, + { 0x40f04, 0x898989 }, + { 0x40f08, 0x8b8b8b }, + { 0x40f0c, 0x8d8d8d }, + { 0x40f10, 0x8e8e8e }, + { 0x40f14, 0x909090 }, + { 0x40f18, 0x919191 }, + { 0x40f1c, 0x939393 }, + { 0x40f20, 0x959595 }, + { 0x40f24, 0x969696 }, + { 0x40f28, 0x989898 }, + { 0x40f2c, 0x9a9a9a }, + { 0x40f30, 0x9b9b9b }, + { 0x40f34, 0x9d9d9d }, + { 0x40f38, 0x9f9f9f }, + { 0x40f3c, 0xa1a1a1 }, + { 0x40f40, 0xa2a2a2 }, + { 0x40f44, 0xa4a4a4 }, + { 0x40f48, 0xa6a6a6 }, + { 0x40f4c, 0xa7a7a7 }, + { 0x40f50, 0xa9a9a9 }, + { 0x40f54, 0xababab }, + { 0x40f58, 0xadadad }, + { 0x40f5c, 0xafafaf }, + { 0x40f60, 0xb0b0b0 }, + { 0x40f64, 0xb2b2b2 }, + { 0x40f68, 0xb4b4b4 }, + { 0x40f6c, 0xb6b6b6 }, + { 0x40f70, 0xb8b8b8 }, + { 0x40f74, 0xbababa }, + { 0x40f78, 0xbbbbbb }, + { 0x40f7c, 0xbdbdbd }, + { 0x40f80, 0xbfbfbf }, + { 0x40f84, 0xc1c1c1 }, + { 0x40f88, 0xc3c3c3 }, + { 0x40f8c, 0xc5c5c5 }, + { 0x40f90, 0xc7c7c7 }, + { 0x40f94, 0xc9c9c9 }, + { 0x40f98, 0xcbcbcb }, + { 0x40f9c, 0xcdcdcd }, + { 0x40fa0, 0xcfcfcf }, + { 0x40fa4, 0xd1d1d1 }, + { 0x40fa8, 0xd3d3d3 }, + { 0x40fac, 0xd5d5d5 }, + { 0x40fb0, 0xd7d7d7 }, + { 0x40fb4, 0xd9d9d9 }, + { 0x40fb8, 0xdbdbdb }, + { 0x40fbc, 0xdddddd }, + { 0x40fc0, 0xdfdfdf }, + { 0x40fc4, 0xe1e1e1 }, + { 0x40fc8, 0xe3e3e3 }, + { 0x40fcc, 0xe5e5e5 }, + { 0x40fd0, 0xe7e7e7 }, + { 0x40fd4, 0xe9e9e9 }, + { 0x40fd8, 0xebebeb }, + { 0x40fdc, 0xeeeeee }, + { 0x40fe0, 0xf0f0f0 }, + { 0x40fe4, 0xf2f2f2 }, + { 0x40fe8, 0xf4f4f4 }, + { 0x40fec, 0xf6f6f6 }, + { 0x40ff0, 0xf8f8f8 }, + { 0x40ff4, 0xfbfbfb }, + { 0x40ff8, 0xfdfdfd }, + { 0x40ffc, 0xffffff }, +}; diff --git a/drivers/video/msm/mdp_cursor.c b/drivers/video/msm/mdp_cursor.c new file mode 100644 index 000000000000..93ff388276f5 --- /dev/null +++ b/drivers/video/msm/mdp_cursor.c @@ -0,0 +1,264 @@ +/* Copyright (c) 2008-2009, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include "mdp.h" +#include "msm_fb.h" + +static int cursor_enabled; + +#include "mdp4.h" + +#if defined(CONFIG_FB_MSM_OVERLAY) && defined(CONFIG_FB_MSM_MDP40) +static struct workqueue_struct *mdp_cursor_ctrl_wq; +static struct work_struct mdp_cursor_ctrl_worker; + +/* cursor configuration */ +static void *cursor_buf_phys; +static __u32 width, height, bg_color; +static int calpha_en, transp_en, alpha; +static int sync_disabled = -1; + +void mdp_cursor_ctrl_workqueue_handler(struct work_struct *work) +{ + unsigned long flag; + + /* disable vsync */ + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_disable_irq(MDP_OVERLAY0_TERM); + spin_unlock_irqrestore(&mdp_spin_lock, flag); +} + +void mdp_hw_cursor_init(void) +{ + mdp_cursor_ctrl_wq = + create_singlethread_workqueue("mdp_cursor_ctrl_wq"); + INIT_WORK(&mdp_cursor_ctrl_worker, mdp_cursor_ctrl_workqueue_handler); +} + +void mdp_hw_cursor_done(void) +{ + /* Cursor configuration: + * + * This is done in DMA_P_DONE ISR because the following registers are + * not double buffered in hardware: + * + * MDP_DMA_P_CURSOR_SIZE, address = 0x90044 + * MDP_DMA_P_CURSOR_BLEND_CONFIG, address = 0x90060 + * MDP_DMA_P_CURSOR_BLEND_PARAM, address = 0x90064 + * MDP_DMA_P_CURSOR_BLEND_TRANS_LOW, address = 0x90068 + * MDP_DMA_P_CURSOR_BLEND_TRANS_HIG, address = 0x9006C + * + * Moving this code out of the ISR will cause the MDP to underrun! + */ + spin_lock(&mdp_spin_lock); + if (sync_disabled) { + spin_unlock(&mdp_spin_lock); + return; + } + + MDP_OUTP(MDP_BASE + 0x90044, (height << 16) | width); + MDP_OUTP(MDP_BASE + 0x90048, cursor_buf_phys); + + MDP_OUTP(MDP_BASE + 0x90060, + (transp_en << 3) | (calpha_en << 1) | + (inp32(MDP_BASE + 0x90060) & 0x1)); + + MDP_OUTP(MDP_BASE + 0x90064, (alpha << 24)); + MDP_OUTP(MDP_BASE + 0x90068, (0xffffff & bg_color)); + MDP_OUTP(MDP_BASE + 0x9006C, (0xffffff & bg_color)); + + /* enable/disable the cursor as per the last request */ + if (cursor_enabled && !(inp32(MDP_BASE + 0x90060) & (0x1))) + MDP_OUTP(MDP_BASE + 0x90060, inp32(MDP_BASE + 0x90060) | 0x1); + else if (!cursor_enabled && (inp32(MDP_BASE + 0x90060) & (0x1))) + MDP_OUTP(MDP_BASE + 0x90060, + inp32(MDP_BASE + 0x90060) & (~0x1)); + + /* enqueue the task to disable MDP interrupts */ + queue_work(mdp_cursor_ctrl_wq, &mdp_cursor_ctrl_worker); + + /* update done */ + sync_disabled = 1; + spin_unlock(&mdp_spin_lock); +} + +static void mdp_hw_cursor_enable_vsync(void) +{ + /* if the cursor registers were updated (once or more) since the + * last vsync, enable the vsync interrupt (if not already enabled) + * for the next update + */ + if (sync_disabled) { + + /* cancel pending task to disable MDP interrupts */ + if (work_pending(&mdp_cursor_ctrl_worker)) + cancel_work_sync(&mdp_cursor_ctrl_worker); + else + /* enable irq */ + mdp_enable_irq(MDP_OVERLAY0_TERM); + + sync_disabled = 0; + + /* enable vsync intr */ + outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE); + mdp_intr_mask |= INTR_OVERLAY0_DONE; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + } +} + +int mdp_hw_cursor_sync_update(struct fb_info *info, struct fb_cursor *cursor) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct fb_image *img = &cursor->image; + unsigned long flag; + int sync_needed = 0, ret = 0; + + if ((img->width > MDP_CURSOR_WIDTH) || + (img->height > MDP_CURSOR_HEIGHT) || + (img->depth != 32)) + return -EINVAL; + + if (cursor->set & FB_CUR_SETPOS) + MDP_OUTP(MDP_BASE + 0x9004c, (img->dy << 16) | img->dx); + + if (cursor->set & FB_CUR_SETIMAGE) { + ret = copy_from_user(mfd->cursor_buf, img->data, + img->width*img->height*4); + if (ret) + return ret; + + spin_lock_irqsave(&mdp_spin_lock, flag); + if (img->bg_color == 0xffffffff) + transp_en = 0; + else + transp_en = 1; + + alpha = (img->fg_color & 0xff000000) >> 24; + + if (alpha) + calpha_en = 0x2; /* xrgb */ + else + calpha_en = 0x1; /* argb */ + + /* cursor parameters */ + height = img->height; + width = img->width; + bg_color = img->bg_color; + cursor_buf_phys = mfd->cursor_buf_phys; + + sync_needed = 1; + } else + spin_lock_irqsave(&mdp_spin_lock, flag); + + if ((cursor->enable) && (!cursor_enabled)) { + cursor_enabled = 1; + sync_needed = 1; + } else if ((!cursor->enable) && (cursor_enabled)) { + cursor_enabled = 0; + sync_needed = 1; + } + + /* if sync cursor update is needed, enable vsync */ + if (sync_needed) + mdp_hw_cursor_enable_vsync(); + + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + return 0; +} +#endif /* CONFIG_FB_MSM_OVERLAY && CONFIG_FB_MSM_MDP40 */ + +int mdp_hw_cursor_update(struct fb_info *info, struct fb_cursor *cursor) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct fb_image *img = &cursor->image; + int calpha_en, transp_en; + int alpha; + int ret = 0; + + if ((img->width > MDP_CURSOR_WIDTH) || + (img->height > MDP_CURSOR_HEIGHT) || + (img->depth != 32)) + return -EINVAL; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + if (cursor->set & FB_CUR_SETPOS) + MDP_OUTP(MDP_BASE + 0x9004c, (img->dy << 16) | img->dx); + + if (cursor->set & FB_CUR_SETIMAGE) { + ret = copy_from_user(mfd->cursor_buf, img->data, + img->width*img->height*4); + if (ret) + return ret; + + if (img->bg_color == 0xffffffff) + transp_en = 0; + else + transp_en = 1; + + alpha = (img->fg_color & 0xff000000) >> 24; + + if (alpha) + calpha_en = 0x2; /* xrgb */ + else + calpha_en = 0x1; /* argb */ + + MDP_OUTP(MDP_BASE + 0x90044, (img->height << 16) | img->width); + MDP_OUTP(MDP_BASE + 0x90048, mfd->cursor_buf_phys); + /* order the writes the cursor_buf before updating the + * hardware */ + dma_coherent_pre_ops(); + MDP_OUTP(MDP_BASE + 0x90060, + (transp_en << 3) | (calpha_en << 1) | + (inp32(MDP_BASE + 0x90060) & 0x1)); +#ifdef CONFIG_FB_MSM_MDP40 + MDP_OUTP(MDP_BASE + 0x90064, (alpha << 24)); + MDP_OUTP(MDP_BASE + 0x90068, (0xffffff & img->bg_color)); + MDP_OUTP(MDP_BASE + 0x9006C, (0xffffff & img->bg_color)); +#else + MDP_OUTP(MDP_BASE + 0x90064, + (alpha << 24) | (0xffffff & img->bg_color)); + MDP_OUTP(MDP_BASE + 0x90068, 0); +#endif + } + + if ((cursor->enable) && (!cursor_enabled)) { + cursor_enabled = 1; + MDP_OUTP(MDP_BASE + 0x90060, inp32(MDP_BASE + 0x90060) | 0x1); + } else if ((!cursor->enable) && (cursor_enabled)) { + cursor_enabled = 0; + MDP_OUTP(MDP_BASE + 0x90060, + inp32(MDP_BASE + 0x90060) & (~0x1)); + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + return 0; +} diff --git a/drivers/video/msm/mdp_debugfs.c b/drivers/video/msm/mdp_debugfs.c new file mode 100644 index 000000000000..254999982f14 --- /dev/null +++ b/drivers/video/msm/mdp_debugfs.c @@ -0,0 +1,1392 @@ +/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mdp.h" +#include "msm_fb.h" +#ifdef CONFIG_FB_MSM_MDP40 +#include "mdp4.h" +#endif +#include "mddihosti.h" +#include "tvenc.h" +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL +#include "hdmi_msm.h" +#endif + +#define MDP_DEBUG_BUF 2048 + +static uint32 mdp_offset; +static uint32 mdp_count; + +static char debug_buf[MDP_DEBUG_BUF]; + +/* + * MDP4 + * + */ + +static int mdp_offset_open(struct inode *inode, struct file *file) +{ + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); + return 0; +} + +static int mdp_offset_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t mdp_offset_write( + struct file *file, + const char __user *buff, + size_t count, + loff_t *ppos) +{ + uint32 off, cnt; + + if (count >= sizeof(debug_buf)) + return -EFAULT; + + if (copy_from_user(debug_buf, buff, count)) + return -EFAULT; + + debug_buf[count] = 0; /* end of string */ + + sscanf(debug_buf, "%x %d", &off, &cnt); + + if (cnt <= 0) + cnt = 1; + + mdp_offset = off; + mdp_count = cnt; + + printk(KERN_INFO "%s: offset=%x cnt=%d\n", __func__, + mdp_offset, mdp_count); + + return count; +} + +static ssize_t mdp_offset_read( + struct file *file, + char __user *buff, + size_t count, + loff_t *ppos) +{ + int len = 0; + + + if (*ppos) + return 0; /* the end */ + + len = snprintf(debug_buf, sizeof(debug_buf), "0x%08x %d\n", + mdp_offset, mdp_count); + if (len < 0) + return 0; + + if (copy_to_user(buff, debug_buf, len)) + return -EFAULT; + + *ppos += len; /* increase offset */ + + return len; +} + +static const struct file_operations mdp_off_fops = { + .open = mdp_offset_open, + .release = mdp_offset_release, + .read = mdp_offset_read, + .write = mdp_offset_write, +}; + +static int mdp_reg_open(struct inode *inode, struct file *file) +{ + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); + return 0; +} + +static int mdp_reg_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t mdp_reg_write( + struct file *file, + const char __user *buff, + size_t count, + loff_t *ppos) +{ + uint32 off, data; + int cnt; + + if (count >= sizeof(debug_buf)) + return -EFAULT; + + if (copy_from_user(debug_buf, buff, count)) + return -EFAULT; + + debug_buf[count] = 0; /* end of string */ + + cnt = sscanf(debug_buf, "%x %x", &off, &data); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + outpdw(MDP_BASE + off, data); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + printk(KERN_INFO "%s: addr=%x data=%x\n", __func__, off, data); + + return count; +} + +static ssize_t mdp_reg_read( + struct file *file, + char __user *buff, + size_t count, + loff_t *ppos) +{ + int len = 0; + uint32 data; + int i, j, off, dlen, num; + char *bp, *cp; + int tot = 0; + + + if (*ppos) + return 0; /* the end */ + + j = 0; + num = 0; + bp = debug_buf; + cp = MDP_BASE + mdp_offset; + dlen = sizeof(debug_buf); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + while (j++ < 8) { + len = snprintf(bp, dlen, "0x%08x: ", (int)cp); + tot += len; + bp += len; + dlen -= len; + off = 0; + i = 0; + while (i++ < 4) { + data = inpdw(cp + off); + len = snprintf(bp, dlen, "%08x ", data); + tot += len; + bp += len; + dlen -= len; + off += 4; + num++; + if (num >= mdp_count) + break; + } + *bp++ = '\n'; + --dlen; + tot++; + cp += off; + if (num >= mdp_count) + break; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + *bp = 0; + tot++; + + if (copy_to_user(buff, debug_buf, tot)) + return -EFAULT; + + *ppos += tot; /* increase offset */ + + return tot; +} + + +static const struct file_operations mdp_reg_fops = { + .open = mdp_reg_open, + .release = mdp_reg_release, + .read = mdp_reg_read, + .write = mdp_reg_write, +}; + +#ifdef CONFIG_FB_MSM_MDP40 +static int mdp_stat_open(struct inode *inode, struct file *file) +{ + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); + return 0; +} + +static int mdp_stat_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t mdp_stat_write( + struct file *file, + const char __user *buff, + size_t count, + loff_t *ppos) +{ + unsigned long flag; + + if (count > sizeof(debug_buf)) + return -EFAULT; + + spin_lock_irqsave(&mdp_spin_lock, flag); + memset((char *)&mdp4_stat, 0 , sizeof(mdp4_stat)); /* reset */ + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + return count; +} + +static ssize_t mdp_stat_read( + struct file *file, + char __user *buff, + size_t count, + loff_t *ppos) +{ + int len = 0; + int tot = 0; + int dlen; + char *bp; + + + if (*ppos) + return 0; /* the end */ + + bp = debug_buf; + dlen = sizeof(debug_buf); + + len = snprintf(bp, dlen, "\nmdp:\n"); + bp += len; + dlen -= len; + + len = snprintf(bp, dlen, "int_total: %08lu\t", + mdp4_stat.intr_tot); + bp += len; + dlen -= len; + + len = snprintf(bp, dlen, "int_overlay0: %08lu\t", + mdp4_stat.intr_overlay0); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "int_overlay1: %08lu\n", + mdp4_stat.intr_overlay1); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "int_overlay1: %08lu\n", + mdp4_stat.intr_overlay2); + bp += len; + dlen -= len; + + len = snprintf(bp, dlen, "int_dmap: %08lu\t", + mdp4_stat.intr_dma_p); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "int_dmas: %08lu\t", + mdp4_stat.intr_dma_s); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "int_dmae: %08lu\n", + mdp4_stat.intr_dma_e); + bp += len; + dlen -= len; + + len = snprintf(bp, dlen, "primary: vsync: %08lu\t", + mdp4_stat.intr_vsync_p); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "underrun: %08lu\n", + mdp4_stat.intr_underrun_p); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "external: vsync: %08lu\t", + mdp4_stat.intr_vsync_e); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "underrun: %08lu\n", + mdp4_stat.intr_underrun_e); + + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "histogram: %08lu\t", + mdp4_stat.intr_histogram); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "read_ptr: %08lu\n\n", + mdp4_stat.intr_rd_ptr); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "dsi:\n"); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "int_total: %08lu\tmdp_start: %08lu\n", + mdp4_stat.intr_dsi, mdp4_stat.dsi_mdp_start); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "int_cmd: %08lu\t", + mdp4_stat.intr_dsi_cmd); + + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "int_mdp: %08lu\t", + mdp4_stat.intr_dsi_mdp); + + bp += len; + dlen -= len; + + len = snprintf(bp, dlen, "int_err: %08lu\n", + mdp4_stat.intr_dsi_err); + + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "clk_on : %08lu\t", + mdp4_stat.dsi_clk_on); + + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "clk_off: %08lu\n\n", + mdp4_stat.dsi_clk_off); + + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "kickoff:\n"); + bp += len; + dlen -= len; + + len = snprintf(bp, dlen, "overlay0: %08lu\t", + mdp4_stat.kickoff_ov0); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "dmap: %08lu\t", + mdp4_stat.kickoff_dmap); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "dmas: %08lu\n", + mdp4_stat.kickoff_dmas); + + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "overlay1: %08lu\t", + mdp4_stat.kickoff_ov1); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "dmae: %08lu\n\n", + mdp4_stat.kickoff_dmae); + + bp += len; + dlen -= len; + + len = snprintf(bp, dlen, "overlay0_play:\n"); + bp += len; + dlen -= len; + + len = snprintf(bp, dlen, "set: %08lu\t", + mdp4_stat.overlay_set[0]); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "unset: %08lu\t", + mdp4_stat.overlay_unset[0]); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "play: %08lu\n", + mdp4_stat.overlay_play[0]); + bp += len; + dlen -= len; + + len = snprintf(bp, dlen, "overlay1_play:\n"); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "set: %08lu\t", + mdp4_stat.overlay_set[1]); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "unset: %08lu\t", + mdp4_stat.overlay_unset[1]); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "play: %08lu\n\n", + mdp4_stat.overlay_play[1]); + + bp += len; + dlen -= len; + + len = snprintf(bp, dlen, "frame_push:\n"); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "rgb1: %08lu\t", + mdp4_stat.pipe[OVERLAY_PIPE_RGB1]); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "rgb2: %08lu\n", + mdp4_stat.pipe[OVERLAY_PIPE_RGB2]); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "vg1 : %08lu\t", + mdp4_stat.pipe[OVERLAY_PIPE_VG1]); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "vg2 : %08lu\n", + mdp4_stat.pipe[OVERLAY_PIPE_VG2]); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "err_mixer : %08lu\t", mdp4_stat.err_mixer); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "err_size : %08lu\n", mdp4_stat.err_size); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "err_scale : %08lu\t", mdp4_stat.err_scale); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "err_format: %08lu\n", mdp4_stat.err_format); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "err_play : %08lu\t", mdp4_stat.err_play); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "err_stage : %08lu\n", mdp4_stat.err_stage); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "err_underflow: %08lu\n\n", + mdp4_stat.err_underflow); + bp += len; + dlen -= len; + + len = snprintf(bp, dlen, "writeback:\n"); + bp += len; + dlen -= len; + + len = snprintf(bp, dlen, "dsi_cmd: %08lu\t", + mdp4_stat.blt_dsi_cmd); + bp += len; + dlen -= len; + + len = snprintf(bp, dlen, "dsi_video: %08lu\n", + mdp4_stat.blt_dsi_video); + bp += len; + dlen -= len; + + len = snprintf(bp, dlen, "lcdc: %08lu\t", + mdp4_stat.blt_lcdc); + bp += len; + dlen -= len; + + len = snprintf(bp, dlen, "dtv: %08lu\t", + mdp4_stat.blt_dtv); + bp += len; + dlen -= len; + + len = snprintf(bp, dlen, "mddi: %08lu\n\n", + mdp4_stat.blt_mddi); + bp += len; + dlen -= len; + + tot = (uint32)bp - (uint32)debug_buf; + *bp = 0; + tot++; + + if (tot < 0) + return 0; + if (copy_to_user(buff, debug_buf, tot)) + return -EFAULT; + + *ppos += tot; /* increase offset */ + + return tot; +} + +static const struct file_operations mdp_stat_fops = { + .open = mdp_stat_open, + .release = mdp_stat_release, + .read = mdp_stat_read, + .write = mdp_stat_write, +}; +#endif + +/* + * MDDI + * + */ + +struct mddi_reg { + char *name; + int off; +}; + +static struct mddi_reg mddi_regs_list[] = { + {"MDDI_CMD", MDDI_CMD}, /* 0x0000 */ + {"MDDI_VERSION", MDDI_VERSION}, /* 0x0004 */ + {"MDDI_PRI_PTR", MDDI_PRI_PTR}, /* 0x0008 */ + {"MDDI_BPS", MDDI_BPS}, /* 0x0010 */ + {"MDDI_SPM", MDDI_SPM}, /* 0x0014 */ + {"MDDI_INT", MDDI_INT}, /* 0x0018 */ + {"MDDI_INTEN", MDDI_INTEN}, /* 0x001c */ + {"MDDI_REV_PTR", MDDI_REV_PTR}, /* 0x0020 */ + {"MDDI_ REV_SIZE", MDDI_REV_SIZE},/* 0x0024 */ + {"MDDI_STAT", MDDI_STAT}, /* 0x0028 */ + {"MDDI_REV_RATE_DIV", MDDI_REV_RATE_DIV}, /* 0x002c */ + {"MDDI_REV_CRC_ERR", MDDI_REV_CRC_ERR}, /* 0x0030 */ + {"MDDI_TA1_LEN", MDDI_TA1_LEN}, /* 0x0034 */ + {"MDDI_TA2_LEN", MDDI_TA2_LEN}, /* 0x0038 */ + {"MDDI_TEST", MDDI_TEST}, /* 0x0040 */ + {"MDDI_REV_PKT_CNT", MDDI_REV_PKT_CNT}, /* 0x0044 */ + {"MDDI_DRIVE_HI", MDDI_DRIVE_HI},/* 0x0048 */ + {"MDDI_DRIVE_LO", MDDI_DRIVE_LO}, /* 0x004c */ + {"MDDI_DISP_WAKE", MDDI_DISP_WAKE},/* 0x0050 */ + {"MDDI_REV_ENCAP_SZ", MDDI_REV_ENCAP_SZ}, /* 0x0054 */ + {"MDDI_RTD_VAL", MDDI_RTD_VAL}, /* 0x0058 */ + {"MDDI_PAD_CTL", MDDI_PAD_CTL}, /* 0x0068 */ + {"MDDI_DRIVER_START_CNT", MDDI_DRIVER_START_CNT}, /* 0x006c */ + {"MDDI_CORE_VER", MDDI_CORE_VER}, /* 0x008c */ + {"MDDI_FIFO_ALLOC", MDDI_FIFO_ALLOC}, /* 0x0090 */ + {"MDDI_PAD_IO_CTL", MDDI_PAD_IO_CTL}, /* 0x00a0 */ + {"MDDI_PAD_CAL", MDDI_PAD_CAL}, /* 0x00a4 */ + {0, 0} +}; + +static int mddi_reg_open(struct inode *inode, struct file *file) +{ + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); + return 0; +} + +static int mddi_reg_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static void mddi_reg_write(int ndx, uint32 off, uint32 data) +{ + char *base; + + if (ndx) + base = (char *)msm_emdh_base; + else + base = (char *)msm_pmdh_base; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + writel(data, base + off); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + printk(KERN_INFO "%s: addr=%x data=%x\n", + __func__, (int)(base+off), (int)data); +} + +static int mddi_reg_read(int ndx) +{ + struct mddi_reg *reg; + unsigned char *base; + int data; + char *bp; + int len = 0; + int tot = 0; + int dlen; + + if (ndx) + base = msm_emdh_base; + else + base = msm_pmdh_base; + + reg = mddi_regs_list; + bp = debug_buf; + dlen = sizeof(debug_buf); + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + while (reg->name) { + data = readl((u32)base + reg->off); + len = snprintf(bp, dlen, "%s:0x%08x\t\t= 0x%08x\n", + reg->name, reg->off, data); + tot += len; + bp += len; + dlen -= len; + reg++; + } + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + *bp = 0; + tot++; + + return tot; +} + +static ssize_t pmdh_reg_write( + struct file *file, + const char __user *buff, + size_t count, + loff_t *ppos) +{ + uint32 off, data; + int cnt; + + if (count >= sizeof(debug_buf)) + return -EFAULT; + + if (copy_from_user(debug_buf, buff, count)) + return -EFAULT; + + debug_buf[count] = 0; /* end of string */ + + cnt = sscanf(debug_buf, "%x %x", &off, &data); + + mddi_reg_write(0, off, data); + + return count; +} + +static ssize_t pmdh_reg_read( + struct file *file, + char __user *buff, + size_t count, + loff_t *ppos) +{ + int tot = 0; + + if (*ppos) + return 0; /* the end */ + + tot = mddi_reg_read(0); /* pmdh */ + + if (tot < 0) + return 0; + if (copy_to_user(buff, debug_buf, tot)) + return -EFAULT; + + *ppos += tot; /* increase offset */ + + return tot; +} + + +static const struct file_operations pmdh_fops = { + .open = mddi_reg_open, + .release = mddi_reg_release, + .read = pmdh_reg_read, + .write = pmdh_reg_write, +}; + + + +#if defined(CONFIG_FB_MSM_OVERLAY) && defined(CONFIG_FB_MSM_MDDI) +static int vsync_reg_open(struct inode *inode, struct file *file) +{ + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); + return 0; +} + +static int vsync_reg_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t vsync_reg_write( + struct file *file, + const char __user *buff, + size_t count, + loff_t *ppos) +{ + uint32 enable; + int cnt; + + if (count >= sizeof(debug_buf)) + return -EFAULT; + + if (copy_from_user(debug_buf, buff, count)) + return -EFAULT; + + debug_buf[count] = 0; /* end of string */ + + cnt = sscanf(debug_buf, "%x", &enable); + + mdp_dmap_vsync_set(enable); + + return count; +} + +static ssize_t vsync_reg_read( + struct file *file, + char __user *buff, + size_t count, + loff_t *ppos) +{ + char *bp; + int len = 0; + int tot = 0; + int dlen; + + if (*ppos) + return 0; /* the end */ + + bp = debug_buf; + dlen = sizeof(debug_buf); + len = snprintf(bp, dlen, "%x\n", mdp_dmap_vsync_get()); + tot += len; + bp += len; + *bp = 0; + tot++; + + if (copy_to_user(buff, debug_buf, tot)) + return -EFAULT; + + *ppos += tot; /* increase offset */ + + return tot; +} + + +static const struct file_operations vsync_fops = { + .open = vsync_reg_open, + .release = vsync_reg_release, + .read = vsync_reg_read, + .write = vsync_reg_write, +}; +#endif + +static ssize_t emdh_reg_write( + struct file *file, + const char __user *buff, + size_t count, + loff_t *ppos) +{ + uint32 off, data; + int cnt; + + if (count >= sizeof(debug_buf)) + return -EFAULT; + + if (copy_from_user(debug_buf, buff, count)) + return -EFAULT; + + debug_buf[count] = 0; /* end of string */ + + cnt = sscanf(debug_buf, "%x %x", &off, &data); + + mddi_reg_write(1, off, data); + + return count; +} + +static ssize_t emdh_reg_read( + struct file *file, + char __user *buff, + size_t count, + loff_t *ppos) +{ + int tot = 0; + + if (*ppos) + return 0; /* the end */ + + tot = mddi_reg_read(1); /* emdh */ + + if (tot < 0) + return 0; + if (copy_to_user(buff, debug_buf, tot)) + return -EFAULT; + + *ppos += tot; /* increase offset */ + + return tot; +} + +static const struct file_operations emdh_fops = { + .open = mddi_reg_open, + .release = mddi_reg_release, + .read = emdh_reg_read, + .write = emdh_reg_write, +}; + + +uint32 dbg_offset; +uint32 dbg_count; +char *dbg_base; + + +static int dbg_open(struct inode *inode, struct file *file) +{ + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); + return 0; +} + +static int dbg_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t dbg_base_write( + struct file *file, + const char __user *buff, + size_t count, + loff_t *ppos) +{ + return count; +} + +static ssize_t dbg_base_read( + struct file *file, + char __user *buff, + size_t count, + loff_t *ppos) +{ + int len = 0; + int tot = 0; + int dlen; + char *bp; + + + if (*ppos) + return 0; /* the end */ + + + bp = debug_buf; + dlen = sizeof(debug_buf); + + len = snprintf(bp, dlen, "mdp_base : %08x\n", + (int)msm_mdp_base); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "mddi_base : %08x\n", + (int)msm_pmdh_base); + bp += len; + dlen -= len; + len = snprintf(bp, dlen, "emdh_base : %08x\n", + (int)msm_emdh_base); + bp += len; + dlen -= len; +#ifdef CONFIG_FB_MSM_TVOUT + len = snprintf(bp, dlen, "tvenv_base: %08x\n", + (int)tvenc_base); + bp += len; + dlen -= len; +#endif + +#ifdef CONFIG_FB_MSM_MIPI_DSI + len = snprintf(bp, dlen, "mipi_dsi_base: %08x\n", + (int)mipi_dsi_base); + bp += len; + dlen -= len; +#endif + + tot = (uint32)bp - (uint32)debug_buf; + *bp = 0; + tot++; + + if (tot < 0) + return 0; + if (copy_to_user(buff, debug_buf, tot)) + return -EFAULT; + + *ppos += tot; /* increase offset */ + + return tot; +} + +static const struct file_operations dbg_base_fops = { + .open = dbg_open, + .release = dbg_release, + .read = dbg_base_read, + .write = dbg_base_write, +}; + +static ssize_t dbg_offset_write( + struct file *file, + const char __user *buff, + size_t count, + loff_t *ppos) +{ + uint32 off, cnt, num, base; + + if (count >= sizeof(debug_buf)) + return -EFAULT; + + if (copy_from_user(debug_buf, buff, count)) + return -EFAULT; + + debug_buf[count] = 0; /* end of string */ + + cnt = sscanf(debug_buf, "%x %d %x", &off, &num, &base); + + if (cnt < 0) + cnt = 0; + + if (cnt >= 1) + dbg_offset = off; + if (cnt >= 2) + dbg_count = num; + if (cnt >= 3) + dbg_base = (char *)base; + + printk(KERN_INFO "%s: offset=%x cnt=%d base=%x\n", __func__, + dbg_offset, dbg_count, (int)dbg_base); + + return count; +} + +static ssize_t dbg_offset_read( + struct file *file, + char __user *buff, + size_t count, + loff_t *ppos) +{ + int len = 0; + + + if (*ppos) + return 0; /* the end */ + + len = snprintf(debug_buf, sizeof(debug_buf), "0x%08x %d 0x%08x\n", + dbg_offset, dbg_count, (int)dbg_base); + if (len < 0) + return 0; + + if (copy_to_user(buff, debug_buf, len)) + return -EFAULT; + + *ppos += len; /* increase offset */ + + return len; +} + +static const struct file_operations dbg_off_fops = { + .open = dbg_open, + .release = dbg_release, + .read = dbg_offset_read, + .write = dbg_offset_write, +}; + + +static ssize_t dbg_reg_write( + struct file *file, + const char __user *buff, + size_t count, + loff_t *ppos) +{ + uint32 off, data; + int cnt; + + if (count >= sizeof(debug_buf)) + return -EFAULT; + + if (copy_from_user(debug_buf, buff, count)) + return -EFAULT; + + debug_buf[count] = 0; /* end of string */ + + cnt = sscanf(debug_buf, "%x %x", &off, &data); + + writel(data, dbg_base + off); + + printk(KERN_INFO "%s: addr=%x data=%x\n", + __func__, (int)(dbg_base+off), (int)data); + + return count; +} + +static ssize_t dbg_reg_read( + struct file *file, + char __user *buff, + size_t count, + loff_t *ppos) +{ + int len = 0; + uint32 data; + int i, j, off, dlen, num; + char *bp, *cp; + int tot = 0; + + + if (*ppos) + return 0; /* the end */ + + if (dbg_base == 0) + return 0; /* nothing to read */ + + j = 0; + num = 0; + bp = debug_buf; + cp = (char *)(dbg_base + dbg_offset); + dlen = sizeof(debug_buf); + while (j++ < 16) { + len = snprintf(bp, dlen, "0x%08x: ", (int)cp); + tot += len; + bp += len; + dlen -= len; + off = 0; + i = 0; + while (i++ < 4) { + data = readl(cp + off); + len = snprintf(bp, dlen, "%08x ", data); + tot += len; + bp += len; + dlen -= len; + off += 4; + num++; + if (num >= dbg_count) + break; + } + data = readl((u32)cp + off); + *bp++ = '\n'; + --dlen; + tot++; + cp += off; + if (num >= dbg_count) + break; + } + *bp = 0; + tot++; + + if (copy_to_user(buff, debug_buf, tot)) + return -EFAULT; + + *ppos += tot; /* increase offset */ + + return tot; +} + + +static const struct file_operations dbg_reg_fops = { + .open = dbg_open, + .release = dbg_release, + .read = dbg_reg_read, + .write = dbg_reg_write, +}; + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL +static uint32 hdmi_offset; +static uint32 hdmi_count; + +static int hdmi_open(struct inode *inode, struct file *file) +{ + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); + return 0; +} + +static int hdmi_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t hdmi_offset_write( + struct file *file, + const char __user *buff, + size_t count, + loff_t *ppos) +{ + uint32 off, cnt, num; + + if (count >= sizeof(debug_buf)) + return -EFAULT; + + if (copy_from_user(debug_buf, buff, count)) + return -EFAULT; + + debug_buf[count] = 0; /* end of string */ + + cnt = sscanf(debug_buf, "%x %d", &off, &num); + + if (cnt < 0) + cnt = 0; + + if (cnt >= 1) + hdmi_offset = off; + if (cnt >= 2) + hdmi_count = num; + + printk(KERN_INFO "%s: offset=%x cnt=%d\n", __func__, + hdmi_offset, hdmi_count); + + return count; +} + +static ssize_t hdmi_offset_read( + struct file *file, + char __user *buff, + size_t count, + loff_t *ppos) +{ + int len = 0; + + + if (*ppos) + return 0; /* the end */ + + len = snprintf(debug_buf, sizeof(debug_buf), "0x%08x %d\n", + hdmi_offset, hdmi_count); + if (len < 0) + return 0; + + if (copy_to_user(buff, debug_buf, len)) + return -EFAULT; + + *ppos += len; /* increase offset */ + + return len; +} + +static const struct file_operations hdmi_off_fops = { + .open = hdmi_open, + .release = hdmi_release, + .read = hdmi_offset_read, + .write = hdmi_offset_write, +}; + + +static ssize_t hdmi_reg_write( + struct file *file, + const char __user *buff, + size_t count, + loff_t *ppos) +{ + uint32 off, data, base; + int cnt; + + if (count >= sizeof(debug_buf)) + return -EFAULT; + + if (copy_from_user(debug_buf, buff, count)) + return -EFAULT; + + base = hdmi_msm_get_io_base(); + if (base == 0) + return -EFAULT; + + debug_buf[count] = 0; /* end of string */ + + cnt = sscanf(debug_buf, "%x %x", &off, &data); + + writel(data, base + off); + + printk(KERN_INFO "%s: addr=%x data=%x\n", + __func__, (int)(base+off), (int)data); + + return count; +} + +static ssize_t hdmi_reg_read( + struct file *file, + char __user *buff, + size_t count, + loff_t *ppos) +{ + int len = 0; + uint32 data; + int i, j, off, dlen, num; + char *bp, *cp; + int tot = 0; + + + if (*ppos) + return 0; /* the end */ + + if (hdmi_msm_get_io_base() == 0) + return 0; /* nothing to read */ + + j = 0; + num = 0; + bp = debug_buf; + cp = (char *)(hdmi_msm_get_io_base() + hdmi_offset); + dlen = sizeof(debug_buf); + while (j++ < 16) { + len = snprintf(bp, dlen, "0x%08x: ", (int)cp); + tot += len; + bp += len; + dlen -= len; + off = 0; + i = 0; + while (i++ < 4) { + data = readl(cp + off); + len = snprintf(bp, dlen, "%08x ", data); + tot += len; + bp += len; + dlen -= len; + off += 4; + num++; + if (num >= hdmi_count) + break; + } + data = readl((u32)cp + off); + *bp++ = '\n'; + --dlen; + tot++; + cp += off; + if (num >= hdmi_count) + break; + } + *bp = 0; + tot++; + + if (copy_to_user(buff, debug_buf, tot)) + return -EFAULT; + + *ppos += tot; /* increase offset */ + + return tot; +} + + +static const struct file_operations hdmi_reg_fops = { + .open = hdmi_open, + .release = hdmi_release, + .read = hdmi_reg_read, + .write = hdmi_reg_write, +}; +#endif + +/* + * debugfs + * + */ + +int mdp_debugfs_init(void) +{ + struct dentry *dent = debugfs_create_dir("mdp", NULL); + + if (IS_ERR(dent)) { + printk(KERN_ERR "%s(%d): debugfs_create_dir fail, error %ld\n", + __FILE__, __LINE__, PTR_ERR(dent)); + return -1; + } + + if (debugfs_create_file("off", 0644, dent, 0, &mdp_off_fops) + == NULL) { + printk(KERN_ERR "%s(%d): debugfs_create_file: index fail\n", + __FILE__, __LINE__); + return -1; + } + + if (debugfs_create_file("reg", 0644, dent, 0, &mdp_reg_fops) + == NULL) { + printk(KERN_ERR "%s(%d): debugfs_create_file: debug fail\n", + __FILE__, __LINE__); + return -1; + } + +#ifdef CONFIG_FB_MSM_MDP40 + if (debugfs_create_file("stat", 0644, dent, 0, &mdp_stat_fops) + == NULL) { + printk(KERN_ERR "%s(%d): debugfs_create_file: debug fail\n", + __FILE__, __LINE__); + return -1; + } +#endif + + dent = debugfs_create_dir("mddi", NULL); + + if (IS_ERR(dent)) { + printk(KERN_ERR "%s(%d): debugfs_create_dir fail, error %ld\n", + __FILE__, __LINE__, PTR_ERR(dent)); + return -1; + } + + if (debugfs_create_file("reg", 0644, dent, 0, &pmdh_fops) + == NULL) { + printk(KERN_ERR "%s(%d): debugfs_create_file: debug fail\n", + __FILE__, __LINE__); + return -1; + } + +#if defined(CONFIG_FB_MSM_OVERLAY) && defined(CONFIG_FB_MSM_MDDI) + if (debugfs_create_file("vsync", 0644, dent, 0, &vsync_fops) + == NULL) { + printk(KERN_ERR "%s(%d): debugfs_create_file: debug fail\n", + __FILE__, __LINE__); + return -1; + } +#endif + + dent = debugfs_create_dir("emdh", NULL); + + if (IS_ERR(dent)) { + printk(KERN_ERR "%s(%d): debugfs_create_dir fail, error %ld\n", + __FILE__, __LINE__, PTR_ERR(dent)); + return -1; + } + + if (debugfs_create_file("reg", 0644, dent, 0, &emdh_fops) + == NULL) { + printk(KERN_ERR "%s(%d): debugfs_create_file: debug fail\n", + __FILE__, __LINE__); + return -1; + } + + dent = debugfs_create_dir("mdp-dbg", NULL); + + if (IS_ERR(dent)) { + printk(KERN_ERR "%s(%d): debugfs_create_dir fail, error %ld\n", + __FILE__, __LINE__, PTR_ERR(dent)); + return -1; + } + + if (debugfs_create_file("base", 0644, dent, 0, &dbg_base_fops) + == NULL) { + printk(KERN_ERR "%s(%d): debugfs_create_file: index fail\n", + __FILE__, __LINE__); + return -1; + } + + if (debugfs_create_file("off", 0644, dent, 0, &dbg_off_fops) + == NULL) { + printk(KERN_ERR "%s(%d): debugfs_create_file: index fail\n", + __FILE__, __LINE__); + return -1; + } + + if (debugfs_create_file("reg", 0644, dent, 0, &dbg_reg_fops) + == NULL) { + printk(KERN_ERR "%s(%d): debugfs_create_file: debug fail\n", + __FILE__, __LINE__); + return -1; + } + +#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL + dent = debugfs_create_dir("hdmi", NULL); + + if (IS_ERR(dent)) { + printk(KERN_ERR "%s(%d): debugfs_create_dir fail, error %ld\n", + __FILE__, __LINE__, PTR_ERR(dent)); + return PTR_ERR(dent); + } + + if (debugfs_create_file("off", 0644, dent, 0, &hdmi_off_fops) + == NULL) { + printk(KERN_ERR "%s(%d): debugfs_create_file: 'off' fail\n", + __FILE__, __LINE__); + return -ENOENT; + } + + if (debugfs_create_file("reg", 0644, dent, 0, &hdmi_reg_fops) + == NULL) { + printk(KERN_ERR "%s(%d): debugfs_create_file: 'reg' fail\n", + __FILE__, __LINE__); + return -ENOENT; + } +#endif + + return 0; +} diff --git a/drivers/video/msm/mdp_dma.c b/drivers/video/msm/mdp_dma.c new file mode 100644 index 000000000000..18da6f2b1ba6 --- /dev/null +++ b/drivers/video/msm/mdp_dma.c @@ -0,0 +1,612 @@ +/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include "mdp.h" +#include "msm_fb.h" +#include "mddihost.h" + +static uint32 mdp_last_dma2_update_width; +static uint32 mdp_last_dma2_update_height; +static uint32 mdp_curr_dma2_update_width; +static uint32 mdp_curr_dma2_update_height; + +ktime_t mdp_dma2_last_update_time = { 0 }; + +int mdp_lcd_rd_cnt_offset_slow = 20; +int mdp_lcd_rd_cnt_offset_fast = 20; +int mdp_vsync_usec_wait_line_too_short = 5; +uint32 mdp_dma2_update_time_in_usec; +uint32 mdp_total_vdopkts; + +extern u32 msm_fb_debug_enabled; +extern struct workqueue_struct *mdp_dma_wq; + +int vsync_start_y_adjust = 4; + +static void mdp_dma2_update_lcd(struct msm_fb_data_type *mfd) +{ + MDPIBUF *iBuf = &mfd->ibuf; + int mddi_dest = FALSE; + int cmd_mode = FALSE; + uint32 outBpp = iBuf->bpp; + uint32 dma2_cfg_reg; + uint8 *src; + uint32 mddi_ld_param; + uint16 mddi_vdo_packet_reg; +#ifndef CONFIG_FB_MSM_MDP303 + struct msm_fb_panel_data *pdata = + (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; +#endif + uint32 ystride = mfd->fbi->fix.line_length; + uint32 mddi_pkt_desc; + + dma2_cfg_reg = DMA_PACK_ALIGN_LSB | + DMA_OUT_SEL_AHB | DMA_IBUF_NONCONTIGUOUS; + +#ifdef CONFIG_FB_MSM_MDP22 + dma2_cfg_reg |= DMA_PACK_TIGHT; +#endif + +#ifdef CONFIG_FB_MSM_MDP30 + /* + * Software workaround: On 7x25/7x27, the MDP will not + * respond if dma_w is 1 pixel. Set the update width to + * 2 pixels and adjust the x offset if needed. + */ + if (iBuf->dma_w == 1) { + iBuf->dma_w = 2; + if (iBuf->dma_x == (iBuf->ibuf_width - 2)) + iBuf->dma_x--; + } +#endif + + if (mfd->fb_imgType == MDP_BGR_565) + dma2_cfg_reg |= DMA_PACK_PATTERN_BGR; + else if (mfd->fb_imgType == MDP_RGBA_8888) + dma2_cfg_reg |= DMA_PACK_PATTERN_BGR; + else + dma2_cfg_reg |= DMA_PACK_PATTERN_RGB; + + if (outBpp == 4) { + dma2_cfg_reg |= DMA_IBUF_C3ALPHA_EN; + dma2_cfg_reg |= DMA_IBUF_FORMAT_xRGB8888_OR_ARGB8888; + } + + if (outBpp == 2) + dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB565; + + mddi_ld_param = 0; + mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt; + + if ((mfd->panel_info.type == MDDI_PANEL) || + (mfd->panel_info.type == EXT_MDDI_PANEL)) { + dma2_cfg_reg |= DMA_OUT_SEL_MDDI; + mddi_dest = TRUE; + + if (mfd->panel_info.type == MDDI_PANEL) { + mdp_total_vdopkts++; + if (mfd->panel_info.pdest == DISPLAY_1) { + dma2_cfg_reg |= DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY; + mddi_ld_param = 0; +#ifdef MDDI_HOST_WINDOW_WORKAROUND + mddi_window_adjust(mfd, iBuf->dma_x, + iBuf->dma_w - 1, iBuf->dma_y, + iBuf->dma_h - 1); +#endif + } else { + dma2_cfg_reg |= + DMA_MDDI_DMAOUT_LCD_SEL_SECONDARY; + mddi_ld_param = 1; +#ifdef MDDI_HOST_WINDOW_WORKAROUND + mddi_window_adjust(mfd, iBuf->dma_x, + iBuf->dma_w - 1, iBuf->dma_y, + iBuf->dma_h - 1); +#endif + } + } else { + dma2_cfg_reg |= DMA_MDDI_DMAOUT_LCD_SEL_EXTERNAL; + mddi_ld_param = 2; + } +#ifdef CONFIG_FB_MSM_MDP303 + } else if (mfd->panel_info.type == MIPI_CMD_PANEL) { + cmd_mode = TRUE; + dma2_cfg_reg |= DMA_OUT_SEL_DSI_CMD; +#endif + } else { + if (mfd->panel_info.pdest == DISPLAY_1) { + dma2_cfg_reg |= DMA_AHBM_LCD_SEL_PRIMARY; + outp32(MDP_EBI2_LCD0, mfd->data_port_phys); + } else { + dma2_cfg_reg |= DMA_AHBM_LCD_SEL_SECONDARY; + outp32(MDP_EBI2_LCD1, mfd->data_port_phys); + } + } + + src = (uint8 *) iBuf->buf; + /* starting input address */ + src += iBuf->dma_x * outBpp + iBuf->dma_y * ystride; + + mdp_curr_dma2_update_width = iBuf->dma_w; + mdp_curr_dma2_update_height = iBuf->dma_h; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + +#ifdef CONFIG_FB_MSM_MDP22 + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0184, + (iBuf->dma_h << 16 | iBuf->dma_w)); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0188, src); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x018C, ystride); +#else + if (cmd_mode) + MDP_OUTP(MDP_BASE + 0x90004, + (mfd->panel_info.yres << 16 | mfd->panel_info.xres)); + else + MDP_OUTP(MDP_BASE + 0x90004, (iBuf->dma_h << 16 | iBuf->dma_w)); + + MDP_OUTP(MDP_BASE + 0x90008, src); + MDP_OUTP(MDP_BASE + 0x9000c, ystride); +#endif + + if (mfd->panel_info.bpp == 18) { + mddi_pkt_desc = MDDI_VDO_PACKET_DESC; + dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */ + DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; + } else if (mfd->panel_info.bpp == 24) { + mddi_pkt_desc = MDDI_VDO_PACKET_DESC_24; + dma2_cfg_reg |= DMA_DSTC0G_8BITS | /* 888 24BPP */ + DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS; + } else { + mddi_pkt_desc = MDDI_VDO_PACKET_DESC_16; + dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */ + DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; + } + +#ifndef CONFIG_FB_MSM_MDP303 + + if (mddi_dest) { +#ifdef CONFIG_FB_MSM_MDP22 + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0194, + (iBuf->dma_y << 16) | iBuf->dma_x); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01a0, mddi_ld_param); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01a4, + (mddi_pkt_desc << 16) | mddi_vdo_packet_reg); +#else + MDP_OUTP(MDP_BASE + 0x90010, (iBuf->dma_y << 16) | iBuf->dma_x); + MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param); + MDP_OUTP(MDP_BASE + 0x00094, + (mddi_pkt_desc << 16) | mddi_vdo_packet_reg); +#endif + } else { + /* setting EBI2 LCDC write window */ + pdata->set_rect(iBuf->dma_x, iBuf->dma_y, iBuf->dma_w, + iBuf->dma_h); + } +#else + if (mfd->panel_info.type == MIPI_CMD_PANEL) { + /* dma_p = 0, dma_s = 1 */ + MDP_OUTP(MDP_BASE + 0xF1000, 0x10); + /* enable dsi trigger on dma_p */ + MDP_OUTP(MDP_BASE + 0xF1004, 0x01); + } +#endif + + /* dma2 config register */ +#ifdef MDP_HW_VSYNC + MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg); + + if ((mfd->use_mdp_vsync) && + (mfd->ibuf.vsync_enable) && (mfd->panel_info.lcd.vsync_enable)) { + uint32 start_y; + + if (vsync_start_y_adjust <= iBuf->dma_y) + start_y = iBuf->dma_y - vsync_start_y_adjust; + else + start_y = + (mfd->total_lcd_lines - 1) - (vsync_start_y_adjust - + iBuf->dma_y); + + /* + * MDP VSYNC clock must be On by now so, we don't have to + * re-enable it + */ + MDP_OUTP(MDP_BASE + 0x210, start_y); + MDP_OUTP(MDP_BASE + 0x20c, 1); /* enable prim vsync */ + } else { + MDP_OUTP(MDP_BASE + 0x20c, 0); /* disable prim vsync */ + } +#else +#ifdef CONFIG_FB_MSM_MDP22 + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0180, dma2_cfg_reg); +#else + MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg); +#endif +#endif /* MDP_HW_VSYNC */ + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} + +static ktime_t vt = { 0 }; +int mdp_usec_diff_threshold = 100; +int mdp_expected_usec_wait; + +enum hrtimer_restart mdp_dma2_vsync_hrtimer_handler(struct hrtimer *ht) +{ + struct msm_fb_data_type *mfd = NULL; + + mfd = container_of(ht, struct msm_fb_data_type, dma_hrtimer); + + mdp_pipe_kickoff(MDP_DMA2_TERM, mfd); + + if (msm_fb_debug_enabled) { + ktime_t t; + int usec_diff; + int actual_wait; + + t = ktime_get_real(); + + actual_wait = ktime_to_us(ktime_sub(t, vt)); + usec_diff = actual_wait - mdp_expected_usec_wait; + + if ((mdp_usec_diff_threshold < usec_diff) || (usec_diff < 0)) + MSM_FB_DEBUG + ("HRT Diff = %d usec Exp=%d usec Act=%d usec\n", + usec_diff, mdp_expected_usec_wait, actual_wait); + } + + return HRTIMER_NORESTART; +} + + +#ifdef CONFIG_FB_MSM_MDP303 +static int busy_wait_cnt; + +void mdp3_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd) +{ + unsigned long flag; + int need_wait = 0; + +#ifdef DSI_CLK_CTRL + mod_timer(&dsi_clock_timer, jiffies + HZ); /* one second */ +#endif + + spin_lock_irqsave(&mdp_spin_lock, flag); +#ifdef DSI_CLK_CTRL + if (mipi_dsi_clk_on == 0) + mipi_dsi_turn_on_clks(); +#endif + + if (mfd->dma->busy == TRUE) { + if (busy_wait_cnt == 0) + INIT_COMPLETION(mfd->dma->comp); + busy_wait_cnt++; + need_wait++; + } + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + if (need_wait) { + /* wait until DMA finishes the current job */ + wait_for_completion(&mfd->dma->comp); + } +} +#endif + +static void mdp_dma_schedule(struct msm_fb_data_type *mfd, uint32 term) +{ + /* + * dma2 configure VSYNC block + * vsync supported on Primary LCD only for now + */ + int32 mdp_lcd_rd_cnt; + uint32 usec_wait_time; + uint32 start_y; + + /* + * ToDo: if we can move HRT timer callback to workqueue, we can + * move DMA2 power on under mdp_pipe_kickoff(). + * This will save a power for hrt time wait. + * However if the latency for context switch (hrt irq -> workqueue) + * is too big, we will miss the vsync timing. + */ + if (term == MDP_DMA2_TERM) + mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + mdp_dma2_update_time_in_usec = ktime_to_us(mdp_dma2_last_update_time); + + if ((!mfd->ibuf.vsync_enable) || (!mfd->panel_info.lcd.vsync_enable) + || (mfd->use_mdp_vsync)) { + mdp_pipe_kickoff(term, mfd); + return; + } + /* SW vsync logic starts here */ + + /* get current rd counter */ + mdp_lcd_rd_cnt = mdp_get_lcd_line_counter(mfd); + if (mdp_dma2_update_time_in_usec != 0) { + uint32 num, den; + + /* + * roi width boundary calculation to know the size of pixel + * width that MDP can send faster or slower than LCD read + * pointer + */ + + num = mdp_last_dma2_update_width * mdp_last_dma2_update_height; + den = + (((mfd->panel_info.lcd.refx100 * mfd->total_lcd_lines) / + 1000) * (mdp_dma2_update_time_in_usec / 100)) / 1000; + + if (den == 0) + mfd->vsync_width_boundary[mdp_last_dma2_update_width] = + mfd->panel_info.xres + 1; + else + mfd->vsync_width_boundary[mdp_last_dma2_update_width] = + (int)(num / den); + } + + if (mfd->vsync_width_boundary[mdp_last_dma2_update_width] > + mdp_curr_dma2_update_width) { + /* MDP wrp is faster than LCD rdp */ + mdp_lcd_rd_cnt += mdp_lcd_rd_cnt_offset_fast; + } else { + /* MDP wrp is slower than LCD rdp */ + mdp_lcd_rd_cnt -= mdp_lcd_rd_cnt_offset_slow; + } + + if (mdp_lcd_rd_cnt < 0) + mdp_lcd_rd_cnt = mfd->total_lcd_lines + mdp_lcd_rd_cnt; + else if (mdp_lcd_rd_cnt > mfd->total_lcd_lines) + mdp_lcd_rd_cnt = mdp_lcd_rd_cnt - mfd->total_lcd_lines - 1; + + /* get wrt pointer position */ + start_y = mfd->ibuf.dma_y; + + /* measure line difference between start_y and rd counter */ + if (start_y > mdp_lcd_rd_cnt) { + /* + * *100 for lcd_ref_hzx100 was already multiplied by 100 + * *1000000 is for usec conversion + */ + + if ((start_y - mdp_lcd_rd_cnt) <= + mdp_vsync_usec_wait_line_too_short) + usec_wait_time = 0; + else + usec_wait_time = + ((start_y - + mdp_lcd_rd_cnt) * 1000000) / + ((mfd->total_lcd_lines * + mfd->panel_info.lcd.refx100) / 100); + } else { + if ((start_y + (mfd->total_lcd_lines - mdp_lcd_rd_cnt)) <= + mdp_vsync_usec_wait_line_too_short) + usec_wait_time = 0; + else + usec_wait_time = + ((start_y + + (mfd->total_lcd_lines - + mdp_lcd_rd_cnt)) * 1000000) / + ((mfd->total_lcd_lines * + mfd->panel_info.lcd.refx100) / 100); + } + + mdp_last_dma2_update_width = mdp_curr_dma2_update_width; + mdp_last_dma2_update_height = mdp_curr_dma2_update_height; + + if (usec_wait_time == 0) { + mdp_pipe_kickoff(term, mfd); + } else { + ktime_t wait_time; + + wait_time = ns_to_ktime(usec_wait_time * 1000); + + if (msm_fb_debug_enabled) { + vt = ktime_get_real(); + mdp_expected_usec_wait = usec_wait_time; + } + hrtimer_start(&mfd->dma_hrtimer, wait_time, HRTIMER_MODE_REL); + } +} + +#ifdef MDDI_HOST_WINDOW_WORKAROUND +static void mdp_dma2_update_sub(struct msm_fb_data_type *mfd); +void mdp_dma2_update(struct msm_fb_data_type *mfd) +{ + MDPIBUF *iBuf; + uint32 upper_height; + + if (mfd->panel.type == EXT_MDDI_PANEL) { + mdp_dma2_update_sub(mfd); + return; + } + + iBuf = &mfd->ibuf; + + upper_height = + (uint32) mddi_assign_pkt_height((uint16) iBuf->dma_w, + (uint16) iBuf->dma_h, 18); + + if (upper_height >= iBuf->dma_h) { + mdp_dma2_update_sub(mfd); + } else { + uint32 lower_height; + + /* sending the upper region first */ + lower_height = iBuf->dma_h - upper_height; + iBuf->dma_h = upper_height; + mdp_dma2_update_sub(mfd); + + /* sending the lower region second */ + iBuf->dma_h = lower_height; + iBuf->dma_y += lower_height; + iBuf->vsync_enable = FALSE; + mdp_dma2_update_sub(mfd); + } +} + +static void mdp_dma2_update_sub(struct msm_fb_data_type *mfd) +#else +void mdp_dma2_update(struct msm_fb_data_type *mfd) +#endif +{ + unsigned long flag; + + down(&mfd->dma->mutex); + if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) { + down(&mfd->sem); + mfd->ibuf_flushed = TRUE; + mdp_dma2_update_lcd(mfd); + + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_enable_irq(MDP_DMA2_TERM); + mfd->dma->busy = TRUE; + INIT_COMPLETION(mfd->dma->comp); + + spin_unlock_irqrestore(&mdp_spin_lock, flag); + /* schedule DMA to start */ + mdp_dma_schedule(mfd, MDP_DMA2_TERM); + up(&mfd->sem); + + /* wait until DMA finishes the current job */ + wait_for_completion_killable(&mfd->dma->comp); + mdp_disable_irq(MDP_DMA2_TERM); + + /* signal if pan function is waiting for the update completion */ + if (mfd->pan_waiting) { + mfd->pan_waiting = FALSE; + complete(&mfd->pan_comp); + } + } + up(&mfd->dma->mutex); +} + +void mdp_lcd_update_workqueue_handler(struct work_struct *work) +{ + struct msm_fb_data_type *mfd = NULL; + + mfd = container_of(work, struct msm_fb_data_type, dma_update_worker); + if (mfd) + mfd->dma_fnc(mfd); +} + +void mdp_set_dma_pan_info(struct fb_info *info, struct mdp_dirty_region *dirty, + boolean sync) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct fb_info *fbi = mfd->fbi; + MDPIBUF *iBuf; + int bpp = info->var.bits_per_pixel / 8; + + down(&mfd->sem); + + iBuf = &mfd->ibuf; + + if (mfd->display_iova) + iBuf->buf = (uint8 *)mfd->display_iova; + else + iBuf->buf = (uint8 *) info->fix.smem_start; + + iBuf->buf += calc_fb_offset(mfd, fbi, bpp); + + iBuf->ibuf_width = info->var.xres_virtual; + iBuf->bpp = bpp; + + iBuf->vsync_enable = sync; + + if (dirty) { + /* + * ToDo: dirty region check inside var.xoffset+xres + * <-> var.yoffset+yres + */ + iBuf->dma_x = dirty->xoffset % info->var.xres; + iBuf->dma_y = dirty->yoffset % info->var.yres; + iBuf->dma_w = dirty->width; + iBuf->dma_h = dirty->height; + } else { + iBuf->dma_x = 0; + iBuf->dma_y = 0; + iBuf->dma_w = info->var.xres; + iBuf->dma_h = info->var.yres; + } + mfd->ibuf_flushed = FALSE; + up(&mfd->sem); +} + +void mdp_dma_pan_update(struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + MDPIBUF *iBuf; + + iBuf = &mfd->ibuf; + + if (mfd->sw_currently_refreshing) { + /* we need to wait for the pending update */ + mfd->pan_waiting = TRUE; + if (!mfd->ibuf_flushed) { + wait_for_completion_killable(&mfd->pan_comp); + } + /* waiting for this update to complete */ + mfd->pan_waiting = TRUE; + wait_for_completion_killable(&mfd->pan_comp); + } else + mfd->dma_fnc(mfd); +} + +void mdp_refresh_screen(unsigned long data) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data; + + if ((mfd->sw_currently_refreshing) && (mfd->sw_refreshing_enable)) { + init_timer(&mfd->refresh_timer); + mfd->refresh_timer.function = mdp_refresh_screen; + mfd->refresh_timer.data = data; + + if (mfd->dma->busy) + /* come back in 1 msec */ + mfd->refresh_timer.expires = jiffies + (HZ / 1000); + else + mfd->refresh_timer.expires = + jiffies + mfd->refresh_timer_duration; + + add_timer(&mfd->refresh_timer); + + if (!mfd->dma->busy) { + if (!queue_work(mdp_dma_wq, &mfd->dma_update_worker)) { + MSM_FB_DEBUG("mdp_dma: can't queue_work! -> \ + MDP/MDDI/LCD clock speed needs to be increased\n"); + } + } + } else { + if (!mfd->hw_refresh) + complete(&mfd->refresher_comp); + } +} diff --git a/drivers/video/msm/mdp_dma_dsi_video.c b/drivers/video/msm/mdp_dma_dsi_video.c new file mode 100644 index 000000000000..94941a7fbfd0 --- /dev/null +++ b/drivers/video/msm/mdp_dma_dsi_video.c @@ -0,0 +1,275 @@ +/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mdp.h" +#include "msm_fb.h" +#include "mdp4.h" + +#define DSI_VIDEO_BASE 0xF0000 +#define DMA_P_BASE 0x90000 + +static int first_pixel_start_x; +static int first_pixel_start_y; + +int mdp_dsi_video_on(struct platform_device *pdev) +{ + int dsi_width; + int dsi_height; + int dsi_bpp; + int dsi_border_clr; + int dsi_underflow_clr; + int dsi_hsync_skew; + + int hsync_period; + int hsync_ctrl; + int vsync_period; + int display_hctl; + int display_v_start; + int display_v_end; + int active_hctl; + int active_h_start; + int active_h_end; + int active_v_start; + int active_v_end; + int ctrl_polarity; + int h_back_porch; + int h_front_porch; + int v_back_porch; + int v_front_porch; + int hsync_pulse_width; + int vsync_pulse_width; + int hsync_polarity; + int vsync_polarity; + int data_en_polarity; + int hsync_start_x; + int hsync_end_x; + uint8 *buf; + uint32 dma2_cfg_reg; + + int bpp; + struct fb_info *fbi; + struct fb_var_screeninfo *var; + struct msm_fb_data_type *mfd; + int ret; + uint32_t mask, curr; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + fbi = mfd->fbi; + var = &fbi->var; + + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + + buf += calc_fb_offset(mfd, fbi, bpp); + + dma2_cfg_reg = DMA_PACK_ALIGN_LSB | DMA_OUT_SEL_DSI_VIDEO; + + if (mfd->fb_imgType == MDP_BGR_565) + dma2_cfg_reg |= DMA_PACK_PATTERN_BGR; + else if (mfd->fb_imgType == MDP_RGBA_8888) + dma2_cfg_reg |= DMA_PACK_PATTERN_BGR; + else + dma2_cfg_reg |= DMA_PACK_PATTERN_RGB; + + if (bpp == 2) + dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB565; + else if (bpp == 3) + dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB888; + else + dma2_cfg_reg |= DMA_IBUF_FORMAT_xRGB8888_OR_ARGB8888; + + switch (mfd->panel_info.bpp) { + case 24: + dma2_cfg_reg |= DMA_DSTC0G_8BITS | + DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS; + break; + case 18: + dma2_cfg_reg |= DMA_DSTC0G_6BITS | + DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; + break; + case 16: + dma2_cfg_reg |= DMA_DSTC0G_6BITS | + DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; + break; + default: + printk(KERN_ERR "mdp lcdc can't support format %d bpp!\n", + mfd->panel_info.bpp); + return -ENODEV; + } + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* starting address */ + MDP_OUTP(MDP_BASE + DMA_P_BASE + 0x8, (uint32) buf); + + /* active window width and height */ + MDP_OUTP(MDP_BASE + DMA_P_BASE + 0x4, ((fbi->var.yres) << 16) | + (fbi->var.xres)); + + /* buffer ystride */ + MDP_OUTP(MDP_BASE + DMA_P_BASE + 0xc, fbi->fix.line_length); + + /* x/y coordinate = always 0 for lcdc */ + MDP_OUTP(MDP_BASE + DMA_P_BASE + 0x10, 0); + + /* dma config */ + curr = inpdw(MDP_BASE + DMA_P_BASE); + mask = 0x0FFFFFFF; + dma2_cfg_reg = (dma2_cfg_reg & mask) | (curr & ~mask); + MDP_OUTP(MDP_BASE + DMA_P_BASE, dma2_cfg_reg); + + /* + * DSI timing setting + */ + h_back_porch = var->left_margin; + h_front_porch = var->right_margin; + v_back_porch = var->upper_margin; + v_front_porch = var->lower_margin; + hsync_pulse_width = var->hsync_len; + vsync_pulse_width = var->vsync_len; + dsi_border_clr = mfd->panel_info.lcdc.border_clr; + dsi_underflow_clr = mfd->panel_info.lcdc.underflow_clr; + dsi_hsync_skew = mfd->panel_info.lcdc.hsync_skew; + dsi_width = mfd->panel_info.xres; + dsi_height = mfd->panel_info.yres; + dsi_bpp = mfd->panel_info.bpp; + hsync_period = h_back_porch + dsi_width + h_front_porch + 1; + hsync_ctrl = (hsync_period << 16) | hsync_pulse_width; + hsync_start_x = h_back_porch; + hsync_end_x = dsi_width + h_back_porch - 1; + display_hctl = (hsync_end_x << 16) | hsync_start_x; + + vsync_period = + (v_back_porch + dsi_height + v_front_porch + 1) * hsync_period; + display_v_start = v_back_porch * hsync_period + dsi_hsync_skew; + display_v_end = (dsi_height + v_back_porch) * hsync_period; + + active_h_start = hsync_start_x + first_pixel_start_x; + active_h_end = active_h_start + var->xres - 1; + active_hctl = ACTIVE_START_X_EN | + (active_h_end << 16) | active_h_start; + + active_v_start = display_v_start + + first_pixel_start_y * hsync_period; + active_v_end = active_v_start + (var->yres) * hsync_period - 1; + active_v_start |= ACTIVE_START_Y_EN; + + dsi_underflow_clr |= 0x80000000; /* enable recovery */ + hsync_polarity = 0; + vsync_polarity = 0; + data_en_polarity = 0; + + ctrl_polarity = (data_en_polarity << 2) | + (vsync_polarity << 1) | (hsync_polarity); + + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x4, hsync_ctrl); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x8, vsync_period); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0xc, vsync_pulse_width); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x10, display_hctl); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x14, display_v_start); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x18, display_v_end); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x1c, active_hctl); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x20, active_v_start); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x24, active_v_end); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x28, dsi_border_clr); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x2c, dsi_underflow_clr); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x30, dsi_hsync_skew); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE + 0x38, ctrl_polarity); + + ret = panel_next_on(pdev); + if (ret == 0) { + /* enable DSI block */ + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 1); + /*Turning on DMA_P block*/ + mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + } + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + return ret; +} + +int mdp_dsi_video_off(struct platform_device *pdev) +{ + int ret = 0; + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0); + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + /*Turning off DMA_P block*/ + mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + ret = panel_next_off(pdev); + /* delay to make sure the last frame finishes */ + msleep(20); + + return ret; +} + +void mdp_dsi_video_update(struct msm_fb_data_type *mfd) +{ + struct fb_info *fbi = mfd->fbi; + uint8 *buf; + int bpp; + unsigned long flag; + int irq_block = MDP_DMA2_TERM; + + if (!mfd->panel_power_on) + return; + + down(&mfd->dma->mutex); + + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + + buf += calc_fb_offset(mfd, fbi, bpp); + + /* no need to power on cmd block since it's dsi mode */ + /* starting address */ + MDP_OUTP(MDP_BASE + DMA_P_BASE + 0x8, (uint32) buf); + /* enable irq */ + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_enable_irq(irq_block); + INIT_COMPLETION(mfd->dma->comp); + mfd->dma->waiting = TRUE; + + outp32(MDP_INTR_CLEAR, LCDC_FRAME_START); + mdp_intr_mask |= LCDC_FRAME_START; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + + spin_unlock_irqrestore(&mdp_spin_lock, flag); + wait_for_completion_killable(&mfd->dma->comp); + mdp_disable_irq(irq_block); + up(&mfd->dma->mutex); +} diff --git a/drivers/video/msm/mdp_dma_lcdc.c b/drivers/video/msm/mdp_dma_lcdc.c new file mode 100644 index 000000000000..3b68e4000af6 --- /dev/null +++ b/drivers/video/msm/mdp_dma_lcdc.c @@ -0,0 +1,377 @@ +/* Copyright (c) 2008-2009, 2012 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "mdp.h" +#include "msm_fb.h" +#include "mdp4.h" + +#ifdef CONFIG_FB_MSM_MDP40 +#define LCDC_BASE 0xC0000 +#define DTV_BASE 0xD0000 +#define DMA_E_BASE 0xB0000 +#else +#define LCDC_BASE 0xE0000 +#endif + +#define DMA_P_BASE 0x90000 + +extern spinlock_t mdp_spin_lock; +#ifndef CONFIG_FB_MSM_MDP40 +extern uint32 mdp_intr_mask; +#endif + +int first_pixel_start_x; +int first_pixel_start_y; + +int mdp_lcdc_on(struct platform_device *pdev) +{ + int lcdc_width; + int lcdc_height; + int lcdc_bpp; + int lcdc_border_clr; + int lcdc_underflow_clr; + int lcdc_hsync_skew; + + int hsync_period; + int hsync_ctrl; + int vsync_period; + int display_hctl; + int display_v_start; + int display_v_end; + int active_hctl; + int active_h_start; + int active_h_end; + int active_v_start; + int active_v_end; + int ctrl_polarity; + int h_back_porch; + int h_front_porch; + int v_back_porch; + int v_front_porch; + int hsync_pulse_width; + int vsync_pulse_width; + int hsync_polarity; + int vsync_polarity; + int data_en_polarity; + int hsync_start_x; + int hsync_end_x; + uint8 *buf; + int bpp; + uint32 dma2_cfg_reg; + struct fb_info *fbi; + struct fb_var_screeninfo *var; + struct msm_fb_data_type *mfd; + uint32 dma_base; + uint32 timer_base = LCDC_BASE; + uint32 block = MDP_DMA2_BLOCK; + int ret; + uint32_t mask, curr; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + fbi = mfd->fbi; + var = &fbi->var; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + + buf += calc_fb_offset(mfd, fbi, bpp); + + dma2_cfg_reg = DMA_PACK_ALIGN_LSB | DMA_OUT_SEL_LCDC; + + if (mfd->fb_imgType == MDP_BGR_565) + dma2_cfg_reg |= DMA_PACK_PATTERN_BGR; + else if (mfd->fb_imgType == MDP_RGBA_8888) + dma2_cfg_reg |= DMA_PACK_PATTERN_BGR; + else + dma2_cfg_reg |= DMA_PACK_PATTERN_RGB; + + if (bpp == 2) + dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB565; + else if (bpp == 3) + dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB888; + else + dma2_cfg_reg |= DMA_IBUF_FORMAT_xRGB8888_OR_ARGB8888; + + switch (mfd->panel_info.bpp) { + case 24: + dma2_cfg_reg |= DMA_DSTC0G_8BITS | + DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS; + break; + + case 18: + dma2_cfg_reg |= DMA_DSTC0G_6BITS | + DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; + break; + + case 16: + dma2_cfg_reg |= DMA_DSTC0G_6BITS | + DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; + break; + + default: + printk(KERN_ERR "mdp lcdc can't support format %d bpp!\n", + mfd->panel_info.bpp); + return -ENODEV; + } + + /* DMA register config */ + + dma_base = DMA_P_BASE; + +#ifdef CONFIG_FB_MSM_MDP40 + if (mfd->panel.type == HDMI_PANEL) + dma_base = DMA_E_BASE; +#endif + + /* starting address */ + MDP_OUTP(MDP_BASE + dma_base + 0x8, (uint32) buf); + /* active window width and height */ + MDP_OUTP(MDP_BASE + dma_base + 0x4, ((fbi->var.yres) << 16) | + (fbi->var.xres)); + /* buffer ystride */ + MDP_OUTP(MDP_BASE + dma_base + 0xc, fbi->fix.line_length); + /* x/y coordinate = always 0 for lcdc */ + MDP_OUTP(MDP_BASE + dma_base + 0x10, 0); + /* dma config */ + curr = inpdw(MDP_BASE + DMA_P_BASE); + mask = 0x0FFFFFFF; + dma2_cfg_reg = (dma2_cfg_reg & mask) | (curr & ~mask); + MDP_OUTP(MDP_BASE + dma_base, dma2_cfg_reg); + + /* + * LCDC timing setting + */ + h_back_porch = var->left_margin; + h_front_porch = var->right_margin; + v_back_porch = var->upper_margin; + v_front_porch = var->lower_margin; + hsync_pulse_width = var->hsync_len; + vsync_pulse_width = var->vsync_len; + lcdc_border_clr = mfd->panel_info.lcdc.border_clr; + lcdc_underflow_clr = mfd->panel_info.lcdc.underflow_clr; + lcdc_hsync_skew = mfd->panel_info.lcdc.hsync_skew; + + lcdc_width = mfd->panel_info.xres; + lcdc_height = mfd->panel_info.yres; + lcdc_bpp = mfd->panel_info.bpp; + + hsync_period = + hsync_pulse_width + h_back_porch + lcdc_width + h_front_porch; + hsync_ctrl = (hsync_period << 16) | hsync_pulse_width; + hsync_start_x = hsync_pulse_width + h_back_porch; + hsync_end_x = hsync_period - h_front_porch - 1; + display_hctl = (hsync_end_x << 16) | hsync_start_x; + + vsync_period = + (vsync_pulse_width + v_back_porch + lcdc_height + + v_front_porch) * hsync_period; + display_v_start = + (vsync_pulse_width + v_back_porch) * hsync_period + lcdc_hsync_skew; + display_v_end = + vsync_period - (v_front_porch * hsync_period) + lcdc_hsync_skew - 1; + + if (lcdc_width != var->xres) { + active_h_start = hsync_start_x + first_pixel_start_x; + active_h_end = active_h_start + var->xres - 1; + active_hctl = + ACTIVE_START_X_EN | (active_h_end << 16) | active_h_start; + } else { + active_hctl = 0; + } + + if (lcdc_height != var->yres) { + active_v_start = + display_v_start + first_pixel_start_y * hsync_period; + active_v_end = active_v_start + (var->yres) * hsync_period - 1; + active_v_start |= ACTIVE_START_Y_EN; + } else { + active_v_start = 0; + active_v_end = 0; + } + + +#ifdef CONFIG_FB_MSM_MDP40 + if (mfd->panel.type == HDMI_PANEL) { + block = MDP_DMA_E_BLOCK; + timer_base = DTV_BASE; + hsync_polarity = 0; + vsync_polarity = 0; + } else { + hsync_polarity = 1; + vsync_polarity = 1; + } + + lcdc_underflow_clr |= 0x80000000; /* enable recovery */ +#else + hsync_polarity = 0; + vsync_polarity = 0; +#endif + data_en_polarity = 0; + + ctrl_polarity = + (data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity); + + MDP_OUTP(MDP_BASE + timer_base + 0x4, hsync_ctrl); + MDP_OUTP(MDP_BASE + timer_base + 0x8, vsync_period); + MDP_OUTP(MDP_BASE + timer_base + 0xc, vsync_pulse_width * hsync_period); + if (timer_base == LCDC_BASE) { + MDP_OUTP(MDP_BASE + timer_base + 0x10, display_hctl); + MDP_OUTP(MDP_BASE + timer_base + 0x14, display_v_start); + MDP_OUTP(MDP_BASE + timer_base + 0x18, display_v_end); + MDP_OUTP(MDP_BASE + timer_base + 0x28, lcdc_border_clr); + MDP_OUTP(MDP_BASE + timer_base + 0x2c, lcdc_underflow_clr); + MDP_OUTP(MDP_BASE + timer_base + 0x30, lcdc_hsync_skew); + MDP_OUTP(MDP_BASE + timer_base + 0x38, ctrl_polarity); + MDP_OUTP(MDP_BASE + timer_base + 0x1c, active_hctl); + MDP_OUTP(MDP_BASE + timer_base + 0x20, active_v_start); + MDP_OUTP(MDP_BASE + timer_base + 0x24, active_v_end); + } else { + MDP_OUTP(MDP_BASE + timer_base + 0x18, display_hctl); + MDP_OUTP(MDP_BASE + timer_base + 0x1c, display_v_start); + MDP_OUTP(MDP_BASE + timer_base + 0x20, display_v_end); + MDP_OUTP(MDP_BASE + timer_base + 0x40, lcdc_border_clr); + MDP_OUTP(MDP_BASE + timer_base + 0x44, lcdc_underflow_clr); + MDP_OUTP(MDP_BASE + timer_base + 0x48, lcdc_hsync_skew); + MDP_OUTP(MDP_BASE + timer_base + 0x50, ctrl_polarity); + MDP_OUTP(MDP_BASE + timer_base + 0x2c, active_hctl); + MDP_OUTP(MDP_BASE + timer_base + 0x30, active_v_start); + MDP_OUTP(MDP_BASE + timer_base + 0x38, active_v_end); + } + + ret = panel_next_on(pdev); + if (ret == 0) { + /* enable LCDC block */ + MDP_OUTP(MDP_BASE + timer_base, 1); + mdp_pipe_ctrl(block, MDP_BLOCK_POWER_ON, FALSE); + } + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + return ret; +} + +int mdp_lcdc_off(struct platform_device *pdev) +{ + int ret = 0; + struct msm_fb_data_type *mfd; + uint32 timer_base = LCDC_BASE; + uint32 block = MDP_DMA2_BLOCK; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + +#ifdef CONFIG_FB_MSM_MDP40 + if (mfd->panel.type == HDMI_PANEL) { + block = MDP_DMA_E_BLOCK; + timer_base = DTV_BASE; + } +#endif + + down(&mfd->dma->mutex); + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + MDP_OUTP(MDP_BASE + timer_base, 0); + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + mdp_pipe_ctrl(block, MDP_BLOCK_POWER_OFF, FALSE); + + ret = panel_next_off(pdev); + up(&mfd->dma->mutex); + + /* delay to make sure the last frame finishes */ + msleep(16); + + return ret; +} + +void mdp_lcdc_update(struct msm_fb_data_type *mfd) +{ + struct fb_info *fbi = mfd->fbi; + uint8 *buf; + int bpp; + unsigned long flag; + uint32 dma_base; + int irq_block = MDP_DMA2_TERM; +#ifdef CONFIG_FB_MSM_MDP40 + int intr = INTR_DMA_P_DONE; +#endif + + if (!mfd->panel_power_on) + return; + + down(&mfd->dma->mutex); + /* no need to power on cmd block since it's lcdc mode */ + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + + buf += calc_fb_offset(mfd, fbi, bpp); + + dma_base = DMA_P_BASE; + +#ifdef CONFIG_FB_MSM_MDP40 + if (mfd->panel.type == HDMI_PANEL) { + intr = INTR_DMA_E_DONE; + irq_block = MDP_DMA_E_TERM; + dma_base = DMA_E_BASE; + } +#endif + + /* starting address */ + MDP_OUTP(MDP_BASE + dma_base + 0x8, (uint32) buf); + + /* enable LCDC irq */ + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_enable_irq(irq_block); + INIT_COMPLETION(mfd->dma->comp); + mfd->dma->waiting = TRUE; +#ifdef CONFIG_FB_MSM_MDP40 + outp32(MDP_INTR_CLEAR, intr); + mdp_intr_mask |= intr; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); +#else + outp32(MDP_INTR_CLEAR, LCDC_FRAME_START); + mdp_intr_mask |= LCDC_FRAME_START; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); +#endif + spin_unlock_irqrestore(&mdp_spin_lock, flag); + wait_for_completion_killable(&mfd->dma->comp); + mdp_disable_irq(irq_block); + up(&mfd->dma->mutex); +} diff --git a/drivers/video/msm/mdp_dma_s.c b/drivers/video/msm/mdp_dma_s.c new file mode 100644 index 000000000000..c5a2402c3651 --- /dev/null +++ b/drivers/video/msm/mdp_dma_s.c @@ -0,0 +1,166 @@ +/* Copyright (c) 2008-2009, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include "mdp.h" +#include "msm_fb.h" + +static void mdp_dma_s_update_lcd(struct msm_fb_data_type *mfd) +{ + MDPIBUF *iBuf = &mfd->ibuf; + int mddi_dest = FALSE; + uint32 outBpp = iBuf->bpp; + uint32 dma_s_cfg_reg; + uint8 *src; + struct msm_fb_panel_data *pdata = + (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + + dma_s_cfg_reg = DMA_PACK_TIGHT | DMA_PACK_ALIGN_LSB | + DMA_OUT_SEL_AHB | DMA_IBUF_NONCONTIGUOUS; + + if (mfd->fb_imgType == MDP_BGR_565) + dma_s_cfg_reg |= DMA_PACK_PATTERN_BGR; + else + dma_s_cfg_reg |= DMA_PACK_PATTERN_RGB; + + if (outBpp == 4) + dma_s_cfg_reg |= DMA_IBUF_C3ALPHA_EN; + + if (outBpp == 2) + dma_s_cfg_reg |= DMA_IBUF_FORMAT_RGB565; + + if (mfd->panel_info.pdest != DISPLAY_2) { + printk(KERN_ERR "error: non-secondary type through dma_s!\n"); + return; + } + + if (mfd->panel_info.type == MDDI_PANEL || + mfd->panel_info.type == EXT_MDDI_PANEL) { + dma_s_cfg_reg |= DMA_OUT_SEL_MDDI; + mddi_dest = TRUE; + } else { + dma_s_cfg_reg |= DMA_AHBM_LCD_SEL_SECONDARY; + outp32(MDP_EBI2_LCD1, mfd->data_port_phys); + } + + src = (uint8 *) iBuf->buf; + /* starting input address */ + src += (iBuf->dma_x + iBuf->dma_y * iBuf->ibuf_width) * outBpp; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + /* PIXELSIZE */ + if (mfd->panel_info.type == MDDI_PANEL) { + MDP_OUTP(MDP_BASE + 0xa0004, + (iBuf->dma_h << 16 | iBuf->dma_w)); + MDP_OUTP(MDP_BASE + 0xa0008, src); /* ibuf address */ + MDP_OUTP(MDP_BASE + 0xa000c, + iBuf->ibuf_width * outBpp);/* ystride */ + } else { + MDP_OUTP(MDP_BASE + 0xb0004, + (iBuf->dma_h << 16 | iBuf->dma_w)); + MDP_OUTP(MDP_BASE + 0xb0008, src); /* ibuf address */ + MDP_OUTP(MDP_BASE + 0xb000c, + iBuf->ibuf_width * outBpp);/* ystride */ + } + + if (mfd->panel_info.bpp == 18) { + dma_s_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */ + DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; + } else { + dma_s_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */ + DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; + } + + if (mddi_dest) { + if (mfd->panel_info.type == MDDI_PANEL) { + MDP_OUTP(MDP_BASE + 0xa0010, + (iBuf->dma_y << 16) | iBuf->dma_x); + MDP_OUTP(MDP_BASE + 0x00090, 1); + } else { + MDP_OUTP(MDP_BASE + 0xb0010, + (iBuf->dma_y << 16) | iBuf->dma_x); + MDP_OUTP(MDP_BASE + 0x00090, 2); + } + MDP_OUTP(MDP_BASE + 0x00094, + (MDDI_VDO_PACKET_DESC << 16) | + mfd->panel_info.mddi.vdopkt); + } else { + /* setting LCDC write window */ + pdata->set_rect(iBuf->dma_x, iBuf->dma_y, iBuf->dma_w, + iBuf->dma_h); + } + + if (mfd->panel_info.type == MDDI_PANEL) + MDP_OUTP(MDP_BASE + 0xa0000, dma_s_cfg_reg); + else + MDP_OUTP(MDP_BASE + 0xb0000, dma_s_cfg_reg); + + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + if (mfd->panel_info.type == MDDI_PANEL) + mdp_pipe_kickoff(MDP_DMA_S_TERM, mfd); + else + mdp_pipe_kickoff(MDP_DMA_E_TERM, mfd); + +} + +void mdp_dma_s_update(struct msm_fb_data_type *mfd) +{ + down(&mfd->dma->mutex); + if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) { + down(&mfd->sem); + mdp_enable_irq(MDP_DMA_S_TERM); + if (mfd->panel_info.type == MDDI_PANEL) + mdp_enable_irq(MDP_DMA_S_TERM); + else + mdp_enable_irq(MDP_DMA_E_TERM); + mfd->dma->busy = TRUE; + INIT_COMPLETION(mfd->dma->comp); + mfd->ibuf_flushed = TRUE; + mdp_dma_s_update_lcd(mfd); + up(&mfd->sem); + + /* wait until DMA finishes the current job */ + wait_for_completion_killable(&mfd->dma->comp); + if (mfd->panel_info.type == MDDI_PANEL) + mdp_disable_irq(MDP_DMA_S_TERM); + else + mdp_disable_irq(MDP_DMA_E_TERM); + + /* signal if pan function is waiting for the update completion */ + if (mfd->pan_waiting) { + mfd->pan_waiting = FALSE; + complete(&mfd->pan_comp); + } + } + up(&mfd->dma->mutex); +} diff --git a/drivers/video/msm/mdp_dma_tv.c b/drivers/video/msm/mdp_dma_tv.c new file mode 100644 index 000000000000..ee2e323f5e29 --- /dev/null +++ b/drivers/video/msm/mdp_dma_tv.c @@ -0,0 +1,140 @@ +/* Copyright (c) 2008-2009, 2012 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include "mdp.h" +#include "msm_fb.h" + +extern spinlock_t mdp_spin_lock; +extern uint32 mdp_intr_mask; + +int mdp_dma3_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct fb_info *fbi; + uint8 *buf; + int bpp; + int ret = 0; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + fbi = mfd->fbi; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + + buf += calc_fb_offset(mfd, fbi, bpp); + + /* starting address[31..8] of Video frame buffer is CS0 */ + MDP_OUTP(MDP_BASE + 0xC0008, (uint32) buf >> 3); + + mdp_pipe_ctrl(MDP_DMA3_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + MDP_OUTP(MDP_BASE + 0xC0004, 0x4c60674); /* flicker filter enabled */ + MDP_OUTP(MDP_BASE + 0xC0010, 0x20); /* sobel treshold */ + + MDP_OUTP(MDP_BASE + 0xC0018, 0xeb0010); /* Y Max, Y min */ + MDP_OUTP(MDP_BASE + 0xC001C, 0xf00010); /* Cb Max, Cb min */ + MDP_OUTP(MDP_BASE + 0xC0020, 0xf00010); /* Cb Max, Cb min */ + + MDP_OUTP(MDP_BASE + 0xC000C, 0x67686970); /* add a few chars for CC */ + MDP_OUTP(MDP_BASE + 0xC0000, 0x1); /* MDP tv out enable */ + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + ret = panel_next_on(pdev); + + return ret; +} + +int mdp_dma3_off(struct platform_device *pdev) +{ + int ret = 0; + + ret = panel_next_off(pdev); + if (ret) + return ret; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + MDP_OUTP(MDP_BASE + 0xC0000, 0x0); + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + mdp_pipe_ctrl(MDP_DMA3_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + /* delay to make sure the last frame finishes */ + msleep(16); + + return ret; +} + +void mdp_dma3_update(struct msm_fb_data_type *mfd) +{ + struct fb_info *fbi = mfd->fbi; + uint8 *buf; + int bpp; + unsigned long flag; + + if (!mfd->panel_power_on) + return; + + /* no need to power on cmd block since dma3 is running */ + bpp = fbi->var.bits_per_pixel / 8; + buf = (uint8 *) fbi->fix.smem_start; + + buf += calc_fb_offset(mfd, fbi, bpp); + + MDP_OUTP(MDP_BASE + 0xC0008, (uint32) buf >> 3); + + spin_lock_irqsave(&mdp_spin_lock, flag); + mdp_enable_irq(MDP_DMA3_TERM); + INIT_COMPLETION(mfd->dma->comp); + mfd->dma->waiting = TRUE; + + outp32(MDP_INTR_CLEAR, TV_OUT_DMA3_START); + mdp_intr_mask |= TV_OUT_DMA3_START; + outp32(MDP_INTR_ENABLE, mdp_intr_mask); + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + wait_for_completion_killable(&mfd->dma->comp); + mdp_disable_irq(MDP_DMA3_TERM); +} diff --git a/drivers/video/msm/mdp_hw.h b/drivers/video/msm/mdp_hw.h new file mode 100644 index 000000000000..f35a757d4731 --- /dev/null +++ b/drivers/video/msm/mdp_hw.h @@ -0,0 +1,769 @@ +/* drivers/video/msm_fb/mdp_hw.h + * + * Copyright (C) 2007 QUALCOMM Incorporated + * Copyright (C) 2007 Google Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef _MDP_HW_H_ +#define _MDP_HW_H_ + +#include +#include +#include +#include + +typedef void (*mdp_dma_start_func_t)(void *private_data, uint32_t addr, + uint32_t stride, uint32_t width, + uint32_t height, uint32_t x, uint32_t y); + +struct mdp_out_interface { + uint32_t registered:1; + void *priv; + + /* If the interface client wants to get DMA_DONE events */ + uint32_t dma_mask; + mdp_dma_start_func_t dma_start; + + struct msmfb_callback *dma_cb; + wait_queue_head_t dma_waitqueue; + + /* If the interface client wants to be notified of non-DMA irqs, + * e.g. LCDC/TV-out frame start */ + uint32_t irq_mask; + struct msmfb_callback *irq_cb; +}; + +struct mdp_info { + spinlock_t lock; + struct mdp_device mdp_dev; + char * __iomem base; + int irq; + struct clk *clk; + struct clk *ebi1_clk; + struct mdp_out_interface out_if[MSM_MDP_NUM_INTERFACES]; + int format; + int pack_pattern; + bool dma_config_dirty; +}; + +extern int mdp_out_if_register(struct mdp_device *mdp_dev, int interface, + void *private_data, uint32_t dma_mask, + mdp_dma_start_func_t dma_start); + +extern int mdp_out_if_req_irq(struct mdp_device *mdp_dev, int interface, + uint32_t mask, struct msmfb_callback *cb); + +struct mdp_blit_req; +struct mdp_device; +int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req, + struct file *src_file, unsigned long src_start, + unsigned long src_len, struct file *dst_file, + unsigned long dst_start, unsigned long dst_len); + +void mdp_ppp_dump_debug(const struct mdp_info *mdp); + +#define mdp_writel(mdp, value, offset) writel(value, mdp->base + offset) +#define mdp_readl(mdp, offset) readl(mdp->base + offset) + +#define MDP_SYNC_CONFIG_0 (0x00000) +#define MDP_SYNC_CONFIG_1 (0x00004) +#define MDP_SYNC_CONFIG_2 (0x00008) +#define MDP_SYNC_STATUS_0 (0x0000c) +#define MDP_SYNC_STATUS_1 (0x00010) +#define MDP_SYNC_STATUS_2 (0x00014) +#define MDP_SYNC_THRESH_0 (0x00018) +#define MDP_SYNC_THRESH_1 (0x0001c) +#define MDP_INTR_ENABLE (0x00020) +#define MDP_INTR_STATUS (0x00024) +#define MDP_INTR_CLEAR (0x00028) +#define MDP_DISPLAY0_START (0x00030) +#define MDP_DISPLAY1_START (0x00034) +#define MDP_DISPLAY_STATUS (0x00038) +#define MDP_EBI2_LCD0 (0x0003c) +#define MDP_EBI2_LCD1 (0x00040) +#define MDP_EBI2_PORTMAP_MODE (0x0005c) + +#ifndef CONFIG_MSM_MDP31 +#define MDP_DISPLAY0_ADDR (0x00054) +#define MDP_DISPLAY1_ADDR (0x00058) +#define MDP_PPP_CMD_MODE (0x00060) +#else +#define MDP_DISPLAY0_ADDR (0x10000) +#define MDP_DISPLAY1_ADDR (0x10004) +#define MDP_PPP_CMD_MODE (0x10060) +#endif + +#define MDP_TV_OUT_STATUS (0x00064) +#define MDP_HW_VERSION (0x00070) +#define MDP_SW_RESET (0x00074) +#define MDP_AXI_ERROR_MASTER_STOP (0x00078) +#define MDP_SEL_CLK_OR_HCLK_TEST_BUS (0x0007c) +#define MDP_PRIMARY_VSYNC_OUT_CTRL (0x00080) +#define MDP_SECONDARY_VSYNC_OUT_CTRL (0x00084) +#define MDP_EXTERNAL_VSYNC_OUT_CTRL (0x00088) +#define MDP_VSYNC_CTRL (0x0008c) +#define MDP_MDDI_PARAM_WR_SEL (0x00090) +#define MDP_MDDI_PARAM (0x00094) +#define MDP_CGC_EN (0x00100) +#define MDP_CMD_STATUS (0x10008) +#define MDP_PROFILE_EN (0x10010) +#define MDP_PROFILE_COUNT (0x10014) +#define MDP_DMA_START (0x10044) +#define MDP_FULL_BYPASS_WORD0 (0x10100) +#define MDP_FULL_BYPASS_WORD1 (0x10104) +#define MDP_COMMAND_CONFIG (0x10104) +#define MDP_FULL_BYPASS_WORD2 (0x10108) +#define MDP_FULL_BYPASS_WORD3 (0x1010c) +#define MDP_FULL_BYPASS_WORD4 (0x10110) +#define MDP_FULL_BYPASS_WORD6 (0x10118) +#define MDP_FULL_BYPASS_WORD7 (0x1011c) +#define MDP_FULL_BYPASS_WORD8 (0x10120) +#define MDP_FULL_BYPASS_WORD9 (0x10124) +#define MDP_PPP_SOURCE_CONFIG (0x10124) +#define MDP_FULL_BYPASS_WORD10 (0x10128) +#define MDP_FULL_BYPASS_WORD11 (0x1012c) +#define MDP_FULL_BYPASS_WORD12 (0x10130) +#define MDP_FULL_BYPASS_WORD13 (0x10134) +#define MDP_FULL_BYPASS_WORD14 (0x10138) +#define MDP_PPP_OPERATION_CONFIG (0x10138) +#define MDP_FULL_BYPASS_WORD15 (0x1013c) +#define MDP_FULL_BYPASS_WORD16 (0x10140) +#define MDP_FULL_BYPASS_WORD17 (0x10144) +#define MDP_FULL_BYPASS_WORD18 (0x10148) +#define MDP_FULL_BYPASS_WORD19 (0x1014c) +#define MDP_FULL_BYPASS_WORD20 (0x10150) +#define MDP_PPP_DESTINATION_CONFIG (0x10150) +#define MDP_FULL_BYPASS_WORD21 (0x10154) +#define MDP_FULL_BYPASS_WORD22 (0x10158) +#define MDP_FULL_BYPASS_WORD23 (0x1015c) +#define MDP_FULL_BYPASS_WORD24 (0x10160) +#define MDP_FULL_BYPASS_WORD25 (0x10164) +#define MDP_FULL_BYPASS_WORD26 (0x10168) +#define MDP_FULL_BYPASS_WORD27 (0x1016c) +#define MDP_FULL_BYPASS_WORD29 (0x10174) +#define MDP_FULL_BYPASS_WORD30 (0x10178) +#define MDP_FULL_BYPASS_WORD31 (0x1017c) +#define MDP_FULL_BYPASS_WORD32 (0x10180) +#define MDP_DMA_CONFIG (0x10180) +#define MDP_FULL_BYPASS_WORD33 (0x10184) +#define MDP_FULL_BYPASS_WORD34 (0x10188) +#define MDP_FULL_BYPASS_WORD35 (0x1018c) +#define MDP_FULL_BYPASS_WORD37 (0x10194) +#define MDP_FULL_BYPASS_WORD39 (0x1019c) +#define MDP_PPP_OUT_XY (0x1019c) +#define MDP_FULL_BYPASS_WORD40 (0x101a0) +#define MDP_FULL_BYPASS_WORD41 (0x101a4) +#define MDP_FULL_BYPASS_WORD43 (0x101ac) +#define MDP_FULL_BYPASS_WORD46 (0x101b8) +#define MDP_FULL_BYPASS_WORD47 (0x101bc) +#define MDP_FULL_BYPASS_WORD48 (0x101c0) +#define MDP_FULL_BYPASS_WORD49 (0x101c4) +#define MDP_FULL_BYPASS_WORD50 (0x101c8) +#define MDP_FULL_BYPASS_WORD51 (0x101cc) +#define MDP_FULL_BYPASS_WORD52 (0x101d0) +#define MDP_FULL_BYPASS_WORD53 (0x101d4) +#define MDP_FULL_BYPASS_WORD54 (0x101d8) +#define MDP_FULL_BYPASS_WORD55 (0x101dc) +#define MDP_FULL_BYPASS_WORD56 (0x101e0) +#define MDP_FULL_BYPASS_WORD57 (0x101e4) +#define MDP_FULL_BYPASS_WORD58 (0x101e8) +#define MDP_FULL_BYPASS_WORD59 (0x101ec) +#define MDP_FULL_BYPASS_WORD60 (0x101f0) +#define MDP_VSYNC_THRESHOLD (0x101f0) +#define MDP_FULL_BYPASS_WORD61 (0x101f4) +#define MDP_FULL_BYPASS_WORD62 (0x101f8) +#define MDP_FULL_BYPASS_WORD63 (0x101fc) + +#ifdef CONFIG_MSM_MDP31 +#define MDP_PPP_SRC_XY (0x10200) +#define MDP_PPP_BG_XY (0x10204) +#define MDP_PPP_SRC_IMAGE_SIZE (0x10208) +#define MDP_PPP_BG_IMAGE_SIZE (0x1020c) +#define MDP_PPP_SCALE_CONFIG (0x10230) +#define MDP_PPP_CSC_CONFIG (0x10240) +#define MDP_PPP_BLEND_BG_ALPHA_SEL (0x70010) +#endif + +#define MDP_TFETCH_TEST_MODE (0x20004) +#define MDP_TFETCH_STATUS (0x20008) +#define MDP_TFETCH_TILE_COUNT (0x20010) +#define MDP_TFETCH_FETCH_COUNT (0x20014) +#define MDP_TFETCH_CONSTANT_COLOR (0x20040) +#define MDP_BGTFETCH_TEST_MODE (0x28004) +#define MDP_BGTFETCH_STATUS (0x28008) +#define MDP_BGTFETCH_TILE_COUNT (0x28010) +#define MDP_BGTFETCH_FETCH_COUNT (0x28014) +#define MDP_BGTFETCH_CONSTANT_COLOR (0x28040) +#define MDP_CSC_BYPASS (0x40004) +#define MDP_SCALE_COEFF_LSB (0x5fffc) +#define MDP_TV_OUT_CTL (0xc0000) +#define MDP_TV_OUT_FIR_COEFF (0xc0004) +#define MDP_TV_OUT_BUF_ADDR (0xc0008) +#define MDP_TV_OUT_CC_DATA (0xc000c) +#define MDP_TV_OUT_SOBEL (0xc0010) +#define MDP_TV_OUT_Y_CLAMP (0xc0018) +#define MDP_TV_OUT_CB_CLAMP (0xc001c) +#define MDP_TV_OUT_CR_CLAMP (0xc0020) +#define MDP_TEST_MODE_CLK (0xd0000) +#define MDP_TEST_MISR_RESET_CLK (0xd0004) +#define MDP_TEST_EXPORT_MISR_CLK (0xd0008) +#define MDP_TEST_MISR_CURR_VAL_CLK (0xd000c) +#define MDP_TEST_MODE_HCLK (0xd0100) +#define MDP_TEST_MISR_RESET_HCLK (0xd0104) +#define MDP_TEST_EXPORT_MISR_HCLK (0xd0108) +#define MDP_TEST_MISR_CURR_VAL_HCLK (0xd010c) +#define MDP_TEST_MODE_DCLK (0xd0200) +#define MDP_TEST_MISR_RESET_DCLK (0xd0204) +#define MDP_TEST_EXPORT_MISR_DCLK (0xd0208) +#define MDP_TEST_MISR_CURR_VAL_DCLK (0xd020c) +#define MDP_TEST_CAPTURED_DCLK (0xd0210) +#define MDP_TEST_MISR_CAPT_VAL_DCLK (0xd0214) + +#define MDP_DMA_P_START (0x00044) +#define MDP_DMA_P_CONFIG (0x90000) +#define MDP_DMA_P_SIZE (0x90004) +#define MDP_DMA_P_IBUF_ADDR (0x90008) +#define MDP_DMA_P_IBUF_Y_STRIDE (0x9000c) +#define MDP_DMA_P_OUT_XY (0x90010) +#define MDP_DMA_P_COLOR_CORRECT_CONFIG (0x90070) + +#define MDP_LCDC_EN (0xe0000) +#define MDP_LCDC_HSYNC_CTL (0xe0004) +#define MDP_LCDC_VSYNC_PERIOD (0xe0008) +#define MDP_LCDC_VSYNC_PULSE_WIDTH (0xe000c) +#define MDP_LCDC_DISPLAY_HCTL (0xe0010) +#define MDP_LCDC_DISPLAY_V_START (0xe0014) +#define MDP_LCDC_DISPLAY_V_END (0xe0018) +#define MDP_LCDC_ACTIVE_HCTL (0xe001c) +#define MDP_LCDC_ACTIVE_V_START (0xe0020) +#define MDP_LCDC_ACTIVE_V_END (0xe0024) +#define MDP_LCDC_BORDER_CLR (0xe0028) +#define MDP_LCDC_UNDERFLOW_CTL (0xe002c) +#define MDP_LCDC_HSYNC_SKEW (0xe0030) +#define MDP_LCDC_TEST_CTL (0xe0034) +#define MDP_LCDC_CTL_POLARITY (0xe0038) + +#define MDP_PPP_SCALE_STATUS (0x50000) +#define MDP_PPP_BLEND_STATUS (0x70000) + +/* MDP_SW_RESET */ +#define MDP_PPP_SW_RESET (1<<4) + +/* MDP_INTR_ENABLE */ +#define DL0_ROI_DONE (1<<0) +#define TV_OUT_DMA3_DONE (1<<6) +#define TV_ENC_UNDERRUN (1<<7) + +#ifdef CONFIG_MSM_MDP22 +#define MDP_DMA_P_DONE (1 << 2) +#else /* CONFIG_MSM_MDP31 */ +#define MDP_DMA_P_DONE (1 << 14) +#define MDP_LCDC_UNDERFLOW (1 << 16) +#define MDP_LCDC_FRAME_START (1 << 15) +#endif + +#define MDP_TOP_LUMA 16 +#define MDP_TOP_CHROMA 0 +#define MDP_BOTTOM_LUMA 19 +#define MDP_BOTTOM_CHROMA 3 +#define MDP_LEFT_LUMA 22 +#define MDP_LEFT_CHROMA 6 +#define MDP_RIGHT_LUMA 25 +#define MDP_RIGHT_CHROMA 9 + +#define CLR_G 0x0 +#define CLR_B 0x1 +#define CLR_R 0x2 +#define CLR_ALPHA 0x3 + +#define CLR_Y CLR_G +#define CLR_CB CLR_B +#define CLR_CR CLR_R + +/* from lsb to msb */ +#define MDP_GET_PACK_PATTERN(a, x, y, z, bit) \ + (((a)<<(bit*3))|((x)<<(bit*2))|((y)< + * + * Based on code from The Linux Foundation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include + +#include "mdp_hw.h" + +static void mdp_dma_to_mddi(void *priv, uint32_t addr, uint32_t stride, + uint32_t width, uint32_t height, uint32_t x, + uint32_t y) +{ + struct mdp_info *mdp = priv; + uint32_t dma2_cfg; + uint16_t ld_param = 0; /* 0=PRIM, 1=SECD, 2=EXT */ + + dma2_cfg = DMA_PACK_TIGHT | + DMA_PACK_ALIGN_LSB; + + dma2_cfg |= mdp->dma_format; + dma2_cfg |= mdp->dma_pack_pattern; + dma2_cfg |= DMA_DITHER_EN; + + /* 666 18BPP */ + dma2_cfg |= DMA_DSTC0G_6BITS | DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; + + /* setup size, address, and stride */ + mdp_writel(mdp, (height << 16) | (width), MDP_DMA_P_SIZE); + mdp_writel(mdp, addr, MDP_DMA_P_IBUF_ADDR); + mdp_writel(mdp, stride, MDP_DMA_P_IBUF_Y_STRIDE); + + /* set y & x offset and MDDI transaction parameters */ + mdp_writel(mdp, (y << 16) | (x), MDP_DMA_P_OUT_XY); + mdp_writel(mdp, ld_param, MDP_MDDI_PARAM_WR_SEL); + mdp_writel(mdp, (MDDI_VDO_PACKET_DESC << 16) | MDDI_VDO_PACKET_PRIM, + MDP_MDDI_PARAM); + + mdp_writel(mdp, 0x1, MDP_MDDI_DATA_XFR); + mdp_writel(mdp, dma2_cfg, MDP_DMA_P_CONFIG); + mdp_writel(mdp, 0, MDP_DMA_P_START); +} + +int mdp_hw_init(struct mdp_info *mdp) +{ + int ret; + + ret = mdp_out_if_register(&mdp->mdp_dev, MSM_MDDI_PMDH_INTERFACE, mdp, + MDP_DMA_P_DONE, mdp_dma_to_mddi); + if (ret) + return ret; + + mdp_writel(mdp, 0, MDP_INTR_ENABLE); + mdp_writel(mdp, 0, MDP_DMA_P_HIST_INTR_ENABLE); + + /* XXX: why set this? QCT says it should be > mdp_pclk, + * but they never set the clkrate of pclk */ + clk_set_rate(mdp->clk, 122880000); /* 122.88 Mhz */ + pr_info("%s: mdp_clk=%lu\n", __func__, clk_get_rate(mdp->clk)); + + /* TODO: Configure the VG/RGB pipes fetch data */ + + /* this should work for any mdp_clk freq. + * TODO: use different value for mdp_clk freqs >= 90Mhz */ + mdp_writel(mdp, 0x27, MDP_DMA_P_FETCH_CFG); /* 8 bytes-burst x 8 req */ + + mdp_writel(mdp, 0x3, MDP_EBI2_PORTMAP_MODE); + + /* 3 pending requests */ + mdp_writel(mdp, 0x02222, MDP_MAX_RD_PENDING_CMD_CONFIG); + + /* no overlay processing, sw controls everything */ + mdp_writel(mdp, 0, MDP_LAYERMIXER_IN_CFG); + mdp_writel(mdp, 1 << 3, MDP_OVERLAYPROC0_CFG); + mdp_writel(mdp, 1 << 3, MDP_OVERLAYPROC1_CFG); + + /* XXX: HACK! hardcode to do mddi on primary */ + mdp_writel(mdp, 0x2, MDP_DISP_INTF_SEL); + return 0; +} + diff --git a/drivers/video/msm/mdp_hw_init.c b/drivers/video/msm/mdp_hw_init.c new file mode 100644 index 000000000000..3818ed497bca --- /dev/null +++ b/drivers/video/msm/mdp_hw_init.c @@ -0,0 +1,714 @@ +/* Copyright (c) 2008-2009, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "mdp.h" + +/* mdp primary csc limit vector */ +uint32 mdp_plv[] = { 0x10, 0xeb, 0x10, 0xf0 }; + +/* Color Coefficient matrix for YUV -> RGB */ +struct mdp_ccs mdp_ccs_yuv2rgb = { + MDP_CCS_YUV2RGB, + { + 0x254, + 0x000, + 0x331, + 0x254, + 0xff38, + 0xfe61, + 0x254, + 0x409, + 0x000, + }, + { +#ifdef CONFIG_FB_MSM_MDP31 + 0x1f0, + 0x180, + 0x180 +#else + 0x10, + 0x80, + 0x80 +#endif + } +}; + +/* Color Coefficient matrix for RGB -> YUV */ +struct mdp_ccs mdp_ccs_rgb2yuv = { + MDP_CCS_RGB2YUV, + { + 0x83, + 0x102, + 0x32, + 0xffb5, + 0xff6c, + 0xe1, + 0xe1, + 0xff45, + 0xffdc, + }, +#ifdef CONFIG_FB_MSM_MDP31 + { + 0x10, + 0x80, + 0x80 + } +#endif +}; + +static void mdp_load_lut_param(void) +{ + outpdw(MDP_BASE + 0x40800, 0x0); + outpdw(MDP_BASE + 0x40804, 0x151515); + outpdw(MDP_BASE + 0x40808, 0x1d1d1d); + outpdw(MDP_BASE + 0x4080c, 0x232323); + outpdw(MDP_BASE + 0x40810, 0x272727); + outpdw(MDP_BASE + 0x40814, 0x2b2b2b); + outpdw(MDP_BASE + 0x40818, 0x2f2f2f); + outpdw(MDP_BASE + 0x4081c, 0x333333); + outpdw(MDP_BASE + 0x40820, 0x363636); + outpdw(MDP_BASE + 0x40824, 0x393939); + outpdw(MDP_BASE + 0x40828, 0x3b3b3b); + outpdw(MDP_BASE + 0x4082c, 0x3e3e3e); + outpdw(MDP_BASE + 0x40830, 0x404040); + outpdw(MDP_BASE + 0x40834, 0x434343); + outpdw(MDP_BASE + 0x40838, 0x454545); + outpdw(MDP_BASE + 0x4083c, 0x474747); + outpdw(MDP_BASE + 0x40840, 0x494949); + outpdw(MDP_BASE + 0x40844, 0x4b4b4b); + outpdw(MDP_BASE + 0x40848, 0x4d4d4d); + outpdw(MDP_BASE + 0x4084c, 0x4f4f4f); + outpdw(MDP_BASE + 0x40850, 0x515151); + outpdw(MDP_BASE + 0x40854, 0x535353); + outpdw(MDP_BASE + 0x40858, 0x555555); + outpdw(MDP_BASE + 0x4085c, 0x565656); + outpdw(MDP_BASE + 0x40860, 0x585858); + outpdw(MDP_BASE + 0x40864, 0x5a5a5a); + outpdw(MDP_BASE + 0x40868, 0x5b5b5b); + outpdw(MDP_BASE + 0x4086c, 0x5d5d5d); + outpdw(MDP_BASE + 0x40870, 0x5e5e5e); + outpdw(MDP_BASE + 0x40874, 0x606060); + outpdw(MDP_BASE + 0x40878, 0x616161); + outpdw(MDP_BASE + 0x4087c, 0x636363); + outpdw(MDP_BASE + 0x40880, 0x646464); + outpdw(MDP_BASE + 0x40884, 0x666666); + outpdw(MDP_BASE + 0x40888, 0x676767); + outpdw(MDP_BASE + 0x4088c, 0x686868); + outpdw(MDP_BASE + 0x40890, 0x6a6a6a); + outpdw(MDP_BASE + 0x40894, 0x6b6b6b); + outpdw(MDP_BASE + 0x40898, 0x6c6c6c); + outpdw(MDP_BASE + 0x4089c, 0x6e6e6e); + outpdw(MDP_BASE + 0x408a0, 0x6f6f6f); + outpdw(MDP_BASE + 0x408a4, 0x707070); + outpdw(MDP_BASE + 0x408a8, 0x717171); + outpdw(MDP_BASE + 0x408ac, 0x727272); + outpdw(MDP_BASE + 0x408b0, 0x747474); + outpdw(MDP_BASE + 0x408b4, 0x757575); + outpdw(MDP_BASE + 0x408b8, 0x767676); + outpdw(MDP_BASE + 0x408bc, 0x777777); + outpdw(MDP_BASE + 0x408c0, 0x787878); + outpdw(MDP_BASE + 0x408c4, 0x797979); + outpdw(MDP_BASE + 0x408c8, 0x7a7a7a); + outpdw(MDP_BASE + 0x408cc, 0x7c7c7c); + outpdw(MDP_BASE + 0x408d0, 0x7d7d7d); + outpdw(MDP_BASE + 0x408d4, 0x7e7e7e); + outpdw(MDP_BASE + 0x408d8, 0x7f7f7f); + outpdw(MDP_BASE + 0x408dc, 0x808080); + outpdw(MDP_BASE + 0x408e0, 0x818181); + outpdw(MDP_BASE + 0x408e4, 0x828282); + outpdw(MDP_BASE + 0x408e8, 0x838383); + outpdw(MDP_BASE + 0x408ec, 0x848484); + outpdw(MDP_BASE + 0x408f0, 0x858585); + outpdw(MDP_BASE + 0x408f4, 0x868686); + outpdw(MDP_BASE + 0x408f8, 0x878787); + outpdw(MDP_BASE + 0x408fc, 0x888888); + outpdw(MDP_BASE + 0x40900, 0x898989); + outpdw(MDP_BASE + 0x40904, 0x8a8a8a); + outpdw(MDP_BASE + 0x40908, 0x8b8b8b); + outpdw(MDP_BASE + 0x4090c, 0x8c8c8c); + outpdw(MDP_BASE + 0x40910, 0x8d8d8d); + outpdw(MDP_BASE + 0x40914, 0x8e8e8e); + outpdw(MDP_BASE + 0x40918, 0x8f8f8f); + outpdw(MDP_BASE + 0x4091c, 0x8f8f8f); + outpdw(MDP_BASE + 0x40920, 0x909090); + outpdw(MDP_BASE + 0x40924, 0x919191); + outpdw(MDP_BASE + 0x40928, 0x929292); + outpdw(MDP_BASE + 0x4092c, 0x939393); + outpdw(MDP_BASE + 0x40930, 0x949494); + outpdw(MDP_BASE + 0x40934, 0x959595); + outpdw(MDP_BASE + 0x40938, 0x969696); + outpdw(MDP_BASE + 0x4093c, 0x969696); + outpdw(MDP_BASE + 0x40940, 0x979797); + outpdw(MDP_BASE + 0x40944, 0x989898); + outpdw(MDP_BASE + 0x40948, 0x999999); + outpdw(MDP_BASE + 0x4094c, 0x9a9a9a); + outpdw(MDP_BASE + 0x40950, 0x9b9b9b); + outpdw(MDP_BASE + 0x40954, 0x9c9c9c); + outpdw(MDP_BASE + 0x40958, 0x9c9c9c); + outpdw(MDP_BASE + 0x4095c, 0x9d9d9d); + outpdw(MDP_BASE + 0x40960, 0x9e9e9e); + outpdw(MDP_BASE + 0x40964, 0x9f9f9f); + outpdw(MDP_BASE + 0x40968, 0xa0a0a0); + outpdw(MDP_BASE + 0x4096c, 0xa0a0a0); + outpdw(MDP_BASE + 0x40970, 0xa1a1a1); + outpdw(MDP_BASE + 0x40974, 0xa2a2a2); + outpdw(MDP_BASE + 0x40978, 0xa3a3a3); + outpdw(MDP_BASE + 0x4097c, 0xa4a4a4); + outpdw(MDP_BASE + 0x40980, 0xa4a4a4); + outpdw(MDP_BASE + 0x40984, 0xa5a5a5); + outpdw(MDP_BASE + 0x40988, 0xa6a6a6); + outpdw(MDP_BASE + 0x4098c, 0xa7a7a7); + outpdw(MDP_BASE + 0x40990, 0xa7a7a7); + outpdw(MDP_BASE + 0x40994, 0xa8a8a8); + outpdw(MDP_BASE + 0x40998, 0xa9a9a9); + outpdw(MDP_BASE + 0x4099c, 0xaaaaaa); + outpdw(MDP_BASE + 0x409a0, 0xaaaaaa); + outpdw(MDP_BASE + 0x409a4, 0xababab); + outpdw(MDP_BASE + 0x409a8, 0xacacac); + outpdw(MDP_BASE + 0x409ac, 0xadadad); + outpdw(MDP_BASE + 0x409b0, 0xadadad); + outpdw(MDP_BASE + 0x409b4, 0xaeaeae); + outpdw(MDP_BASE + 0x409b8, 0xafafaf); + outpdw(MDP_BASE + 0x409bc, 0xafafaf); + outpdw(MDP_BASE + 0x409c0, 0xb0b0b0); + outpdw(MDP_BASE + 0x409c4, 0xb1b1b1); + outpdw(MDP_BASE + 0x409c8, 0xb2b2b2); + outpdw(MDP_BASE + 0x409cc, 0xb2b2b2); + outpdw(MDP_BASE + 0x409d0, 0xb3b3b3); + outpdw(MDP_BASE + 0x409d4, 0xb4b4b4); + outpdw(MDP_BASE + 0x409d8, 0xb4b4b4); + outpdw(MDP_BASE + 0x409dc, 0xb5b5b5); + outpdw(MDP_BASE + 0x409e0, 0xb6b6b6); + outpdw(MDP_BASE + 0x409e4, 0xb6b6b6); + outpdw(MDP_BASE + 0x409e8, 0xb7b7b7); + outpdw(MDP_BASE + 0x409ec, 0xb8b8b8); + outpdw(MDP_BASE + 0x409f0, 0xb8b8b8); + outpdw(MDP_BASE + 0x409f4, 0xb9b9b9); + outpdw(MDP_BASE + 0x409f8, 0xbababa); + outpdw(MDP_BASE + 0x409fc, 0xbababa); + outpdw(MDP_BASE + 0x40a00, 0xbbbbbb); + outpdw(MDP_BASE + 0x40a04, 0xbcbcbc); + outpdw(MDP_BASE + 0x40a08, 0xbcbcbc); + outpdw(MDP_BASE + 0x40a0c, 0xbdbdbd); + outpdw(MDP_BASE + 0x40a10, 0xbebebe); + outpdw(MDP_BASE + 0x40a14, 0xbebebe); + outpdw(MDP_BASE + 0x40a18, 0xbfbfbf); + outpdw(MDP_BASE + 0x40a1c, 0xc0c0c0); + outpdw(MDP_BASE + 0x40a20, 0xc0c0c0); + outpdw(MDP_BASE + 0x40a24, 0xc1c1c1); + outpdw(MDP_BASE + 0x40a28, 0xc1c1c1); + outpdw(MDP_BASE + 0x40a2c, 0xc2c2c2); + outpdw(MDP_BASE + 0x40a30, 0xc3c3c3); + outpdw(MDP_BASE + 0x40a34, 0xc3c3c3); + outpdw(MDP_BASE + 0x40a38, 0xc4c4c4); + outpdw(MDP_BASE + 0x40a3c, 0xc5c5c5); + outpdw(MDP_BASE + 0x40a40, 0xc5c5c5); + outpdw(MDP_BASE + 0x40a44, 0xc6c6c6); + outpdw(MDP_BASE + 0x40a48, 0xc6c6c6); + outpdw(MDP_BASE + 0x40a4c, 0xc7c7c7); + outpdw(MDP_BASE + 0x40a50, 0xc8c8c8); + outpdw(MDP_BASE + 0x40a54, 0xc8c8c8); + outpdw(MDP_BASE + 0x40a58, 0xc9c9c9); + outpdw(MDP_BASE + 0x40a5c, 0xc9c9c9); + outpdw(MDP_BASE + 0x40a60, 0xcacaca); + outpdw(MDP_BASE + 0x40a64, 0xcbcbcb); + outpdw(MDP_BASE + 0x40a68, 0xcbcbcb); + outpdw(MDP_BASE + 0x40a6c, 0xcccccc); + outpdw(MDP_BASE + 0x40a70, 0xcccccc); + outpdw(MDP_BASE + 0x40a74, 0xcdcdcd); + outpdw(MDP_BASE + 0x40a78, 0xcecece); + outpdw(MDP_BASE + 0x40a7c, 0xcecece); + outpdw(MDP_BASE + 0x40a80, 0xcfcfcf); + outpdw(MDP_BASE + 0x40a84, 0xcfcfcf); + outpdw(MDP_BASE + 0x40a88, 0xd0d0d0); + outpdw(MDP_BASE + 0x40a8c, 0xd0d0d0); + outpdw(MDP_BASE + 0x40a90, 0xd1d1d1); + outpdw(MDP_BASE + 0x40a94, 0xd2d2d2); + outpdw(MDP_BASE + 0x40a98, 0xd2d2d2); + outpdw(MDP_BASE + 0x40a9c, 0xd3d3d3); + outpdw(MDP_BASE + 0x40aa0, 0xd3d3d3); + outpdw(MDP_BASE + 0x40aa4, 0xd4d4d4); + outpdw(MDP_BASE + 0x40aa8, 0xd4d4d4); + outpdw(MDP_BASE + 0x40aac, 0xd5d5d5); + outpdw(MDP_BASE + 0x40ab0, 0xd6d6d6); + outpdw(MDP_BASE + 0x40ab4, 0xd6d6d6); + outpdw(MDP_BASE + 0x40ab8, 0xd7d7d7); + outpdw(MDP_BASE + 0x40abc, 0xd7d7d7); + outpdw(MDP_BASE + 0x40ac0, 0xd8d8d8); + outpdw(MDP_BASE + 0x40ac4, 0xd8d8d8); + outpdw(MDP_BASE + 0x40ac8, 0xd9d9d9); + outpdw(MDP_BASE + 0x40acc, 0xd9d9d9); + outpdw(MDP_BASE + 0x40ad0, 0xdadada); + outpdw(MDP_BASE + 0x40ad4, 0xdbdbdb); + outpdw(MDP_BASE + 0x40ad8, 0xdbdbdb); + outpdw(MDP_BASE + 0x40adc, 0xdcdcdc); + outpdw(MDP_BASE + 0x40ae0, 0xdcdcdc); + outpdw(MDP_BASE + 0x40ae4, 0xdddddd); + outpdw(MDP_BASE + 0x40ae8, 0xdddddd); + outpdw(MDP_BASE + 0x40aec, 0xdedede); + outpdw(MDP_BASE + 0x40af0, 0xdedede); + outpdw(MDP_BASE + 0x40af4, 0xdfdfdf); + outpdw(MDP_BASE + 0x40af8, 0xdfdfdf); + outpdw(MDP_BASE + 0x40afc, 0xe0e0e0); + outpdw(MDP_BASE + 0x40b00, 0xe0e0e0); + outpdw(MDP_BASE + 0x40b04, 0xe1e1e1); + outpdw(MDP_BASE + 0x40b08, 0xe1e1e1); + outpdw(MDP_BASE + 0x40b0c, 0xe2e2e2); + outpdw(MDP_BASE + 0x40b10, 0xe3e3e3); + outpdw(MDP_BASE + 0x40b14, 0xe3e3e3); + outpdw(MDP_BASE + 0x40b18, 0xe4e4e4); + outpdw(MDP_BASE + 0x40b1c, 0xe4e4e4); + outpdw(MDP_BASE + 0x40b20, 0xe5e5e5); + outpdw(MDP_BASE + 0x40b24, 0xe5e5e5); + outpdw(MDP_BASE + 0x40b28, 0xe6e6e6); + outpdw(MDP_BASE + 0x40b2c, 0xe6e6e6); + outpdw(MDP_BASE + 0x40b30, 0xe7e7e7); + outpdw(MDP_BASE + 0x40b34, 0xe7e7e7); + outpdw(MDP_BASE + 0x40b38, 0xe8e8e8); + outpdw(MDP_BASE + 0x40b3c, 0xe8e8e8); + outpdw(MDP_BASE + 0x40b40, 0xe9e9e9); + outpdw(MDP_BASE + 0x40b44, 0xe9e9e9); + outpdw(MDP_BASE + 0x40b48, 0xeaeaea); + outpdw(MDP_BASE + 0x40b4c, 0xeaeaea); + outpdw(MDP_BASE + 0x40b50, 0xebebeb); + outpdw(MDP_BASE + 0x40b54, 0xebebeb); + outpdw(MDP_BASE + 0x40b58, 0xececec); + outpdw(MDP_BASE + 0x40b5c, 0xececec); + outpdw(MDP_BASE + 0x40b60, 0xededed); + outpdw(MDP_BASE + 0x40b64, 0xededed); + outpdw(MDP_BASE + 0x40b68, 0xeeeeee); + outpdw(MDP_BASE + 0x40b6c, 0xeeeeee); + outpdw(MDP_BASE + 0x40b70, 0xefefef); + outpdw(MDP_BASE + 0x40b74, 0xefefef); + outpdw(MDP_BASE + 0x40b78, 0xf0f0f0); + outpdw(MDP_BASE + 0x40b7c, 0xf0f0f0); + outpdw(MDP_BASE + 0x40b80, 0xf1f1f1); + outpdw(MDP_BASE + 0x40b84, 0xf1f1f1); + outpdw(MDP_BASE + 0x40b88, 0xf2f2f2); + outpdw(MDP_BASE + 0x40b8c, 0xf2f2f2); + outpdw(MDP_BASE + 0x40b90, 0xf2f2f2); + outpdw(MDP_BASE + 0x40b94, 0xf3f3f3); + outpdw(MDP_BASE + 0x40b98, 0xf3f3f3); + outpdw(MDP_BASE + 0x40b9c, 0xf4f4f4); + outpdw(MDP_BASE + 0x40ba0, 0xf4f4f4); + outpdw(MDP_BASE + 0x40ba4, 0xf5f5f5); + outpdw(MDP_BASE + 0x40ba8, 0xf5f5f5); + outpdw(MDP_BASE + 0x40bac, 0xf6f6f6); + outpdw(MDP_BASE + 0x40bb0, 0xf6f6f6); + outpdw(MDP_BASE + 0x40bb4, 0xf7f7f7); + outpdw(MDP_BASE + 0x40bb8, 0xf7f7f7); + outpdw(MDP_BASE + 0x40bbc, 0xf8f8f8); + outpdw(MDP_BASE + 0x40bc0, 0xf8f8f8); + outpdw(MDP_BASE + 0x40bc4, 0xf9f9f9); + outpdw(MDP_BASE + 0x40bc8, 0xf9f9f9); + outpdw(MDP_BASE + 0x40bcc, 0xfafafa); + outpdw(MDP_BASE + 0x40bd0, 0xfafafa); + outpdw(MDP_BASE + 0x40bd4, 0xfafafa); + outpdw(MDP_BASE + 0x40bd8, 0xfbfbfb); + outpdw(MDP_BASE + 0x40bdc, 0xfbfbfb); + outpdw(MDP_BASE + 0x40be0, 0xfcfcfc); + outpdw(MDP_BASE + 0x40be4, 0xfcfcfc); + outpdw(MDP_BASE + 0x40be8, 0xfdfdfd); + outpdw(MDP_BASE + 0x40bec, 0xfdfdfd); + outpdw(MDP_BASE + 0x40bf0, 0xfefefe); + outpdw(MDP_BASE + 0x40bf4, 0xfefefe); + outpdw(MDP_BASE + 0x40bf8, 0xffffff); + outpdw(MDP_BASE + 0x40bfc, 0xffffff); + outpdw(MDP_BASE + 0x40c00, 0x0); + outpdw(MDP_BASE + 0x40c04, 0x0); + outpdw(MDP_BASE + 0x40c08, 0x0); + outpdw(MDP_BASE + 0x40c0c, 0x0); + outpdw(MDP_BASE + 0x40c10, 0x0); + outpdw(MDP_BASE + 0x40c14, 0x0); + outpdw(MDP_BASE + 0x40c18, 0x0); + outpdw(MDP_BASE + 0x40c1c, 0x0); + outpdw(MDP_BASE + 0x40c20, 0x0); + outpdw(MDP_BASE + 0x40c24, 0x0); + outpdw(MDP_BASE + 0x40c28, 0x0); + outpdw(MDP_BASE + 0x40c2c, 0x0); + outpdw(MDP_BASE + 0x40c30, 0x0); + outpdw(MDP_BASE + 0x40c34, 0x0); + outpdw(MDP_BASE + 0x40c38, 0x0); + outpdw(MDP_BASE + 0x40c3c, 0x0); + outpdw(MDP_BASE + 0x40c40, 0x10101); + outpdw(MDP_BASE + 0x40c44, 0x10101); + outpdw(MDP_BASE + 0x40c48, 0x10101); + outpdw(MDP_BASE + 0x40c4c, 0x10101); + outpdw(MDP_BASE + 0x40c50, 0x10101); + outpdw(MDP_BASE + 0x40c54, 0x10101); + outpdw(MDP_BASE + 0x40c58, 0x10101); + outpdw(MDP_BASE + 0x40c5c, 0x10101); + outpdw(MDP_BASE + 0x40c60, 0x10101); + outpdw(MDP_BASE + 0x40c64, 0x10101); + outpdw(MDP_BASE + 0x40c68, 0x20202); + outpdw(MDP_BASE + 0x40c6c, 0x20202); + outpdw(MDP_BASE + 0x40c70, 0x20202); + outpdw(MDP_BASE + 0x40c74, 0x20202); + outpdw(MDP_BASE + 0x40c78, 0x20202); + outpdw(MDP_BASE + 0x40c7c, 0x20202); + outpdw(MDP_BASE + 0x40c80, 0x30303); + outpdw(MDP_BASE + 0x40c84, 0x30303); + outpdw(MDP_BASE + 0x40c88, 0x30303); + outpdw(MDP_BASE + 0x40c8c, 0x30303); + outpdw(MDP_BASE + 0x40c90, 0x30303); + outpdw(MDP_BASE + 0x40c94, 0x40404); + outpdw(MDP_BASE + 0x40c98, 0x40404); + outpdw(MDP_BASE + 0x40c9c, 0x40404); + outpdw(MDP_BASE + 0x40ca0, 0x40404); + outpdw(MDP_BASE + 0x40ca4, 0x40404); + outpdw(MDP_BASE + 0x40ca8, 0x50505); + outpdw(MDP_BASE + 0x40cac, 0x50505); + outpdw(MDP_BASE + 0x40cb0, 0x50505); + outpdw(MDP_BASE + 0x40cb4, 0x50505); + outpdw(MDP_BASE + 0x40cb8, 0x60606); + outpdw(MDP_BASE + 0x40cbc, 0x60606); + outpdw(MDP_BASE + 0x40cc0, 0x60606); + outpdw(MDP_BASE + 0x40cc4, 0x70707); + outpdw(MDP_BASE + 0x40cc8, 0x70707); + outpdw(MDP_BASE + 0x40ccc, 0x70707); + outpdw(MDP_BASE + 0x40cd0, 0x70707); + outpdw(MDP_BASE + 0x40cd4, 0x80808); + outpdw(MDP_BASE + 0x40cd8, 0x80808); + outpdw(MDP_BASE + 0x40cdc, 0x80808); + outpdw(MDP_BASE + 0x40ce0, 0x90909); + outpdw(MDP_BASE + 0x40ce4, 0x90909); + outpdw(MDP_BASE + 0x40ce8, 0xa0a0a); + outpdw(MDP_BASE + 0x40cec, 0xa0a0a); + outpdw(MDP_BASE + 0x40cf0, 0xa0a0a); + outpdw(MDP_BASE + 0x40cf4, 0xb0b0b); + outpdw(MDP_BASE + 0x40cf8, 0xb0b0b); + outpdw(MDP_BASE + 0x40cfc, 0xb0b0b); + outpdw(MDP_BASE + 0x40d00, 0xc0c0c); + outpdw(MDP_BASE + 0x40d04, 0xc0c0c); + outpdw(MDP_BASE + 0x40d08, 0xd0d0d); + outpdw(MDP_BASE + 0x40d0c, 0xd0d0d); + outpdw(MDP_BASE + 0x40d10, 0xe0e0e); + outpdw(MDP_BASE + 0x40d14, 0xe0e0e); + outpdw(MDP_BASE + 0x40d18, 0xe0e0e); + outpdw(MDP_BASE + 0x40d1c, 0xf0f0f); + outpdw(MDP_BASE + 0x40d20, 0xf0f0f); + outpdw(MDP_BASE + 0x40d24, 0x101010); + outpdw(MDP_BASE + 0x40d28, 0x101010); + outpdw(MDP_BASE + 0x40d2c, 0x111111); + outpdw(MDP_BASE + 0x40d30, 0x111111); + outpdw(MDP_BASE + 0x40d34, 0x121212); + outpdw(MDP_BASE + 0x40d38, 0x121212); + outpdw(MDP_BASE + 0x40d3c, 0x131313); + outpdw(MDP_BASE + 0x40d40, 0x131313); + outpdw(MDP_BASE + 0x40d44, 0x141414); + outpdw(MDP_BASE + 0x40d48, 0x151515); + outpdw(MDP_BASE + 0x40d4c, 0x151515); + outpdw(MDP_BASE + 0x40d50, 0x161616); + outpdw(MDP_BASE + 0x40d54, 0x161616); + outpdw(MDP_BASE + 0x40d58, 0x171717); + outpdw(MDP_BASE + 0x40d5c, 0x171717); + outpdw(MDP_BASE + 0x40d60, 0x181818); + outpdw(MDP_BASE + 0x40d64, 0x191919); + outpdw(MDP_BASE + 0x40d68, 0x191919); + outpdw(MDP_BASE + 0x40d6c, 0x1a1a1a); + outpdw(MDP_BASE + 0x40d70, 0x1b1b1b); + outpdw(MDP_BASE + 0x40d74, 0x1b1b1b); + outpdw(MDP_BASE + 0x40d78, 0x1c1c1c); + outpdw(MDP_BASE + 0x40d7c, 0x1c1c1c); + outpdw(MDP_BASE + 0x40d80, 0x1d1d1d); + outpdw(MDP_BASE + 0x40d84, 0x1e1e1e); + outpdw(MDP_BASE + 0x40d88, 0x1f1f1f); + outpdw(MDP_BASE + 0x40d8c, 0x1f1f1f); + outpdw(MDP_BASE + 0x40d90, 0x202020); + outpdw(MDP_BASE + 0x40d94, 0x212121); + outpdw(MDP_BASE + 0x40d98, 0x212121); + outpdw(MDP_BASE + 0x40d9c, 0x222222); + outpdw(MDP_BASE + 0x40da0, 0x232323); + outpdw(MDP_BASE + 0x40da4, 0x242424); + outpdw(MDP_BASE + 0x40da8, 0x242424); + outpdw(MDP_BASE + 0x40dac, 0x252525); + outpdw(MDP_BASE + 0x40db0, 0x262626); + outpdw(MDP_BASE + 0x40db4, 0x272727); + outpdw(MDP_BASE + 0x40db8, 0x272727); + outpdw(MDP_BASE + 0x40dbc, 0x282828); + outpdw(MDP_BASE + 0x40dc0, 0x292929); + outpdw(MDP_BASE + 0x40dc4, 0x2a2a2a); + outpdw(MDP_BASE + 0x40dc8, 0x2b2b2b); + outpdw(MDP_BASE + 0x40dcc, 0x2c2c2c); + outpdw(MDP_BASE + 0x40dd0, 0x2c2c2c); + outpdw(MDP_BASE + 0x40dd4, 0x2d2d2d); + outpdw(MDP_BASE + 0x40dd8, 0x2e2e2e); + outpdw(MDP_BASE + 0x40ddc, 0x2f2f2f); + outpdw(MDP_BASE + 0x40de0, 0x303030); + outpdw(MDP_BASE + 0x40de4, 0x313131); + outpdw(MDP_BASE + 0x40de8, 0x323232); + outpdw(MDP_BASE + 0x40dec, 0x333333); + outpdw(MDP_BASE + 0x40df0, 0x333333); + outpdw(MDP_BASE + 0x40df4, 0x343434); + outpdw(MDP_BASE + 0x40df8, 0x353535); + outpdw(MDP_BASE + 0x40dfc, 0x363636); + outpdw(MDP_BASE + 0x40e00, 0x373737); + outpdw(MDP_BASE + 0x40e04, 0x383838); + outpdw(MDP_BASE + 0x40e08, 0x393939); + outpdw(MDP_BASE + 0x40e0c, 0x3a3a3a); + outpdw(MDP_BASE + 0x40e10, 0x3b3b3b); + outpdw(MDP_BASE + 0x40e14, 0x3c3c3c); + outpdw(MDP_BASE + 0x40e18, 0x3d3d3d); + outpdw(MDP_BASE + 0x40e1c, 0x3e3e3e); + outpdw(MDP_BASE + 0x40e20, 0x3f3f3f); + outpdw(MDP_BASE + 0x40e24, 0x404040); + outpdw(MDP_BASE + 0x40e28, 0x414141); + outpdw(MDP_BASE + 0x40e2c, 0x424242); + outpdw(MDP_BASE + 0x40e30, 0x434343); + outpdw(MDP_BASE + 0x40e34, 0x444444); + outpdw(MDP_BASE + 0x40e38, 0x464646); + outpdw(MDP_BASE + 0x40e3c, 0x474747); + outpdw(MDP_BASE + 0x40e40, 0x484848); + outpdw(MDP_BASE + 0x40e44, 0x494949); + outpdw(MDP_BASE + 0x40e48, 0x4a4a4a); + outpdw(MDP_BASE + 0x40e4c, 0x4b4b4b); + outpdw(MDP_BASE + 0x40e50, 0x4c4c4c); + outpdw(MDP_BASE + 0x40e54, 0x4d4d4d); + outpdw(MDP_BASE + 0x40e58, 0x4f4f4f); + outpdw(MDP_BASE + 0x40e5c, 0x505050); + outpdw(MDP_BASE + 0x40e60, 0x515151); + outpdw(MDP_BASE + 0x40e64, 0x525252); + outpdw(MDP_BASE + 0x40e68, 0x535353); + outpdw(MDP_BASE + 0x40e6c, 0x545454); + outpdw(MDP_BASE + 0x40e70, 0x565656); + outpdw(MDP_BASE + 0x40e74, 0x575757); + outpdw(MDP_BASE + 0x40e78, 0x585858); + outpdw(MDP_BASE + 0x40e7c, 0x595959); + outpdw(MDP_BASE + 0x40e80, 0x5b5b5b); + outpdw(MDP_BASE + 0x40e84, 0x5c5c5c); + outpdw(MDP_BASE + 0x40e88, 0x5d5d5d); + outpdw(MDP_BASE + 0x40e8c, 0x5e5e5e); + outpdw(MDP_BASE + 0x40e90, 0x606060); + outpdw(MDP_BASE + 0x40e94, 0x616161); + outpdw(MDP_BASE + 0x40e98, 0x626262); + outpdw(MDP_BASE + 0x40e9c, 0x646464); + outpdw(MDP_BASE + 0x40ea0, 0x656565); + outpdw(MDP_BASE + 0x40ea4, 0x666666); + outpdw(MDP_BASE + 0x40ea8, 0x686868); + outpdw(MDP_BASE + 0x40eac, 0x696969); + outpdw(MDP_BASE + 0x40eb0, 0x6a6a6a); + outpdw(MDP_BASE + 0x40eb4, 0x6c6c6c); + outpdw(MDP_BASE + 0x40eb8, 0x6d6d6d); + outpdw(MDP_BASE + 0x40ebc, 0x6f6f6f); + outpdw(MDP_BASE + 0x40ec0, 0x707070); + outpdw(MDP_BASE + 0x40ec4, 0x717171); + outpdw(MDP_BASE + 0x40ec8, 0x737373); + outpdw(MDP_BASE + 0x40ecc, 0x747474); + outpdw(MDP_BASE + 0x40ed0, 0x767676); + outpdw(MDP_BASE + 0x40ed4, 0x777777); + outpdw(MDP_BASE + 0x40ed8, 0x797979); + outpdw(MDP_BASE + 0x40edc, 0x7a7a7a); + outpdw(MDP_BASE + 0x40ee0, 0x7c7c7c); + outpdw(MDP_BASE + 0x40ee4, 0x7d7d7d); + outpdw(MDP_BASE + 0x40ee8, 0x7f7f7f); + outpdw(MDP_BASE + 0x40eec, 0x808080); + outpdw(MDP_BASE + 0x40ef0, 0x828282); + outpdw(MDP_BASE + 0x40ef4, 0x838383); + outpdw(MDP_BASE + 0x40ef8, 0x858585); + outpdw(MDP_BASE + 0x40efc, 0x868686); + outpdw(MDP_BASE + 0x40f00, 0x888888); + outpdw(MDP_BASE + 0x40f04, 0x898989); + outpdw(MDP_BASE + 0x40f08, 0x8b8b8b); + outpdw(MDP_BASE + 0x40f0c, 0x8d8d8d); + outpdw(MDP_BASE + 0x40f10, 0x8e8e8e); + outpdw(MDP_BASE + 0x40f14, 0x909090); + outpdw(MDP_BASE + 0x40f18, 0x919191); + outpdw(MDP_BASE + 0x40f1c, 0x939393); + outpdw(MDP_BASE + 0x40f20, 0x959595); + outpdw(MDP_BASE + 0x40f24, 0x969696); + outpdw(MDP_BASE + 0x40f28, 0x989898); + outpdw(MDP_BASE + 0x40f2c, 0x9a9a9a); + outpdw(MDP_BASE + 0x40f30, 0x9b9b9b); + outpdw(MDP_BASE + 0x40f34, 0x9d9d9d); + outpdw(MDP_BASE + 0x40f38, 0x9f9f9f); + outpdw(MDP_BASE + 0x40f3c, 0xa1a1a1); + outpdw(MDP_BASE + 0x40f40, 0xa2a2a2); + outpdw(MDP_BASE + 0x40f44, 0xa4a4a4); + outpdw(MDP_BASE + 0x40f48, 0xa6a6a6); + outpdw(MDP_BASE + 0x40f4c, 0xa7a7a7); + outpdw(MDP_BASE + 0x40f50, 0xa9a9a9); + outpdw(MDP_BASE + 0x40f54, 0xababab); + outpdw(MDP_BASE + 0x40f58, 0xadadad); + outpdw(MDP_BASE + 0x40f5c, 0xafafaf); + outpdw(MDP_BASE + 0x40f60, 0xb0b0b0); + outpdw(MDP_BASE + 0x40f64, 0xb2b2b2); + outpdw(MDP_BASE + 0x40f68, 0xb4b4b4); + outpdw(MDP_BASE + 0x40f6c, 0xb6b6b6); + outpdw(MDP_BASE + 0x40f70, 0xb8b8b8); + outpdw(MDP_BASE + 0x40f74, 0xbababa); + outpdw(MDP_BASE + 0x40f78, 0xbbbbbb); + outpdw(MDP_BASE + 0x40f7c, 0xbdbdbd); + outpdw(MDP_BASE + 0x40f80, 0xbfbfbf); + outpdw(MDP_BASE + 0x40f84, 0xc1c1c1); + outpdw(MDP_BASE + 0x40f88, 0xc3c3c3); + outpdw(MDP_BASE + 0x40f8c, 0xc5c5c5); + outpdw(MDP_BASE + 0x40f90, 0xc7c7c7); + outpdw(MDP_BASE + 0x40f94, 0xc9c9c9); + outpdw(MDP_BASE + 0x40f98, 0xcbcbcb); + outpdw(MDP_BASE + 0x40f9c, 0xcdcdcd); + outpdw(MDP_BASE + 0x40fa0, 0xcfcfcf); + outpdw(MDP_BASE + 0x40fa4, 0xd1d1d1); + outpdw(MDP_BASE + 0x40fa8, 0xd3d3d3); + outpdw(MDP_BASE + 0x40fac, 0xd5d5d5); + outpdw(MDP_BASE + 0x40fb0, 0xd7d7d7); + outpdw(MDP_BASE + 0x40fb4, 0xd9d9d9); + outpdw(MDP_BASE + 0x40fb8, 0xdbdbdb); + outpdw(MDP_BASE + 0x40fbc, 0xdddddd); + outpdw(MDP_BASE + 0x40fc0, 0xdfdfdf); + outpdw(MDP_BASE + 0x40fc4, 0xe1e1e1); + outpdw(MDP_BASE + 0x40fc8, 0xe3e3e3); + outpdw(MDP_BASE + 0x40fcc, 0xe5e5e5); + outpdw(MDP_BASE + 0x40fd0, 0xe7e7e7); + outpdw(MDP_BASE + 0x40fd4, 0xe9e9e9); + outpdw(MDP_BASE + 0x40fd8, 0xebebeb); + outpdw(MDP_BASE + 0x40fdc, 0xeeeeee); + outpdw(MDP_BASE + 0x40fe0, 0xf0f0f0); + outpdw(MDP_BASE + 0x40fe4, 0xf2f2f2); + outpdw(MDP_BASE + 0x40fe8, 0xf4f4f4); + outpdw(MDP_BASE + 0x40fec, 0xf6f6f6); + outpdw(MDP_BASE + 0x40ff0, 0xf8f8f8); + outpdw(MDP_BASE + 0x40ff4, 0xfbfbfb); + outpdw(MDP_BASE + 0x40ff8, 0xfdfdfd); + outpdw(MDP_BASE + 0x40ffc, 0xffffff); +} + +#define IRQ_EN_1__MDP_IRQ___M 0x00000800 + +void mdp_hw_init(void) +{ + int i; + + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* debug interface write access */ + outpdw(MDP_BASE + 0x60, 1); + + outp32(MDP_INTR_ENABLE, MDP_ANY_INTR_MASK); + outp32(MDP_EBI2_PORTMAP_MODE, 0x3); + outpdw(MDP_CMD_DEBUG_ACCESS_BASE + 0x01f8, 0x0); + outpdw(MDP_CMD_DEBUG_ACCESS_BASE + 0x01fc, 0x0); + outpdw(MDP_BASE + 0x60, 0x1); + mdp_load_lut_param(); + + /* + * clear up unused fg/main registers + */ + /* comp.plane 2&3 ystride */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0120, 0x0); + /* unpacked pattern */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x012c, 0x0); + /* unpacked pattern */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0130, 0x0); + /* unpacked pattern */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0134, 0x0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0158, 0x0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x15c, 0x0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0160, 0x0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0170, 0x0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0174, 0x0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x017c, 0x0); + + /* comp.plane 2 */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0114, 0x0); + /* comp.plane 3 */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0118, 0x0); + + /* clear up unused bg registers */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01c8, 0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01d0, 0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01dc, 0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01e0, 0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01e4, 0); + +#ifndef CONFIG_FB_MSM_MDP22 + MDP_OUTP(MDP_BASE + 0xE0000, 0); + MDP_OUTP(MDP_BASE + 0x100, 0xffffffff); + MDP_OUTP(MDP_BASE + 0x90070, 0); +#endif + + /* + * limit vector + * pre gets applied before color matrix conversion + * post is after ccs + */ + writel(mdp_plv[0], MDP_CSC_PRE_LV1n(0)); + writel(mdp_plv[1], MDP_CSC_PRE_LV1n(1)); + writel(mdp_plv[2], MDP_CSC_PRE_LV1n(2)); + writel(mdp_plv[3], MDP_CSC_PRE_LV1n(3)); + +#ifdef CONFIG_FB_MSM_MDP31 + writel(mdp_plv[2], MDP_CSC_PRE_LV1n(4)); + writel(mdp_plv[3], MDP_CSC_PRE_LV1n(5)); + + writel(0, MDP_CSC_POST_LV1n(0)); + writel(0xff, MDP_CSC_POST_LV1n(1)); + writel(0, MDP_CSC_POST_LV1n(2)); + writel(0xff, MDP_CSC_POST_LV1n(3)); + writel(0, MDP_CSC_POST_LV1n(4)); + writel(0xff, MDP_CSC_POST_LV1n(5)); + + writel(0, MDP_CSC_PRE_LV2n(0)); + writel(0xff, MDP_CSC_PRE_LV2n(1)); + writel(0, MDP_CSC_PRE_LV2n(2)); + writel(0xff, MDP_CSC_PRE_LV2n(3)); + writel(0, MDP_CSC_PRE_LV2n(4)); + writel(0xff, MDP_CSC_PRE_LV2n(5)); + + writel(mdp_plv[0], MDP_CSC_POST_LV2n(0)); + writel(mdp_plv[1], MDP_CSC_POST_LV2n(1)); + writel(mdp_plv[2], MDP_CSC_POST_LV2n(2)); + writel(mdp_plv[3], MDP_CSC_POST_LV2n(3)); + writel(mdp_plv[2], MDP_CSC_POST_LV2n(4)); + writel(mdp_plv[3], MDP_CSC_POST_LV2n(5)); +#endif + + /* primary forward matrix */ + for (i = 0; i < MDP_CCS_SIZE; i++) + writel(mdp_ccs_rgb2yuv.ccs[i], MDP_CSC_PFMVn(i)); + +#ifdef CONFIG_FB_MSM_MDP31 + for (i = 0; i < MDP_BV_SIZE; i++) + writel(mdp_ccs_rgb2yuv.bv[i], MDP_CSC_POST_BV2n(i)); + + writel(0, MDP_CSC_PRE_BV2n(0)); + writel(0, MDP_CSC_PRE_BV2n(1)); + writel(0, MDP_CSC_PRE_BV2n(2)); +#endif + /* primary reverse matrix */ + for (i = 0; i < MDP_CCS_SIZE; i++) + writel(mdp_ccs_yuv2rgb.ccs[i], MDP_CSC_PRMVn(i)); + + for (i = 0; i < MDP_BV_SIZE; i++) + writel(mdp_ccs_yuv2rgb.bv[i], MDP_CSC_PRE_BV1n(i)); + +#ifdef CONFIG_FB_MSM_MDP31 + writel(0, MDP_CSC_POST_BV1n(0)); + writel(0, MDP_CSC_POST_BV1n(1)); + writel(0, MDP_CSC_POST_BV1n(2)); + + outpdw(MDP_BASE + 0x30010, 0x03e0); + outpdw(MDP_BASE + 0x30014, 0x0360); + outpdw(MDP_BASE + 0x30018, 0x0120); + outpdw(MDP_BASE + 0x3001c, 0x0140); +#endif + mdp_init_scale_table(); + +#ifndef CONFIG_FB_MSM_MDP31 + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0104, + ((16 << 6) << 16) | (16) << 6); +#endif + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} diff --git a/drivers/video/msm/mdp_lcdc.c b/drivers/video/msm/mdp_lcdc.c new file mode 100644 index 000000000000..22bab96a4297 --- /dev/null +++ b/drivers/video/msm/mdp_lcdc.c @@ -0,0 +1,432 @@ +/* drivers/video/msm/mdp_lcdc.c + * + * Copyright (c) 2009 Google Inc. + * Copyright (c) 2009 The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Author: Dima Zavin + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "mdp_hw.h" + +struct mdp_lcdc_info { + struct mdp_info *mdp; + struct clk *mdp_clk; + struct clk *pclk; + struct clk *pad_pclk; + struct msm_panel_data fb_panel_data; + struct platform_device fb_pdev; + struct msm_lcdc_platform_data *pdata; + uint32_t fb_start; + + struct msmfb_callback frame_start_cb; + wait_queue_head_t vsync_waitq; + int got_vsync; + + struct { + uint32_t clk_rate; + uint32_t hsync_ctl; + uint32_t vsync_period; + uint32_t vsync_pulse_width; + uint32_t display_hctl; + uint32_t display_vstart; + uint32_t display_vend; + uint32_t hsync_skew; + uint32_t polarity; + } parms; +}; + +static struct mdp_device *mdp_dev; + +#define panel_to_lcdc(p) container_of((p), struct mdp_lcdc_info, fb_panel_data) + +static int lcdc_unblank(struct msm_panel_data *fb_panel) +{ + struct mdp_lcdc_info *lcdc = panel_to_lcdc(fb_panel); + struct msm_lcdc_panel_ops *panel_ops = lcdc->pdata->panel_ops; + + pr_info("%s: ()\n", __func__); + panel_ops->unblank(panel_ops); + + return 0; +} + +static int lcdc_blank(struct msm_panel_data *fb_panel) +{ + struct mdp_lcdc_info *lcdc = panel_to_lcdc(fb_panel); + struct msm_lcdc_panel_ops *panel_ops = lcdc->pdata->panel_ops; + + pr_info("%s: ()\n", __func__); + panel_ops->blank(panel_ops); + + return 0; +} + +static int lcdc_suspend(struct msm_panel_data *fb_panel) +{ + struct mdp_lcdc_info *lcdc = panel_to_lcdc(fb_panel); + + pr_info("%s: suspending\n", __func__); + + mdp_writel(lcdc->mdp, 0, MDP_LCDC_EN); + clk_disable_unprepare(lcdc->pad_pclk); + clk_disable_unprepare(lcdc->pclk); + clk_disable_unprepare(lcdc->mdp_clk); + + return 0; +} + +static int lcdc_resume(struct msm_panel_data *fb_panel) +{ + struct mdp_lcdc_info *lcdc = panel_to_lcdc(fb_panel); + + pr_info("%s: resuming\n", __func__); + + clk_prepare_enable(lcdc->mdp_clk); + clk_prepare_enable(lcdc->pclk); + clk_prepare_enable(lcdc->pad_pclk); + mdp_writel(lcdc->mdp, 1, MDP_LCDC_EN); + + return 0; +} + +static int lcdc_hw_init(struct mdp_lcdc_info *lcdc) +{ + struct msm_panel_data *fb_panel = &lcdc->fb_panel_data; + uint32_t dma_cfg; + + clk_prepare_enable(lcdc->mdp_clk); + clk_prepare_enable(lcdc->pclk); + clk_prepare_enable(lcdc->pad_pclk); + + clk_set_rate(lcdc->pclk, lcdc->parms.clk_rate); + clk_set_rate(lcdc->pad_pclk, lcdc->parms.clk_rate); + + /* write the lcdc params */ + mdp_writel(lcdc->mdp, lcdc->parms.hsync_ctl, MDP_LCDC_HSYNC_CTL); + mdp_writel(lcdc->mdp, lcdc->parms.vsync_period, MDP_LCDC_VSYNC_PERIOD); + mdp_writel(lcdc->mdp, lcdc->parms.vsync_pulse_width, + MDP_LCDC_VSYNC_PULSE_WIDTH); + mdp_writel(lcdc->mdp, lcdc->parms.display_hctl, MDP_LCDC_DISPLAY_HCTL); + mdp_writel(lcdc->mdp, lcdc->parms.display_vstart, + MDP_LCDC_DISPLAY_V_START); + mdp_writel(lcdc->mdp, lcdc->parms.display_vend, MDP_LCDC_DISPLAY_V_END); + mdp_writel(lcdc->mdp, lcdc->parms.hsync_skew, MDP_LCDC_HSYNC_SKEW); + + mdp_writel(lcdc->mdp, 0, MDP_LCDC_BORDER_CLR); + mdp_writel(lcdc->mdp, 0xff, MDP_LCDC_UNDERFLOW_CTL); + mdp_writel(lcdc->mdp, 0, MDP_LCDC_ACTIVE_HCTL); + mdp_writel(lcdc->mdp, 0, MDP_LCDC_ACTIVE_V_START); + mdp_writel(lcdc->mdp, 0, MDP_LCDC_ACTIVE_V_END); + mdp_writel(lcdc->mdp, lcdc->parms.polarity, MDP_LCDC_CTL_POLARITY); + + /* config the dma_p block that drives the lcdc data */ + mdp_writel(lcdc->mdp, lcdc->fb_start, MDP_DMA_P_IBUF_ADDR); + mdp_writel(lcdc->mdp, (((fb_panel->fb_data->yres & 0x7ff) << 16) | + (fb_panel->fb_data->xres & 0x7ff)), + MDP_DMA_P_SIZE); + + mdp_writel(lcdc->mdp, 0, MDP_DMA_P_OUT_XY); + + dma_cfg = mdp_readl(lcdc->mdp, MDP_DMA_P_CONFIG); + dma_cfg |= (DMA_PACK_ALIGN_LSB | + DMA_PACK_PATTERN_RGB | + DMA_DITHER_EN); + dma_cfg |= DMA_OUT_SEL_LCDC; + dma_cfg &= ~DMA_DST_BITS_MASK; + + if (fb_panel->fb_data->output_format == MSM_MDP_OUT_IF_FMT_RGB666) + dma_cfg |= DMA_DSTC0G_6BITS | DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; + else + dma_cfg |= DMA_DSTC0G_6BITS | DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; + + mdp_writel(lcdc->mdp, dma_cfg, MDP_DMA_P_CONFIG); + + /* enable the lcdc timing generation */ + mdp_writel(lcdc->mdp, 1, MDP_LCDC_EN); + + return 0; +} + +static void lcdc_wait_vsync(struct msm_panel_data *panel) +{ + struct mdp_lcdc_info *lcdc = panel_to_lcdc(panel); + int ret; + + ret = wait_event_timeout(lcdc->vsync_waitq, lcdc->got_vsync, HZ / 2); + if (!ret && !lcdc->got_vsync) + pr_err("%s: timeout waiting for VSYNC\n", __func__); + lcdc->got_vsync = 0; +} + +static void lcdc_request_vsync(struct msm_panel_data *fb_panel, + struct msmfb_callback *vsync_cb) +{ + struct mdp_lcdc_info *lcdc = panel_to_lcdc(fb_panel); + + /* the vsync callback will start the dma */ + vsync_cb->func(vsync_cb); + lcdc->got_vsync = 0; + mdp_out_if_req_irq(mdp_dev, MSM_LCDC_INTERFACE, MDP_LCDC_FRAME_START, + &lcdc->frame_start_cb); + lcdc_wait_vsync(fb_panel); +} + +static void lcdc_clear_vsync(struct msm_panel_data *fb_panel) +{ + struct mdp_lcdc_info *lcdc = panel_to_lcdc(fb_panel); + lcdc->got_vsync = 0; + mdp_out_if_req_irq(mdp_dev, MSM_LCDC_INTERFACE, 0, NULL); +} + +/* called in irq context with mdp lock held, when mdp gets the + * MDP_LCDC_FRAME_START interrupt */ +static void lcdc_frame_start(struct msmfb_callback *cb) +{ + struct mdp_lcdc_info *lcdc; + + lcdc = container_of(cb, struct mdp_lcdc_info, frame_start_cb); + + lcdc->got_vsync = 1; + wake_up(&lcdc->vsync_waitq); +} + +static void lcdc_dma_start(void *priv, uint32_t addr, uint32_t stride, + uint32_t width, uint32_t height, uint32_t x, + uint32_t y) +{ + struct mdp_lcdc_info *lcdc = priv; + + struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); + if (mdp->dma_config_dirty) + { + mdp_writel(lcdc->mdp, 0, MDP_LCDC_EN); + mdelay(20); + mdp_dev->configure_dma(mdp_dev); + mdp_writel(lcdc->mdp, 1, MDP_LCDC_EN); + } + mdp_writel(lcdc->mdp, stride, MDP_DMA_P_IBUF_Y_STRIDE); + mdp_writel(lcdc->mdp, addr, MDP_DMA_P_IBUF_ADDR); +} + +static void precompute_timing_parms(struct mdp_lcdc_info *lcdc) +{ + struct msm_lcdc_timing *timing = lcdc->pdata->timing; + struct msm_fb_data *fb_data = lcdc->pdata->fb_data; + unsigned int hsync_period; + unsigned int hsync_start_x; + unsigned int hsync_end_x; + unsigned int vsync_period; + unsigned int display_vstart; + unsigned int display_vend; + + hsync_period = (timing->hsync_back_porch + + fb_data->xres + timing->hsync_front_porch); + hsync_start_x = timing->hsync_back_porch; + hsync_end_x = hsync_start_x + fb_data->xres - 1; + + vsync_period = (timing->vsync_back_porch + + fb_data->yres + timing->vsync_front_porch); + vsync_period *= hsync_period; + + display_vstart = timing->vsync_back_porch; + display_vstart *= hsync_period; + display_vstart += timing->hsync_skew; + + display_vend = (timing->vsync_back_porch + fb_data->yres) * + hsync_period; + display_vend += timing->hsync_skew - 1; + + /* register values we pre-compute at init time from the timing + * information in the panel info */ + lcdc->parms.hsync_ctl = (((hsync_period & 0xfff) << 16) | + (timing->hsync_pulse_width & 0xfff)); + lcdc->parms.vsync_period = vsync_period & 0xffffff; + lcdc->parms.vsync_pulse_width = (timing->vsync_pulse_width * + hsync_period) & 0xffffff; + + lcdc->parms.display_hctl = (((hsync_end_x & 0xfff) << 16) | + (hsync_start_x & 0xfff)); + lcdc->parms.display_vstart = display_vstart & 0xffffff; + lcdc->parms.display_vend = display_vend & 0xffffff; + lcdc->parms.hsync_skew = timing->hsync_skew & 0xfff; + lcdc->parms.polarity = ((timing->hsync_act_low << 0) | + (timing->vsync_act_low << 1) | + (timing->den_act_low << 2)); + lcdc->parms.clk_rate = timing->clk_rate; +} + +static int mdp_lcdc_probe(struct platform_device *pdev) +{ + struct msm_lcdc_platform_data *pdata = pdev->dev.platform_data; + struct mdp_lcdc_info *lcdc; + int ret = 0; + + if (!pdata) { + pr_err("%s: no LCDC platform data found\n", __func__); + return -EINVAL; + } + + lcdc = kzalloc(sizeof(struct mdp_lcdc_info), GFP_KERNEL); + if (!lcdc) + return -ENOMEM; + + /* We don't actually own the clocks, the mdp does. */ + lcdc->mdp_clk = clk_get(mdp_dev->dev.parent, "mdp_clk"); + if (IS_ERR(lcdc->mdp_clk)) { + pr_err("%s: failed to get mdp_clk\n", __func__); + ret = PTR_ERR(lcdc->mdp_clk); + goto err_get_mdp_clk; + } + + lcdc->pclk = clk_get(mdp_dev->dev.parent, "lcdc_pclk_clk"); + if (IS_ERR(lcdc->pclk)) { + pr_err("%s: failed to get lcdc_pclk\n", __func__); + ret = PTR_ERR(lcdc->pclk); + goto err_get_pclk; + } + + lcdc->pad_pclk = clk_get(mdp_dev->dev.parent, "lcdc_pad_pclk_clk"); + if (IS_ERR(lcdc->pad_pclk)) { + pr_err("%s: failed to get lcdc_pad_pclk\n", __func__); + ret = PTR_ERR(lcdc->pad_pclk); + goto err_get_pad_pclk; + } + + init_waitqueue_head(&lcdc->vsync_waitq); + lcdc->pdata = pdata; + lcdc->frame_start_cb.func = lcdc_frame_start; + + platform_set_drvdata(pdev, lcdc); + + mdp_out_if_register(mdp_dev, MSM_LCDC_INTERFACE, lcdc, MDP_DMA_P_DONE, + lcdc_dma_start); + + precompute_timing_parms(lcdc); + + lcdc->fb_start = pdata->fb_resource->start; + lcdc->mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); + + lcdc->fb_panel_data.suspend = lcdc_suspend; + lcdc->fb_panel_data.resume = lcdc_resume; + lcdc->fb_panel_data.wait_vsync = lcdc_wait_vsync; + lcdc->fb_panel_data.request_vsync = lcdc_request_vsync; + lcdc->fb_panel_data.clear_vsync = lcdc_clear_vsync; + lcdc->fb_panel_data.blank = lcdc_blank; + lcdc->fb_panel_data.unblank = lcdc_unblank; + lcdc->fb_panel_data.fb_data = pdata->fb_data; + lcdc->fb_panel_data.interface_type = MSM_LCDC_INTERFACE; + + ret = lcdc_hw_init(lcdc); + if (ret) { + pr_err("%s: Cannot initialize the mdp_lcdc\n", __func__); + goto err_hw_init; + } + + lcdc->fb_pdev.name = "msm_panel"; + lcdc->fb_pdev.id = pdata->fb_id; + lcdc->fb_pdev.resource = pdata->fb_resource; + lcdc->fb_pdev.num_resources = 1; + lcdc->fb_pdev.dev.platform_data = &lcdc->fb_panel_data; + + if (pdata->panel_ops->init) + pdata->panel_ops->init(pdata->panel_ops); + + ret = platform_device_register(&lcdc->fb_pdev); + if (ret) { + pr_err("%s: Cannot register msm_panel pdev\n", __func__); + goto err_plat_dev_reg; + } + + pr_info("%s: initialized\n", __func__); + + return 0; + +err_plat_dev_reg: +err_hw_init: + platform_set_drvdata(pdev, NULL); + clk_put(lcdc->pad_pclk); +err_get_pad_pclk: + clk_put(lcdc->pclk); +err_get_pclk: + clk_put(lcdc->mdp_clk); +err_get_mdp_clk: + kfree(lcdc); + return ret; +} + +static int mdp_lcdc_remove(struct platform_device *pdev) +{ + struct mdp_lcdc_info *lcdc = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + clk_put(lcdc->pclk); + clk_put(lcdc->pad_pclk); + kfree(lcdc); + + return 0; +} + +static struct platform_driver mdp_lcdc_driver = { + .probe = mdp_lcdc_probe, + .remove = mdp_lcdc_remove, + .driver = { + .name = "msm_mdp_lcdc", + .owner = THIS_MODULE, + }, +}; + +static int mdp_lcdc_add_mdp_device(struct device *dev, + struct class_interface *class_intf) +{ + /* might need locking if mulitple mdp devices */ + if (mdp_dev) + return 0; + mdp_dev = container_of(dev, struct mdp_device, dev); + return platform_driver_register(&mdp_lcdc_driver); +} + +static void mdp_lcdc_remove_mdp_device(struct device *dev, + struct class_interface *class_intf) +{ + /* might need locking if mulitple mdp devices */ + if (dev != &mdp_dev->dev) + return; + platform_driver_unregister(&mdp_lcdc_driver); + mdp_dev = NULL; +} + +static struct class_interface mdp_lcdc_interface = { + .add_dev = &mdp_lcdc_add_mdp_device, + .remove_dev = &mdp_lcdc_remove_mdp_device, +}; + +static int __init mdp_lcdc_init(void) +{ + return register_mdp_client(&mdp_lcdc_interface); +} + +module_init(mdp_lcdc_init); diff --git a/drivers/video/msm/mdp_ppp.c b/drivers/video/msm/mdp_ppp.c new file mode 100644 index 000000000000..91fa68f675fe --- /dev/null +++ b/drivers/video/msm/mdp_ppp.c @@ -0,0 +1,1686 @@ +/* drivers/video/msm/src/drv/mdp/mdp_ppp.c + * + * Copyright (C) 2007 Google Incorporated + * Copyright (c) 2008-2009, 2012 The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "linux/proc_fs.h" + +#include +#include + +#include +#include +#include +#include + +#include "mdp.h" +#include "msm_fb.h" + +#define MDP_IS_IMGTYPE_BAD(x) (((x) >= MDP_IMGTYPE_LIMIT) && \ + (((x) < MDP_IMGTYPE2_START) || \ + ((x) >= MDP_IMGTYPE_LIMIT2))) + +static uint32_t bytes_per_pixel[] = { + [MDP_RGB_565] = 2, + [MDP_RGB_888] = 3, + [MDP_XRGB_8888] = 4, + [MDP_ARGB_8888] = 4, + [MDP_RGBA_8888] = 4, + [MDP_BGRA_8888] = 4, + [MDP_RGBX_8888] = 4, + [MDP_Y_CBCR_H2V1] = 1, + [MDP_Y_CBCR_H2V2] = 1, + [MDP_Y_CBCR_H2V2_ADRENO] = 1, + [MDP_Y_CRCB_H2V1] = 1, + [MDP_Y_CRCB_H2V2] = 1, + [MDP_YCRYCB_H2V1] = 2, + [MDP_BGR_565] = 2 +}; + +extern uint32 mdp_plv[]; +extern struct semaphore mdp_ppp_mutex; + +int mdp_get_bytes_per_pixel(uint32_t format, + struct msm_fb_data_type *mfd) +{ + int bpp = -EINVAL; + if (format == MDP_FB_FORMAT) + format = mfd->fb_imgType; + if (format < ARRAY_SIZE(bytes_per_pixel)) + bpp = bytes_per_pixel[format]; + + if (bpp <= 0) + printk(KERN_ERR "%s incorrect format %d\n", __func__, format); + return bpp; +} + +static uint32 mdp_conv_matx_rgb2yuv(uint32 input_pixel, + uint16 *matrix_and_bias_vector, + uint32 *clamp_vector, + uint32 *look_up_table) +{ + uint8 input_C2, input_C0, input_C1; + uint32 output; + int32 comp_C2, comp_C1, comp_C0, temp; + int32 temp1, temp2, temp3; + int32 matrix[9]; + int32 bias_vector[3]; + int32 Y_low_limit, Y_high_limit, C_low_limit, C_high_limit; + int32 i; + uint32 _is_lookup_table_enabled; + + input_C2 = (input_pixel >> 16) & 0xFF; + input_C1 = (input_pixel >> 8) & 0xFF; + input_C0 = (input_pixel >> 0) & 0xFF; + + comp_C0 = input_C0; + comp_C1 = input_C1; + comp_C2 = input_C2; + + for (i = 0; i < 9; i++) + matrix[i] = + ((int32) (((int32) matrix_and_bias_vector[i]) << 20)) >> 20; + + bias_vector[0] = (int32) (matrix_and_bias_vector[9] & 0xFF); + bias_vector[1] = (int32) (matrix_and_bias_vector[10] & 0xFF); + bias_vector[2] = (int32) (matrix_and_bias_vector[11] & 0xFF); + + Y_low_limit = (int32) clamp_vector[0]; + Y_high_limit = (int32) clamp_vector[1]; + C_low_limit = (int32) clamp_vector[2]; + C_high_limit = (int32) clamp_vector[3]; + + if (look_up_table == 0) /* check for NULL point */ + _is_lookup_table_enabled = 0; + else + _is_lookup_table_enabled = 1; + + if (_is_lookup_table_enabled == 1) { + comp_C2 = (look_up_table[comp_C2] >> 16) & 0xFF; + comp_C1 = (look_up_table[comp_C1] >> 8) & 0xFF; + comp_C0 = (look_up_table[comp_C0] >> 0) & 0xFF; + } + /* + * Color Conversion + * reorder input colors + */ + temp = comp_C2; + comp_C2 = comp_C1; + comp_C1 = comp_C0; + comp_C0 = temp; + + /* matrix multiplication */ + temp1 = comp_C0 * matrix[0] + comp_C1 * matrix[1] + comp_C2 * matrix[2]; + temp2 = comp_C0 * matrix[3] + comp_C1 * matrix[4] + comp_C2 * matrix[5]; + temp3 = comp_C0 * matrix[6] + comp_C1 * matrix[7] + comp_C2 * matrix[8]; + + comp_C0 = temp1 + 0x100; + comp_C1 = temp2 + 0x100; + comp_C2 = temp3 + 0x100; + + /* take interger part */ + comp_C0 >>= 9; + comp_C1 >>= 9; + comp_C2 >>= 9; + + /* post bias (+) */ + comp_C0 += bias_vector[0]; + comp_C1 += bias_vector[1]; + comp_C2 += bias_vector[2]; + + /* limit pixel to 8-bit */ + if (comp_C0 < 0) + comp_C0 = 0; + + if (comp_C0 > 255) + comp_C0 = 255; + + if (comp_C1 < 0) + comp_C1 = 0; + + if (comp_C1 > 255) + comp_C1 = 255; + + if (comp_C2 < 0) + comp_C2 = 0; + + if (comp_C2 > 255) + comp_C2 = 255; + + /* clamp */ + if (comp_C0 < Y_low_limit) + comp_C0 = Y_low_limit; + + if (comp_C0 > Y_high_limit) + comp_C0 = Y_high_limit; + + if (comp_C1 < C_low_limit) + comp_C1 = C_low_limit; + + if (comp_C1 > C_high_limit) + comp_C1 = C_high_limit; + + if (comp_C2 < C_low_limit) + comp_C2 = C_low_limit; + + if (comp_C2 > C_high_limit) + comp_C2 = C_high_limit; + + output = (comp_C2 << 16) | (comp_C1 << 8) | comp_C0; + return output; +} + +uint32 mdp_conv_matx_yuv2rgb(uint32 input_pixel, + uint16 *matrix_and_bias_vector, + uint32 *clamp_vector, uint32 *look_up_table) +{ + uint8 input_C2, input_C0, input_C1; + uint32 output; + int32 comp_C2, comp_C1, comp_C0, temp; + int32 temp1, temp2, temp3; + int32 matrix[9]; + int32 bias_vector[3]; + int32 Y_low_limit, Y_high_limit, C_low_limit, C_high_limit; + int32 i; + uint32 _is_lookup_table_enabled; + + input_C2 = (input_pixel >> 16) & 0xFF; + input_C1 = (input_pixel >> 8) & 0xFF; + input_C0 = (input_pixel >> 0) & 0xFF; + + comp_C0 = input_C0; + comp_C1 = input_C1; + comp_C2 = input_C2; + + for (i = 0; i < 9; i++) + matrix[i] = + ((int32) (((int32) matrix_and_bias_vector[i]) << 20)) >> 20; + + bias_vector[0] = (int32) (matrix_and_bias_vector[9] & 0xFF); + bias_vector[1] = (int32) (matrix_and_bias_vector[10] & 0xFF); + bias_vector[2] = (int32) (matrix_and_bias_vector[11] & 0xFF); + + Y_low_limit = (int32) clamp_vector[0]; + Y_high_limit = (int32) clamp_vector[1]; + C_low_limit = (int32) clamp_vector[2]; + C_high_limit = (int32) clamp_vector[3]; + + if (look_up_table == 0) /* check for NULL point */ + _is_lookup_table_enabled = 0; + else + _is_lookup_table_enabled = 1; + + /* clamp */ + if (comp_C0 < Y_low_limit) + comp_C0 = Y_low_limit; + + if (comp_C0 > Y_high_limit) + comp_C0 = Y_high_limit; + + if (comp_C1 < C_low_limit) + comp_C1 = C_low_limit; + + if (comp_C1 > C_high_limit) + comp_C1 = C_high_limit; + + if (comp_C2 < C_low_limit) + comp_C2 = C_low_limit; + + if (comp_C2 > C_high_limit) + comp_C2 = C_high_limit; + + /* + * Color Conversion + * pre bias (-) + */ + comp_C0 -= bias_vector[0]; + comp_C1 -= bias_vector[1]; + comp_C2 -= bias_vector[2]; + + /* matrix multiplication */ + temp1 = comp_C0 * matrix[0] + comp_C1 * matrix[1] + comp_C2 * matrix[2]; + temp2 = comp_C0 * matrix[3] + comp_C1 * matrix[4] + comp_C2 * matrix[5]; + temp3 = comp_C0 * matrix[6] + comp_C1 * matrix[7] + comp_C2 * matrix[8]; + + comp_C0 = temp1 + 0x100; + comp_C1 = temp2 + 0x100; + comp_C2 = temp3 + 0x100; + + /* take interger part */ + comp_C0 >>= 9; + comp_C1 >>= 9; + comp_C2 >>= 9; + + /* reorder output colors */ + temp = comp_C0; + comp_C0 = comp_C1; + comp_C1 = comp_C2; + comp_C2 = temp; + + /* limit pixel to 8-bit */ + if (comp_C0 < 0) + comp_C0 = 0; + + if (comp_C0 > 255) + comp_C0 = 255; + + if (comp_C1 < 0) + comp_C1 = 0; + + if (comp_C1 > 255) + comp_C1 = 255; + + if (comp_C2 < 0) + comp_C2 = 0; + + if (comp_C2 > 255) + comp_C2 = 255; + + /* Look-up table */ + if (_is_lookup_table_enabled == 1) { + comp_C2 = (look_up_table[comp_C2] >> 16) & 0xFF; + comp_C1 = (look_up_table[comp_C1] >> 8) & 0xFF; + comp_C0 = (look_up_table[comp_C0] >> 0) & 0xFF; + } + + output = (comp_C2 << 16) | (comp_C1 << 8) | comp_C0; + return output; +} + +static uint32 mdp_calc_tpval(MDPIMG *mdpImg) +{ + uint32 tpVal; + uint8 plane_tp; + + tpVal = 0; + if ((mdpImg->imgType == MDP_RGB_565) + || (mdpImg->imgType == MDP_BGR_565)) { + /* + * transparent color conversion into 24 bpp + * + * C2R_8BIT + * left shift the entire bit and or it with the upper most bits + */ + plane_tp = (uint8) ((mdpImg->tpVal & 0xF800) >> 11); + tpVal |= ((plane_tp << 3) | ((plane_tp & 0x1C) >> 2)) << 16; + + /* C1B_8BIT */ + plane_tp = (uint8) (mdpImg->tpVal & 0x1F); + tpVal |= ((plane_tp << 3) | ((plane_tp & 0x1C) >> 2)) << 8; + + /* C0G_8BIT */ + plane_tp = (uint8) ((mdpImg->tpVal & 0x7E0) >> 5); + tpVal |= ((plane_tp << 2) | ((plane_tp & 0x30) >> 4)); + } else { + /* 24bit RGB to RBG conversion */ + + tpVal = (mdpImg->tpVal & 0xFF00) >> 8; + tpVal |= (mdpImg->tpVal & 0xFF) << 8; + tpVal |= (mdpImg->tpVal & 0xFF0000); + } + + return tpVal; +} + +static uint8 *mdp_get_chroma_addr(MDPIBUF *iBuf) +{ + uint8 *dest1; + + dest1 = NULL; + switch (iBuf->ibuf_type) { + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + dest1 = (uint8 *) iBuf->buf; + dest1 += iBuf->ibuf_width * iBuf->ibuf_height * iBuf->bpp; + break; + + default: + break; + } + + return dest1; +} + +static void mdp_ppp_setbg(MDPIBUF *iBuf) +{ + uint8 *bg0_addr; + uint8 *bg1_addr; + uint32 bg0_ystride, bg1_ystride; + uint32 ppp_src_cfg_reg, unpack_pattern; + int v_slice, h_slice; + + v_slice = h_slice = 1; + bg0_addr = (uint8 *) iBuf->buf; + bg1_addr = mdp_get_chroma_addr(iBuf); + + bg0_ystride = iBuf->ibuf_width * iBuf->bpp; + bg1_ystride = iBuf->ibuf_width * iBuf->bpp; + + switch (iBuf->ibuf_type) { + case MDP_BGR_565: + case MDP_RGB_565: + /* 888 = 3bytes + * RGB = 3Components + * RGB interleaved + */ + ppp_src_cfg_reg = PPP_SRC_C2R_5BITS | PPP_SRC_C0G_6BITS | + PPP_SRC_C1B_5BITS | PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | + PPP_SRC_FETCH_PLANES_INTERLVD; + + if (iBuf->ibuf_type == MDP_RGB_565) + unpack_pattern = + MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8); + else + unpack_pattern = + MDP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8); + break; + + case MDP_RGB_888: + /* + * 888 = 3bytes + * RGB = 3Components + * RGB interleaved + */ + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | PPP_SRC_BPP_INTERLVD_3BYTES | + PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_INTERLVD; + + unpack_pattern = + MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8); + break; + + case MDP_BGRA_8888: + case MDP_RGBA_8888: + case MDP_ARGB_8888: + case MDP_XRGB_8888: + case MDP_RGBX_8888: + /* + * 8888 = 4bytes + * ARGB = 4Components + * ARGB interleaved + */ + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | PPP_SRC_C3A_8BITS | PPP_SRC_C3_ALPHA_EN | + PPP_SRC_BPP_INTERLVD_4BYTES | PPP_SRC_INTERLVD_4COMPONENTS | + PPP_SRC_UNPACK_TIGHT | PPP_SRC_UNPACK_ALIGN_LSB | + PPP_SRC_FETCH_PLANES_INTERLVD; + + if (iBuf->ibuf_type == MDP_BGRA_8888) + unpack_pattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + else if (iBuf->ibuf_type == MDP_RGBA_8888 || + iBuf->ibuf_type == MDP_RGBX_8888) + unpack_pattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G, CLR_R, + 8); + else if (iBuf->ibuf_type == MDP_XRGB_8888) + unpack_pattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + else + unpack_pattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + break; + + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | + PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | + PPP_SRC_C3A_8BITS | + PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_2COMPONENTS | + PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_PSEUDOPLNR; + + if (iBuf->ibuf_type == MDP_Y_CBCR_H2V1) + unpack_pattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8); + else + unpack_pattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8); + v_slice = h_slice = 2; + break; + + case MDP_YCRYCB_H2V1: + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | + PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | + PPP_SRC_C3A_8BITS | + PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_4COMPONENTS | + PPP_SRC_UNPACK_TIGHT | PPP_SRC_UNPACK_ALIGN_LSB; + + unpack_pattern = + MDP_GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8); + h_slice = 2; + break; + + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | + PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | + PPP_SRC_C3A_8BITS | + PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_2COMPONENTS | + PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_PSEUDOPLNR; + + if (iBuf->ibuf_type == MDP_Y_CBCR_H2V1) + unpack_pattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8); + else + unpack_pattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8); + h_slice = 2; + break; + + default: + return; + } + + /* starting input address adjustment */ + mdp_adjust_start_addr(&bg0_addr, &bg1_addr, v_slice, h_slice, + iBuf->roi.lcd_x, iBuf->roi.lcd_y, + iBuf->ibuf_width, iBuf->ibuf_height, iBuf->bpp, + iBuf, 1); + + /* + * 0x01c0: background plane 0 addr + * 0x01c4: background plane 1 addr + * 0x01c8: background plane 2 addr + * 0x01cc: bg y stride for plane 0 and 1 + * 0x01d0: bg y stride for plane 2 + * 0x01d4: bg src PPP config + * 0x01d8: unpack pattern + */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01c0, bg0_addr); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01c4, bg1_addr); + + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01cc, + (bg1_ystride << 16) | bg0_ystride); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01d4, ppp_src_cfg_reg); + + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01d8, unpack_pattern); +} + +#define IS_PSEUDOPLNR(img) ((img == MDP_Y_CRCB_H2V2) | \ + (img == MDP_Y_CBCR_H2V2) | \ + (img == MDP_Y_CBCR_H2V2_ADRENO) | \ + (img == MDP_Y_CRCB_H2V1) | \ + (img == MDP_Y_CBCR_H2V1)) + +#define IMG_LEN(rect_h, w, rect_w, bpp) (((rect_h) * w) * bpp) + +#define Y_TO_CRCB_RATIO(format) \ + ((format == MDP_Y_CBCR_H2V2 || format == MDP_Y_CBCR_H2V2_ADRENO || \ + format == MDP_Y_CRCB_H2V2) ? 2 : (format == MDP_Y_CBCR_H2V1 || \ + format == MDP_Y_CRCB_H2V1) ? 1 : 1) + +#ifdef CONFIG_ANDROID_PMEM +static void get_len(struct mdp_img *img, struct mdp_rect *rect, uint32_t bpp, + uint32_t *len0, uint32_t *len1) +{ + *len0 = IMG_LEN(rect->h, img->width, rect->w, bpp); + if (IS_PSEUDOPLNR(img->format)) + *len1 = *len0/Y_TO_CRCB_RATIO(img->format); + else + *len1 = 0; +} + +static void flush_imgs(struct mdp_blit_req *req, int src_bpp, int dst_bpp, + struct file *p_src_file, struct file *p_dst_file) +{ + uint32_t src0_len, src1_len; + + if (!(req->flags & MDP_BLIT_NON_CACHED)) { + /* flush src images to memory before dma to mdp */ + get_len(&req->src, &req->src_rect, src_bpp, + &src0_len, &src1_len); + + flush_pmem_file(p_src_file, + req->src.offset, src0_len); + + if (IS_PSEUDOPLNR(req->src.format)) + flush_pmem_file(p_src_file, + req->src.offset + src0_len, src1_len); + } + +} +#else +static void flush_imgs(struct mdp_blit_req *req, int src_bpp, int dst_bpp, + struct file *p_src_file, struct file *p_dst_file) { } +#endif + +static void mdp_start_ppp(struct msm_fb_data_type *mfd, MDPIBUF *iBuf, +struct mdp_blit_req *req, struct file *p_src_file, struct file *p_dst_file) +{ + uint8 *src0, *src1; + uint8 *dest0, *dest1; + uint16 inpBpp; + uint32 dest0_ystride; + uint32 src_width; + uint32 src_height; + uint32 src0_ystride; + uint32 src0_y1stride; + uint32 dst_roi_width; + uint32 dst_roi_height; + uint32 ppp_src_cfg_reg, ppp_operation_reg, ppp_dst_cfg_reg; + uint32 alpha, tpVal; + uint32 packPattern; + uint32 dst_packPattern; + boolean inputRGB, outputRGB, pseudoplanr_output; + int sv_slice, sh_slice; + int dv_slice, dh_slice; + boolean perPixelAlpha = FALSE; + boolean ppp_lookUp_enable = FALSE; + + sv_slice = sh_slice = dv_slice = dh_slice = 1; + alpha = tpVal = 0; + src_width = iBuf->mdpImg.width; + src_height = iBuf->roi.y + iBuf->roi.height; + src1 = NULL; + dest1 = NULL; + + inputRGB = outputRGB = TRUE; + pseudoplanr_output = FALSE; + ppp_operation_reg = 0; + ppp_dst_cfg_reg = 0; + ppp_src_cfg_reg = 0; + + /* Wait for the pipe to clear */ + do { } while (mdp_ppp_pipe_wait() <= 0); + + /* + * destination config + */ + switch (iBuf->ibuf_type) { + case MDP_RGB_888: + dst_packPattern = + MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8); + ppp_dst_cfg_reg = + PPP_DST_C0G_8BIT | PPP_DST_C1B_8BIT | PPP_DST_C2R_8BIT | + PPP_DST_PACKET_CNT_INTERLVD_3ELEM | PPP_DST_PACK_TIGHT | + PPP_DST_PACK_ALIGN_LSB | PPP_DST_OUT_SEL_AXI | + PPP_DST_BPP_3BYTES | PPP_DST_PLANE_INTERLVD; + break; + + case MDP_BGRA_8888: + case MDP_XRGB_8888: + case MDP_ARGB_8888: + case MDP_RGBA_8888: + case MDP_RGBX_8888: + if (iBuf->ibuf_type == MDP_BGRA_8888) + dst_packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + else if (iBuf->ibuf_type == MDP_RGBA_8888 || + iBuf->ibuf_type == MDP_RGBX_8888) + dst_packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G, CLR_R, + 8); + else if (iBuf->ibuf_type == MDP_XRGB_8888) + dst_packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + else + dst_packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + + ppp_dst_cfg_reg = PPP_DST_C0G_8BIT | + PPP_DST_C1B_8BIT | + PPP_DST_C2R_8BIT | + PPP_DST_C3A_8BIT | + PPP_DST_C3ALPHA_EN | + PPP_DST_PACKET_CNT_INTERLVD_4ELEM | + PPP_DST_PACK_TIGHT | + PPP_DST_PACK_ALIGN_LSB | + PPP_DST_OUT_SEL_AXI | + PPP_DST_BPP_4BYTES | PPP_DST_PLANE_INTERLVD; + break; + + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + if (iBuf->ibuf_type == MDP_Y_CBCR_H2V2) + dst_packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8); + else + dst_packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8); + + ppp_dst_cfg_reg = PPP_DST_C2R_8BIT | + PPP_DST_C0G_8BIT | + PPP_DST_C1B_8BIT | + PPP_DST_C3A_8BIT | + PPP_DST_PACKET_CNT_INTERLVD_2ELEM | + PPP_DST_PACK_TIGHT | + PPP_DST_PACK_ALIGN_LSB | + PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES; + + ppp_operation_reg |= PPP_OP_DST_CHROMA_420; + outputRGB = FALSE; + pseudoplanr_output = TRUE; + /* + * vertically (y direction) and horizontally (x direction) + * sample reduction by 2 + */ + + /* + * H2V2(YUV420) Cosite + * + * Y Y Y Y + * CbCr CbCr + * Y Y Y Y + * Y Y Y Y + * CbCr CbCr + * Y Y Y Y + */ + dv_slice = dh_slice = 2; + + /* (x,y) and (width,height) must be even numbern */ + iBuf->roi.lcd_x = (iBuf->roi.lcd_x / 2) * 2; + iBuf->roi.dst_width = (iBuf->roi.dst_width / 2) * 2; + iBuf->roi.x = (iBuf->roi.x / 2) * 2; + iBuf->roi.width = (iBuf->roi.width / 2) * 2; + + iBuf->roi.lcd_y = (iBuf->roi.lcd_y / 2) * 2; + iBuf->roi.dst_height = (iBuf->roi.dst_height / 2) * 2; + iBuf->roi.y = (iBuf->roi.y / 2) * 2; + iBuf->roi.height = (iBuf->roi.height / 2) * 2; + break; + + case MDP_YCRYCB_H2V1: + dst_packPattern = + MDP_GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8); + ppp_dst_cfg_reg = + PPP_DST_C2R_8BIT | PPP_DST_C0G_8BIT | PPP_DST_C1B_8BIT | + PPP_DST_C3A_8BIT | PPP_DST_PACKET_CNT_INTERLVD_4ELEM | + PPP_DST_PACK_TIGHT | PPP_DST_PACK_ALIGN_LSB | + PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES | + PPP_DST_PLANE_INTERLVD; + + ppp_operation_reg |= PPP_OP_DST_CHROMA_H2V1; + outputRGB = FALSE; + /* + * horizontally (x direction) sample reduction by 2 + * + * H2V1(YUV422) Cosite + * + * YCbCr Y YCbCr Y + * YCbCr Y YCbCr Y + * YCbCr Y YCbCr Y + * YCbCr Y YCbCr Y + */ + dh_slice = 2; + + /* + * if it's TV-Out/MDP_YCRYCB_H2V1, let's go through the + * preloaded gamma setting of 2.2 when the content is + * non-linear ppp_lookUp_enable = TRUE; + */ + + /* x and width must be even number */ + iBuf->roi.lcd_x = (iBuf->roi.lcd_x / 2) * 2; + iBuf->roi.dst_width = (iBuf->roi.dst_width / 2) * 2; + iBuf->roi.x = (iBuf->roi.x / 2) * 2; + iBuf->roi.width = (iBuf->roi.width / 2) * 2; + break; + + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + if (iBuf->ibuf_type == MDP_Y_CBCR_H2V1) + dst_packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8); + else + dst_packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8); + + ppp_dst_cfg_reg = PPP_DST_C2R_8BIT | + PPP_DST_C0G_8BIT | + PPP_DST_C1B_8BIT | + PPP_DST_C3A_8BIT | + PPP_DST_PACKET_CNT_INTERLVD_2ELEM | + PPP_DST_PACK_TIGHT | + PPP_DST_PACK_ALIGN_LSB | + PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES; + + ppp_operation_reg |= PPP_OP_DST_CHROMA_H2V1; + outputRGB = FALSE; + pseudoplanr_output = TRUE; + /* horizontally (x direction) sample reduction by 2 */ + dh_slice = 2; + + /* x and width must be even number */ + iBuf->roi.lcd_x = (iBuf->roi.lcd_x / 2) * 2; + iBuf->roi.dst_width = (iBuf->roi.dst_width / 2) * 2; + iBuf->roi.x = (iBuf->roi.x / 2) * 2; + iBuf->roi.width = (iBuf->roi.width / 2) * 2; + break; + + case MDP_BGR_565: + case MDP_RGB_565: + default: + if (iBuf->ibuf_type == MDP_RGB_565) + dst_packPattern = + MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8); + else + dst_packPattern = + MDP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8); + + ppp_dst_cfg_reg = PPP_DST_C0G_6BIT | + PPP_DST_C1B_5BIT | + PPP_DST_C2R_5BIT | + PPP_DST_PACKET_CNT_INTERLVD_3ELEM | + PPP_DST_PACK_TIGHT | + PPP_DST_PACK_ALIGN_LSB | + PPP_DST_OUT_SEL_AXI | + PPP_DST_BPP_2BYTES | PPP_DST_PLANE_INTERLVD; + break; + } + + /* source config */ + switch (iBuf->mdpImg.imgType) { + case MDP_RGB_888: + inpBpp = 3; + /* + * 565 = 2bytes + * RGB = 3Components + * RGB interleaved + */ + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | PPP_SRC_BPP_INTERLVD_3BYTES | + PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | + PPP_SRC_FETCH_PLANES_INTERLVD; + + packPattern = MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8); + + ppp_operation_reg |= PPP_OP_COLOR_SPACE_RGB | + PPP_OP_SRC_CHROMA_RGB | PPP_OP_DST_CHROMA_RGB; + break; + + case MDP_BGRA_8888: + case MDP_RGBA_8888: + case MDP_ARGB_8888: + perPixelAlpha = TRUE; + case MDP_XRGB_8888: + case MDP_RGBX_8888: + inpBpp = 4; + /* + * 8888 = 4bytes + * ARGB = 4Components + * ARGB interleaved + */ + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | PPP_SRC_C3A_8BITS | + PPP_SRC_C3_ALPHA_EN | PPP_SRC_BPP_INTERLVD_4BYTES | + PPP_SRC_INTERLVD_4COMPONENTS | PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | + PPP_SRC_FETCH_PLANES_INTERLVD; + + if (iBuf->mdpImg.imgType == MDP_BGRA_8888) + packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + else if (iBuf->mdpImg.imgType == MDP_RGBA_8888 || + iBuf->mdpImg.imgType == MDP_RGBX_8888) + packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G, CLR_R, + 8); + else if (iBuf->ibuf_type == MDP_XRGB_8888) + packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + else + packPattern = + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, + 8); + + ppp_operation_reg |= PPP_OP_COLOR_SPACE_RGB | + PPP_OP_SRC_CHROMA_RGB | PPP_OP_DST_CHROMA_RGB; + break; + + case MDP_Y_CBCR_H2V2: + case MDP_Y_CBCR_H2V2_ADRENO: + case MDP_Y_CRCB_H2V2: + inpBpp = 1; + src1 = (uint8 *) iBuf->mdpImg.cbcr_addr; + + /* + * CbCr = 2bytes + * CbCr = 2Components + * Y+CbCr + */ + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_2COMPONENTS | PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | + PPP_SRC_FETCH_PLANES_PSEUDOPLNR; + + if (iBuf->mdpImg.imgType == MDP_Y_CRCB_H2V2) + packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8); + else + packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8); + + ppp_operation_reg |= PPP_OP_COLOR_SPACE_YCBCR | + PPP_OP_SRC_CHROMA_420 | + PPP_OP_SRC_CHROMA_COSITE | + PPP_OP_DST_CHROMA_RGB | PPP_OP_DST_CHROMA_COSITE; + + inputRGB = FALSE; + sh_slice = sv_slice = 2; + break; + + case MDP_YCRYCB_H2V1: + inpBpp = 2; + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | + PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | + PPP_SRC_C3A_8BITS | + PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_4COMPONENTS | + PPP_SRC_UNPACK_TIGHT | PPP_SRC_UNPACK_ALIGN_LSB; + + packPattern = + MDP_GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8); + + ppp_operation_reg |= PPP_OP_SRC_CHROMA_H2V1 | + PPP_OP_SRC_CHROMA_COSITE | PPP_OP_DST_CHROMA_COSITE; + + /* + * if it's TV-Out/MDP_YCRYCB_H2V1, let's go through the + * preloaded inverse gamma setting of 2.2 since they're + * symetric when the content is non-linear + * ppp_lookUp_enable = TRUE; + */ + + /* x and width must be even number */ + iBuf->roi.lcd_x = (iBuf->roi.lcd_x / 2) * 2; + iBuf->roi.dst_width = (iBuf->roi.dst_width / 2) * 2; + iBuf->roi.x = (iBuf->roi.x / 2) * 2; + iBuf->roi.width = (iBuf->roi.width / 2) * 2; + + inputRGB = FALSE; + sh_slice = 2; + break; + + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + inpBpp = 1; + src1 = (uint8 *) iBuf->mdpImg.cbcr_addr; + + ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | + PPP_SRC_C0G_8BITS | + PPP_SRC_C1B_8BITS | + PPP_SRC_C3A_8BITS | + PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_2COMPONENTS | + PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_PSEUDOPLNR; + + if (iBuf->mdpImg.imgType == MDP_Y_CBCR_H2V1) + packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8); + else + packPattern = + MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8); + + ppp_operation_reg |= PPP_OP_SRC_CHROMA_H2V1 | + PPP_OP_SRC_CHROMA_COSITE | PPP_OP_DST_CHROMA_COSITE; + inputRGB = FALSE; + sh_slice = 2; + break; + + case MDP_BGR_565: + case MDP_RGB_565: + default: + inpBpp = 2; + /* + * 565 = 2bytes + * RGB = 3Components + * RGB interleaved + */ + ppp_src_cfg_reg = PPP_SRC_C2R_5BITS | PPP_SRC_C0G_6BITS | + PPP_SRC_C1B_5BITS | PPP_SRC_BPP_INTERLVD_2BYTES | + PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT | + PPP_SRC_UNPACK_ALIGN_LSB | + PPP_SRC_FETCH_PLANES_INTERLVD; + + if (iBuf->mdpImg.imgType == MDP_RGB_565) + packPattern = + MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8); + else + packPattern = + MDP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8); + + ppp_operation_reg |= PPP_OP_COLOR_SPACE_RGB | + PPP_OP_SRC_CHROMA_RGB | PPP_OP_DST_CHROMA_RGB; + break; + + } + + if (pseudoplanr_output) + ppp_dst_cfg_reg |= PPP_DST_PLANE_PSEUDOPLN; + + /* YCbCr to RGB color conversion flag */ + if ((!inputRGB) && (outputRGB)) { + ppp_operation_reg |= PPP_OP_CONVERT_YCBCR2RGB | + PPP_OP_CONVERT_ON; + + /* + * primary/secondary is sort of misleading term...but + * in mdp2.2/3.0 we only use primary matrix (forward/rev) + * in mdp3.1 we use set1(prim) and set2(secd) + */ +#ifdef CONFIG_FB_MSM_MDP31 + ppp_operation_reg |= PPP_OP_CONVERT_MATRIX_SECONDARY | + PPP_OP_DST_RGB; + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0240, 0); +#endif + + if (ppp_lookUp_enable) { + ppp_operation_reg |= PPP_OP_LUT_C0_ON | + PPP_OP_LUT_C1_ON | PPP_OP_LUT_C2_ON; + } + } + /* RGB to YCbCr color conversion flag */ + if ((inputRGB) && (!outputRGB)) { + ppp_operation_reg |= PPP_OP_CONVERT_RGB2YCBCR | + PPP_OP_CONVERT_ON; + +#ifdef CONFIG_FB_MSM_MDP31 + ppp_operation_reg |= PPP_OP_CONVERT_MATRIX_PRIMARY | + PPP_OP_DST_YCBCR; + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0240, 0x1e); +#endif + + if (ppp_lookUp_enable) { + ppp_operation_reg |= PPP_OP_LUT_C0_ON | + PPP_OP_LUT_C1_ON | PPP_OP_LUT_C2_ON; + } + } + /* YCbCr to YCbCr color conversion flag */ + if ((!inputRGB) && (!outputRGB)) { + if ((ppp_lookUp_enable) && + (iBuf->mdpImg.imgType != iBuf->ibuf_type)) { + ppp_operation_reg |= PPP_OP_LUT_C0_ON; + } + } + + ppp_src_cfg_reg |= (iBuf->roi.x % 2) ? PPP_SRC_BPP_ROI_ODD_X : 0; + ppp_src_cfg_reg |= (iBuf->roi.y % 2) ? PPP_SRC_BPP_ROI_ODD_Y : 0; + + if (req->flags & MDP_DEINTERLACE) + ppp_operation_reg |= PPP_OP_DEINT_EN; + + /* Dither at DMA side only since iBuf format is RGB888 */ + if (iBuf->mdpImg.mdpOp & MDPOP_DITHER) + ppp_operation_reg |= PPP_OP_DITHER_EN; + + if (iBuf->mdpImg.mdpOp & MDPOP_ROTATION) { + ppp_operation_reg |= PPP_OP_ROT_ON; + + if (iBuf->mdpImg.mdpOp & MDPOP_ROT90) { + ppp_operation_reg |= PPP_OP_ROT_90; + } + if (iBuf->mdpImg.mdpOp & MDPOP_LR) { + ppp_operation_reg |= PPP_OP_FLIP_LR; + } + if (iBuf->mdpImg.mdpOp & MDPOP_UD) { + ppp_operation_reg |= PPP_OP_FLIP_UD; + } + } + + if (iBuf->mdpImg.imgType == MDP_Y_CBCR_H2V2_ADRENO) + src0_ystride = ALIGN(src_width, 32) * inpBpp; + else + src0_ystride = src_width * inpBpp; + + if (iBuf->mdpImg.imgType == MDP_Y_CBCR_H2V2_ADRENO) + src0_y1stride = 2 * ALIGN(src_width/2, 32); + else + src0_y1stride = src0_ystride; + + dest0_ystride = iBuf->ibuf_width * iBuf->bpp; + + /* no need to care about rotation since it's the real-XY. */ + dst_roi_width = iBuf->roi.dst_width; + dst_roi_height = iBuf->roi.dst_height; + + src0 = (uint8 *) iBuf->mdpImg.bmy_addr; + dest0 = (uint8 *) iBuf->buf; + + /* Jumping from Y-Plane to Chroma Plane */ + dest1 = mdp_get_chroma_addr(iBuf); + + /* first pixel addr calculation */ + mdp_adjust_start_addr(&src0, &src1, sv_slice, sh_slice, iBuf->roi.x, + iBuf->roi.y, src_width, src_height, inpBpp, iBuf, + 0); + mdp_adjust_start_addr(&dest0, &dest1, dv_slice, dh_slice, + iBuf->roi.lcd_x, iBuf->roi.lcd_y, + iBuf->ibuf_width, iBuf->ibuf_height, iBuf->bpp, + iBuf, 2); + + /* set scale operation */ + mdp_set_scale(iBuf, dst_roi_width, dst_roi_height, + inputRGB, outputRGB, &ppp_operation_reg); + + /* + * setting background source for blending + */ + mdp_set_blend_attr(iBuf, &alpha, &tpVal, perPixelAlpha, + &ppp_operation_reg); + + if (ppp_operation_reg & PPP_OP_BLEND_ON) { + mdp_ppp_setbg(iBuf); + + if (iBuf->ibuf_type == MDP_YCRYCB_H2V1) { + ppp_operation_reg |= PPP_OP_BG_CHROMA_H2V1; + + if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP) { + tpVal = mdp_conv_matx_rgb2yuv(tpVal, + (uint16 *) & + mdp_ccs_rgb2yuv, + &mdp_plv[0], NULL); + } + } + } + + /* + * 0x0004: enable dbg bus + * 0x0100: "don't care" Edge Condit until scaling is on + * 0x0104: xrc tile x&y size u7.6 format = 7bit.6bit + * 0x0108: src pixel size + * 0x010c: component plane 0 starting address + * 0x011c: component plane 0 ystride + * 0x0124: PPP source config register + * 0x0128: unpacked pattern from lsb to msb (eg. RGB->BGR) + */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0108, (iBuf->roi.height << 16 | + iBuf->roi.width)); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x010c, src0); /* comp.plane 0 */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0110, src1); /* comp.plane 1 */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x011c, + (src0_y1stride << 16 | src0_ystride)); + + /* setup for rgb 565 */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0124, ppp_src_cfg_reg); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0128, packPattern); + /* + * 0x0138: PPP destination operation register + * 0x014c: constant_alpha|transparent_color + * 0x0150: PPP destination config register + * 0x0154: PPP packing pattern + */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0138, ppp_operation_reg); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x014c, alpha << 24 | (tpVal & + 0xffffff)); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0150, ppp_dst_cfg_reg); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0154, dst_packPattern); + + /* + * 0x0164: ROI height and width + * 0x0168: Component Plane 0 starting addr + * 0x016c: Component Plane 1 starting addr + * 0x0178: Component Plane 1/0 y stride + */ + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0164, + (dst_roi_height << 16 | dst_roi_width)); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0168, dest0); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x016c, dest1); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0178, + (dest0_ystride << 16 | dest0_ystride)); + + flush_imgs(req, inpBpp, iBuf->bpp, p_src_file, p_dst_file); +#ifdef CONFIG_FB_MSM_MDP31 + MDP_OUTP(MDP_BASE + 0x00100, 0xFF00); +#endif + mdp_pipe_kickoff(MDP_PPP_TERM, mfd); +} + +static int mdp_ppp_verify_req(struct mdp_blit_req *req) +{ + u32 src_width, src_height, dst_width, dst_height; + + if (req == NULL) { + printk(KERN_ERR "\n%s(): Error in Line %u", __func__, + __LINE__); + return -1; + } + + if (MDP_IS_IMGTYPE_BAD(req->src.format) || + MDP_IS_IMGTYPE_BAD(req->dst.format)) { + printk(KERN_ERR "\n%s(): Error in Line %u", __func__, + __LINE__); + return -1; + } + + if ((req->src.width == 0) || (req->src.height == 0) || + (req->src_rect.w == 0) || (req->src_rect.h == 0) || + (req->dst.width == 0) || (req->dst.height == 0) || + (req->dst_rect.w == 0) || (req->dst_rect.h == 0)) { + printk(KERN_ERR "\n%s(): Error in Line %u", __func__, + __LINE__); + + return -1; + } + + if (((req->src_rect.x + req->src_rect.w) > req->src.width) || + ((req->src_rect.y + req->src_rect.h) > req->src.height)) { + printk(KERN_ERR "\n%s(): Error in Line %u", __func__, + __LINE__); + return -1; + } + + if (((req->dst_rect.x + req->dst_rect.w) > req->dst.width) || + ((req->dst_rect.y + req->dst_rect.h) > req->dst.height)) { + printk(KERN_ERR "\n%s(): Error in Line %u", __func__, + __LINE__); + return -1; + } + + /* + * scaling range check + */ + src_width = req->src_rect.w; + src_height = req->src_rect.h; + + if (req->flags & MDP_ROT_90) { + dst_width = req->dst_rect.h; + dst_height = req->dst_rect.w; + } else { + dst_width = req->dst_rect.w; + dst_height = req->dst_rect.h; + } + + switch (req->dst.format) { + case MDP_Y_CRCB_H2V2: + case MDP_Y_CBCR_H2V2: + src_width = (src_width / 2) * 2; + src_height = (src_height / 2) * 2; + dst_width = (src_width / 2) * 2; + dst_height = (src_height / 2) * 2; + break; + + case MDP_Y_CRCB_H2V1: + case MDP_Y_CBCR_H2V1: + case MDP_YCRYCB_H2V1: + src_width = (src_width / 2) * 2; + dst_width = (src_width / 2) * 2; + break; + + default: + break; + } + + if (((MDP_SCALE_Q_FACTOR * dst_width) / src_width > + MDP_MAX_X_SCALE_FACTOR) + || ((MDP_SCALE_Q_FACTOR * dst_width) / src_width < + MDP_MIN_X_SCALE_FACTOR)) { + printk(KERN_ERR "\n%s(): Error in Line %u", __func__, + __LINE__); + return -1; + } + + if (((MDP_SCALE_Q_FACTOR * dst_height) / src_height > + MDP_MAX_Y_SCALE_FACTOR) + || ((MDP_SCALE_Q_FACTOR * dst_height) / src_height < + MDP_MIN_Y_SCALE_FACTOR)) { + printk(KERN_ERR "\n%s(): Error in Line %u", __func__, + __LINE__); + return -1; + } + return 0; +} + +int get_gem_img(struct mdp_img *img, unsigned long *start, unsigned long *len) +{ + /* Set len to zero to appropriately error out if + kgsl_gem_obj_addr fails */ + + *len = 0; + return kgsl_gem_obj_addr(img->memory_id, (int) img->priv, start, len); +} + +int get_img(struct mdp_img *img, struct fb_info *info, unsigned long *start, + unsigned long *len, struct file **pp_file) +{ + int put_needed, ret = 0; + struct file *file; +#ifdef CONFIG_ANDROID_PMEM + unsigned long vstart; +#endif + +#ifdef CONFIG_ANDROID_PMEM + if (!get_pmem_file(img->memory_id, start, &vstart, len, pp_file)) + return 0; +#endif + file = fget_light(img->memory_id, &put_needed); + if (file == NULL) + return -1; + + if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) { + *start = info->fix.smem_start; + *len = info->fix.smem_len; + *pp_file = file; + } else { + ret = -1; + fput_light(file, put_needed); + } + return ret; +} + + +void put_img(struct file *p_src_file) +{ +#ifdef CONFIG_ANDROID_PMEM + if (p_src_file) + put_pmem_file(p_src_file); +#endif +} + + +static int mdp_ppp_blit_addr(struct fb_info *info, struct mdp_blit_req *req, + unsigned long srcp0_start, unsigned long srcp0_len, + unsigned long srcp1_start, unsigned long srcp1_len, + unsigned long dst_start, unsigned long dst_len, + struct file *p_src_file, struct file *p_dst_file) +{ + MDPIBUF iBuf; + u32 dst_width, dst_height; + struct msm_fb_data_type *mfd = info->par; + + if (req->dst.format == MDP_FB_FORMAT) + req->dst.format = mfd->fb_imgType; + if (req->src.format == MDP_FB_FORMAT) + req->src.format = mfd->fb_imgType; + + if (mdp_ppp_verify_req(req)) { + printk(KERN_ERR "mdp_ppp: invalid image!\n"); + put_img(p_src_file); + put_img(p_dst_file); + return -1; + } + + iBuf.ibuf_width = req->dst.width; + iBuf.ibuf_height = req->dst.height; + iBuf.bpp = bytes_per_pixel[req->dst.format]; + + iBuf.ibuf_type = req->dst.format; + iBuf.buf = (uint8 *) dst_start; + iBuf.buf += req->dst.offset; + + iBuf.roi.lcd_x = req->dst_rect.x; + iBuf.roi.lcd_y = req->dst_rect.y; + iBuf.roi.dst_width = req->dst_rect.w; + iBuf.roi.dst_height = req->dst_rect.h; + + iBuf.roi.x = req->src_rect.x; + iBuf.roi.width = req->src_rect.w; + iBuf.roi.y = req->src_rect.y; + iBuf.roi.height = req->src_rect.h; + + iBuf.mdpImg.width = req->src.width; + iBuf.mdpImg.imgType = req->src.format; + + + iBuf.mdpImg.bmy_addr = (uint32 *) (srcp0_start + req->src.offset); + if (iBuf.mdpImg.imgType == MDP_Y_CBCR_H2V2_ADRENO) + iBuf.mdpImg.cbcr_addr = + (uint32 *) ((uint32) iBuf.mdpImg.bmy_addr + + ALIGN((ALIGN(req->src.width, 32) * + ALIGN(req->src.height, 32)), 4096)); + else + iBuf.mdpImg.cbcr_addr = srcp1_start ? (uint32 *)srcp1_start : + (uint32 *) ((uint32) iBuf.mdpImg.bmy_addr + + req->src.width * req->src.height); + + iBuf.mdpImg.mdpOp = MDPOP_NOP; + + /* blending check */ + if (req->transp_mask != MDP_TRANSP_NOP) { + iBuf.mdpImg.mdpOp |= MDPOP_TRANSP; + iBuf.mdpImg.tpVal = req->transp_mask; + iBuf.mdpImg.tpVal = mdp_calc_tpval(&iBuf.mdpImg); + } else { + iBuf.mdpImg.tpVal = 0; + } + + req->alpha &= 0xff; + if (req->alpha < MDP_ALPHA_NOP) { + iBuf.mdpImg.mdpOp |= MDPOP_ALPHAB; + iBuf.mdpImg.alpha = req->alpha; + } else { + iBuf.mdpImg.alpha = 0xff; + } + + /* rotation check */ + if (req->flags & MDP_FLIP_LR) + iBuf.mdpImg.mdpOp |= MDPOP_LR; + if (req->flags & MDP_FLIP_UD) + iBuf.mdpImg.mdpOp |= MDPOP_UD; + if (req->flags & MDP_ROT_90) + iBuf.mdpImg.mdpOp |= MDPOP_ROT90; + if (req->flags & MDP_DITHER) + iBuf.mdpImg.mdpOp |= MDPOP_DITHER; + + if (req->flags & MDP_BLEND_FG_PREMULT) { +#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP303) + iBuf.mdpImg.mdpOp |= MDPOP_FG_PM_ALPHA; +#else + put_img(p_src_file); + put_img(p_dst_file); + return -EINVAL; +#endif + } + + if (req->flags & MDP_DEINTERLACE) { +#ifdef CONFIG_FB_MSM_MDP31 + if ((req->src.format != MDP_Y_CBCR_H2V2) && + (req->src.format != MDP_Y_CRCB_H2V2)) { +#endif + put_img(p_src_file); + put_img(p_dst_file); + return -EINVAL; +#ifdef CONFIG_FB_MSM_MDP31 + } +#endif + } + + /* scale check */ + if (req->flags & MDP_ROT_90) { + dst_width = req->dst_rect.h; + dst_height = req->dst_rect.w; + } else { + dst_width = req->dst_rect.w; + dst_height = req->dst_rect.h; + } + + if ((iBuf.roi.width != dst_width) || (iBuf.roi.height != dst_height)) + iBuf.mdpImg.mdpOp |= MDPOP_ASCALE; + + if (req->flags & MDP_BLUR) { +#ifdef CONFIG_FB_MSM_MDP31 + if (req->flags & MDP_SHARPENING) + printk(KERN_WARNING + "mdp: MDP_SHARPENING is set with MDP_BLUR!\n"); + req->flags |= MDP_SHARPENING; + req->sharpening_strength = -127; +#else + iBuf.mdpImg.mdpOp |= MDPOP_ASCALE | MDPOP_BLUR; + +#endif + } + + if (req->flags & MDP_SHARPENING) { +#ifdef CONFIG_FB_MSM_MDP31 + if ((req->sharpening_strength > 127) || + (req->sharpening_strength < -127)) { + printk(KERN_ERR + "%s: sharpening strength out of range\n", + __func__); + put_img(p_src_file); + put_img(p_dst_file); + return -EINVAL; + } + + iBuf.mdpImg.mdpOp |= MDPOP_ASCALE | MDPOP_SHARPENING; + iBuf.mdpImg.sp_value = req->sharpening_strength & 0xff; +#else + put_img(p_src_file); + put_img(p_dst_file); + return -EINVAL; +#endif + } + + down(&mdp_ppp_mutex); + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + +#ifndef CONFIG_FB_MSM_MDP22 + mdp_start_ppp(mfd, &iBuf, req, p_src_file, p_dst_file); +#else + /* bg tile fetching HW workaround */ + if (((iBuf.mdpImg.mdpOp & (MDPOP_TRANSP | MDPOP_ALPHAB)) || + (req->src.format == MDP_ARGB_8888) || + (req->src.format == MDP_BGRA_8888) || + (req->src.format == MDP_RGBA_8888)) && + (iBuf.mdpImg.mdpOp & MDPOP_ROT90) && (req->dst_rect.w <= 16)) { + int dst_h, src_w, i; + uint32 mdpOp = iBuf.mdpImg.mdpOp; + + src_w = req->src_rect.w; + dst_h = iBuf.roi.dst_height; + + for (i = 0; i < (req->dst_rect.h / 16); i++) { + /* this tile size */ + iBuf.roi.dst_height = 16; + iBuf.roi.width = + (16 * req->src_rect.w) / req->dst_rect.h; + + /* if it's out of scale range... */ + if (((MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + iBuf.roi.width) > MDP_MAX_X_SCALE_FACTOR) + iBuf.roi.width = + (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + MDP_MAX_X_SCALE_FACTOR; + else if (((MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + iBuf.roi.width) < MDP_MIN_X_SCALE_FACTOR) + iBuf.roi.width = + (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + MDP_MIN_X_SCALE_FACTOR; + + mdp_start_ppp(mfd, &iBuf, req, p_src_file, p_dst_file); + + /* next tile location */ + iBuf.roi.lcd_y += 16; + iBuf.roi.x += iBuf.roi.width; + + /* this is for a remainder update */ + dst_h -= 16; + src_w -= iBuf.roi.width; + /* restore mdpOp since MDPOP_ASCALE have been cleared */ + iBuf.mdpImg.mdpOp = mdpOp; + } + + if ((dst_h < 0) || (src_w < 0)) + printk + ("msm_fb: mdp_blt_ex() unexpected result! line:%d\n", + __LINE__); + + /* remainder update */ + if ((dst_h > 0) && (src_w > 0)) { + u32 tmp_v; + + iBuf.roi.dst_height = dst_h; + iBuf.roi.width = src_w; + + if (((MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + iBuf.roi.width) > MDP_MAX_X_SCALE_FACTOR) { + tmp_v = + (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + MDP_MAX_X_SCALE_FACTOR + + (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) % + MDP_MAX_X_SCALE_FACTOR ? 1 : 0; + + /* move x location as roi width gets bigger */ + iBuf.roi.x -= tmp_v - iBuf.roi.width; + iBuf.roi.width = tmp_v; + } else + if (((MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + iBuf.roi.width) < MDP_MIN_X_SCALE_FACTOR) { + tmp_v = + (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) / + MDP_MIN_X_SCALE_FACTOR + + (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) % + MDP_MIN_X_SCALE_FACTOR ? 1 : 0; + + /* + * we don't move x location for continuity of + * source image + */ + iBuf.roi.width = tmp_v; + } + + mdp_start_ppp(mfd, &iBuf, req, p_src_file, p_dst_file); + } + } else { + mdp_start_ppp(mfd, &iBuf, req, p_src_file, p_dst_file); + } +#endif + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + up(&mdp_ppp_mutex); + + put_img(p_src_file); + put_img(p_dst_file); + return 0; +} + +int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req) +{ + unsigned long src_start, dst_start; + unsigned long src_len = 0; + unsigned long dst_len = 0; + struct file *p_src_file = 0 , *p_dst_file = 0; + + if (req->flags & MDP_BLIT_SRC_GEM) + get_gem_img(&req->src, &src_start, &src_len); + else + get_img(&req->src, info, &src_start, &src_len, &p_src_file); + if (src_len == 0) { + printk(KERN_ERR "mdp_ppp: could not retrieve image from " + "memory\n"); + return -EINVAL; + } + if (req->flags & MDP_BLIT_DST_GEM) + get_gem_img(&req->dst, &dst_start, &dst_len); + else + get_img(&req->dst, info, &dst_start, &dst_len, &p_dst_file); + if (dst_len == 0) { + put_img(p_src_file); + printk(KERN_ERR "mdp_ppp: could not retrieve image from " + "memory\n"); + return -EINVAL; + } + + return mdp_ppp_blit_addr(info, req, src_start, src_len, 0, 0, dst_start, + dst_len, p_src_file, p_dst_file); +} + +static struct mdp_blit_req overlay_req; +static bool mdp_overlay_req_set; + +int mdp_ppp_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req) +{ + memset(&overlay_req, 0, sizeof(struct mdp_blit_req)); + + overlay_req.src.width = req->src.width; + overlay_req.src.height = req->src.height; + overlay_req.src.format = req->src.format; + + + overlay_req.dst.width = req->dst_rect.w; + overlay_req.dst.height = req->dst_rect.h; + overlay_req.dst.format = MDP_FB_FORMAT; + overlay_req.transp_mask = req->transp_mask; + overlay_req.flags = req->flags; + overlay_req.alpha = req->alpha; + + overlay_req.src_rect.x = req->src_rect.x; + overlay_req.src_rect.y = req->src_rect.y; + overlay_req.src_rect.w = req->src_rect.w; + overlay_req.src_rect.h = req->src_rect.h; + overlay_req.dst_rect.x = req->dst_rect.x; + overlay_req.dst_rect.y = req->dst_rect.y; + overlay_req.dst_rect.w = req->dst_rect.w; + overlay_req.dst_rect.h = req->dst_rect.h; + mdp_overlay_req_set = true; + + pr_debug("%s: Overlay parameters:", __func__); + pr_debug("Src_Image (%u %u)\n", overlay_req.src.width, + overlay_req.src.height); + + if (overlay_req.src.format == MDP_Y_CRCB_H2V2) + pr_debug("Overlay format MDP_Y_CRCB_H2V2\n"); + else if (overlay_req.src.format == MDP_RGB_565) + pr_debug("Overlay format MDP_RGB_565\n"); + else + pr_debug("Overlay format(%u) unknown\n", + overlay_req.src.format); + + pr_debug("Dst_Image (%u %u)\n", overlay_req.dst.width, + overlay_req.dst.height); + pr_debug("Src rect: (%u,%u,%u,%u), Dst rect: (%u,%u,%u,%u)\n", + overlay_req.src_rect.x, overlay_req.src_rect.y, + overlay_req.src_rect.w, overlay_req.src_rect.h, + overlay_req.dst_rect.x, overlay_req.dst_rect.y, + overlay_req.dst_rect.w, overlay_req.dst_rect.h); + return 0; +} + +int mdp_ppp_v4l2_overlay_clear(void) +{ + memset(&overlay_req, 0, sizeof(struct mdp_overlay)); + mdp_overlay_req_set = false; + return 0; +} + +int mdp_ppp_v4l2_overlay_play(struct fb_info *info, + unsigned long srcp0_addr, unsigned long srcp0_size, + unsigned long srcp1_addr, unsigned long srcp1_size) +{ + int ret; + + if (!mdp_overlay_req_set) { + pr_err("mdp_ppp:v4l2:No overlay set, ignore play req\n"); + return -EINVAL; + } + + overlay_req.dst.width = info->var.xres; + overlay_req.dst.height = info->var.yres; + + ret = mdp_ppp_blit_addr(info, &overlay_req, + srcp0_addr, srcp0_size, srcp1_addr, srcp1_size, + info->fix.smem_start, info->fix.smem_len, NULL, NULL); + + if (ret) + pr_err("%s:Blitting overlay failed(%d)\n", __func__, ret); + + return ret; +} diff --git a/drivers/video/msm/mdp_ppp.h b/drivers/video/msm/mdp_ppp.h new file mode 100644 index 000000000000..e04564347bdf --- /dev/null +++ b/drivers/video/msm/mdp_ppp.h @@ -0,0 +1,82 @@ +/* drivers/video/msm/mdp_ppp.h + * + * Copyright (C) 2009 Google Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _VIDEO_MSM_MDP_PPP_H_ +#define _VIDEO_MSM_MDP_PPP_H_ + +#include + +struct ppp_regs { + uint32_t src0; + uint32_t src1; + uint32_t dst0; + uint32_t dst1; + uint32_t src_cfg; + uint32_t dst_cfg; + uint32_t src_pack; + uint32_t dst_pack; + uint32_t src_rect; + uint32_t dst_rect; + uint32_t src_ystride; + uint32_t dst_ystride; + uint32_t op; + uint32_t src_bpp; + uint32_t dst_bpp; + uint32_t edge; + uint32_t phasex_init; + uint32_t phasey_init; + uint32_t phasex_step; + uint32_t phasey_step; + + uint32_t bg0; + uint32_t bg1; + uint32_t bg_cfg; + uint32_t bg_bpp; + uint32_t bg_pack; + uint32_t bg_ystride; + +#ifdef CONFIG_MSM_MDP31 + uint32_t src_xy; + uint32_t src_img_sz; + uint32_t dst_xy; + uint32_t bg_xy; + uint32_t bg_img_sz; + uint32_t bg_alpha_sel; + + uint32_t scale_cfg; + uint32_t csc_cfg; +#endif +}; + +struct mdp_info; +struct mdp_rect; +struct mdp_blit_req; + +void mdp_ppp_init_scale(const struct mdp_info *mdp); +int mdp_ppp_cfg_scale(const struct mdp_info *mdp, struct ppp_regs *regs, + struct mdp_rect *src_rect, struct mdp_rect *dst_rect, + uint32_t src_format, uint32_t dst_format); +int mdp_ppp_load_blur(const struct mdp_info *mdp); + +#ifndef CONFIG_MSM_MDP31 +int mdp_ppp_cfg_edge_cond(struct mdp_blit_req *req, struct ppp_regs *regs); +#else +static inline int mdp_ppp_cfg_edge_cond(struct mdp_blit_req *req, + struct ppp_regs *regs) +{ + return 0; +} +#endif + +#endif /* _VIDEO_MSM_MDP_PPP_H_ */ diff --git a/drivers/video/msm/mdp_ppp22.c b/drivers/video/msm/mdp_ppp22.c new file mode 100644 index 000000000000..799ce524f836 --- /dev/null +++ b/drivers/video/msm/mdp_ppp22.c @@ -0,0 +1,1091 @@ +/* drivers/video/msm/mdp_ppp22.c + * + * Copyright (C) 2007 The Linux Foundation. All rights reserved. + * Copyright (C) 2007 Google Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + +#include "mdp_hw.h" +#include "mdp_ppp.h" + +struct mdp_table_entry { + uint32_t reg; + uint32_t val; +}; + +enum { + MDP_DOWNSCALE_PT2TOPT4, + MDP_DOWNSCALE_PT4TOPT6, + MDP_DOWNSCALE_PT6TOPT8, + MDP_DOWNSCALE_PT8TO1, + MDP_DOWNSCALE_MAX, + + /* not technically in the downscale table list */ + MDP_DOWNSCALE_BLUR, +}; + +static int downscale_x_table; +static int downscale_y_table; + +static struct mdp_table_entry mdp_upscale_table[] = { + { 0x5fffc, 0x0 }, + { 0x50200, 0x7fc00000 }, + { 0x5fffc, 0xff80000d }, + { 0x50204, 0x7ec003f9 }, + { 0x5fffc, 0xfec0001c }, + { 0x50208, 0x7d4003f3 }, + { 0x5fffc, 0xfe40002b }, + { 0x5020c, 0x7b8003ed }, + { 0x5fffc, 0xfd80003c }, + { 0x50210, 0x794003e8 }, + { 0x5fffc, 0xfcc0004d }, + { 0x50214, 0x76c003e4 }, + { 0x5fffc, 0xfc40005f }, + { 0x50218, 0x73c003e0 }, + { 0x5fffc, 0xfb800071 }, + { 0x5021c, 0x708003de }, + { 0x5fffc, 0xfac00085 }, + { 0x50220, 0x6d0003db }, + { 0x5fffc, 0xfa000098 }, + { 0x50224, 0x698003d9 }, + { 0x5fffc, 0xf98000ac }, + { 0x50228, 0x654003d8 }, + { 0x5fffc, 0xf8c000c1 }, + { 0x5022c, 0x610003d7 }, + { 0x5fffc, 0xf84000d5 }, + { 0x50230, 0x5c8003d7 }, + { 0x5fffc, 0xf7c000e9 }, + { 0x50234, 0x580003d7 }, + { 0x5fffc, 0xf74000fd }, + { 0x50238, 0x534003d8 }, + { 0x5fffc, 0xf6c00112 }, + { 0x5023c, 0x4e8003d8 }, + { 0x5fffc, 0xf6800126 }, + { 0x50240, 0x494003da }, + { 0x5fffc, 0xf600013a }, + { 0x50244, 0x448003db }, + { 0x5fffc, 0xf600014d }, + { 0x50248, 0x3f4003dd }, + { 0x5fffc, 0xf5c00160 }, + { 0x5024c, 0x3a4003df }, + { 0x5fffc, 0xf5c00172 }, + { 0x50250, 0x354003e1 }, + { 0x5fffc, 0xf5c00184 }, + { 0x50254, 0x304003e3 }, + { 0x5fffc, 0xf6000195 }, + { 0x50258, 0x2b0003e6 }, + { 0x5fffc, 0xf64001a6 }, + { 0x5025c, 0x260003e8 }, + { 0x5fffc, 0xf6c001b4 }, + { 0x50260, 0x214003eb }, + { 0x5fffc, 0xf78001c2 }, + { 0x50264, 0x1c4003ee }, + { 0x5fffc, 0xf80001cf }, + { 0x50268, 0x17c003f1 }, + { 0x5fffc, 0xf90001db }, + { 0x5026c, 0x134003f3 }, + { 0x5fffc, 0xfa0001e5 }, + { 0x50270, 0xf0003f6 }, + { 0x5fffc, 0xfb4001ee }, + { 0x50274, 0xac003f9 }, + { 0x5fffc, 0xfcc001f5 }, + { 0x50278, 0x70003fb }, + { 0x5fffc, 0xfe4001fb }, + { 0x5027c, 0x34003fe }, +}; + +static struct mdp_table_entry mdp_downscale_x_table_PT2TOPT4[] = { + { 0x5fffc, 0x740008c }, + { 0x50280, 0x33800088 }, + { 0x5fffc, 0x800008e }, + { 0x50284, 0x33400084 }, + { 0x5fffc, 0x8400092 }, + { 0x50288, 0x33000080 }, + { 0x5fffc, 0x9000094 }, + { 0x5028c, 0x3300007b }, + { 0x5fffc, 0x9c00098 }, + { 0x50290, 0x32400077 }, + { 0x5fffc, 0xa40009b }, + { 0x50294, 0x32000073 }, + { 0x5fffc, 0xb00009d }, + { 0x50298, 0x31c0006f }, + { 0x5fffc, 0xbc000a0 }, + { 0x5029c, 0x3140006b }, + { 0x5fffc, 0xc8000a2 }, + { 0x502a0, 0x31000067 }, + { 0x5fffc, 0xd8000a5 }, + { 0x502a4, 0x30800062 }, + { 0x5fffc, 0xe4000a8 }, + { 0x502a8, 0x2fc0005f }, + { 0x5fffc, 0xec000aa }, + { 0x502ac, 0x2fc0005b }, + { 0x5fffc, 0xf8000ad }, + { 0x502b0, 0x2f400057 }, + { 0x5fffc, 0x108000b0 }, + { 0x502b4, 0x2e400054 }, + { 0x5fffc, 0x114000b2 }, + { 0x502b8, 0x2e000050 }, + { 0x5fffc, 0x124000b4 }, + { 0x502bc, 0x2d80004c }, + { 0x5fffc, 0x130000b6 }, + { 0x502c0, 0x2d000049 }, + { 0x5fffc, 0x140000b8 }, + { 0x502c4, 0x2c800045 }, + { 0x5fffc, 0x150000b9 }, + { 0x502c8, 0x2c000042 }, + { 0x5fffc, 0x15c000bd }, + { 0x502cc, 0x2b40003e }, + { 0x5fffc, 0x16c000bf }, + { 0x502d0, 0x2a80003b }, + { 0x5fffc, 0x17c000bf }, + { 0x502d4, 0x2a000039 }, + { 0x5fffc, 0x188000c2 }, + { 0x502d8, 0x29400036 }, + { 0x5fffc, 0x19c000c4 }, + { 0x502dc, 0x28800032 }, + { 0x5fffc, 0x1ac000c5 }, + { 0x502e0, 0x2800002f }, + { 0x5fffc, 0x1bc000c7 }, + { 0x502e4, 0x2740002c }, + { 0x5fffc, 0x1cc000c8 }, + { 0x502e8, 0x26c00029 }, + { 0x5fffc, 0x1dc000c9 }, + { 0x502ec, 0x26000027 }, + { 0x5fffc, 0x1ec000cc }, + { 0x502f0, 0x25000024 }, + { 0x5fffc, 0x200000cc }, + { 0x502f4, 0x24800021 }, + { 0x5fffc, 0x210000cd }, + { 0x502f8, 0x23800020 }, + { 0x5fffc, 0x220000ce }, + { 0x502fc, 0x2300001d }, +}; + +static struct mdp_table_entry mdp_downscale_x_table_PT4TOPT6[] = { + { 0x5fffc, 0x740008c }, + { 0x50280, 0x33800088 }, + { 0x5fffc, 0x800008e }, + { 0x50284, 0x33400084 }, + { 0x5fffc, 0x8400092 }, + { 0x50288, 0x33000080 }, + { 0x5fffc, 0x9000094 }, + { 0x5028c, 0x3300007b }, + { 0x5fffc, 0x9c00098 }, + { 0x50290, 0x32400077 }, + { 0x5fffc, 0xa40009b }, + { 0x50294, 0x32000073 }, + { 0x5fffc, 0xb00009d }, + { 0x50298, 0x31c0006f }, + { 0x5fffc, 0xbc000a0 }, + { 0x5029c, 0x3140006b }, + { 0x5fffc, 0xc8000a2 }, + { 0x502a0, 0x31000067 }, + { 0x5fffc, 0xd8000a5 }, + { 0x502a4, 0x30800062 }, + { 0x5fffc, 0xe4000a8 }, + { 0x502a8, 0x2fc0005f }, + { 0x5fffc, 0xec000aa }, + { 0x502ac, 0x2fc0005b }, + { 0x5fffc, 0xf8000ad }, + { 0x502b0, 0x2f400057 }, + { 0x5fffc, 0x108000b0 }, + { 0x502b4, 0x2e400054 }, + { 0x5fffc, 0x114000b2 }, + { 0x502b8, 0x2e000050 }, + { 0x5fffc, 0x124000b4 }, + { 0x502bc, 0x2d80004c }, + { 0x5fffc, 0x130000b6 }, + { 0x502c0, 0x2d000049 }, + { 0x5fffc, 0x140000b8 }, + { 0x502c4, 0x2c800045 }, + { 0x5fffc, 0x150000b9 }, + { 0x502c8, 0x2c000042 }, + { 0x5fffc, 0x15c000bd }, + { 0x502cc, 0x2b40003e }, + { 0x5fffc, 0x16c000bf }, + { 0x502d0, 0x2a80003b }, + { 0x5fffc, 0x17c000bf }, + { 0x502d4, 0x2a000039 }, + { 0x5fffc, 0x188000c2 }, + { 0x502d8, 0x29400036 }, + { 0x5fffc, 0x19c000c4 }, + { 0x502dc, 0x28800032 }, + { 0x5fffc, 0x1ac000c5 }, + { 0x502e0, 0x2800002f }, + { 0x5fffc, 0x1bc000c7 }, + { 0x502e4, 0x2740002c }, + { 0x5fffc, 0x1cc000c8 }, + { 0x502e8, 0x26c00029 }, + { 0x5fffc, 0x1dc000c9 }, + { 0x502ec, 0x26000027 }, + { 0x5fffc, 0x1ec000cc }, + { 0x502f0, 0x25000024 }, + { 0x5fffc, 0x200000cc }, + { 0x502f4, 0x24800021 }, + { 0x5fffc, 0x210000cd }, + { 0x502f8, 0x23800020 }, + { 0x5fffc, 0x220000ce }, + { 0x502fc, 0x2300001d }, +}; + +static struct mdp_table_entry mdp_downscale_x_table_PT6TOPT8[] = { + { 0x5fffc, 0xfe000070 }, + { 0x50280, 0x4bc00068 }, + { 0x5fffc, 0xfe000078 }, + { 0x50284, 0x4bc00060 }, + { 0x5fffc, 0xfe000080 }, + { 0x50288, 0x4b800059 }, + { 0x5fffc, 0xfe000089 }, + { 0x5028c, 0x4b000052 }, + { 0x5fffc, 0xfe400091 }, + { 0x50290, 0x4a80004b }, + { 0x5fffc, 0xfe40009a }, + { 0x50294, 0x4a000044 }, + { 0x5fffc, 0xfe8000a3 }, + { 0x50298, 0x4940003d }, + { 0x5fffc, 0xfec000ac }, + { 0x5029c, 0x48400037 }, + { 0x5fffc, 0xff0000b4 }, + { 0x502a0, 0x47800031 }, + { 0x5fffc, 0xff8000bd }, + { 0x502a4, 0x4640002b }, + { 0x5fffc, 0xc5 }, + { 0x502a8, 0x45000026 }, + { 0x5fffc, 0x8000ce }, + { 0x502ac, 0x43800021 }, + { 0x5fffc, 0x10000d6 }, + { 0x502b0, 0x4240001c }, + { 0x5fffc, 0x18000df }, + { 0x502b4, 0x40800018 }, + { 0x5fffc, 0x24000e6 }, + { 0x502b8, 0x3f000014 }, + { 0x5fffc, 0x30000ee }, + { 0x502bc, 0x3d400010 }, + { 0x5fffc, 0x40000f5 }, + { 0x502c0, 0x3b80000c }, + { 0x5fffc, 0x50000fc }, + { 0x502c4, 0x39800009 }, + { 0x5fffc, 0x6000102 }, + { 0x502c8, 0x37c00006 }, + { 0x5fffc, 0x7000109 }, + { 0x502cc, 0x35800004 }, + { 0x5fffc, 0x840010e }, + { 0x502d0, 0x33800002 }, + { 0x5fffc, 0x9800114 }, + { 0x502d4, 0x31400000 }, + { 0x5fffc, 0xac00119 }, + { 0x502d8, 0x2f4003fe }, + { 0x5fffc, 0xc40011e }, + { 0x502dc, 0x2d0003fc }, + { 0x5fffc, 0xdc00121 }, + { 0x502e0, 0x2b0003fb }, + { 0x5fffc, 0xf400125 }, + { 0x502e4, 0x28c003fa }, + { 0x5fffc, 0x11000128 }, + { 0x502e8, 0x268003f9 }, + { 0x5fffc, 0x12c0012a }, + { 0x502ec, 0x244003f9 }, + { 0x5fffc, 0x1480012c }, + { 0x502f0, 0x224003f8 }, + { 0x5fffc, 0x1640012e }, + { 0x502f4, 0x200003f8 }, + { 0x5fffc, 0x1800012f }, + { 0x502f8, 0x1e0003f8 }, + { 0x5fffc, 0x1a00012f }, + { 0x502fc, 0x1c0003f8 }, +}; + +static struct mdp_table_entry mdp_downscale_x_table_PT8TO1[] = { + { 0x5fffc, 0x0 }, + { 0x50280, 0x7fc00000 }, + { 0x5fffc, 0xff80000d }, + { 0x50284, 0x7ec003f9 }, + { 0x5fffc, 0xfec0001c }, + { 0x50288, 0x7d4003f3 }, + { 0x5fffc, 0xfe40002b }, + { 0x5028c, 0x7b8003ed }, + { 0x5fffc, 0xfd80003c }, + { 0x50290, 0x794003e8 }, + { 0x5fffc, 0xfcc0004d }, + { 0x50294, 0x76c003e4 }, + { 0x5fffc, 0xfc40005f }, + { 0x50298, 0x73c003e0 }, + { 0x5fffc, 0xfb800071 }, + { 0x5029c, 0x708003de }, + { 0x5fffc, 0xfac00085 }, + { 0x502a0, 0x6d0003db }, + { 0x5fffc, 0xfa000098 }, + { 0x502a4, 0x698003d9 }, + { 0x5fffc, 0xf98000ac }, + { 0x502a8, 0x654003d8 }, + { 0x5fffc, 0xf8c000c1 }, + { 0x502ac, 0x610003d7 }, + { 0x5fffc, 0xf84000d5 }, + { 0x502b0, 0x5c8003d7 }, + { 0x5fffc, 0xf7c000e9 }, + { 0x502b4, 0x580003d7 }, + { 0x5fffc, 0xf74000fd }, + { 0x502b8, 0x534003d8 }, + { 0x5fffc, 0xf6c00112 }, + { 0x502bc, 0x4e8003d8 }, + { 0x5fffc, 0xf6800126 }, + { 0x502c0, 0x494003da }, + { 0x5fffc, 0xf600013a }, + { 0x502c4, 0x448003db }, + { 0x5fffc, 0xf600014d }, + { 0x502c8, 0x3f4003dd }, + { 0x5fffc, 0xf5c00160 }, + { 0x502cc, 0x3a4003df }, + { 0x5fffc, 0xf5c00172 }, + { 0x502d0, 0x354003e1 }, + { 0x5fffc, 0xf5c00184 }, + { 0x502d4, 0x304003e3 }, + { 0x5fffc, 0xf6000195 }, + { 0x502d8, 0x2b0003e6 }, + { 0x5fffc, 0xf64001a6 }, + { 0x502dc, 0x260003e8 }, + { 0x5fffc, 0xf6c001b4 }, + { 0x502e0, 0x214003eb }, + { 0x5fffc, 0xf78001c2 }, + { 0x502e4, 0x1c4003ee }, + { 0x5fffc, 0xf80001cf }, + { 0x502e8, 0x17c003f1 }, + { 0x5fffc, 0xf90001db }, + { 0x502ec, 0x134003f3 }, + { 0x5fffc, 0xfa0001e5 }, + { 0x502f0, 0xf0003f6 }, + { 0x5fffc, 0xfb4001ee }, + { 0x502f4, 0xac003f9 }, + { 0x5fffc, 0xfcc001f5 }, + { 0x502f8, 0x70003fb }, + { 0x5fffc, 0xfe4001fb }, + { 0x502fc, 0x34003fe }, +}; + +struct mdp_table_entry *mdp_downscale_x_table[MDP_DOWNSCALE_MAX] = { + [MDP_DOWNSCALE_PT2TOPT4] = mdp_downscale_x_table_PT2TOPT4, + [MDP_DOWNSCALE_PT4TOPT6] = mdp_downscale_x_table_PT4TOPT6, + [MDP_DOWNSCALE_PT6TOPT8] = mdp_downscale_x_table_PT6TOPT8, + [MDP_DOWNSCALE_PT8TO1] = mdp_downscale_x_table_PT8TO1, +}; + +static struct mdp_table_entry mdp_downscale_y_table_PT2TOPT4[] = { + { 0x5fffc, 0x740008c }, + { 0x50300, 0x33800088 }, + { 0x5fffc, 0x800008e }, + { 0x50304, 0x33400084 }, + { 0x5fffc, 0x8400092 }, + { 0x50308, 0x33000080 }, + { 0x5fffc, 0x9000094 }, + { 0x5030c, 0x3300007b }, + { 0x5fffc, 0x9c00098 }, + { 0x50310, 0x32400077 }, + { 0x5fffc, 0xa40009b }, + { 0x50314, 0x32000073 }, + { 0x5fffc, 0xb00009d }, + { 0x50318, 0x31c0006f }, + { 0x5fffc, 0xbc000a0 }, + { 0x5031c, 0x3140006b }, + { 0x5fffc, 0xc8000a2 }, + { 0x50320, 0x31000067 }, + { 0x5fffc, 0xd8000a5 }, + { 0x50324, 0x30800062 }, + { 0x5fffc, 0xe4000a8 }, + { 0x50328, 0x2fc0005f }, + { 0x5fffc, 0xec000aa }, + { 0x5032c, 0x2fc0005b }, + { 0x5fffc, 0xf8000ad }, + { 0x50330, 0x2f400057 }, + { 0x5fffc, 0x108000b0 }, + { 0x50334, 0x2e400054 }, + { 0x5fffc, 0x114000b2 }, + { 0x50338, 0x2e000050 }, + { 0x5fffc, 0x124000b4 }, + { 0x5033c, 0x2d80004c }, + { 0x5fffc, 0x130000b6 }, + { 0x50340, 0x2d000049 }, + { 0x5fffc, 0x140000b8 }, + { 0x50344, 0x2c800045 }, + { 0x5fffc, 0x150000b9 }, + { 0x50348, 0x2c000042 }, + { 0x5fffc, 0x15c000bd }, + { 0x5034c, 0x2b40003e }, + { 0x5fffc, 0x16c000bf }, + { 0x50350, 0x2a80003b }, + { 0x5fffc, 0x17c000bf }, + { 0x50354, 0x2a000039 }, + { 0x5fffc, 0x188000c2 }, + { 0x50358, 0x29400036 }, + { 0x5fffc, 0x19c000c4 }, + { 0x5035c, 0x28800032 }, + { 0x5fffc, 0x1ac000c5 }, + { 0x50360, 0x2800002f }, + { 0x5fffc, 0x1bc000c7 }, + { 0x50364, 0x2740002c }, + { 0x5fffc, 0x1cc000c8 }, + { 0x50368, 0x26c00029 }, + { 0x5fffc, 0x1dc000c9 }, + { 0x5036c, 0x26000027 }, + { 0x5fffc, 0x1ec000cc }, + { 0x50370, 0x25000024 }, + { 0x5fffc, 0x200000cc }, + { 0x50374, 0x24800021 }, + { 0x5fffc, 0x210000cd }, + { 0x50378, 0x23800020 }, + { 0x5fffc, 0x220000ce }, + { 0x5037c, 0x2300001d }, +}; + +static struct mdp_table_entry mdp_downscale_y_table_PT4TOPT6[] = { + { 0x5fffc, 0x740008c }, + { 0x50300, 0x33800088 }, + { 0x5fffc, 0x800008e }, + { 0x50304, 0x33400084 }, + { 0x5fffc, 0x8400092 }, + { 0x50308, 0x33000080 }, + { 0x5fffc, 0x9000094 }, + { 0x5030c, 0x3300007b }, + { 0x5fffc, 0x9c00098 }, + { 0x50310, 0x32400077 }, + { 0x5fffc, 0xa40009b }, + { 0x50314, 0x32000073 }, + { 0x5fffc, 0xb00009d }, + { 0x50318, 0x31c0006f }, + { 0x5fffc, 0xbc000a0 }, + { 0x5031c, 0x3140006b }, + { 0x5fffc, 0xc8000a2 }, + { 0x50320, 0x31000067 }, + { 0x5fffc, 0xd8000a5 }, + { 0x50324, 0x30800062 }, + { 0x5fffc, 0xe4000a8 }, + { 0x50328, 0x2fc0005f }, + { 0x5fffc, 0xec000aa }, + { 0x5032c, 0x2fc0005b }, + { 0x5fffc, 0xf8000ad }, + { 0x50330, 0x2f400057 }, + { 0x5fffc, 0x108000b0 }, + { 0x50334, 0x2e400054 }, + { 0x5fffc, 0x114000b2 }, + { 0x50338, 0x2e000050 }, + { 0x5fffc, 0x124000b4 }, + { 0x5033c, 0x2d80004c }, + { 0x5fffc, 0x130000b6 }, + { 0x50340, 0x2d000049 }, + { 0x5fffc, 0x140000b8 }, + { 0x50344, 0x2c800045 }, + { 0x5fffc, 0x150000b9 }, + { 0x50348, 0x2c000042 }, + { 0x5fffc, 0x15c000bd }, + { 0x5034c, 0x2b40003e }, + { 0x5fffc, 0x16c000bf }, + { 0x50350, 0x2a80003b }, + { 0x5fffc, 0x17c000bf }, + { 0x50354, 0x2a000039 }, + { 0x5fffc, 0x188000c2 }, + { 0x50358, 0x29400036 }, + { 0x5fffc, 0x19c000c4 }, + { 0x5035c, 0x28800032 }, + { 0x5fffc, 0x1ac000c5 }, + { 0x50360, 0x2800002f }, + { 0x5fffc, 0x1bc000c7 }, + { 0x50364, 0x2740002c }, + { 0x5fffc, 0x1cc000c8 }, + { 0x50368, 0x26c00029 }, + { 0x5fffc, 0x1dc000c9 }, + { 0x5036c, 0x26000027 }, + { 0x5fffc, 0x1ec000cc }, + { 0x50370, 0x25000024 }, + { 0x5fffc, 0x200000cc }, + { 0x50374, 0x24800021 }, + { 0x5fffc, 0x210000cd }, + { 0x50378, 0x23800020 }, + { 0x5fffc, 0x220000ce }, + { 0x5037c, 0x2300001d }, +}; + +static struct mdp_table_entry mdp_downscale_y_table_PT6TOPT8[] = { + { 0x5fffc, 0xfe000070 }, + { 0x50300, 0x4bc00068 }, + { 0x5fffc, 0xfe000078 }, + { 0x50304, 0x4bc00060 }, + { 0x5fffc, 0xfe000080 }, + { 0x50308, 0x4b800059 }, + { 0x5fffc, 0xfe000089 }, + { 0x5030c, 0x4b000052 }, + { 0x5fffc, 0xfe400091 }, + { 0x50310, 0x4a80004b }, + { 0x5fffc, 0xfe40009a }, + { 0x50314, 0x4a000044 }, + { 0x5fffc, 0xfe8000a3 }, + { 0x50318, 0x4940003d }, + { 0x5fffc, 0xfec000ac }, + { 0x5031c, 0x48400037 }, + { 0x5fffc, 0xff0000b4 }, + { 0x50320, 0x47800031 }, + { 0x5fffc, 0xff8000bd }, + { 0x50324, 0x4640002b }, + { 0x5fffc, 0xc5 }, + { 0x50328, 0x45000026 }, + { 0x5fffc, 0x8000ce }, + { 0x5032c, 0x43800021 }, + { 0x5fffc, 0x10000d6 }, + { 0x50330, 0x4240001c }, + { 0x5fffc, 0x18000df }, + { 0x50334, 0x40800018 }, + { 0x5fffc, 0x24000e6 }, + { 0x50338, 0x3f000014 }, + { 0x5fffc, 0x30000ee }, + { 0x5033c, 0x3d400010 }, + { 0x5fffc, 0x40000f5 }, + { 0x50340, 0x3b80000c }, + { 0x5fffc, 0x50000fc }, + { 0x50344, 0x39800009 }, + { 0x5fffc, 0x6000102 }, + { 0x50348, 0x37c00006 }, + { 0x5fffc, 0x7000109 }, + { 0x5034c, 0x35800004 }, + { 0x5fffc, 0x840010e }, + { 0x50350, 0x33800002 }, + { 0x5fffc, 0x9800114 }, + { 0x50354, 0x31400000 }, + { 0x5fffc, 0xac00119 }, + { 0x50358, 0x2f4003fe }, + { 0x5fffc, 0xc40011e }, + { 0x5035c, 0x2d0003fc }, + { 0x5fffc, 0xdc00121 }, + { 0x50360, 0x2b0003fb }, + { 0x5fffc, 0xf400125 }, + { 0x50364, 0x28c003fa }, + { 0x5fffc, 0x11000128 }, + { 0x50368, 0x268003f9 }, + { 0x5fffc, 0x12c0012a }, + { 0x5036c, 0x244003f9 }, + { 0x5fffc, 0x1480012c }, + { 0x50370, 0x224003f8 }, + { 0x5fffc, 0x1640012e }, + { 0x50374, 0x200003f8 }, + { 0x5fffc, 0x1800012f }, + { 0x50378, 0x1e0003f8 }, + { 0x5fffc, 0x1a00012f }, + { 0x5037c, 0x1c0003f8 }, +}; + +static struct mdp_table_entry mdp_downscale_y_table_PT8TO1[] = { + { 0x5fffc, 0x0 }, + { 0x50300, 0x7fc00000 }, + { 0x5fffc, 0xff80000d }, + { 0x50304, 0x7ec003f9 }, + { 0x5fffc, 0xfec0001c }, + { 0x50308, 0x7d4003f3 }, + { 0x5fffc, 0xfe40002b }, + { 0x5030c, 0x7b8003ed }, + { 0x5fffc, 0xfd80003c }, + { 0x50310, 0x794003e8 }, + { 0x5fffc, 0xfcc0004d }, + { 0x50314, 0x76c003e4 }, + { 0x5fffc, 0xfc40005f }, + { 0x50318, 0x73c003e0 }, + { 0x5fffc, 0xfb800071 }, + { 0x5031c, 0x708003de }, + { 0x5fffc, 0xfac00085 }, + { 0x50320, 0x6d0003db }, + { 0x5fffc, 0xfa000098 }, + { 0x50324, 0x698003d9 }, + { 0x5fffc, 0xf98000ac }, + { 0x50328, 0x654003d8 }, + { 0x5fffc, 0xf8c000c1 }, + { 0x5032c, 0x610003d7 }, + { 0x5fffc, 0xf84000d5 }, + { 0x50330, 0x5c8003d7 }, + { 0x5fffc, 0xf7c000e9 }, + { 0x50334, 0x580003d7 }, + { 0x5fffc, 0xf74000fd }, + { 0x50338, 0x534003d8 }, + { 0x5fffc, 0xf6c00112 }, + { 0x5033c, 0x4e8003d8 }, + { 0x5fffc, 0xf6800126 }, + { 0x50340, 0x494003da }, + { 0x5fffc, 0xf600013a }, + { 0x50344, 0x448003db }, + { 0x5fffc, 0xf600014d }, + { 0x50348, 0x3f4003dd }, + { 0x5fffc, 0xf5c00160 }, + { 0x5034c, 0x3a4003df }, + { 0x5fffc, 0xf5c00172 }, + { 0x50350, 0x354003e1 }, + { 0x5fffc, 0xf5c00184 }, + { 0x50354, 0x304003e3 }, + { 0x5fffc, 0xf6000195 }, + { 0x50358, 0x2b0003e6 }, + { 0x5fffc, 0xf64001a6 }, + { 0x5035c, 0x260003e8 }, + { 0x5fffc, 0xf6c001b4 }, + { 0x50360, 0x214003eb }, + { 0x5fffc, 0xf78001c2 }, + { 0x50364, 0x1c4003ee }, + { 0x5fffc, 0xf80001cf }, + { 0x50368, 0x17c003f1 }, + { 0x5fffc, 0xf90001db }, + { 0x5036c, 0x134003f3 }, + { 0x5fffc, 0xfa0001e5 }, + { 0x50370, 0xf0003f6 }, + { 0x5fffc, 0xfb4001ee }, + { 0x50374, 0xac003f9 }, + { 0x5fffc, 0xfcc001f5 }, + { 0x50378, 0x70003fb }, + { 0x5fffc, 0xfe4001fb }, + { 0x5037c, 0x34003fe }, +}; + +struct mdp_table_entry *mdp_downscale_y_table[MDP_DOWNSCALE_MAX] = { + [MDP_DOWNSCALE_PT2TOPT4] = mdp_downscale_y_table_PT2TOPT4, + [MDP_DOWNSCALE_PT4TOPT6] = mdp_downscale_y_table_PT4TOPT6, + [MDP_DOWNSCALE_PT6TOPT8] = mdp_downscale_y_table_PT6TOPT8, + [MDP_DOWNSCALE_PT8TO1] = mdp_downscale_y_table_PT8TO1, +}; + +struct mdp_table_entry mdp_gaussian_blur_table[] = { + /* max variance */ + { 0x5fffc, 0x20000080 }, + { 0x50280, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50284, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50288, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5028c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50290, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50294, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50298, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5029c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502a0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502a4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502a8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502ac, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502b0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502b4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502b8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502bc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502c0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502c4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502c8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502cc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502d0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502d4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502d8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502dc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502e0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502e4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502e8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502ec, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502f0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502f4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502f8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502fc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50300, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50304, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50308, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5030c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50310, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50314, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50318, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5031c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50320, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50324, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50328, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5032c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50330, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50334, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50338, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5033c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50340, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50344, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50348, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5034c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50350, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50354, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50358, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5035c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50360, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50364, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50368, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5036c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50370, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50374, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50378, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5037c, 0x20000080 }, +}; + +static void load_table(const struct mdp_info *mdp, + struct mdp_table_entry *table, int len) +{ + int i; + for (i = 0; i < len; i++) + mdp_writel(mdp, table[i].val, table[i].reg); +} + +enum { + IMG_LEFT, + IMG_RIGHT, + IMG_TOP, + IMG_BOTTOM, +}; + +static void get_edge_info(uint32_t src, uint32_t src_coord, uint32_t dst, + uint32_t *interp1, uint32_t *interp2, + uint32_t *repeat1, uint32_t *repeat2) { + if (src > 3 * dst) { + *interp1 = 0; + *interp2 = src - 1; + *repeat1 = 0; + *repeat2 = 0; + } else if (src == 3 * dst) { + *interp1 = 0; + *interp2 = src; + *repeat1 = 0; + *repeat2 = 1; + } else if (src > dst && src < 3 * dst) { + *interp1 = -1; + *interp2 = src; + *repeat1 = 1; + *repeat2 = 1; + } else if (src == dst) { + *interp1 = -1; + *interp2 = src + 1; + *repeat1 = 1; + *repeat2 = 2; + } else { + *interp1 = -2; + *interp2 = src + 1; + *repeat1 = 2; + *repeat2 = 2; + } + *interp1 += src_coord; + *interp2 += src_coord; +} + +int mdp_ppp_cfg_edge_cond(struct mdp_blit_req *req, struct ppp_regs *regs) +{ + int32_t luma_interp[4]; + int32_t luma_repeat[4]; + int32_t chroma_interp[4]; + int32_t chroma_bound[4]; + int32_t chroma_repeat[4]; + uint32_t dst_w, dst_h; + + memset(&luma_interp, 0, sizeof(int32_t) * 4); + memset(&luma_repeat, 0, sizeof(int32_t) * 4); + memset(&chroma_interp, 0, sizeof(int32_t) * 4); + memset(&chroma_bound, 0, sizeof(int32_t) * 4); + memset(&chroma_repeat, 0, sizeof(int32_t) * 4); + regs->edge = 0; + + if (req->flags & MDP_ROT_90) { + dst_w = req->dst_rect.h; + dst_h = req->dst_rect.w; + } else { + dst_w = req->dst_rect.w; + dst_h = req->dst_rect.h; + } + + if (regs->op & (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON)) { + get_edge_info(req->src_rect.h, req->src_rect.y, dst_h, + &luma_interp[IMG_TOP], &luma_interp[IMG_BOTTOM], + &luma_repeat[IMG_TOP], &luma_repeat[IMG_BOTTOM]); + get_edge_info(req->src_rect.w, req->src_rect.x, dst_w, + &luma_interp[IMG_LEFT], &luma_interp[IMG_RIGHT], + &luma_repeat[IMG_LEFT], &luma_repeat[IMG_RIGHT]); + } else { + luma_interp[IMG_LEFT] = req->src_rect.x; + luma_interp[IMG_RIGHT] = req->src_rect.x + req->src_rect.w - 1; + luma_interp[IMG_TOP] = req->src_rect.y; + luma_interp[IMG_BOTTOM] = req->src_rect.y + req->src_rect.h - 1; + luma_repeat[IMG_LEFT] = 0; + luma_repeat[IMG_TOP] = 0; + luma_repeat[IMG_RIGHT] = 0; + luma_repeat[IMG_BOTTOM] = 0; + } + + chroma_interp[IMG_LEFT] = luma_interp[IMG_LEFT]; + chroma_interp[IMG_RIGHT] = luma_interp[IMG_RIGHT]; + chroma_interp[IMG_TOP] = luma_interp[IMG_TOP]; + chroma_interp[IMG_BOTTOM] = luma_interp[IMG_BOTTOM]; + + chroma_bound[IMG_LEFT] = req->src_rect.x; + chroma_bound[IMG_RIGHT] = req->src_rect.x + req->src_rect.w - 1; + chroma_bound[IMG_TOP] = req->src_rect.y; + chroma_bound[IMG_BOTTOM] = req->src_rect.y + req->src_rect.h - 1; + + if (IS_YCRCB(req->src.format)) { + chroma_interp[IMG_LEFT] = chroma_interp[IMG_LEFT] >> 1; + chroma_interp[IMG_RIGHT] = (chroma_interp[IMG_RIGHT] + 1) >> 1; + + chroma_bound[IMG_LEFT] = chroma_bound[IMG_LEFT] >> 1; + chroma_bound[IMG_RIGHT] = chroma_bound[IMG_RIGHT] >> 1; + } + + if (req->src.format == MDP_Y_CBCR_H2V2 || + req->src.format == MDP_Y_CRCB_H2V2) { + chroma_interp[IMG_TOP] = (chroma_interp[IMG_TOP] - 1) >> 1; + chroma_interp[IMG_BOTTOM] = (chroma_interp[IMG_BOTTOM] + 1) + >> 1; + chroma_bound[IMG_TOP] = (chroma_bound[IMG_TOP] + 1) >> 1; + chroma_bound[IMG_BOTTOM] = chroma_bound[IMG_BOTTOM] >> 1; + } + + chroma_repeat[IMG_LEFT] = chroma_bound[IMG_LEFT] - + chroma_interp[IMG_LEFT]; + chroma_repeat[IMG_RIGHT] = chroma_interp[IMG_RIGHT] - + chroma_bound[IMG_RIGHT]; + chroma_repeat[IMG_TOP] = chroma_bound[IMG_TOP] - + chroma_interp[IMG_TOP]; + chroma_repeat[IMG_BOTTOM] = chroma_interp[IMG_BOTTOM] - + chroma_bound[IMG_BOTTOM]; + + if (chroma_repeat[IMG_LEFT] < 0 || chroma_repeat[IMG_LEFT] > 3 || + chroma_repeat[IMG_RIGHT] < 0 || chroma_repeat[IMG_RIGHT] > 3 || + chroma_repeat[IMG_TOP] < 0 || chroma_repeat[IMG_TOP] > 3 || + chroma_repeat[IMG_BOTTOM] < 0 || chroma_repeat[IMG_BOTTOM] > 3 || + luma_repeat[IMG_LEFT] < 0 || luma_repeat[IMG_LEFT] > 3 || + luma_repeat[IMG_RIGHT] < 0 || luma_repeat[IMG_RIGHT] > 3 || + luma_repeat[IMG_TOP] < 0 || luma_repeat[IMG_TOP] > 3 || + luma_repeat[IMG_BOTTOM] < 0 || luma_repeat[IMG_BOTTOM] > 3) + return -1; + + regs->edge |= (chroma_repeat[IMG_LEFT] & 3) << MDP_LEFT_CHROMA; + regs->edge |= (chroma_repeat[IMG_RIGHT] & 3) << MDP_RIGHT_CHROMA; + regs->edge |= (chroma_repeat[IMG_TOP] & 3) << MDP_TOP_CHROMA; + regs->edge |= (chroma_repeat[IMG_BOTTOM] & 3) << MDP_BOTTOM_CHROMA; + regs->edge |= (luma_repeat[IMG_LEFT] & 3) << MDP_LEFT_LUMA; + regs->edge |= (luma_repeat[IMG_RIGHT] & 3) << MDP_RIGHT_LUMA; + regs->edge |= (luma_repeat[IMG_TOP] & 3) << MDP_TOP_LUMA; + regs->edge |= (luma_repeat[IMG_BOTTOM] & 3) << MDP_BOTTOM_LUMA; + return 0; +} + +#define ONE_HALF (1LL << 32) +#define ONE (1LL << 33) +#define TWO (2LL << 33) +#define THREE (3LL << 33) +#define FRAC_MASK (ONE - 1) +#define INT_MASK (~FRAC_MASK) + +static int scale_params(uint32_t dim_in, uint32_t dim_out, uint32_t origin, + uint32_t *phase_init, uint32_t *phase_step) +{ + /* to improve precicsion calculations are done in U31.33 and converted + * to U3.29 at the end */ + int64_t k1, k2, k3, k4, tmp; + uint64_t n, d, os, os_p, od, od_p, oreq; + unsigned rpa = 0; + int64_t ip64, delta; + + if (dim_out % 3 == 0) + rpa = !(dim_in % (dim_out / 3)); + + n = ((uint64_t)dim_out) << 34; + d = dim_in; + if (!d) + return -1; + do_div(n, d); + k3 = (n + 1) >> 1; + if ((k3 >> 4) < (1LL << 27) || (k3 >> 4) > (1LL << 31)) + return -1; + + n = ((uint64_t)dim_in) << 34; + d = (uint64_t)dim_out; + if (!d) + return -1; + do_div(n, d); + k1 = (n + 1) >> 1; + k2 = (k1 - ONE) >> 1; + + *phase_init = (int)(k2 >> 4); + k4 = (k3 - ONE) >> 1; + + if (rpa) { + os = ((uint64_t)origin << 33) - ONE_HALF; + tmp = (dim_out * os) + ONE_HALF; + if (!dim_in) + return -1; + do_div(tmp, dim_in); + od = tmp - ONE_HALF; + } else { + os = ((uint64_t)origin << 1) - 1; + od = (((k3 * os) >> 1) + k4); + } + + od_p = od & INT_MASK; + if (od_p != od) + od_p += ONE; + + if (rpa) { + tmp = (dim_in * od_p) + ONE_HALF; + if (!dim_in) + return -1; + do_div(tmp, dim_in); + os_p = tmp - ONE_HALF; + } else { + os_p = ((k1 * (od_p >> 33)) + k2); + } + + oreq = (os_p & INT_MASK) - ONE; + + ip64 = os_p - oreq; + delta = ((int64_t)(origin) << 33) - oreq; + ip64 -= delta; + /* limit to valid range before the left shift */ + delta = (ip64 & (1LL << 63)) ? 4 : -4; + delta <<= 33; + while (abs((int)(ip64 >> 33)) > 4) + ip64 += delta; + *phase_init = (int)(ip64 >> 4); + *phase_step = (uint32_t)(k1 >> 4); + return 0; +} + +int mdp_ppp_cfg_scale(const struct mdp_info *mdp, struct ppp_regs *regs, + struct mdp_rect *src_rect, struct mdp_rect *dst_rect, + uint32_t src_format, uint32_t dst_format) +{ + int downscale; + uint32_t phase_init_x, phase_init_y, phase_step_x, phase_step_y; + uint32_t scale_factor_x, scale_factor_y; + + if (scale_params(src_rect->w, dst_rect->w, 1, &phase_init_x, + &phase_step_x) || + scale_params(src_rect->h, dst_rect->h, 1, &phase_init_y, + &phase_step_y)) + return -1; + + regs->phasex_init = phase_init_x; + regs->phasey_init = phase_init_y; + regs->phasex_step = phase_step_x; + regs->phasey_step = phase_step_y; + + scale_factor_x = (dst_rect->w * 10) / src_rect->w; + scale_factor_y = (dst_rect->h * 10) / src_rect->h; + + if (scale_factor_x > 8) + downscale = MDP_DOWNSCALE_PT8TO1; + else if (scale_factor_x > 6) + downscale = MDP_DOWNSCALE_PT6TOPT8; + else if (scale_factor_x > 4) + downscale = MDP_DOWNSCALE_PT4TOPT6; + else + downscale = MDP_DOWNSCALE_PT2TOPT4; + + if (downscale != downscale_x_table) { + load_table(mdp, mdp_downscale_x_table[downscale], 64); + downscale_x_table = downscale; + } + + if (scale_factor_y > 8) + downscale = MDP_DOWNSCALE_PT8TO1; + else if (scale_factor_y > 6) + downscale = MDP_DOWNSCALE_PT6TOPT8; + else if (scale_factor_y > 4) + downscale = MDP_DOWNSCALE_PT4TOPT6; + else + downscale = MDP_DOWNSCALE_PT2TOPT4; + + if (downscale != downscale_y_table) { + load_table(mdp, mdp_downscale_y_table[downscale], 64); + downscale_y_table = downscale; + } + + return 0; +} + + +int mdp_ppp_load_blur(const struct mdp_info *mdp) +{ + if (!(downscale_x_table == MDP_DOWNSCALE_BLUR && + downscale_y_table == MDP_DOWNSCALE_BLUR)) { + load_table(mdp, mdp_gaussian_blur_table, 128); + downscale_x_table = MDP_DOWNSCALE_BLUR; + downscale_y_table = MDP_DOWNSCALE_BLUR; + } + + return 0; +} + +void mdp_ppp_init_scale(const struct mdp_info *mdp) +{ + downscale_x_table = MDP_DOWNSCALE_MAX; + downscale_y_table = MDP_DOWNSCALE_MAX; + + load_table(mdp, mdp_upscale_table, ARRAY_SIZE(mdp_upscale_table)); +} diff --git a/drivers/video/msm/mdp_ppp31.c b/drivers/video/msm/mdp_ppp31.c new file mode 100644 index 000000000000..2d28358fe2df --- /dev/null +++ b/drivers/video/msm/mdp_ppp31.c @@ -0,0 +1,332 @@ +/* drivers/video/msm/mdp_ppp31.c + * + * Copyright (C) 2009 The Linux Foundation. All rights reserved. + * Copyright (C) 2009 Google Incorporated + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include "mdp_hw.h" +#include "mdp_ppp.h" + +#define NUM_COEFFS 32 + +struct mdp_scale_coeffs { + uint16_t c[4][NUM_COEFFS]; +}; + +struct mdp_scale_tbl_info { + uint16_t offset; + uint32_t set:2; + int use_pr; + struct mdp_scale_coeffs coeffs; +}; + +enum { + MDP_SCALE_PT2TOPT4, + MDP_SCALE_PT4TOPT6, + MDP_SCALE_PT6TOPT8, + MDP_SCALE_PT8TO8, + MDP_SCALE_MAX, +}; + +static struct mdp_scale_coeffs mdp_scale_pr_coeffs = { + .c = { + [0] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }, + [1] = { + 511, 511, 511, 511, 511, 511, 511, 511, + 511, 511, 511, 511, 511, 511, 511, 511, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }, + [2] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 511, 511, 511, 511, 511, 511, 511, 511, + 511, 511, 511, 511, 511, 511, 511, 511, + }, + [3] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }, + }, +}; + +static struct mdp_scale_tbl_info mdp_scale_tbl[MDP_SCALE_MAX] = { + [ MDP_SCALE_PT2TOPT4 ] = { + .offset = 0, + .set = MDP_PPP_SCALE_COEFF_D0_SET, + .use_pr = -1, + .coeffs.c = { + [0] = { + 131, 131, 130, 129, 128, 127, 127, 126, + 125, 125, 124, 123, 123, 121, 120, 119, + 119, 118, 117, 117, 116, 115, 115, 114, + 113, 112, 111, 110, 109, 109, 108, 107, + }, + [1] = { + 141, 140, 140, 140, 140, 139, 138, 138, + 138, 137, 137, 137, 136, 137, 137, 137, + 136, 136, 136, 135, 135, 135, 134, 134, + 134, 134, 134, 133, 133, 132, 132, 132, + }, + [2] = { + 132, 132, 132, 133, 133, 134, 134, 134, + 134, 134, 135, 135, 135, 136, 136, 136, + 137, 137, 137, 136, 137, 137, 137, 138, + 138, 138, 139, 140, 140, 140, 140, 141, + }, + [3] = { + 107, 108, 109, 109, 110, 111, 112, 113, + 114, 115, 115, 116, 117, 117, 118, 119, + 119, 120, 121, 123, 123, 124, 125, 125, + 126, 127, 127, 128, 129, 130, 131, 131, + } + }, + }, + [ MDP_SCALE_PT4TOPT6 ] = { + .offset = 32, + .set = MDP_PPP_SCALE_COEFF_D1_SET, + .use_pr = -1, + .coeffs.c = { + [0] = { + 136, 132, 128, 123, 119, 115, 111, 107, + 103, 98, 95, 91, 87, 84, 80, 76, + 73, 69, 66, 62, 59, 57, 54, 50, + 47, 44, 41, 39, 36, 33, 32, 29, + }, + [1] = { + 206, 205, 204, 204, 201, 200, 199, 197, + 196, 194, 191, 191, 189, 185, 184, 182, + 180, 178, 176, 173, 170, 168, 165, 162, + 160, 157, 155, 152, 148, 146, 142, 140, + }, + [2] = { + 140, 142, 146, 148, 152, 155, 157, 160, + 162, 165, 168, 170, 173, 176, 178, 180, + 182, 184, 185, 189, 191, 191, 194, 196, + 197, 199, 200, 201, 204, 204, 205, 206, + }, + [3] = { + 29, 32, 33, 36, 39, 41, 44, 47, + 50, 54, 57, 59, 62, 66, 69, 73, + 76, 80, 84, 87, 91, 95, 98, 103, + 107, 111, 115, 119, 123, 128, 132, 136, + }, + }, + }, + [ MDP_SCALE_PT6TOPT8 ] = { + .offset = 64, + .set = MDP_PPP_SCALE_COEFF_D2_SET, + .use_pr = -1, + .coeffs.c = { + [0] = { + 104, 96, 89, 82, 75, 68, 61, 55, + 49, 43, 38, 33, 28, 24, 20, 16, + 12, 9, 6, 4, 2, 0, -2, -4, + -5, -6, -7, -7, -8, -8, -8, -8, + }, + [1] = { + 303, 303, 302, 300, 298, 296, 293, 289, + 286, 281, 276, 270, 265, 258, 252, 245, + 238, 230, 223, 214, 206, 197, 189, 180, + 172, 163, 154, 145, 137, 128, 120, 112, + }, + [2] = { + 112, 120, 128, 137, 145, 154, 163, 172, + 180, 189, 197, 206, 214, 223, 230, 238, + 245, 252, 258, 265, 270, 276, 281, 286, + 289, 293, 296, 298, 300, 302, 303, 303, + }, + [3] = { + -8, -8, -8, -8, -7, -7, -6, -5, + -4, -2, 0, 2, 4, 6, 9, 12, + 16, 20, 24, 28, 33, 38, 43, 49, + 55, 61, 68, 75, 82, 89, 96, 104, + }, + }, + }, + [ MDP_SCALE_PT8TO8 ] = { + .offset = 96, + .set = MDP_PPP_SCALE_COEFF_U1_SET, + .use_pr = -1, + .coeffs.c = { + [0] = { + 0, -7, -13, -19, -24, -28, -32, -34, + -37, -39, -40, -41, -41, -41, -40, -40, + -38, -37, -35, -33, -31, -29, -26, -24, + -21, -18, -15, -13, -10, -7, -5, -2, + }, + [1] = { + 511, 507, 501, 494, 485, 475, 463, 450, + 436, 422, 405, 388, 370, 352, 333, 314, + 293, 274, 253, 233, 213, 193, 172, 152, + 133, 113, 95, 77, 60, 43, 28, 13, + }, + [2] = { + 0, 13, 28, 43, 60, 77, 95, 113, + 133, 152, 172, 193, 213, 233, 253, 274, + 294, 314, 333, 352, 370, 388, 405, 422, + 436, 450, 463, 475, 485, 494, 501, 507, + }, + [3] = { + 0, -2, -5, -7, -10, -13, -15, -18, + -21, -24, -26, -29, -31, -33, -35, -37, + -38, -40, -40, -41, -41, -41, -40, -39, + -37, -34, -32, -28, -24, -19, -13, -7, + }, + }, + }, +}; + +static void load_table(const struct mdp_info *mdp, int scale, int use_pr) +{ + int i; + uint32_t val; + struct mdp_scale_coeffs *coeffs; + struct mdp_scale_tbl_info *tbl = &mdp_scale_tbl[scale]; + + if (use_pr == tbl->use_pr) + return; + + tbl->use_pr = use_pr; + if (!use_pr) + coeffs = &tbl->coeffs; + else + coeffs = &mdp_scale_pr_coeffs; + + for (i = 0; i < NUM_COEFFS; ++i) { + val = ((coeffs->c[1][i] & 0x3ff) << 16) | + (coeffs->c[0][i] & 0x3ff); + mdp_writel(mdp, val, MDP_PPP_SCALE_COEFF_LSBn(tbl->offset + i)); + + val = ((coeffs->c[3][i] & 0x3ff) << 16) | + (coeffs->c[2][i] & 0x3ff); + mdp_writel(mdp, val, MDP_PPP_SCALE_COEFF_MSBn(tbl->offset + i)); + } +} + +#define SCALER_PHASE_BITS 29 +static void scale_params(uint32_t dim_in, uint32_t dim_out, uint32_t scaler, + uint32_t *phase_init, uint32_t *phase_step) +{ + uint64_t src = dim_in; + uint64_t dst = dim_out; + uint64_t numer; + uint64_t denom; + + *phase_init = 0; + + if (dst == 1) { + /* if destination is 1 pixel wide, the value of phase_step + * is unimportant. */ + *phase_step = (uint32_t) (src << SCALER_PHASE_BITS); + if (scaler == MDP_PPP_SCALER_FIR) + *phase_init = + (uint32_t) ((src - 1) << SCALER_PHASE_BITS); + return; + } + + if (scaler == MDP_PPP_SCALER_FIR) { + numer = (src - 1) << SCALER_PHASE_BITS; + denom = dst - 1; + /* we want to round up the result*/ + numer += denom - 1; + } else { + numer = src << SCALER_PHASE_BITS; + denom = dst; + } + + do_div(numer, denom); + *phase_step = (uint32_t) numer; +} + +static int scale_idx(int factor) +{ + int idx; + + if (factor > 80) + idx = MDP_SCALE_PT8TO8; + else if (factor > 60) + idx = MDP_SCALE_PT6TOPT8; + else if (factor > 40) + idx = MDP_SCALE_PT4TOPT6; + else + idx = MDP_SCALE_PT2TOPT4; + + return idx; +} + +int mdp_ppp_cfg_scale(const struct mdp_info *mdp, struct ppp_regs *regs, + struct mdp_rect *src_rect, struct mdp_rect *dst_rect, + uint32_t src_format, uint32_t dst_format) +{ + uint32_t x_fac; + uint32_t y_fac; + uint32_t scaler_x = MDP_PPP_SCALER_FIR; + uint32_t scaler_y = MDP_PPP_SCALER_FIR; + // Don't use pixel repeat mode, it looks bad + int use_pr = 0; + int x_idx; + int y_idx; + + if (unlikely(src_rect->w > 2048 || src_rect->h > 2048)) + return -ENOTSUPP; + + x_fac = (dst_rect->w * 100) / src_rect->w; + y_fac = (dst_rect->h * 100) / src_rect->h; + + /* if down-scaling by a factor smaller than 1/4, use M/N */ + scaler_x = x_fac <= 25 ? MDP_PPP_SCALER_MN : MDP_PPP_SCALER_FIR; + scaler_y = y_fac <= 25 ? MDP_PPP_SCALER_MN : MDP_PPP_SCALER_FIR; + scale_params(src_rect->w, dst_rect->w, scaler_x, ®s->phasex_init, + ®s->phasex_step); + scale_params(src_rect->h, dst_rect->h, scaler_y, ®s->phasey_init, + ®s->phasey_step); + + x_idx = scale_idx(x_fac); + y_idx = scale_idx(y_fac); + load_table(mdp, x_idx, use_pr); + load_table(mdp, y_idx, use_pr); + + regs->scale_cfg = 0; + // Enable SVI when source or destination is YUV + if (!IS_RGB(src_format) && !IS_RGB(dst_format)) + regs->scale_cfg |= (1 << 6); + regs->scale_cfg |= (mdp_scale_tbl[x_idx].set << 2) | + (mdp_scale_tbl[x_idx].set << 4); + regs->scale_cfg |= (scaler_x << 0) | (scaler_y << 1); + + return 0; +} + +int mdp_ppp_load_blur(const struct mdp_info *mdp) +{ + return -ENOTSUPP; +} + +void mdp_ppp_init_scale(const struct mdp_info *mdp) +{ + int scale; + for (scale = 0; scale < MDP_SCALE_MAX; ++scale) + load_table(mdp, scale, 0); +} diff --git a/drivers/video/msm/mdp_ppp_v20.c b/drivers/video/msm/mdp_ppp_v20.c new file mode 100644 index 000000000000..4062d3abb434 --- /dev/null +++ b/drivers/video/msm/mdp_ppp_v20.c @@ -0,0 +1,2541 @@ +/* Copyright (c) 2008-2009, 2012 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "linux/proc_fs.h" + +#include +#include + +#include +#include +#include +#include + +#include "mdp.h" +#include "msm_fb.h" + +static MDP_SCALE_MODE mdp_curr_up_scale_xy; +static MDP_SCALE_MODE mdp_curr_down_scale_x; +static MDP_SCALE_MODE mdp_curr_down_scale_y; + +static long long mdp_do_div(long long num, long long den) +{ + do_div(num, den); + return num; +} + +struct mdp_table_entry mdp_gaussian_blur_table[] = { + /* max variance */ + { 0x5fffc, 0x20000080 }, + { 0x50280, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50284, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50288, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5028c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50290, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50294, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50298, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5029c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502a0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502a4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502a8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502ac, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502b0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502b4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502b8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502bc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502c0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502c4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502c8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502cc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502d0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502d4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502d8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502dc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502e0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502e4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502e8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502ec, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502f0, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502f4, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502f8, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x502fc, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50300, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50304, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50308, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5030c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50310, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50314, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50318, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5031c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50320, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50324, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50328, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5032c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50330, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50334, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50338, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5033c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50340, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50344, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50348, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5034c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50350, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50354, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50358, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5035c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50360, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50364, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50368, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5036c, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50370, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50374, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x50378, 0x20000080 }, + { 0x5fffc, 0x20000080 }, + { 0x5037c, 0x20000080 }, +}; + +static void load_scale_table( + struct mdp_table_entry *table, int len) +{ + int i; + for (i = 0; i < len; i++) + MDP_OUTP(MDP_BASE + table[i].reg, table[i].val); +} + +static void mdp_load_pr_upscale_table(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50200, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50204, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50208, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5020c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50210, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50214, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50218, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5021c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50220, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50224, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50228, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5022c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50230, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50234, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50238, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5023c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50240, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50244, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50248, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5024c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50250, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50254, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50258, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5025c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50260, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50264, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50268, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5026c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50270, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50274, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50278, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5027c, 0x0); +} + +static void mdp_load_pr_downscale_table_x_point2TOpoint4(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50284, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50288, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5028c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50290, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50294, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50298, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5029c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502ac, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502bc, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502cc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502dc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502ec, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502fc, 0x0); +} + +static void mdp_load_pr_downscale_table_y_point2TOpoint4(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50304, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50308, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5030c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50310, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50314, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50318, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5031c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50320, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50324, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50328, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5032c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50330, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50334, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50338, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5033c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50340, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50344, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50348, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5034c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50350, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50354, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50358, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5035c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50360, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50364, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50368, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5036c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50370, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50374, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50378, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5037c, 0x0); +} + +static void mdp_load_pr_downscale_table_x_point4TOpoint6(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50284, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50288, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5028c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50290, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50294, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50298, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5029c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502ac, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502bc, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502cc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502dc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502ec, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502fc, 0x0); +} + +static void mdp_load_pr_downscale_table_y_point4TOpoint6(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50304, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50308, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5030c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50310, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50314, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50318, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5031c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50320, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50324, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50328, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5032c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50330, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50334, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50338, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5033c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50340, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50344, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50348, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5034c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50350, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50354, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50358, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5035c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50360, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50364, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50368, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5036c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50370, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50374, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50378, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5037c, 0x0); +} + +static void mdp_load_pr_downscale_table_x_point6TOpoint8(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50284, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50288, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5028c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50290, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50294, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50298, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5029c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502ac, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502bc, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502cc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502dc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502ec, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502fc, 0x0); +} + +static void mdp_load_pr_downscale_table_y_point6TOpoint8(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50304, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50308, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5030c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50310, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50314, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50318, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5031c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50320, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50324, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50328, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5032c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50330, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50334, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50338, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5033c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50340, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50344, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50348, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5034c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50350, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50354, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50358, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5035c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50360, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50364, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50368, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5036c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50370, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50374, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50378, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5037c, 0x0); +} + +static void mdp_load_pr_downscale_table_x_point8TO1(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50284, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50288, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5028c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50290, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50294, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50298, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5029c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502a8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502ac, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b0, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b4, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502b8, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x502bc, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502c8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502cc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502d8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502dc, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502e8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502ec, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f0, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f4, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502f8, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x502fc, 0x0); +} + +static void mdp_load_pr_downscale_table_y_point8TO1(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50304, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50308, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5030c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50310, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50314, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50318, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5031c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50320, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50324, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50328, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5032c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50330, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50334, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50338, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x5033c, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50340, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50344, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50348, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5034c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50350, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50354, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50358, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5035c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50360, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50364, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50368, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5036c, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50370, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50374, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x50378, 0x0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff); + MDP_OUTP(MDP_BASE + 0x5037c, 0x0); +} + +static void mdp_load_bc_upscale_table(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50200, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff80000d); + MDP_OUTP(MDP_BASE + 0x50204, 0x7ec003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec0001c); + MDP_OUTP(MDP_BASE + 0x50208, 0x7d4003f3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40002b); + MDP_OUTP(MDP_BASE + 0x5020c, 0x7b8003ed); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfd80003c); + MDP_OUTP(MDP_BASE + 0x50210, 0x794003e8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc0004d); + MDP_OUTP(MDP_BASE + 0x50214, 0x76c003e4); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfc40005f); + MDP_OUTP(MDP_BASE + 0x50218, 0x73c003e0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb800071); + MDP_OUTP(MDP_BASE + 0x5021c, 0x708003de); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfac00085); + MDP_OUTP(MDP_BASE + 0x50220, 0x6d0003db); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa000098); + MDP_OUTP(MDP_BASE + 0x50224, 0x698003d9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf98000ac); + MDP_OUTP(MDP_BASE + 0x50228, 0x654003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8c000c1); + MDP_OUTP(MDP_BASE + 0x5022c, 0x610003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf84000d5); + MDP_OUTP(MDP_BASE + 0x50230, 0x5c8003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf7c000e9); + MDP_OUTP(MDP_BASE + 0x50234, 0x580003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf74000fd); + MDP_OUTP(MDP_BASE + 0x50238, 0x534003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c00112); + MDP_OUTP(MDP_BASE + 0x5023c, 0x4e8003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6800126); + MDP_OUTP(MDP_BASE + 0x50240, 0x494003da); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600013a); + MDP_OUTP(MDP_BASE + 0x50244, 0x448003db); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600014d); + MDP_OUTP(MDP_BASE + 0x50248, 0x3f4003dd); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00160); + MDP_OUTP(MDP_BASE + 0x5024c, 0x3a4003df); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00172); + MDP_OUTP(MDP_BASE + 0x50250, 0x354003e1); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00184); + MDP_OUTP(MDP_BASE + 0x50254, 0x304003e3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6000195); + MDP_OUTP(MDP_BASE + 0x50258, 0x2b0003e6); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf64001a6); + MDP_OUTP(MDP_BASE + 0x5025c, 0x260003e8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c001b4); + MDP_OUTP(MDP_BASE + 0x50260, 0x214003eb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf78001c2); + MDP_OUTP(MDP_BASE + 0x50264, 0x1c4003ee); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf80001cf); + MDP_OUTP(MDP_BASE + 0x50268, 0x17c003f1); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf90001db); + MDP_OUTP(MDP_BASE + 0x5026c, 0x134003f3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa0001e5); + MDP_OUTP(MDP_BASE + 0x50270, 0xf0003f6); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb4001ee); + MDP_OUTP(MDP_BASE + 0x50274, 0xac003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc001f5); + MDP_OUTP(MDP_BASE + 0x50278, 0x70003fb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe4001fb); + MDP_OUTP(MDP_BASE + 0x5027c, 0x34003fe); +} + +static void mdp_load_bc_downscale_table_x_point2TOpoint4(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ac00084); + MDP_OUTP(MDP_BASE + 0x50280, 0x23400083); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b000084); + MDP_OUTP(MDP_BASE + 0x50284, 0x23000083); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b400084); + MDP_OUTP(MDP_BASE + 0x50288, 0x23000082); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b400085); + MDP_OUTP(MDP_BASE + 0x5028c, 0x23000081); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b800085); + MDP_OUTP(MDP_BASE + 0x50290, 0x23000080); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1bc00086); + MDP_OUTP(MDP_BASE + 0x50294, 0x22c0007f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c000086); + MDP_OUTP(MDP_BASE + 0x50298, 0x2280007f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c400086); + MDP_OUTP(MDP_BASE + 0x5029c, 0x2280007e); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c800086); + MDP_OUTP(MDP_BASE + 0x502a0, 0x2280007d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc00086); + MDP_OUTP(MDP_BASE + 0x502a4, 0x2240007d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc00087); + MDP_OUTP(MDP_BASE + 0x502a8, 0x2240007c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d000087); + MDP_OUTP(MDP_BASE + 0x502ac, 0x2240007b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d400087); + MDP_OUTP(MDP_BASE + 0x502b0, 0x2200007b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d400088); + MDP_OUTP(MDP_BASE + 0x502b4, 0x22400079); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d800088); + MDP_OUTP(MDP_BASE + 0x502b8, 0x22400078); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc00088); + MDP_OUTP(MDP_BASE + 0x502bc, 0x22400077); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc00089); + MDP_OUTP(MDP_BASE + 0x502c0, 0x22000077); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1e000089); + MDP_OUTP(MDP_BASE + 0x502c4, 0x22000076); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1e400089); + MDP_OUTP(MDP_BASE + 0x502c8, 0x22000075); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec00088); + MDP_OUTP(MDP_BASE + 0x502cc, 0x21c00075); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec00089); + MDP_OUTP(MDP_BASE + 0x502d0, 0x21c00074); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f000089); + MDP_OUTP(MDP_BASE + 0x502d4, 0x21c00073); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f400089); + MDP_OUTP(MDP_BASE + 0x502d8, 0x21800073); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f40008a); + MDP_OUTP(MDP_BASE + 0x502dc, 0x21800072); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f80008a); + MDP_OUTP(MDP_BASE + 0x502e0, 0x21800071); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1fc0008a); + MDP_OUTP(MDP_BASE + 0x502e4, 0x21800070); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1fc0008b); + MDP_OUTP(MDP_BASE + 0x502e8, 0x2180006f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x2000008c); + MDP_OUTP(MDP_BASE + 0x502ec, 0x2140006e); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x2040008c); + MDP_OUTP(MDP_BASE + 0x502f0, 0x2140006d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x2080008c); + MDP_OUTP(MDP_BASE + 0x502f4, 0x2100006d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x20c0008c); + MDP_OUTP(MDP_BASE + 0x502f8, 0x2100006c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x20c0008d); + MDP_OUTP(MDP_BASE + 0x502fc, 0x2100006b); +} + +static void mdp_load_bc_downscale_table_y_point2TOpoint4(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ac00084); + MDP_OUTP(MDP_BASE + 0x50300, 0x23400083); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b000084); + MDP_OUTP(MDP_BASE + 0x50304, 0x23000083); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b400084); + MDP_OUTP(MDP_BASE + 0x50308, 0x23000082); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b400085); + MDP_OUTP(MDP_BASE + 0x5030c, 0x23000081); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b800085); + MDP_OUTP(MDP_BASE + 0x50310, 0x23000080); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1bc00086); + MDP_OUTP(MDP_BASE + 0x50314, 0x22c0007f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c000086); + MDP_OUTP(MDP_BASE + 0x50318, 0x2280007f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c400086); + MDP_OUTP(MDP_BASE + 0x5031c, 0x2280007e); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c800086); + MDP_OUTP(MDP_BASE + 0x50320, 0x2280007d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc00086); + MDP_OUTP(MDP_BASE + 0x50324, 0x2240007d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc00087); + MDP_OUTP(MDP_BASE + 0x50328, 0x2240007c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d000087); + MDP_OUTP(MDP_BASE + 0x5032c, 0x2240007b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d400087); + MDP_OUTP(MDP_BASE + 0x50330, 0x2200007b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d400088); + MDP_OUTP(MDP_BASE + 0x50334, 0x22400079); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d800088); + MDP_OUTP(MDP_BASE + 0x50338, 0x22400078); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc00088); + MDP_OUTP(MDP_BASE + 0x5033c, 0x22400077); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc00089); + MDP_OUTP(MDP_BASE + 0x50340, 0x22000077); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1e000089); + MDP_OUTP(MDP_BASE + 0x50344, 0x22000076); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1e400089); + MDP_OUTP(MDP_BASE + 0x50348, 0x22000075); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec00088); + MDP_OUTP(MDP_BASE + 0x5034c, 0x21c00075); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec00089); + MDP_OUTP(MDP_BASE + 0x50350, 0x21c00074); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f000089); + MDP_OUTP(MDP_BASE + 0x50354, 0x21c00073); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f400089); + MDP_OUTP(MDP_BASE + 0x50358, 0x21800073); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f40008a); + MDP_OUTP(MDP_BASE + 0x5035c, 0x21800072); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f80008a); + MDP_OUTP(MDP_BASE + 0x50360, 0x21800071); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1fc0008a); + MDP_OUTP(MDP_BASE + 0x50364, 0x21800070); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1fc0008b); + MDP_OUTP(MDP_BASE + 0x50368, 0x2180006f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x2000008c); + MDP_OUTP(MDP_BASE + 0x5036c, 0x2140006e); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x2040008c); + MDP_OUTP(MDP_BASE + 0x50370, 0x2140006d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x2080008c); + MDP_OUTP(MDP_BASE + 0x50374, 0x2100006d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x20c0008c); + MDP_OUTP(MDP_BASE + 0x50378, 0x2100006c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x20c0008d); + MDP_OUTP(MDP_BASE + 0x5037c, 0x2100006b); +} + +static void mdp_load_bc_downscale_table_x_point4TOpoint6(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x740008c); + MDP_OUTP(MDP_BASE + 0x50280, 0x33800088); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x800008e); + MDP_OUTP(MDP_BASE + 0x50284, 0x33400084); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x8400092); + MDP_OUTP(MDP_BASE + 0x50288, 0x33000080); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x9000094); + MDP_OUTP(MDP_BASE + 0x5028c, 0x3300007b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x9c00098); + MDP_OUTP(MDP_BASE + 0x50290, 0x32400077); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xa40009b); + MDP_OUTP(MDP_BASE + 0x50294, 0x32000073); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xb00009d); + MDP_OUTP(MDP_BASE + 0x50298, 0x31c0006f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xbc000a0); + MDP_OUTP(MDP_BASE + 0x5029c, 0x3140006b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xc8000a2); + MDP_OUTP(MDP_BASE + 0x502a0, 0x31000067); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xd8000a5); + MDP_OUTP(MDP_BASE + 0x502a4, 0x30800062); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xe4000a8); + MDP_OUTP(MDP_BASE + 0x502a8, 0x2fc0005f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xec000aa); + MDP_OUTP(MDP_BASE + 0x502ac, 0x2fc0005b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8000ad); + MDP_OUTP(MDP_BASE + 0x502b0, 0x2f400057); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x108000b0); + MDP_OUTP(MDP_BASE + 0x502b4, 0x2e400054); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x114000b2); + MDP_OUTP(MDP_BASE + 0x502b8, 0x2e000050); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x124000b4); + MDP_OUTP(MDP_BASE + 0x502bc, 0x2d80004c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x130000b6); + MDP_OUTP(MDP_BASE + 0x502c0, 0x2d000049); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x140000b8); + MDP_OUTP(MDP_BASE + 0x502c4, 0x2c800045); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x150000b9); + MDP_OUTP(MDP_BASE + 0x502c8, 0x2c000042); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x15c000bd); + MDP_OUTP(MDP_BASE + 0x502cc, 0x2b40003e); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x16c000bf); + MDP_OUTP(MDP_BASE + 0x502d0, 0x2a80003b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x17c000bf); + MDP_OUTP(MDP_BASE + 0x502d4, 0x2a000039); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x188000c2); + MDP_OUTP(MDP_BASE + 0x502d8, 0x29400036); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x19c000c4); + MDP_OUTP(MDP_BASE + 0x502dc, 0x28800032); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ac000c5); + MDP_OUTP(MDP_BASE + 0x502e0, 0x2800002f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1bc000c7); + MDP_OUTP(MDP_BASE + 0x502e4, 0x2740002c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc000c8); + MDP_OUTP(MDP_BASE + 0x502e8, 0x26c00029); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc000c9); + MDP_OUTP(MDP_BASE + 0x502ec, 0x26000027); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec000cc); + MDP_OUTP(MDP_BASE + 0x502f0, 0x25000024); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x200000cc); + MDP_OUTP(MDP_BASE + 0x502f4, 0x24800021); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x210000cd); + MDP_OUTP(MDP_BASE + 0x502f8, 0x23800020); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x220000ce); + MDP_OUTP(MDP_BASE + 0x502fc, 0x2300001d); +} + +static void mdp_load_bc_downscale_table_y_point4TOpoint6(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x740008c); + MDP_OUTP(MDP_BASE + 0x50300, 0x33800088); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x800008e); + MDP_OUTP(MDP_BASE + 0x50304, 0x33400084); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x8400092); + MDP_OUTP(MDP_BASE + 0x50308, 0x33000080); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x9000094); + MDP_OUTP(MDP_BASE + 0x5030c, 0x3300007b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x9c00098); + MDP_OUTP(MDP_BASE + 0x50310, 0x32400077); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xa40009b); + MDP_OUTP(MDP_BASE + 0x50314, 0x32000073); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xb00009d); + MDP_OUTP(MDP_BASE + 0x50318, 0x31c0006f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xbc000a0); + MDP_OUTP(MDP_BASE + 0x5031c, 0x3140006b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xc8000a2); + MDP_OUTP(MDP_BASE + 0x50320, 0x31000067); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xd8000a5); + MDP_OUTP(MDP_BASE + 0x50324, 0x30800062); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xe4000a8); + MDP_OUTP(MDP_BASE + 0x50328, 0x2fc0005f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xec000aa); + MDP_OUTP(MDP_BASE + 0x5032c, 0x2fc0005b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8000ad); + MDP_OUTP(MDP_BASE + 0x50330, 0x2f400057); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x108000b0); + MDP_OUTP(MDP_BASE + 0x50334, 0x2e400054); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x114000b2); + MDP_OUTP(MDP_BASE + 0x50338, 0x2e000050); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x124000b4); + MDP_OUTP(MDP_BASE + 0x5033c, 0x2d80004c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x130000b6); + MDP_OUTP(MDP_BASE + 0x50340, 0x2d000049); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x140000b8); + MDP_OUTP(MDP_BASE + 0x50344, 0x2c800045); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x150000b9); + MDP_OUTP(MDP_BASE + 0x50348, 0x2c000042); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x15c000bd); + MDP_OUTP(MDP_BASE + 0x5034c, 0x2b40003e); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x16c000bf); + MDP_OUTP(MDP_BASE + 0x50350, 0x2a80003b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x17c000bf); + MDP_OUTP(MDP_BASE + 0x50354, 0x2a000039); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x188000c2); + MDP_OUTP(MDP_BASE + 0x50358, 0x29400036); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x19c000c4); + MDP_OUTP(MDP_BASE + 0x5035c, 0x28800032); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ac000c5); + MDP_OUTP(MDP_BASE + 0x50360, 0x2800002f); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1bc000c7); + MDP_OUTP(MDP_BASE + 0x50364, 0x2740002c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc000c8); + MDP_OUTP(MDP_BASE + 0x50368, 0x26c00029); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc000c9); + MDP_OUTP(MDP_BASE + 0x5036c, 0x26000027); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec000cc); + MDP_OUTP(MDP_BASE + 0x50370, 0x25000024); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x200000cc); + MDP_OUTP(MDP_BASE + 0x50374, 0x24800021); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x210000cd); + MDP_OUTP(MDP_BASE + 0x50378, 0x23800020); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x220000ce); + MDP_OUTP(MDP_BASE + 0x5037c, 0x2300001d); +} + +static void mdp_load_bc_downscale_table_x_point6TOpoint8(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000070); + MDP_OUTP(MDP_BASE + 0x50280, 0x4bc00068); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000078); + MDP_OUTP(MDP_BASE + 0x50284, 0x4bc00060); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000080); + MDP_OUTP(MDP_BASE + 0x50288, 0x4b800059); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000089); + MDP_OUTP(MDP_BASE + 0x5028c, 0x4b000052); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe400091); + MDP_OUTP(MDP_BASE + 0x50290, 0x4a80004b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40009a); + MDP_OUTP(MDP_BASE + 0x50294, 0x4a000044); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe8000a3); + MDP_OUTP(MDP_BASE + 0x50298, 0x4940003d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec000ac); + MDP_OUTP(MDP_BASE + 0x5029c, 0x48400037); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff0000b4); + MDP_OUTP(MDP_BASE + 0x502a0, 0x47800031); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff8000bd); + MDP_OUTP(MDP_BASE + 0x502a4, 0x4640002b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xc5); + MDP_OUTP(MDP_BASE + 0x502a8, 0x45000026); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x8000ce); + MDP_OUTP(MDP_BASE + 0x502ac, 0x43800021); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x10000d6); + MDP_OUTP(MDP_BASE + 0x502b0, 0x4240001c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x18000df); + MDP_OUTP(MDP_BASE + 0x502b4, 0x40800018); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x24000e6); + MDP_OUTP(MDP_BASE + 0x502b8, 0x3f000014); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x30000ee); + MDP_OUTP(MDP_BASE + 0x502bc, 0x3d400010); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x40000f5); + MDP_OUTP(MDP_BASE + 0x502c0, 0x3b80000c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x50000fc); + MDP_OUTP(MDP_BASE + 0x502c4, 0x39800009); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x6000102); + MDP_OUTP(MDP_BASE + 0x502c8, 0x37c00006); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x7000109); + MDP_OUTP(MDP_BASE + 0x502cc, 0x35800004); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x840010e); + MDP_OUTP(MDP_BASE + 0x502d0, 0x33800002); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x9800114); + MDP_OUTP(MDP_BASE + 0x502d4, 0x31400000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xac00119); + MDP_OUTP(MDP_BASE + 0x502d8, 0x2f4003fe); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xc40011e); + MDP_OUTP(MDP_BASE + 0x502dc, 0x2d0003fc); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xdc00121); + MDP_OUTP(MDP_BASE + 0x502e0, 0x2b0003fb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf400125); + MDP_OUTP(MDP_BASE + 0x502e4, 0x28c003fa); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x11000128); + MDP_OUTP(MDP_BASE + 0x502e8, 0x268003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x12c0012a); + MDP_OUTP(MDP_BASE + 0x502ec, 0x244003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1480012c); + MDP_OUTP(MDP_BASE + 0x502f0, 0x224003f8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1640012e); + MDP_OUTP(MDP_BASE + 0x502f4, 0x200003f8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1800012f); + MDP_OUTP(MDP_BASE + 0x502f8, 0x1e0003f8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1a00012f); + MDP_OUTP(MDP_BASE + 0x502fc, 0x1c0003f8); +} + +static void mdp_load_bc_downscale_table_y_point6TOpoint8(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000070); + MDP_OUTP(MDP_BASE + 0x50300, 0x4bc00068); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000078); + MDP_OUTP(MDP_BASE + 0x50304, 0x4bc00060); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000080); + MDP_OUTP(MDP_BASE + 0x50308, 0x4b800059); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000089); + MDP_OUTP(MDP_BASE + 0x5030c, 0x4b000052); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe400091); + MDP_OUTP(MDP_BASE + 0x50310, 0x4a80004b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40009a); + MDP_OUTP(MDP_BASE + 0x50314, 0x4a000044); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe8000a3); + MDP_OUTP(MDP_BASE + 0x50318, 0x4940003d); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec000ac); + MDP_OUTP(MDP_BASE + 0x5031c, 0x48400037); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff0000b4); + MDP_OUTP(MDP_BASE + 0x50320, 0x47800031); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff8000bd); + MDP_OUTP(MDP_BASE + 0x50324, 0x4640002b); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xc5); + MDP_OUTP(MDP_BASE + 0x50328, 0x45000026); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x8000ce); + MDP_OUTP(MDP_BASE + 0x5032c, 0x43800021); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x10000d6); + MDP_OUTP(MDP_BASE + 0x50330, 0x4240001c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x18000df); + MDP_OUTP(MDP_BASE + 0x50334, 0x40800018); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x24000e6); + MDP_OUTP(MDP_BASE + 0x50338, 0x3f000014); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x30000ee); + MDP_OUTP(MDP_BASE + 0x5033c, 0x3d400010); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x40000f5); + MDP_OUTP(MDP_BASE + 0x50340, 0x3b80000c); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x50000fc); + MDP_OUTP(MDP_BASE + 0x50344, 0x39800009); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x6000102); + MDP_OUTP(MDP_BASE + 0x50348, 0x37c00006); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x7000109); + MDP_OUTP(MDP_BASE + 0x5034c, 0x35800004); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x840010e); + MDP_OUTP(MDP_BASE + 0x50350, 0x33800002); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x9800114); + MDP_OUTP(MDP_BASE + 0x50354, 0x31400000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xac00119); + MDP_OUTP(MDP_BASE + 0x50358, 0x2f4003fe); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xc40011e); + MDP_OUTP(MDP_BASE + 0x5035c, 0x2d0003fc); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xdc00121); + MDP_OUTP(MDP_BASE + 0x50360, 0x2b0003fb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf400125); + MDP_OUTP(MDP_BASE + 0x50364, 0x28c003fa); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x11000128); + MDP_OUTP(MDP_BASE + 0x50368, 0x268003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x12c0012a); + MDP_OUTP(MDP_BASE + 0x5036c, 0x244003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1480012c); + MDP_OUTP(MDP_BASE + 0x50370, 0x224003f8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1640012e); + MDP_OUTP(MDP_BASE + 0x50374, 0x200003f8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1800012f); + MDP_OUTP(MDP_BASE + 0x50378, 0x1e0003f8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0x1a00012f); + MDP_OUTP(MDP_BASE + 0x5037c, 0x1c0003f8); +} + +static void mdp_load_bc_downscale_table_x_point8TO1(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff80000d); + MDP_OUTP(MDP_BASE + 0x50284, 0x7ec003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec0001c); + MDP_OUTP(MDP_BASE + 0x50288, 0x7d4003f3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40002b); + MDP_OUTP(MDP_BASE + 0x5028c, 0x7b8003ed); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfd80003c); + MDP_OUTP(MDP_BASE + 0x50290, 0x794003e8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc0004d); + MDP_OUTP(MDP_BASE + 0x50294, 0x76c003e4); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfc40005f); + MDP_OUTP(MDP_BASE + 0x50298, 0x73c003e0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb800071); + MDP_OUTP(MDP_BASE + 0x5029c, 0x708003de); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfac00085); + MDP_OUTP(MDP_BASE + 0x502a0, 0x6d0003db); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa000098); + MDP_OUTP(MDP_BASE + 0x502a4, 0x698003d9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf98000ac); + MDP_OUTP(MDP_BASE + 0x502a8, 0x654003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8c000c1); + MDP_OUTP(MDP_BASE + 0x502ac, 0x610003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf84000d5); + MDP_OUTP(MDP_BASE + 0x502b0, 0x5c8003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf7c000e9); + MDP_OUTP(MDP_BASE + 0x502b4, 0x580003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf74000fd); + MDP_OUTP(MDP_BASE + 0x502b8, 0x534003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c00112); + MDP_OUTP(MDP_BASE + 0x502bc, 0x4e8003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6800126); + MDP_OUTP(MDP_BASE + 0x502c0, 0x494003da); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600013a); + MDP_OUTP(MDP_BASE + 0x502c4, 0x448003db); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600014d); + MDP_OUTP(MDP_BASE + 0x502c8, 0x3f4003dd); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00160); + MDP_OUTP(MDP_BASE + 0x502cc, 0x3a4003df); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00172); + MDP_OUTP(MDP_BASE + 0x502d0, 0x354003e1); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00184); + MDP_OUTP(MDP_BASE + 0x502d4, 0x304003e3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6000195); + MDP_OUTP(MDP_BASE + 0x502d8, 0x2b0003e6); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf64001a6); + MDP_OUTP(MDP_BASE + 0x502dc, 0x260003e8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c001b4); + MDP_OUTP(MDP_BASE + 0x502e0, 0x214003eb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf78001c2); + MDP_OUTP(MDP_BASE + 0x502e4, 0x1c4003ee); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf80001cf); + MDP_OUTP(MDP_BASE + 0x502e8, 0x17c003f1); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf90001db); + MDP_OUTP(MDP_BASE + 0x502ec, 0x134003f3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa0001e5); + MDP_OUTP(MDP_BASE + 0x502f0, 0xf0003f6); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb4001ee); + MDP_OUTP(MDP_BASE + 0x502f4, 0xac003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc001f5); + MDP_OUTP(MDP_BASE + 0x502f8, 0x70003fb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe4001fb); + MDP_OUTP(MDP_BASE + 0x502fc, 0x34003fe); +} + +static void mdp_load_bc_downscale_table_y_point8TO1(void) +{ + MDP_OUTP(MDP_BASE + 0x5fffc, 0x0); + MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xff80000d); + MDP_OUTP(MDP_BASE + 0x50304, 0x7ec003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec0001c); + MDP_OUTP(MDP_BASE + 0x50308, 0x7d4003f3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40002b); + MDP_OUTP(MDP_BASE + 0x5030c, 0x7b8003ed); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfd80003c); + MDP_OUTP(MDP_BASE + 0x50310, 0x794003e8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc0004d); + MDP_OUTP(MDP_BASE + 0x50314, 0x76c003e4); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfc40005f); + MDP_OUTP(MDP_BASE + 0x50318, 0x73c003e0); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb800071); + MDP_OUTP(MDP_BASE + 0x5031c, 0x708003de); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfac00085); + MDP_OUTP(MDP_BASE + 0x50320, 0x6d0003db); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa000098); + MDP_OUTP(MDP_BASE + 0x50324, 0x698003d9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf98000ac); + MDP_OUTP(MDP_BASE + 0x50328, 0x654003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8c000c1); + MDP_OUTP(MDP_BASE + 0x5032c, 0x610003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf84000d5); + MDP_OUTP(MDP_BASE + 0x50330, 0x5c8003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf7c000e9); + MDP_OUTP(MDP_BASE + 0x50334, 0x580003d7); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf74000fd); + MDP_OUTP(MDP_BASE + 0x50338, 0x534003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c00112); + MDP_OUTP(MDP_BASE + 0x5033c, 0x4e8003d8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6800126); + MDP_OUTP(MDP_BASE + 0x50340, 0x494003da); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600013a); + MDP_OUTP(MDP_BASE + 0x50344, 0x448003db); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600014d); + MDP_OUTP(MDP_BASE + 0x50348, 0x3f4003dd); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00160); + MDP_OUTP(MDP_BASE + 0x5034c, 0x3a4003df); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00172); + MDP_OUTP(MDP_BASE + 0x50350, 0x354003e1); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00184); + MDP_OUTP(MDP_BASE + 0x50354, 0x304003e3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6000195); + MDP_OUTP(MDP_BASE + 0x50358, 0x2b0003e6); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf64001a6); + MDP_OUTP(MDP_BASE + 0x5035c, 0x260003e8); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c001b4); + MDP_OUTP(MDP_BASE + 0x50360, 0x214003eb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf78001c2); + MDP_OUTP(MDP_BASE + 0x50364, 0x1c4003ee); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf80001cf); + MDP_OUTP(MDP_BASE + 0x50368, 0x17c003f1); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xf90001db); + MDP_OUTP(MDP_BASE + 0x5036c, 0x134003f3); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa0001e5); + MDP_OUTP(MDP_BASE + 0x50370, 0xf0003f6); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb4001ee); + MDP_OUTP(MDP_BASE + 0x50374, 0xac003f9); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc001f5); + MDP_OUTP(MDP_BASE + 0x50378, 0x70003fb); + MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe4001fb); + MDP_OUTP(MDP_BASE + 0x5037c, 0x34003fe); +} + +static int mdp_get_edge_cond(MDPIBUF *iBuf, uint32 *dup, uint32 *dup2) +{ + uint32 reg; + uint32 dst_roi_width; /* Dimensions of DST ROI. */ + uint32 dst_roi_height; /* Used to calculate scaling ratios. */ + + /* + * positions of the luma pixel(relative to the image ) required for + * scaling the ROI + */ + int32 luma_interp_point_left = 0; /* left-most luma pixel needed */ + int32 luma_interp_point_right = 0; /* right-most luma pixel needed */ + int32 luma_interp_point_top = 0; /* top-most luma pixel needed */ + int32 luma_interp_point_bottom = 0; /* bottom-most luma pixel needed */ + + /* + * positions of the chroma pixel(relative to the image ) required for + * interpolating a chroma value at all required luma positions + */ + /* left-most chroma pixel needed */ + int32 chroma_interp_point_left = 0; + /* right-most chroma pixel needed */ + int32 chroma_interp_point_right = 0; + /* top-most chroma pixel needed */ + int32 chroma_interp_point_top = 0; + /* bottom-most chroma pixel needed */ + int32 chroma_interp_point_bottom = 0; + + /* + * a rectangular region within the chroma plane of the "image". + * Chroma pixels falling inside of this rectangle belongs to the ROI + */ + int32 chroma_bound_left = 0; + int32 chroma_bound_right = 0; + int32 chroma_bound_top = 0; + int32 chroma_bound_bottom = 0; + + /* + * number of chroma pixels to replicate on the left, right, + * top and bottom edge of the ROI. + */ + int32 chroma_repeat_left = 0; + int32 chroma_repeat_right = 0; + int32 chroma_repeat_top = 0; + int32 chroma_repeat_bottom = 0; + + /* + * number of luma pixels to replicate on the left, right, + * top and bottom edge of the ROI. + */ + int32 luma_repeat_left = 0; + int32 luma_repeat_right = 0; + int32 luma_repeat_top = 0; + int32 luma_repeat_bottom = 0; + + boolean chroma_edge_enable; + + uint32 _is_scale_enabled = 0; + uint32 _is_yuv_offsite_vertical = 0; + + /* fg edge duplicate */ + reg = 0x0; + + if (iBuf->mdpImg.mdpOp & MDPOP_ASCALE) { /* if scaling enabled */ + + _is_scale_enabled = 1; + + /* + * if rotation mode involves a 90 deg rotation, flip + * dst_roi_width with dst_roi_height. + * Scaling ratios is based on source ROI dimensions, and + * dst ROI dimensions before rotation. + */ + if (iBuf->mdpImg.mdpOp & MDPOP_ROT90) { + dst_roi_width = iBuf->roi.dst_height; + dst_roi_height = iBuf->roi.dst_width; + } else { + dst_roi_width = iBuf->roi.dst_width; + dst_roi_height = iBuf->roi.dst_height; + } + + /* + * Find out the luma pixels needed for scaling in the + * x direction (LEFT and RIGHT). Locations of pixels are + * relative to the ROI. Upper-left corner of ROI corresponds + * to coordinates (0,0). Also set the number of luma pixel + * to repeat. + */ + if (iBuf->roi.width > 3 * dst_roi_width) { + /* scale factor < 1/3 */ + luma_interp_point_left = 0; + luma_interp_point_right = (iBuf->roi.width - 1); + luma_repeat_left = 0; + luma_repeat_right = 0; + } else if (iBuf->roi.width == 3 * dst_roi_width) { + /* scale factor == 1/3 */ + luma_interp_point_left = 0; + luma_interp_point_right = (iBuf->roi.width - 1) + 1; + luma_repeat_left = 0; + luma_repeat_right = 1; + } else if ((iBuf->roi.width > dst_roi_width) && + (iBuf->roi.width < 3 * dst_roi_width)) { + /* 1/3 < scale factor < 1 */ + luma_interp_point_left = -1; + luma_interp_point_right = (iBuf->roi.width - 1) + 1; + luma_repeat_left = 1; + luma_repeat_right = 1; + } + + else if (iBuf->roi.width == dst_roi_width) { + /* scale factor == 1 */ + luma_interp_point_left = -1; + luma_interp_point_right = (iBuf->roi.width - 1) + 2; + luma_repeat_left = 1; + luma_repeat_right = 2; + } else { /* (iBuf->roi.width < dst_roi_width) */ + /* scale factor > 1 */ + luma_interp_point_left = -2; + luma_interp_point_right = (iBuf->roi.width - 1) + 2; + luma_repeat_left = 2; + luma_repeat_right = 2; + } + + /* + * Find out the number of pixels needed for scaling in the + * y direction (TOP and BOTTOM). Locations of pixels are + * relative to the ROI. Upper-left corner of ROI corresponds + * to coordinates (0,0). Also set the number of luma pixel + * to repeat. + */ + if (iBuf->roi.height > 3 * dst_roi_height) { + /* scale factor < 1/3 */ + luma_interp_point_top = 0; + luma_interp_point_bottom = (iBuf->roi.height - 1); + luma_repeat_top = 0; + luma_repeat_bottom = 0; + } else if (iBuf->roi.height == 3 * dst_roi_height) { + /* scale factor == 1/3 */ + luma_interp_point_top = 0; + luma_interp_point_bottom = (iBuf->roi.height - 1) + 1; + luma_repeat_top = 0; + luma_repeat_bottom = 1; + } else if ((iBuf->roi.height > dst_roi_height) && + (iBuf->roi.height < 3 * dst_roi_height)) { + /* 1/3 < scale factor < 1 */ + luma_interp_point_top = -1; + luma_interp_point_bottom = (iBuf->roi.height - 1) + 1; + luma_repeat_top = 1; + luma_repeat_bottom = 1; + } else if (iBuf->roi.height == dst_roi_height) { + /* scale factor == 1 */ + luma_interp_point_top = -1; + luma_interp_point_bottom = (iBuf->roi.height - 1) + 2; + luma_repeat_top = 1; + luma_repeat_bottom = 2; + } else { /* (iBuf->roi.height < dst_roi_height) */ + /* scale factor > 1 */ + luma_interp_point_top = -2; + luma_interp_point_bottom = (iBuf->roi.height - 1) + 2; + luma_repeat_top = 2; + luma_repeat_bottom = 2; + } + } /* if (iBuf->scale.scale_flag) */ + else { /* scaling disabled */ + /* + * Since no scaling needed, Tile Fetch does not require any + * more luma pixel than what the ROI contains. + */ + luma_interp_point_left = (int32) 0; + luma_interp_point_right = (int32) (iBuf->roi.width - 1); + luma_interp_point_top = (int32) 0; + luma_interp_point_bottom = (int32) (iBuf->roi.height - 1); + + luma_repeat_left = 0; + luma_repeat_right = 0; + luma_repeat_top = 0; + luma_repeat_bottom = 0; + } + + /* After adding the ROI offsets, we have locations of + * luma_interp_points relative to the image. + */ + luma_interp_point_left += (int32) (iBuf->roi.x); + luma_interp_point_right += (int32) (iBuf->roi.x); + luma_interp_point_top += (int32) (iBuf->roi.y); + luma_interp_point_bottom += (int32) (iBuf->roi.y); + + /* + * After adding the ROI offsets, we have locations of + * chroma_interp_points relative to the image. + */ + chroma_interp_point_left = luma_interp_point_left; + chroma_interp_point_right = luma_interp_point_right; + chroma_interp_point_top = luma_interp_point_top; + chroma_interp_point_bottom = luma_interp_point_bottom; + + chroma_edge_enable = TRUE; + /* find out which chroma pixels are needed for chroma upsampling. */ + switch (iBuf->mdpImg.imgType) { + /* + * cosite in horizontal axis + * fully sampled in vertical axis + */ + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + case MDP_YCRYCB_H2V1: + /* floor( luma_interp_point_left / 2 ); */ + chroma_interp_point_left = luma_interp_point_left >> 1; + /* floor( ( luma_interp_point_right + 1 ) / 2 ); */ + chroma_interp_point_right = (luma_interp_point_right + 1) >> 1; + + chroma_interp_point_top = luma_interp_point_top; + chroma_interp_point_bottom = luma_interp_point_bottom; + break; + + /* + * cosite in horizontal axis + * offsite in vertical axis + */ + case MDP_Y_CBCR_H2V2: + case MDP_Y_CBCR_H2V2_ADRENO: + case MDP_Y_CRCB_H2V2: + /* floor( luma_interp_point_left / 2) */ + chroma_interp_point_left = luma_interp_point_left >> 1; + + /* floor( ( luma_interp_point_right + 1 )/ 2 ) */ + chroma_interp_point_right = (luma_interp_point_right + 1) >> 1; + + /* floor( (luma_interp_point_top - 1 ) / 2 ) */ + chroma_interp_point_top = (luma_interp_point_top - 1) >> 1; + + /* floor( ( luma_interp_point_bottom + 1 ) / 2 ) */ + chroma_interp_point_bottom = + (luma_interp_point_bottom + 1) >> 1; + + _is_yuv_offsite_vertical = 1; + break; + + default: + chroma_edge_enable = FALSE; + chroma_interp_point_left = luma_interp_point_left; + chroma_interp_point_right = luma_interp_point_right; + chroma_interp_point_top = luma_interp_point_top; + chroma_interp_point_bottom = luma_interp_point_bottom; + + break; + } + + /* only if the image type is in YUV domain, we calculate chroma edge */ + if (chroma_edge_enable) { + /* Defines which chroma pixels belongs to the roi */ + switch (iBuf->mdpImg.imgType) { + /* + * Cosite in horizontal direction, and fully sampled + * in vertical direction. + */ + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + case MDP_YCRYCB_H2V1: + /* + * width of chroma ROI is 1/2 of size of luma ROI + * height of chroma ROI same as size of luma ROI + */ + chroma_bound_left = iBuf->roi.x / 2; + + /* there are half as many chroma pixel as luma pixels */ + chroma_bound_right = + (iBuf->roi.width + iBuf->roi.x - 1) / 2; + chroma_bound_top = iBuf->roi.y; + chroma_bound_bottom = + (iBuf->roi.height + iBuf->roi.y - 1); + break; + + case MDP_Y_CBCR_H2V2: + case MDP_Y_CBCR_H2V2_ADRENO: + case MDP_Y_CRCB_H2V2: + /* + * cosite in horizontal dir, and offsite in vertical dir + * width of chroma ROI is 1/2 of size of luma ROI + * height of chroma ROI is 1/2 of size of luma ROI + */ + + chroma_bound_left = iBuf->roi.x / 2; + chroma_bound_right = + (iBuf->roi.width + iBuf->roi.x - 1) / 2; + chroma_bound_top = iBuf->roi.y / 2; + chroma_bound_bottom = + (iBuf->roi.height + iBuf->roi.y - 1) / 2; + break; + + default: + /* + * If no valid chroma sub-sampling format specified, + * assume 4:4:4 ( i.e. fully sampled). Set ROI + * boundaries for chroma same as ROI boundaries for + * luma. + */ + chroma_bound_left = iBuf->roi.x; + chroma_bound_right = iBuf->roi.width + iBuf->roi.x - 1; + chroma_bound_top = iBuf->roi.y; + chroma_bound_bottom = + (iBuf->roi.height + iBuf->roi.y - 1); + break; + } + + /* + * Knowing which chroma pixels are needed, and which chroma + * pixels belong to the ROI (i.e. available for fetching ), + * calculate how many chroma pixels Tile Fetch needs to + * duplicate. If any required chroma pixels falls outside + * of the ROI, Tile Fetch must obtain them by replicating + * pixels. + */ + if (chroma_bound_left > chroma_interp_point_left) + chroma_repeat_left = + chroma_bound_left - chroma_interp_point_left; + else + chroma_repeat_left = 0; + + if (chroma_interp_point_right > chroma_bound_right) + chroma_repeat_right = + chroma_interp_point_right - chroma_bound_right; + else + chroma_repeat_right = 0; + + if (chroma_bound_top > chroma_interp_point_top) + chroma_repeat_top = + chroma_bound_top - chroma_interp_point_top; + else + chroma_repeat_top = 0; + + if (chroma_interp_point_bottom > chroma_bound_bottom) + chroma_repeat_bottom = + chroma_interp_point_bottom - chroma_bound_bottom; + else + chroma_repeat_bottom = 0; + + if (_is_scale_enabled && (iBuf->roi.height == 1) + && _is_yuv_offsite_vertical) { + chroma_repeat_bottom = 3; + chroma_repeat_top = 0; + } + } + /* make sure chroma repeats are non-negative */ + if ((chroma_repeat_left < 0) || (chroma_repeat_right < 0) || + (chroma_repeat_top < 0) || (chroma_repeat_bottom < 0)) + return -1; + + /* make sure chroma repeats are no larger than 3 pixels */ + if ((chroma_repeat_left > 3) || (chroma_repeat_right > 3) || + (chroma_repeat_top > 3) || (chroma_repeat_bottom > 3)) + return -1; + + /* make sure luma repeats are non-negative */ + if ((luma_repeat_left < 0) || (luma_repeat_right < 0) || + (luma_repeat_top < 0) || (luma_repeat_bottom < 0)) + return -1; + + /* make sure luma repeats are no larger than 3 pixels */ + if ((luma_repeat_left > 3) || (luma_repeat_right > 3) || + (luma_repeat_top > 3) || (luma_repeat_bottom > 3)) + return -1; + + /* write chroma_repeat_left to register */ + reg |= (chroma_repeat_left & 3) << MDP_LEFT_CHROMA; + + /* write chroma_repeat_right to register */ + reg |= (chroma_repeat_right & 3) << MDP_RIGHT_CHROMA; + + /* write chroma_repeat_top to register */ + reg |= (chroma_repeat_top & 3) << MDP_TOP_CHROMA; + + /* write chroma_repeat_bottom to register */ + reg |= (chroma_repeat_bottom & 3) << MDP_BOTTOM_CHROMA; + + /* write luma_repeat_left to register */ + reg |= (luma_repeat_left & 3) << MDP_LEFT_LUMA; + + /* write luma_repeat_right to register */ + reg |= (luma_repeat_right & 3) << MDP_RIGHT_LUMA; + + /* write luma_repeat_top to register */ + reg |= (luma_repeat_top & 3) << MDP_TOP_LUMA; + + /* write luma_repeat_bottom to register */ + reg |= (luma_repeat_bottom & 3) << MDP_BOTTOM_LUMA; + + /* done with reg */ + *dup = reg; + + /* bg edge duplicate */ + reg = 0x0; + + switch (iBuf->ibuf_type) { + case MDP_Y_CBCR_H2V2: + case MDP_Y_CRCB_H2V2: + /* + * Edge condition for MDP_Y_CRCB/CBCR_H2V2 cosite only. + * For 420 cosite, 1 chroma replicated on all sides except + * left, so reg 101b8 should be 0x0209. For 420 offsite, + * 1 chroma replicated all sides. + */ + if (iBuf->roi.lcd_y == 0) { + reg |= BIT(MDP_TOP_CHROMA); + } + + if ((iBuf->roi.lcd_y + iBuf->roi.dst_height) == + iBuf->ibuf_height) { + reg |= BIT(MDP_BOTTOM_CHROMA); + } + + if (((iBuf->roi.lcd_x + iBuf->roi.dst_width) == + iBuf->ibuf_width) && ((iBuf->roi.dst_width % 2) == 0)) { + reg |= BIT(MDP_RIGHT_CHROMA); + } + + break; + + case MDP_Y_CBCR_H2V1: + case MDP_Y_CRCB_H2V1: + case MDP_YCRYCB_H2V1: + if (((iBuf->roi.lcd_x + iBuf->roi.dst_width) == + iBuf->ibuf_width) && ((iBuf->roi.dst_width % 2) == 0)) { + reg |= BIT(MDP_RIGHT_CHROMA); + } + break; + default: + break; + } + + *dup2 = reg; + + return 0; +} + +#define ADJUST_IP /* for 1/3 scale factor fix */ + +static int mdp_calc_scale_params( +/* ROI origin coordinate for the dimension */ + uint32 org, +/* src ROI dimension */ + uint32 dim_in, +/* scaled ROI dimension*/ + uint32 dim_out, +/* is this ROI width dimension? */ + boolean is_W, +/* initial phase location address */ + int32 *phase_init_ptr, +/* phase increment location address */ + uint32 *phase_step_ptr, +/* ROI start over-fetch location address */ + uint32 *num_repl_beg_ptr, +/* ROI end over-fetch location address */ + uint32 *num_repl_end_ptr) +{ + boolean rpa_on = FALSE; + int init_phase = 0; + uint32 beg_of = 0; + uint32 end_of = 0; + uint64 numer = 0; + uint64 denom = 0; + /*uint64 inverter = 1; */ + int64 point5 = 1; + int64 one = 1; + int64 k1, k2, k3, k4; /* linear equation coefficients */ + uint64 int_mask; + uint64 fract_mask; + uint64 Os; + int64 Osprime; + int64 Od; + int64 Odprime; + int64 Oreq; + uint64 Es; + uint64 Ed; + uint64 Ereq; +#ifdef ADJUST_IP + int64 IP64; + int64 delta; +#endif + uint32 mult; + + /* + * The phase accumulator should really be rational for all cases in a + * general purpose polyphase scaler for a tiled architecture with + * non-zero * origin capability because there is no way to represent + * certain scale factors in fixed point regardless of precision. + * The error incurred in attempting to use fixed point is most + * eggregious for SF where 1/SF is an integral multiple of 1/3. + * + * However, since the MDP2 has already been committed to HW, we + * only use the rational phase accumulator (RPA) when 1/SF is an + * integral multiple of 1/3. This will help minimize regressions in + * matching the HW to the C-Sim. + */ + /* + * Set the RPA flag for this dimension. + * + * In order for 1/SF (dim_in/dim_out) to be an integral multiple of + * 1/3, dim_out must be an integral multiple of 3. + */ + if (!(dim_out % 3)) { + mult = dim_out / 3; + rpa_on = (!(dim_in % mult)); + } + + numer = dim_out; + denom = dim_in; + + /* + * convert to U30.34 before division + * + * The K vectors carry 4 extra bits of precision + * and are rounded. + * + * We initially go 5 bits over then round by adding + * 1 and right shifting by 1 + * so final result is U31.33 + */ + numer <<= PQF_PLUS_5; + + /* now calculate the scale factor (aka k3) */ + k3 = ((mdp_do_div(numer, denom) + 1) >> 1); + + /* check scale factor for legal range [0.25 - 4.0] */ + if (((k3 >> 4) < (1LL << PQF_MINUS_2)) || + ((k3 >> 4) > (1LL << PQF_PLUS_2))) { + return -1; + } + + /* calculate inverse scale factor (aka k1) for phase init */ + numer = dim_in; + denom = dim_out; + numer <<= PQF_PLUS_5; + k1 = ((mdp_do_div(numer, denom) + 1) >> 1); + + /* + * calculate initial phase and ROI overfetch + */ + /* convert point5 & one to S39.24 (will always be positive) */ + point5 <<= (PQF_PLUS_4 - 1); + one <<= PQF_PLUS_4; + k2 = ((k1 - one) >> 1); + init_phase = (int)(k2 >> 4); + k4 = ((k3 - one) >> 1); + if (k3 == one) { + /* the simple case; SF = 1.0 */ + beg_of = 1; + end_of = 2; + } else { + /* calculate the masks */ + fract_mask = one - 1; + int_mask = ~fract_mask; + + if (!rpa_on) { + /* + * FIXED POINT IMPLEMENTATION + */ + if (!org) { + /* A fairly simple case; ROI origin = 0 */ + if (k1 < one) { + /* upscaling */ + beg_of = end_of = 2; + } + /* 0.33 <= SF < 1.0 */ + else if (k1 < (3LL << PQF_PLUS_4)) + beg_of = end_of = 1; + /* 0.33 == SF */ + else if (k1 == (3LL << PQF_PLUS_4)) { + beg_of = 0; + end_of = 1; + } + /* 0.25 <= SF < 0.33 */ + else + beg_of = end_of = 0; + } else { + /* + * The complicated case; ROI origin != 0 + * init_phase needs to be adjusted + * OF is also position dependent + */ + + /* map (org - .5) into destination space */ + Os = ((uint64) org << 1) - 1; + Od = ((k3 * Os) >> 1) + k4; + + /* take the ceiling */ + Odprime = (Od & int_mask); + if (Odprime != Od) + Odprime += one; + + /* now map that back to source space */ + Osprime = (k1 * (Odprime >> PQF_PLUS_4)) + k2; + + /* then floor & decrement to calculate the required + starting coordinate */ + Oreq = (Osprime & int_mask) - one; + + /* calculate end coord in destination space then map to + source space */ + Ed = Odprime + + ((uint64) dim_out << PQF_PLUS_4) - one; + Es = (k1 * (Ed >> PQF_PLUS_4)) + k2; + + /* now floor & increment by 2 to calculate the required + ending coordinate */ + Ereq = (Es & int_mask) + (one << 1); + + /* calculate initial phase */ +#ifdef ADJUST_IP + + IP64 = Osprime - Oreq; + delta = ((int64) (org) << PQF_PLUS_4) - Oreq; + IP64 -= delta; + + /* limit to valid range before the left shift */ + delta = (IP64 & (1LL << 63)) ? 4 : -4; + delta <<= PQF_PLUS_4; + while (abs((int)(IP64 >> PQF_PLUS_4)) > 4) + IP64 += delta; + + /* right shift to account for extra bits of precision */ + init_phase = (int)(IP64 >> 4); + +#else /* ADJUST_IP */ + + /* just calculate the real initial phase */ + init_phase = (int)((Osprime - Oreq) >> 4); + +#endif /* ADJUST_IP */ + + /* calculate the overfetch */ + beg_of = org - (uint32) (Oreq >> PQF_PLUS_4); + end_of = + (uint32) (Ereq >> PQF_PLUS_4) - (org + + dim_in - + 1); + } + } else { + /* + * RPA IMPLEMENTATION + * + * init_phase needs to be calculated in all RPA_on cases + * because it's a numerator, not a fixed point value. + */ + + /* map (org - .5) into destination space */ + Os = ((uint64) org << PQF_PLUS_4) - point5; + Od = mdp_do_div((dim_out * (Os + point5)), + dim_in) - point5; + + /* take the ceiling */ + Odprime = (Od & int_mask); + if (Odprime != Od) + Odprime += one; + + /* now map that back to source space */ + Osprime = + mdp_do_div((dim_in * (Odprime + point5)), + dim_out) - point5; + + /* then floor & decrement to calculate the required + starting coordinate */ + Oreq = (Osprime & int_mask) - one; + + /* calculate end coord in destination space then map to + source space */ + Ed = Odprime + ((uint64) dim_out << PQF_PLUS_4) - one; + Es = mdp_do_div((dim_in * (Ed + point5)), + dim_out) - point5; + + /* now floor & increment by 2 to calculate the required + ending coordinate */ + Ereq = (Es & int_mask) + (one << 1); + + /* calculate initial phase */ + +#ifdef ADJUST_IP + + IP64 = Osprime - Oreq; + delta = ((int64) (org) << PQF_PLUS_4) - Oreq; + IP64 -= delta; + + /* limit to valid range before the left shift */ + delta = (IP64 & (1LL << 63)) ? 4 : -4; + delta <<= PQF_PLUS_4; + while (abs((int)(IP64 >> PQF_PLUS_4)) > 4) + IP64 += delta; + + /* right shift to account for extra bits of precision */ + init_phase = (int)(IP64 >> 4); + +#else /* ADJUST_IP */ + + /* just calculate the real initial phase */ + init_phase = (int)((Osprime - Oreq) >> 4); + +#endif /* ADJUST_IP */ + + /* calculate the overfetch */ + beg_of = org - (uint32) (Oreq >> PQF_PLUS_4); + end_of = + (uint32) (Ereq >> PQF_PLUS_4) - (org + dim_in - 1); + } + } + + /* return the scale parameters */ + *phase_init_ptr = init_phase; + *phase_step_ptr = (uint32) (k1 >> 4); + *num_repl_beg_ptr = beg_of; + *num_repl_end_ptr = end_of; + + return 0; +} + +static uint8 *mdp_adjust_rot_addr(MDPIBUF *iBuf, uint8 *addr, uint32 uv) +{ + uint32 dest_ystride = iBuf->ibuf_width * iBuf->bpp; + uint32 h_slice = 1; + + if (uv && ((iBuf->ibuf_type == MDP_Y_CBCR_H2V2) || + (iBuf->ibuf_type == MDP_Y_CRCB_H2V2))) + h_slice = 2; + + if (MDP_CHKBIT(iBuf->mdpImg.mdpOp, MDPOP_ROT90) ^ + MDP_CHKBIT(iBuf->mdpImg.mdpOp, MDPOP_LR)) { + addr = + addr + (iBuf->roi.dst_width - + MIN(16, iBuf->roi.dst_width)) * iBuf->bpp; + } + if (MDP_CHKBIT(iBuf->mdpImg.mdpOp, MDPOP_UD)) { + addr = + addr + ((iBuf->roi.dst_height - + MIN(16, iBuf->roi.dst_height))/h_slice) * dest_ystride; + } + + return addr; +} + +void mdp_set_scale(MDPIBUF *iBuf, + uint32 dst_roi_width, + uint32 dst_roi_height, + boolean inputRGB, boolean outputRGB, uint32 *pppop_reg_ptr) +{ + uint32 dst_roi_width_scale; + uint32 dst_roi_height_scale; + boolean use_pr; + uint32 phasex_step = 0; + uint32 phasey_step = 0; + int32 phasex_init = 0; + int32 phasey_init = 0; + uint32 lines_dup = 0; + uint32 lines_dup_bg = 0; + uint32 dummy; + uint32 mdp_blur = 0; + + if (iBuf->mdpImg.mdpOp & MDPOP_ASCALE) { + if (iBuf->mdpImg.mdpOp & MDPOP_ROT90) { + dst_roi_width_scale = dst_roi_height; + dst_roi_height_scale = dst_roi_width; + } else { + dst_roi_width_scale = dst_roi_width; + dst_roi_height_scale = dst_roi_height; + } + + mdp_blur = iBuf->mdpImg.mdpOp & MDPOP_BLUR; + + if ((dst_roi_width_scale != iBuf->roi.width) || + (dst_roi_height_scale != iBuf->roi.height) || + mdp_blur) { + *pppop_reg_ptr |= + (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON); + + /* let's use SHIM logic to calculate the + partial ROI scaling */ + mdp_calc_scale_params(iBuf->roi.x, iBuf->roi.width, + dst_roi_width_scale, 1, + &phasex_init, &phasex_step, + &dummy, &dummy); + mdp_calc_scale_params(iBuf->roi.y, iBuf->roi.height, + dst_roi_height_scale, 0, + &phasey_init, &phasey_step, + &dummy, &dummy); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x013c, + phasex_init); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0140, + phasey_init); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0144, + phasex_step); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0148, + phasey_step); + + /* disable the pixel repeat option for scaling */ + use_pr = false; + + if ((dst_roi_width_scale > iBuf->roi.width) || + (dst_roi_height_scale > iBuf->roi.height)) { + if ((use_pr) + && (mdp_curr_up_scale_xy != + MDP_PR_SCALE_UP)) { + mdp_load_pr_upscale_table(); + mdp_curr_up_scale_xy = MDP_PR_SCALE_UP; + } else if ((!use_pr) + && (mdp_curr_up_scale_xy != + MDP_BC_SCALE_UP)) { + mdp_load_bc_upscale_table(); + mdp_curr_up_scale_xy = MDP_BC_SCALE_UP; + } + } + + if (mdp_blur) { + load_scale_table(mdp_gaussian_blur_table, + ARRAY_SIZE(mdp_gaussian_blur_table)); + mdp_curr_down_scale_x = MDP_SCALE_BLUR; + mdp_curr_down_scale_y = MDP_SCALE_BLUR; + } + + /* 0.2 < x <= 1 scaling factor */ + if ((dst_roi_width_scale <= iBuf->roi.width) && + !mdp_blur) { + if (((dst_roi_width_scale * 10) / + iBuf->roi.width) > 8) { + if ((use_pr) + && (mdp_curr_down_scale_x != + MDP_PR_SCALE_POINT8_1)) { + mdp_load_pr_downscale_table_x_point8TO1 + (); + mdp_curr_down_scale_x = + MDP_PR_SCALE_POINT8_1; + } else if ((!use_pr) + && (mdp_curr_down_scale_x != + MDP_BC_SCALE_POINT8_1)) { + mdp_load_bc_downscale_table_x_point8TO1 + (); + mdp_curr_down_scale_x = + MDP_BC_SCALE_POINT8_1; + } + } else + if (((dst_roi_width_scale * 10) / + iBuf->roi.width) > 6) { + if ((use_pr) + && (mdp_curr_down_scale_x != + MDP_PR_SCALE_POINT6_POINT8)) { + mdp_load_pr_downscale_table_x_point6TOpoint8 + (); + mdp_curr_down_scale_x = + MDP_PR_SCALE_POINT6_POINT8; + } else if ((!use_pr) + && (mdp_curr_down_scale_x != + MDP_BC_SCALE_POINT6_POINT8)) + { + mdp_load_bc_downscale_table_x_point6TOpoint8 + (); + mdp_curr_down_scale_x = + MDP_BC_SCALE_POINT6_POINT8; + } + } else + if (((dst_roi_width_scale * 10) / + iBuf->roi.width) > 4) { + if ((use_pr) + && (mdp_curr_down_scale_x != + MDP_PR_SCALE_POINT4_POINT6)) { + mdp_load_pr_downscale_table_x_point4TOpoint6 + (); + mdp_curr_down_scale_x = + MDP_PR_SCALE_POINT4_POINT6; + } else if ((!use_pr) + && (mdp_curr_down_scale_x != + MDP_BC_SCALE_POINT4_POINT6)) + { + mdp_load_bc_downscale_table_x_point4TOpoint6 + (); + mdp_curr_down_scale_x = + MDP_BC_SCALE_POINT4_POINT6; + } + } else { + if ((use_pr) + && (mdp_curr_down_scale_x != + MDP_PR_SCALE_POINT2_POINT4)) { + mdp_load_pr_downscale_table_x_point2TOpoint4 + (); + mdp_curr_down_scale_x = + MDP_PR_SCALE_POINT2_POINT4; + } else if ((!use_pr) + && (mdp_curr_down_scale_x != + MDP_BC_SCALE_POINT2_POINT4)) + { + mdp_load_bc_downscale_table_x_point2TOpoint4 + (); + mdp_curr_down_scale_x = + MDP_BC_SCALE_POINT2_POINT4; + } + } + } + /* 0.2 < y <= 1 scaling factor */ + if ((dst_roi_height_scale <= iBuf->roi.height) && + !mdp_blur) { + if (((dst_roi_height_scale * 10) / + iBuf->roi.height) > 8) { + if ((use_pr) + && (mdp_curr_down_scale_y != + MDP_PR_SCALE_POINT8_1)) { + mdp_load_pr_downscale_table_y_point8TO1 + (); + mdp_curr_down_scale_y = + MDP_PR_SCALE_POINT8_1; + } else if ((!use_pr) + && (mdp_curr_down_scale_y != + MDP_BC_SCALE_POINT8_1)) { + mdp_load_bc_downscale_table_y_point8TO1 + (); + mdp_curr_down_scale_y = + MDP_BC_SCALE_POINT8_1; + } + } else + if (((dst_roi_height_scale * 10) / + iBuf->roi.height) > 6) { + if ((use_pr) + && (mdp_curr_down_scale_y != + MDP_PR_SCALE_POINT6_POINT8)) { + mdp_load_pr_downscale_table_y_point6TOpoint8 + (); + mdp_curr_down_scale_y = + MDP_PR_SCALE_POINT6_POINT8; + } else if ((!use_pr) + && (mdp_curr_down_scale_y != + MDP_BC_SCALE_POINT6_POINT8)) + { + mdp_load_bc_downscale_table_y_point6TOpoint8 + (); + mdp_curr_down_scale_y = + MDP_BC_SCALE_POINT6_POINT8; + } + } else + if (((dst_roi_height_scale * 10) / + iBuf->roi.height) > 4) { + if ((use_pr) + && (mdp_curr_down_scale_y != + MDP_PR_SCALE_POINT4_POINT6)) { + mdp_load_pr_downscale_table_y_point4TOpoint6 + (); + mdp_curr_down_scale_y = + MDP_PR_SCALE_POINT4_POINT6; + } else if ((!use_pr) + && (mdp_curr_down_scale_y != + MDP_BC_SCALE_POINT4_POINT6)) + { + mdp_load_bc_downscale_table_y_point4TOpoint6 + (); + mdp_curr_down_scale_y = + MDP_BC_SCALE_POINT4_POINT6; + } + } else { + if ((use_pr) + && (mdp_curr_down_scale_y != + MDP_PR_SCALE_POINT2_POINT4)) { + mdp_load_pr_downscale_table_y_point2TOpoint4 + (); + mdp_curr_down_scale_y = + MDP_PR_SCALE_POINT2_POINT4; + } else if ((!use_pr) + && (mdp_curr_down_scale_y != + MDP_BC_SCALE_POINT2_POINT4)) + { + mdp_load_bc_downscale_table_y_point2TOpoint4 + (); + mdp_curr_down_scale_y = + MDP_BC_SCALE_POINT2_POINT4; + } + } + } + } else { + iBuf->mdpImg.mdpOp &= ~(MDPOP_ASCALE); + } + } + /* setting edge condition here after scaling check */ + if (mdp_get_edge_cond(iBuf, &lines_dup, &lines_dup_bg)) + printk(KERN_ERR "msm_fb: mdp_get_edge_cond() error!\n"); + + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01b8, lines_dup); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01bc, lines_dup_bg); +} + +void mdp_init_scale_table(void) +{ + mdp_curr_up_scale_xy = MDP_INIT_SCALE; + mdp_curr_down_scale_x = MDP_INIT_SCALE; + mdp_curr_down_scale_y = MDP_INIT_SCALE; +} + +void mdp_adjust_start_addr(uint8 **src0, + uint8 **src1, + int v_slice, + int h_slice, + int x, + int y, + uint32 width, + uint32 height, int bpp, MDPIBUF *iBuf, int layer) +{ + if (iBuf->mdpImg.imgType == MDP_Y_CBCR_H2V2_ADRENO && layer == 0) + *src0 += (x + y * ALIGN(width, 32)) * bpp; + else + *src0 += (x + y * width) * bpp; + + /* if it's dest/bg buffer, we need to adjust it for rotation */ + if (layer != 0) + *src0 = mdp_adjust_rot_addr(iBuf, *src0, 0); + + if (*src1) { + /* + * MDP_Y_CBCR_H2V2/MDP_Y_CRCB_H2V2 cosite for now + * we need to shift x direction same as y dir for offsite + */ + if (iBuf->mdpImg.imgType == MDP_Y_CBCR_H2V2_ADRENO + && layer == 0) + *src1 += ((x / h_slice) * h_slice + ((y == 0) ? 0 : + (((y + 1) / v_slice - 1) * (ALIGN(width/2, 32) * 2)))) + * bpp; + else + *src1 += ((x / h_slice) * h_slice + + ((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp; + + /* if it's dest/bg buffer, we need to adjust it for rotation */ + if (layer != 0) + *src1 = mdp_adjust_rot_addr(iBuf, *src1, 1); + } +} + +void mdp_set_blend_attr(MDPIBUF *iBuf, + uint32 *alpha, + uint32 *tpVal, + uint32 perPixelAlpha, uint32 *pppop_reg_ptr) +{ + if (mdp_rev == MDP_REV_303) { + int bg_alpha; + + *alpha = iBuf->mdpImg.alpha; + *tpVal = iBuf->mdpImg.tpVal; + + if (iBuf->mdpImg.mdpOp & MDPOP_FG_PM_ALPHA) { + if (perPixelAlpha) { + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | + PPP_OP_BLEND_CONSTANT_ALPHA; + } else { + if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) + && (iBuf->mdpImg.alpha == 0xff)) { + iBuf->mdpImg.mdpOp &= ~(MDPOP_ALPHAB); + } + + if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) + || (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)) { + + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | + PPP_OP_BLEND_CONSTANT_ALPHA | + PPP_OP_BLEND_ALPHA_BLEND_NORMAL; + } + } + + bg_alpha = PPP_BLEND_BG_USE_ALPHA_SEL | + PPP_BLEND_BG_ALPHA_REVERSE; + + if (perPixelAlpha) { + bg_alpha |= PPP_BLEND_BG_SRCPIXEL_ALPHA; + } else { + bg_alpha |= PPP_BLEND_BG_CONSTANT_ALPHA; + bg_alpha |= iBuf->mdpImg.alpha << 24; + } + outpdw(MDP_BASE + 0x70010, bg_alpha); + + if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP) + *pppop_reg_ptr |= PPP_BLEND_CALPHA_TRNASP; + } else if (perPixelAlpha) { + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | + PPP_OP_BLEND_SRCPIXEL_ALPHA; + outpdw(MDP_BASE + 0x70010, 0); + } else { + if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) + && (iBuf->mdpImg.alpha == 0xff)) { + iBuf->mdpImg.mdpOp &= + ~(MDPOP_ALPHAB); + } + + if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) + || (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)) { + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | + PPP_OP_BLEND_CONSTANT_ALPHA | + PPP_OP_BLEND_ALPHA_BLEND_NORMAL; + } + + if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP) + *pppop_reg_ptr |= + PPP_BLEND_CALPHA_TRNASP; + outpdw(MDP_BASE + 0x70010, 0); + } + } else { + if (perPixelAlpha) { + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | PPP_OP_BLEND_SRCPIXEL_ALPHA; + } else { + if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) + && (iBuf->mdpImg.alpha == 0xff)) { + iBuf->mdpImg.mdpOp &= ~(MDPOP_ALPHAB); + } + + if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) + && (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)) { + *pppop_reg_ptr |= + PPP_OP_ROT_ON | PPP_OP_BLEND_ON | + PPP_OP_BLEND_CONSTANT_ALPHA | + PPP_OP_BLEND_ALPHA_BLEND_NORMAL | + PPP_BLEND_CALPHA_TRNASP; + + *alpha = iBuf->mdpImg.alpha; + *tpVal = iBuf->mdpImg.tpVal; + } else { + if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP) { + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | + PPP_OP_BLEND_SRCPIXEL_TRANSP; + *tpVal = iBuf->mdpImg.tpVal; + } else if (iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) { + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | + PPP_OP_BLEND_ALPHA_BLEND_NORMAL | + PPP_OP_BLEND_CONSTANT_ALPHA; + *alpha = iBuf->mdpImg.alpha; + } + } + } + } +} diff --git a/drivers/video/msm/mdp_ppp_v31.c b/drivers/video/msm/mdp_ppp_v31.c new file mode 100644 index 000000000000..3c149b19782d --- /dev/null +++ b/drivers/video/msm/mdp_ppp_v31.c @@ -0,0 +1,844 @@ +/* Copyright (c) 2008-2009, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "linux/proc_fs.h" + +#include +#include + +#include +#include +#include +#include + +#include "mdp.h" +#include "msm_fb.h" + +#define MDP_SCALE_COEFF_NUM 32 +#define MDP_SCALE_0P2_TO_0P4_INDEX 0 +#define MDP_SCALE_0P4_TO_0P6_INDEX 32 +#define MDP_SCALE_0P6_TO_0P8_INDEX 64 +#define MDP_SCALE_0P8_TO_8P0_INDEX 96 +#define MDP_SCALE_COEFF_MASK 0x3ff + +#define MDP_SCALE_PR 0 +#define MDP_SCALE_FIR 1 + +static uint32 mdp_scale_0p8_to_8p0_mode; +static uint32 mdp_scale_0p6_to_0p8_mode; +static uint32 mdp_scale_0p4_to_0p6_mode; +static uint32 mdp_scale_0p2_to_0p4_mode; + +/* -------- All scaling range, "pixel repeat" -------- */ +static int16 mdp_scale_pixel_repeat_C0[MDP_SCALE_COEFF_NUM] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static int16 mdp_scale_pixel_repeat_C1[MDP_SCALE_COEFF_NUM] = { + 511, 511, 511, 511, 511, 511, 511, 511, + 511, 511, 511, 511, 511, 511, 511, 511, + 511, 511, 511, 511, 511, 511, 511, 511, + 511, 511, 511, 511, 511, 511, 511, 511 +}; + +static int16 mdp_scale_pixel_repeat_C2[MDP_SCALE_COEFF_NUM] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static int16 mdp_scale_pixel_repeat_C3[MDP_SCALE_COEFF_NUM] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* --------------------------- FIR ------------------------------------- */ +/* -------- Downscale, ranging from 0.8x to 8.0x of original size -------- */ + +static int16 mdp_scale_0p8_to_8p0_C0[MDP_SCALE_COEFF_NUM] = { + 0, -7, -13, -19, -24, -28, -32, -34, -37, -39, + -40, -41, -41, -41, -40, -40, -38, -37, -35, -33, + -31, -29, -26, -24, -21, -18, -15, -13, -10, -7, + -5, -2 +}; + +static int16 mdp_scale_0p8_to_8p0_C1[MDP_SCALE_COEFF_NUM] = { + 511, 507, 501, 494, 485, 475, 463, 450, 436, 422, + 405, 388, 370, 352, 333, 314, 293, 274, 253, 233, + 213, 193, 172, 152, 133, 113, 95, 77, 60, 43, + 28, 13 +}; + +static int16 mdp_scale_0p8_to_8p0_C2[MDP_SCALE_COEFF_NUM] = { + 0, 13, 28, 43, 60, 77, 95, 113, 133, 152, + 172, 193, 213, 233, 253, 274, 294, 314, 333, 352, + 370, 388, 405, 422, 436, 450, 463, 475, 485, 494, + 501, 507, +}; + +static int16 mdp_scale_0p8_to_8p0_C3[MDP_SCALE_COEFF_NUM] = { + 0, -2, -5, -7, -10, -13, -15, -18, -21, -24, + -26, -29, -31, -33, -35, -37, -38, -40, -40, -41, + -41, -41, -40, -39, -37, -34, -32, -28, -24, -19, + -13, -7 +}; + +/* -------- Downscale, ranging from 0.6x to 0.8x of original size -------- */ + +static int16 mdp_scale_0p6_to_0p8_C0[MDP_SCALE_COEFF_NUM] = { + 104, 96, 89, 82, 75, 68, 61, 55, 49, 43, + 38, 33, 28, 24, 20, 16, 12, 9, 6, 4, + 2, 0, -2, -4, -5, -6, -7, -7, -8, -8, + -8, -8 +}; + +static int16 mdp_scale_0p6_to_0p8_C1[MDP_SCALE_COEFF_NUM] = { + 303, 303, 302, 300, 298, 296, 293, 289, 286, 281, + 276, 270, 265, 258, 252, 245, 238, 230, 223, 214, + 206, 197, 189, 180, 172, 163, 154, 145, 137, 128, + 120, 112 +}; + +static int16 mdp_scale_0p6_to_0p8_C2[MDP_SCALE_COEFF_NUM] = { + 112, 120, 128, 137, 145, 154, 163, 172, 180, 189, + 197, 206, 214, 223, 230, 238, 245, 252, 258, 265, + 270, 276, 281, 286, 289, 293, 296, 298, 300, 302, + 303, 303 +}; + +static int16 mdp_scale_0p6_to_0p8_C3[MDP_SCALE_COEFF_NUM] = { + -8, -8, -8, -8, -7, -7, -6, -5, -4, -2, + 0, 2, 4, 6, 9, 12, 16, 20, 24, 28, + 33, 38, 43, 49, 55, 61, 68, 75, 82, 89, + 96, 104 +}; + +/* -------- Downscale, ranging from 0.4x to 0.6x of original size -------- */ + +static int16 mdp_scale_0p4_to_0p6_C0[MDP_SCALE_COEFF_NUM] = { + 136, 132, 128, 123, 119, 115, 111, 107, 103, 98, + 95, 91, 87, 84, 80, 76, 73, 69, 66, 62, + 59, 57, 54, 50, 47, 44, 41, 39, 36, 33, + 32, 29 +}; + +static int16 mdp_scale_0p4_to_0p6_C1[MDP_SCALE_COEFF_NUM] = { + 206, 205, 204, 204, 201, 200, 199, 197, 196, 194, + 191, 191, 189, 185, 184, 182, 180, 178, 176, 173, + 170, 168, 165, 162, 160, 157, 155, 152, 148, 146, + 142, 140 +}; + +static int16 mdp_scale_0p4_to_0p6_C2[MDP_SCALE_COEFF_NUM] = { + 140, 142, 146, 148, 152, 155, 157, 160, 162, 165, + 168, 170, 173, 176, 178, 180, 182, 184, 185, 189, + 191, 191, 194, 196, 197, 199, 200, 201, 204, 204, + 205, 206 +}; + +static int16 mdp_scale_0p4_to_0p6_C3[MDP_SCALE_COEFF_NUM] = { + 29, 32, 33, 36, 39, 41, 44, 47, 50, 54, + 57, 59, 62, 66, 69, 73, 76, 80, 84, 87, + 91, 95, 98, 103, 107, 111, 115, 119, 123, 128, + 132, 136 +}; + +/* -------- Downscale, ranging from 0.2x to 0.4x of original size -------- */ + +static int16 mdp_scale_0p2_to_0p4_C0[MDP_SCALE_COEFF_NUM] = { + 131, 131, 130, 129, 128, 127, 127, 126, 125, 125, + 124, 123, 123, 121, 120, 119, 119, 118, 117, 117, + 116, 115, 115, 114, 113, 112, 111, 110, 109, 109, + 108, 107 +}; + +static int16 mdp_scale_0p2_to_0p4_C1[MDP_SCALE_COEFF_NUM] = { + 141, 140, 140, 140, 140, 139, 138, 138, 138, 137, + 137, 137, 136, 137, 137, 137, 136, 136, 136, 135, + 135, 135, 134, 134, 134, 134, 134, 133, 133, 132, + 132, 132 +}; + +static int16 mdp_scale_0p2_to_0p4_C2[MDP_SCALE_COEFF_NUM] = { + 132, 132, 132, 133, 133, 134, 134, 134, 134, 134, + 135, 135, 135, 136, 136, 136, 137, 137, 137, 136, + 137, 137, 137, 138, 138, 138, 139, 140, 140, 140, + 140, 141 +}; + +static int16 mdp_scale_0p2_to_0p4_C3[MDP_SCALE_COEFF_NUM] = { + 107, 108, 109, 109, 110, 111, 112, 113, 114, 115, + 115, 116, 117, 117, 118, 119, 119, 120, 121, 123, + 123, 124, 125, 125, 126, 127, 127, 128, 129, 130, + 131, 131 +}; + +static void mdp_update_scale_table(int index, int16 *c0, int16 *c1, + int16 *c2, int16 *c3) +{ + int i, val; + + for (i = 0; i < MDP_SCALE_COEFF_NUM; i++) { + val = + ((MDP_SCALE_COEFF_MASK & c1[i]) << 16) | + (MDP_SCALE_COEFF_MASK & c0[i]); + writel(val, MDP_PPP_SCALE_COEFF_LSBn(index)); + val = + ((MDP_SCALE_COEFF_MASK & c3[i]) << 16) | + (MDP_SCALE_COEFF_MASK & c2[i]); + writel(val, MDP_PPP_SCALE_COEFF_MSBn(index)); + index++; + } +} + +void mdp_init_scale_table(void) +{ + mdp_scale_0p2_to_0p4_mode = MDP_SCALE_FIR; + mdp_update_scale_table(MDP_SCALE_0P2_TO_0P4_INDEX, + mdp_scale_0p2_to_0p4_C0, + mdp_scale_0p2_to_0p4_C1, + mdp_scale_0p2_to_0p4_C2, + mdp_scale_0p2_to_0p4_C3); + + mdp_scale_0p4_to_0p6_mode = MDP_SCALE_FIR; + mdp_update_scale_table(MDP_SCALE_0P4_TO_0P6_INDEX, + mdp_scale_0p4_to_0p6_C0, + mdp_scale_0p4_to_0p6_C1, + mdp_scale_0p4_to_0p6_C2, + mdp_scale_0p4_to_0p6_C3); + + mdp_scale_0p6_to_0p8_mode = MDP_SCALE_FIR; + mdp_update_scale_table(MDP_SCALE_0P6_TO_0P8_INDEX, + mdp_scale_0p6_to_0p8_C0, + mdp_scale_0p6_to_0p8_C1, + mdp_scale_0p6_to_0p8_C2, + mdp_scale_0p6_to_0p8_C3); + + mdp_scale_0p8_to_8p0_mode = MDP_SCALE_FIR; + mdp_update_scale_table(MDP_SCALE_0P8_TO_8P0_INDEX, + mdp_scale_0p8_to_8p0_C0, + mdp_scale_0p8_to_8p0_C1, + mdp_scale_0p8_to_8p0_C2, + mdp_scale_0p8_to_8p0_C3); +} + +static long long mdp_do_div(long long num, long long den) +{ + do_div(num, den); + return num; +} + +#define SCALER_PHASE_BITS 29 +#define HAL_MDP_PHASE_STEP_2P50 0x50000000 +#define HAL_MDP_PHASE_STEP_1P66 0x35555555 +#define HAL_MDP_PHASE_STEP_1P25 0x28000000 + +struct phase_val { + int phase_init_x; + int phase_init_y; + int phase_step_x; + int phase_step_y; +}; + +static void mdp_calc_scaleInitPhase_3p1(uint32 in_w, + uint32 in_h, + uint32 out_w, + uint32 out_h, + boolean is_rotate, + boolean is_pp_x, + boolean is_pp_y, struct phase_val *pval) +{ + uint64 dst_ROI_width; + uint64 dst_ROI_height; + uint64 src_ROI_width; + uint64 src_ROI_height; + + /* + * phase_step_x, phase_step_y, phase_init_x and phase_init_y + * are represented in fixed-point, unsigned 3.29 format + */ + uint32 phase_step_x = 0; + uint32 phase_step_y = 0; + uint32 phase_init_x = 0; + uint32 phase_init_y = 0; + uint32 yscale_filter_sel, xscale_filter_sel; + uint32 scale_unit_sel_x, scale_unit_sel_y; + + uint64 numerator, denominator; + uint64 temp_dim; + + src_ROI_width = in_w; + src_ROI_height = in_h; + dst_ROI_width = out_w; + dst_ROI_height = out_h; + + /* if there is a 90 degree rotation */ + if (is_rotate) { + /* decide whether to use FIR or M/N for scaling */ + + /* if down-scaling by a factor smaller than 1/4 */ + if ((dst_ROI_height == 1 && src_ROI_width < 4) || + (src_ROI_width < 4 * dst_ROI_height - 3)) + scale_unit_sel_x = 0;/* use FIR scalar */ + else + scale_unit_sel_x = 1;/* use M/N scalar */ + + /* if down-scaling by a factor smaller than 1/4 */ + if ((dst_ROI_width == 1 && src_ROI_height < 4) || + (src_ROI_height < 4 * dst_ROI_width - 3)) + scale_unit_sel_y = 0;/* use FIR scalar */ + else + scale_unit_sel_y = 1;/* use M/N scalar */ + } else { + /* decide whether to use FIR or M/N for scaling */ + if ((dst_ROI_width == 1 && src_ROI_width < 4) || + (src_ROI_width < 4 * dst_ROI_width - 3)) + scale_unit_sel_x = 0;/* use FIR scalar */ + else + scale_unit_sel_x = 1;/* use M/N scalar */ + + if ((dst_ROI_height == 1 && src_ROI_height < 4) || + (src_ROI_height < 4 * dst_ROI_height - 3)) + scale_unit_sel_y = 0;/* use FIR scalar */ + else + scale_unit_sel_y = 1;/* use M/N scalar */ + } + + /* if there is a 90 degree rotation */ + if (is_rotate) { + /* swap the width and height of dst ROI */ + temp_dim = dst_ROI_width; + dst_ROI_width = dst_ROI_height; + dst_ROI_height = temp_dim; + } + + /* calculate phase step for the x direction */ + + /* if destination is only 1 pixel wide, the value of phase_step_x + is unimportant. Assigning phase_step_x to src ROI width + as an arbitrary value. */ + if (dst_ROI_width == 1) + phase_step_x = (uint32) ((src_ROI_width) << SCALER_PHASE_BITS); + + /* if using FIR scalar */ + else if (scale_unit_sel_x == 0) { + + /* Calculate the quotient ( src_ROI_width - 1 ) / ( dst_ROI_width - 1) + with u3.29 precision. Quotient is rounded up to the larger + 29th decimal point. */ + numerator = (src_ROI_width - 1) << SCALER_PHASE_BITS; + denominator = (dst_ROI_width - 1); /* never equals to 0 because of the "( dst_ROI_width == 1 ) case" */ + phase_step_x = (uint32) mdp_do_div((numerator + denominator - 1), denominator); /* divide and round up to the larger 29th decimal point. */ + + } + + /* if M/N scalar */ + else if (scale_unit_sel_x == 1) { + /* Calculate the quotient ( src_ROI_width ) / ( dst_ROI_width) + with u3.29 precision. Quotient is rounded down to the + smaller 29th decimal point. */ + numerator = (src_ROI_width) << SCALER_PHASE_BITS; + denominator = (dst_ROI_width); + phase_step_x = (uint32) mdp_do_div(numerator, denominator); + } + /* calculate phase step for the y direction */ + + /* if destination is only 1 pixel wide, the value of + phase_step_x is unimportant. Assigning phase_step_x + to src ROI width as an arbitrary value. */ + if (dst_ROI_height == 1) + phase_step_y = (uint32) ((src_ROI_height) << SCALER_PHASE_BITS); + + /* if FIR scalar */ + else if (scale_unit_sel_y == 0) { + /* Calculate the quotient ( src_ROI_height - 1 ) / ( dst_ROI_height - 1) + with u3.29 precision. Quotient is rounded up to the larger + 29th decimal point. */ + numerator = (src_ROI_height - 1) << SCALER_PHASE_BITS; + denominator = (dst_ROI_height - 1); /* never equals to 0 because of the "( dst_ROI_height == 1 )" case */ + phase_step_y = (uint32) mdp_do_div((numerator + denominator - 1), denominator); /* Quotient is rounded up to the larger 29th decimal point. */ + + } + + /* if M/N scalar */ + else if (scale_unit_sel_y == 1) { + /* Calculate the quotient ( src_ROI_height ) / ( dst_ROI_height) + with u3.29 precision. Quotient is rounded down to the smaller + 29th decimal point. */ + numerator = (src_ROI_height) << SCALER_PHASE_BITS; + denominator = (dst_ROI_height); + phase_step_y = (uint32) mdp_do_div(numerator, denominator); + } + + /* decide which set of FIR coefficients to use */ + if (phase_step_x > HAL_MDP_PHASE_STEP_2P50) + xscale_filter_sel = 0; + else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66) + xscale_filter_sel = 1; + else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25) + xscale_filter_sel = 2; + else + xscale_filter_sel = 3; + + if (phase_step_y > HAL_MDP_PHASE_STEP_2P50) + yscale_filter_sel = 0; + else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66) + yscale_filter_sel = 1; + else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25) + yscale_filter_sel = 2; + else + yscale_filter_sel = 3; + + /* calculate phase init for the x direction */ + + /* if using FIR scalar */ + if (scale_unit_sel_x == 0) { + if (dst_ROI_width == 1) + phase_init_x = + (uint32) ((src_ROI_width - 1) << SCALER_PHASE_BITS); + else + phase_init_x = 0; + + } + /* M over N scalar */ + else if (scale_unit_sel_x == 1) + phase_init_x = 0; + + /* calculate phase init for the y direction + if using FIR scalar */ + if (scale_unit_sel_y == 0) { + if (dst_ROI_height == 1) + phase_init_y = + (uint32) ((src_ROI_height - + 1) << SCALER_PHASE_BITS); + else + phase_init_y = 0; + + } + /* M over N scalar */ + else if (scale_unit_sel_y == 1) + phase_init_y = 0; + + /* write registers */ + pval->phase_step_x = (uint32) phase_step_x; + pval->phase_step_y = (uint32) phase_step_y; + pval->phase_init_x = (uint32) phase_init_x; + pval->phase_init_y = (uint32) phase_init_y; + + return; +} + +void mdp_set_scale(MDPIBUF *iBuf, + uint32 dst_roi_width, + uint32 dst_roi_height, + boolean inputRGB, boolean outputRGB, uint32 *pppop_reg_ptr) +{ + uint32 dst_roi_width_scale; + uint32 dst_roi_height_scale; + struct phase_val pval; + boolean use_pr; + uint32 ppp_scale_config = 0; + + if (!inputRGB) + ppp_scale_config |= BIT(6); + + if (iBuf->mdpImg.mdpOp & MDPOP_ASCALE) { + if (iBuf->mdpImg.mdpOp & MDPOP_ROT90) { + dst_roi_width_scale = dst_roi_height; + dst_roi_height_scale = dst_roi_width; + } else { + dst_roi_width_scale = dst_roi_width; + dst_roi_height_scale = dst_roi_height; + } + + if ((dst_roi_width_scale != iBuf->roi.width) || + (dst_roi_height_scale != iBuf->roi.height) || + (iBuf->mdpImg.mdpOp & MDPOP_SHARPENING)) { + *pppop_reg_ptr |= + (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON); + + mdp_calc_scaleInitPhase_3p1(iBuf->roi.width, + iBuf->roi.height, + dst_roi_width, + dst_roi_height, + iBuf->mdpImg. + mdpOp & MDPOP_ROT90, 1, 1, + &pval); + + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x013c, + pval.phase_init_x); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0140, + pval.phase_init_y); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0144, + pval.phase_step_x); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0148, + pval.phase_step_y); + + /* disable the pixel repeat option for scaling */ + use_pr = false; + + /* x-direction */ + if ((dst_roi_width_scale == iBuf->roi.width) && + !(iBuf->mdpImg.mdpOp & MDPOP_SHARPENING)) { + *pppop_reg_ptr &= ~PPP_OP_SCALE_X_ON; + } else + if (((dst_roi_width_scale * 10) / iBuf->roi.width) > + 8) { + if ((use_pr) + && (mdp_scale_0p8_to_8p0_mode != + MDP_SCALE_PR)) { + mdp_scale_0p8_to_8p0_mode = + MDP_SCALE_PR; + mdp_update_scale_table + (MDP_SCALE_0P8_TO_8P0_INDEX, + mdp_scale_pixel_repeat_C0, + mdp_scale_pixel_repeat_C1, + mdp_scale_pixel_repeat_C2, + mdp_scale_pixel_repeat_C3); + } else if ((!use_pr) + && (mdp_scale_0p8_to_8p0_mode != + MDP_SCALE_FIR)) { + mdp_scale_0p8_to_8p0_mode = + MDP_SCALE_FIR; + mdp_update_scale_table + (MDP_SCALE_0P8_TO_8P0_INDEX, + mdp_scale_0p8_to_8p0_C0, + mdp_scale_0p8_to_8p0_C1, + mdp_scale_0p8_to_8p0_C2, + mdp_scale_0p8_to_8p0_C3); + } + ppp_scale_config |= (SCALE_U1_SET << 2); + } else + if (((dst_roi_width_scale * 10) / iBuf->roi.width) > + 6) { + if ((use_pr) + && (mdp_scale_0p6_to_0p8_mode != + MDP_SCALE_PR)) { + mdp_scale_0p6_to_0p8_mode = + MDP_SCALE_PR; + mdp_update_scale_table + (MDP_SCALE_0P6_TO_0P8_INDEX, + mdp_scale_pixel_repeat_C0, + mdp_scale_pixel_repeat_C1, + mdp_scale_pixel_repeat_C2, + mdp_scale_pixel_repeat_C3); + } else if ((!use_pr) + && (mdp_scale_0p6_to_0p8_mode != + MDP_SCALE_FIR)) { + mdp_scale_0p6_to_0p8_mode = + MDP_SCALE_FIR; + mdp_update_scale_table + (MDP_SCALE_0P6_TO_0P8_INDEX, + mdp_scale_0p6_to_0p8_C0, + mdp_scale_0p6_to_0p8_C1, + mdp_scale_0p6_to_0p8_C2, + mdp_scale_0p6_to_0p8_C3); + } + ppp_scale_config |= (SCALE_D2_SET << 2); + } else + if (((dst_roi_width_scale * 10) / iBuf->roi.width) > + 4) { + if ((use_pr) + && (mdp_scale_0p4_to_0p6_mode != + MDP_SCALE_PR)) { + mdp_scale_0p4_to_0p6_mode = + MDP_SCALE_PR; + mdp_update_scale_table + (MDP_SCALE_0P4_TO_0P6_INDEX, + mdp_scale_pixel_repeat_C0, + mdp_scale_pixel_repeat_C1, + mdp_scale_pixel_repeat_C2, + mdp_scale_pixel_repeat_C3); + } else if ((!use_pr) + && (mdp_scale_0p4_to_0p6_mode != + MDP_SCALE_FIR)) { + mdp_scale_0p4_to_0p6_mode = + MDP_SCALE_FIR; + mdp_update_scale_table + (MDP_SCALE_0P4_TO_0P6_INDEX, + mdp_scale_0p4_to_0p6_C0, + mdp_scale_0p4_to_0p6_C1, + mdp_scale_0p4_to_0p6_C2, + mdp_scale_0p4_to_0p6_C3); + } + ppp_scale_config |= (SCALE_D1_SET << 2); + } else + if ((dst_roi_width_scale == 1 && iBuf->roi.width < 4) || + (iBuf->roi.width < 4 * dst_roi_width_scale - 3)) { + if ((use_pr) + && (mdp_scale_0p2_to_0p4_mode != + MDP_SCALE_PR)) { + mdp_scale_0p2_to_0p4_mode = + MDP_SCALE_PR; + mdp_update_scale_table + (MDP_SCALE_0P2_TO_0P4_INDEX, + mdp_scale_pixel_repeat_C0, + mdp_scale_pixel_repeat_C1, + mdp_scale_pixel_repeat_C2, + mdp_scale_pixel_repeat_C3); + } else if ((!use_pr) + && (mdp_scale_0p2_to_0p4_mode != + MDP_SCALE_FIR)) { + mdp_scale_0p2_to_0p4_mode = + MDP_SCALE_FIR; + mdp_update_scale_table + (MDP_SCALE_0P2_TO_0P4_INDEX, + mdp_scale_0p2_to_0p4_C0, + mdp_scale_0p2_to_0p4_C1, + mdp_scale_0p2_to_0p4_C2, + mdp_scale_0p2_to_0p4_C3); + } + ppp_scale_config |= (SCALE_D0_SET << 2); + } else + ppp_scale_config |= BIT(0); + + /* y-direction */ + if ((dst_roi_height_scale == iBuf->roi.height) && + !(iBuf->mdpImg.mdpOp & MDPOP_SHARPENING)) { + *pppop_reg_ptr &= ~PPP_OP_SCALE_Y_ON; + } else if (((dst_roi_height_scale * 10) / + iBuf->roi.height) > 8) { + if ((use_pr) + && (mdp_scale_0p8_to_8p0_mode != + MDP_SCALE_PR)) { + mdp_scale_0p8_to_8p0_mode = + MDP_SCALE_PR; + mdp_update_scale_table + (MDP_SCALE_0P8_TO_8P0_INDEX, + mdp_scale_pixel_repeat_C0, + mdp_scale_pixel_repeat_C1, + mdp_scale_pixel_repeat_C2, + mdp_scale_pixel_repeat_C3); + } else if ((!use_pr) + && (mdp_scale_0p8_to_8p0_mode != + MDP_SCALE_FIR)) { + mdp_scale_0p8_to_8p0_mode = + MDP_SCALE_FIR; + mdp_update_scale_table + (MDP_SCALE_0P8_TO_8P0_INDEX, + mdp_scale_0p8_to_8p0_C0, + mdp_scale_0p8_to_8p0_C1, + mdp_scale_0p8_to_8p0_C2, + mdp_scale_0p8_to_8p0_C3); + } + ppp_scale_config |= (SCALE_U1_SET << 4); + } else + if (((dst_roi_height_scale * 10) / + iBuf->roi.height) > 6) { + if ((use_pr) + && (mdp_scale_0p6_to_0p8_mode != + MDP_SCALE_PR)) { + mdp_scale_0p6_to_0p8_mode = + MDP_SCALE_PR; + mdp_update_scale_table + (MDP_SCALE_0P6_TO_0P8_INDEX, + mdp_scale_pixel_repeat_C0, + mdp_scale_pixel_repeat_C1, + mdp_scale_pixel_repeat_C2, + mdp_scale_pixel_repeat_C3); + } else if ((!use_pr) + && (mdp_scale_0p6_to_0p8_mode != + MDP_SCALE_FIR)) { + mdp_scale_0p6_to_0p8_mode = + MDP_SCALE_FIR; + mdp_update_scale_table + (MDP_SCALE_0P6_TO_0P8_INDEX, + mdp_scale_0p6_to_0p8_C0, + mdp_scale_0p6_to_0p8_C1, + mdp_scale_0p6_to_0p8_C2, + mdp_scale_0p6_to_0p8_C3); + } + ppp_scale_config |= (SCALE_D2_SET << 4); + } else + if (((dst_roi_height_scale * 10) / + iBuf->roi.height) > 4) { + if ((use_pr) + && (mdp_scale_0p4_to_0p6_mode != + MDP_SCALE_PR)) { + mdp_scale_0p4_to_0p6_mode = + MDP_SCALE_PR; + mdp_update_scale_table + (MDP_SCALE_0P4_TO_0P6_INDEX, + mdp_scale_pixel_repeat_C0, + mdp_scale_pixel_repeat_C1, + mdp_scale_pixel_repeat_C2, + mdp_scale_pixel_repeat_C3); + } else if ((!use_pr) + && (mdp_scale_0p4_to_0p6_mode != + MDP_SCALE_FIR)) { + mdp_scale_0p4_to_0p6_mode = + MDP_SCALE_FIR; + mdp_update_scale_table + (MDP_SCALE_0P4_TO_0P6_INDEX, + mdp_scale_0p4_to_0p6_C0, + mdp_scale_0p4_to_0p6_C1, + mdp_scale_0p4_to_0p6_C2, + mdp_scale_0p4_to_0p6_C3); + } + ppp_scale_config |= (SCALE_D1_SET << 4); + } else if ((dst_roi_height_scale == 1 && + iBuf->roi.height < 4) || + (iBuf->roi.height < 4 * dst_roi_height_scale - 3)) { + if ((use_pr) + && (mdp_scale_0p2_to_0p4_mode != + MDP_SCALE_PR)) { + mdp_scale_0p2_to_0p4_mode = + MDP_SCALE_PR; + mdp_update_scale_table + (MDP_SCALE_0P2_TO_0P4_INDEX, + mdp_scale_pixel_repeat_C0, + mdp_scale_pixel_repeat_C1, + mdp_scale_pixel_repeat_C2, + mdp_scale_pixel_repeat_C3); + } else if ((!use_pr) + && (mdp_scale_0p2_to_0p4_mode != + MDP_SCALE_FIR)) { + mdp_scale_0p2_to_0p4_mode = + MDP_SCALE_FIR; + mdp_update_scale_table + (MDP_SCALE_0P2_TO_0P4_INDEX, + mdp_scale_0p2_to_0p4_C0, + mdp_scale_0p2_to_0p4_C1, + mdp_scale_0p2_to_0p4_C2, + mdp_scale_0p2_to_0p4_C3); + } + ppp_scale_config |= (SCALE_D0_SET << 4); + } else + ppp_scale_config |= BIT(1); + + if (iBuf->mdpImg.mdpOp & MDPOP_SHARPENING) { + ppp_scale_config |= BIT(7); + MDP_OUTP(MDP_BASE + 0x50020, + iBuf->mdpImg.sp_value); + } + + MDP_OUTP(MDP_BASE + 0x10230, ppp_scale_config); + } else { + iBuf->mdpImg.mdpOp &= ~(MDPOP_ASCALE); + } + } +} + +void mdp_adjust_start_addr(uint8 **src0, + uint8 **src1, + int v_slice, + int h_slice, + int x, + int y, + uint32 width, + uint32 height, int bpp, MDPIBUF *iBuf, int layer) +{ + switch (layer) { + case 0: + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0200, (y << 16) | (x)); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0208, + (height << 16) | (width)); + break; + + case 1: + /* MDP 3.1 HW bug workaround */ + if (iBuf->ibuf_type == MDP_YCRYCB_H2V1) { + *src0 += (x + y * width) * bpp; + x = y = 0; + width = iBuf->roi.dst_width; + height = iBuf->roi.dst_height; + } + + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0204, (y << 16) | (x)); + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x020c, + (height << 16) | (width)); + break; + + case 2: + MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x019c, (y << 16) | (x)); + break; + } +} + +void mdp_set_blend_attr(MDPIBUF *iBuf, + uint32 *alpha, + uint32 *tpVal, + uint32 perPixelAlpha, uint32 *pppop_reg_ptr) +{ + int bg_alpha; + + *alpha = iBuf->mdpImg.alpha; + *tpVal = iBuf->mdpImg.tpVal; + + if (iBuf->mdpImg.mdpOp & MDPOP_FG_PM_ALPHA) { + if (perPixelAlpha) { + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | PPP_OP_BLEND_CONSTANT_ALPHA; + } + else { + if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) + && (iBuf->mdpImg.alpha == 0xff)) { + iBuf->mdpImg.mdpOp &= ~(MDPOP_ALPHAB); + } + + if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) + || (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)) { + *pppop_reg_ptr |= + PPP_OP_ROT_ON | PPP_OP_BLEND_ON | + PPP_OP_BLEND_CONSTANT_ALPHA | + PPP_OP_BLEND_ALPHA_BLEND_NORMAL; + } + } + + bg_alpha = PPP_BLEND_BG_USE_ALPHA_SEL | + PPP_BLEND_BG_ALPHA_REVERSE; + + if (perPixelAlpha) + bg_alpha |= PPP_BLEND_BG_SRCPIXEL_ALPHA; + else { + bg_alpha |= PPP_BLEND_BG_CONSTANT_ALPHA; + bg_alpha |= iBuf->mdpImg.alpha << 24; + } + outpdw(MDP_BASE + 0x70010, bg_alpha); + + if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP) + *pppop_reg_ptr |= PPP_BLEND_CALPHA_TRNASP; + } else if (perPixelAlpha) { + *pppop_reg_ptr |= PPP_OP_ROT_ON | + PPP_OP_BLEND_ON | PPP_OP_BLEND_SRCPIXEL_ALPHA; + } else { + if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) + && (iBuf->mdpImg.alpha == 0xff)) { + iBuf->mdpImg.mdpOp &= ~(MDPOP_ALPHAB); + } + + if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) + || (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)) { + *pppop_reg_ptr |= + PPP_OP_ROT_ON | PPP_OP_BLEND_ON | + PPP_OP_BLEND_CONSTANT_ALPHA | + PPP_OP_BLEND_ALPHA_BLEND_NORMAL; + } + + if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP) + *pppop_reg_ptr |= PPP_BLEND_CALPHA_TRNASP; + } +} diff --git a/drivers/video/msm/mdp_vsync.c b/drivers/video/msm/mdp_vsync.c new file mode 100644 index 000000000000..c80a7cc8e078 --- /dev/null +++ b/drivers/video/msm/mdp_vsync.c @@ -0,0 +1,491 @@ +/* Copyright (c) 2008-2009, 2012 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "mdp.h" +#include "msm_fb.h" +#include "mddihost.h" + +#ifdef CONFIG_FB_MSM_MDP40 +#include "mdp4.h" + +#define MDP_SYNC_CFG_0 0x100 +#define MDP_SYNC_STATUS_0 0x10c +#define MDP_SYNC_CFG_1 0x104 +#define MDP_SYNC_STATUS_1 0x110 +#define MDP_PRIM_VSYNC_OUT_CTRL 0x118 +#define MDP_SEC_VSYNC_OUT_CTRL 0x11C +#define MDP_VSYNC_SEL 0x124 +#define MDP_PRIM_VSYNC_INIT_VAL 0x128 +#define MDP_SEC_VSYNC_INIT_VAL 0x12C +#else +#define MDP_SYNC_CFG_0 0x300 +#define MDP_SYNC_STATUS_0 0x30c +#define MDP_PRIM_VSYNC_OUT_CTRL 0x318 +#define MDP_PRIM_VSYNC_INIT_VAL 0x328 +#endif + +extern mddi_lcd_type mddi_lcd_idx; +extern spinlock_t mdp_spin_lock; +extern struct workqueue_struct *mdp_vsync_wq; +extern int lcdc_mode; +extern int vsync_mode; + +#ifdef MDP_HW_VSYNC +int vsync_above_th = 4; +int vsync_start_th = 1; +int vsync_load_cnt; +int vsync_clk_status; +DEFINE_MUTEX(vsync_clk_lock); +static DEFINE_SPINLOCK(vsync_timer_lock); + +static struct clk *mdp_vsync_clk; +static struct msm_fb_data_type *vsync_mfd; +static unsigned char timer_shutdown_flag; +static uint32 vsync_cnt_cfg; + +void mdp_hw_vsync_clk_enable(struct msm_fb_data_type *mfd) +{ + if (vsync_clk_status == 1) + return; + mutex_lock(&vsync_clk_lock); + if (mfd->use_mdp_vsync) { + clk_prepare_enable(mdp_vsync_clk); + vsync_clk_status = 1; + } + mutex_unlock(&vsync_clk_lock); +} + +void mdp_hw_vsync_clk_disable(struct msm_fb_data_type *mfd) +{ + if (vsync_clk_status == 0) + return; + mutex_lock(&vsync_clk_lock); + if (mfd->use_mdp_vsync) { + clk_disable_unprepare(mdp_vsync_clk); + vsync_clk_status = 0; + } + mutex_unlock(&vsync_clk_lock); +} + +static void mdp_set_vsync(unsigned long data); +void mdp_vsync_clk_enable(void) +{ + if (vsync_mfd) { + mdp_hw_vsync_clk_enable(vsync_mfd); + if (!vsync_mfd->vsync_resync_timer.function) + mdp_set_vsync((unsigned long) vsync_mfd); + } +} + +void mdp_vsync_clk_disable(void) +{ + if (vsync_mfd) { + if (vsync_mfd->vsync_resync_timer.function) { + spin_lock(&vsync_timer_lock); + timer_shutdown_flag = 1; + spin_unlock(&vsync_timer_lock); + del_timer_sync(&vsync_mfd->vsync_resync_timer); + spin_lock(&vsync_timer_lock); + timer_shutdown_flag = 0; + spin_unlock(&vsync_timer_lock); + vsync_mfd->vsync_resync_timer.function = NULL; + } + + mdp_hw_vsync_clk_disable(vsync_mfd); + } +} +#endif + +static void mdp_set_vsync(unsigned long data) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data; + struct msm_fb_panel_data *pdata = NULL; + + pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + + vsync_mfd = mfd; + init_timer(&mfd->vsync_resync_timer); + + if ((pdata) && (pdata->set_vsync_notifier == NULL)) + return; + + if ((mfd->panel_info.lcd.vsync_enable) && (mfd->panel_power_on) + && (!mfd->vsync_handler_pending)) { + mfd->vsync_handler_pending = TRUE; + if (!queue_work(mdp_vsync_wq, &mfd->vsync_resync_worker)) { + MSM_FB_INFO + ("mdp_set_vsync: can't queue_work! -> needs to increase vsync_resync_timer_duration\n"); + } + } else { + MSM_FB_DEBUG + ("mdp_set_vsync failed! EN:%d PWR:%d PENDING:%d\n", + mfd->panel_info.lcd.vsync_enable, mfd->panel_power_on, + mfd->vsync_handler_pending); + } + + spin_lock(&vsync_timer_lock); + if (!timer_shutdown_flag) { + mfd->vsync_resync_timer.function = mdp_set_vsync; + mfd->vsync_resync_timer.data = data; + mfd->vsync_resync_timer.expires = + jiffies + mfd->panel_info.lcd.vsync_notifier_period; + add_timer(&mfd->vsync_resync_timer); + } + spin_unlock(&vsync_timer_lock); +} + +static void mdp_vsync_handler(void *data) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data; + + if (vsync_clk_status == 0) { + pr_debug("Warning: vsync clk is disabled\n"); + mfd->vsync_handler_pending = FALSE; + return; + } + + if (mfd->use_mdp_vsync) { +#ifdef MDP_HW_VSYNC + if (mfd->panel_power_on) { + MDP_OUTP(MDP_BASE + MDP_SYNC_STATUS_0, vsync_load_cnt); + +#ifdef CONFIG_FB_MSM_MDP40 + if (mdp_hw_revision < MDP4_REVISION_V2_1) + MDP_OUTP(MDP_BASE + MDP_SYNC_STATUS_1, + vsync_load_cnt); +#endif + } + +#endif + } else { + mfd->last_vsync_timetick = ktime_get_real(); + } + + mfd->vsync_handler_pending = FALSE; +} + +irqreturn_t mdp_hw_vsync_handler_proxy(int irq, void *data) +{ + /* + * ToDo: tried enabling/disabling GPIO MDP HW VSYNC interrupt + * but getting inaccurate timing in mdp_vsync_handler() + * disable_irq(MDP_HW_VSYNC_IRQ); + */ + mdp_vsync_handler(data); + + return IRQ_HANDLED; +} + +#ifdef MDP_HW_VSYNC +static void mdp_set_sync_cfg_0(struct msm_fb_data_type *mfd, int vsync_cnt) +{ + unsigned long cfg; + + cfg = mfd->total_lcd_lines - 1; + cfg <<= MDP_SYNCFG_HGT_LOC; + if (mfd->panel_info.lcd.hw_vsync_mode) + cfg |= MDP_SYNCFG_VSYNC_EXT_EN; + cfg |= (MDP_SYNCFG_VSYNC_INT_EN | vsync_cnt); + + MDP_OUTP(MDP_BASE + MDP_SYNC_CFG_0, cfg); +} + +#ifdef CONFIG_FB_MSM_MDP40 +static void mdp_set_sync_cfg_1(struct msm_fb_data_type *mfd, int vsync_cnt) +{ + unsigned long cfg; + + cfg = mfd->total_lcd_lines - 1; + cfg <<= MDP_SYNCFG_HGT_LOC; + if (mfd->panel_info.lcd.hw_vsync_mode) + cfg |= MDP_SYNCFG_VSYNC_EXT_EN; + cfg |= (MDP_SYNCFG_VSYNC_INT_EN | vsync_cnt); + + MDP_OUTP(MDP_BASE + MDP_SYNC_CFG_1, cfg); +} +#endif + +void mdp_vsync_cfg_regs(struct msm_fb_data_type *mfd, + boolean first_time) +{ + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, + FALSE); + if (first_time) + mdp_hw_vsync_clk_enable(mfd); + + mdp_set_sync_cfg_0(mfd, vsync_cnt_cfg); + +#ifdef CONFIG_FB_MSM_MDP40 + if (mdp_hw_revision < MDP4_REVISION_V2_1) + mdp_set_sync_cfg_1(mfd, vsync_cnt_cfg); +#endif + + /* + * load the last line + 1 to be in the + * safety zone + */ + vsync_load_cnt = mfd->panel_info.yres; + + /* line counter init value at the next pulse */ + MDP_OUTP(MDP_BASE + MDP_PRIM_VSYNC_INIT_VAL, + vsync_load_cnt); +#ifdef CONFIG_FB_MSM_MDP40 + if (mdp_hw_revision < MDP4_REVISION_V2_1) { + MDP_OUTP(MDP_BASE + MDP_SEC_VSYNC_INIT_VAL, + vsync_load_cnt); + } +#endif + + /* + * external vsync source pulse width and + * polarity flip + */ + MDP_OUTP(MDP_BASE + MDP_PRIM_VSYNC_OUT_CTRL, BIT(0)); +#ifdef CONFIG_FB_MSM_MDP40 + if (mdp_hw_revision < MDP4_REVISION_V2_1) { + MDP_OUTP(MDP_BASE + MDP_SEC_VSYNC_OUT_CTRL, BIT(0)); + MDP_OUTP(MDP_BASE + MDP_VSYNC_SEL, 0x20); + } +#endif + + /* threshold */ + MDP_OUTP(MDP_BASE + 0x200, (vsync_above_th << 16) | + (vsync_start_th)); + + if (first_time) + mdp_hw_vsync_clk_disable(mfd); + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); +} +#endif + +void mdp_config_vsync(struct platform_device *pdev, + struct msm_fb_data_type *mfd) +{ + /* vsync on primary lcd only for now */ + if ((mfd->dest != DISPLAY_LCD) || (mfd->panel_info.pdest != DISPLAY_1) + || (!vsync_mode)) { + goto err_handle; + } + + vsync_clk_status = 0; + if (mfd->panel_info.lcd.vsync_enable) { + mfd->total_porch_lines = mfd->panel_info.lcd.v_back_porch + + mfd->panel_info.lcd.v_front_porch + + mfd->panel_info.lcd.v_pulse_width; + mfd->total_lcd_lines = + mfd->panel_info.yres + mfd->total_porch_lines; + mfd->lcd_ref_usec_time = + 100000000 / mfd->panel_info.lcd.refx100; + mfd->vsync_handler_pending = FALSE; + + mfd->last_vsync_timetick.tv64 = 0; + +#ifdef MDP_HW_VSYNC + if (mdp_vsync_clk == NULL) + mdp_vsync_clk = clk_get(&pdev->dev, "vsync_clk"); + + if (IS_ERR(mdp_vsync_clk)) { + printk(KERN_ERR "error: can't get mdp_vsync_clk!\n"); + mfd->use_mdp_vsync = 0; + } else + mfd->use_mdp_vsync = 1; + + if (mfd->use_mdp_vsync) { + uint32 vsync_cnt_cfg_dem; + uint32 mdp_vsync_clk_speed_hz; + + mdp_vsync_clk_speed_hz = clk_get_rate(mdp_vsync_clk); + + if (mdp_vsync_clk_speed_hz == 0) { + mfd->use_mdp_vsync = 0; + } else { + /* + * Do this calculation in 2 steps for + * rounding uint32 properly. + */ + vsync_cnt_cfg_dem = + (mfd->panel_info.lcd.refx100 * + mfd->total_lcd_lines) / 100; + vsync_cnt_cfg = + (mdp_vsync_clk_speed_hz) / + vsync_cnt_cfg_dem; + mdp_vsync_cfg_regs(mfd, TRUE); + } + } +#else + mfd->use_mdp_vsync = 0; + hrtimer_init(&mfd->dma_hrtimer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + mfd->dma_hrtimer.function = mdp_dma2_vsync_hrtimer_handler; + mfd->vsync_width_boundary = vmalloc(mfd->panel_info.xres * 4); +#endif + +#ifdef CONFIG_FB_MSM_MDDI + mfd->channel_irq = 0; + if (mfd->panel_info.lcd.hw_vsync_mode) { + u32 vsync_gpio = mfd->vsync_gpio; + u32 ret; + + if (vsync_gpio == -1) { + MSM_FB_INFO("vsync_gpio not defined!\n"); + goto err_handle; + } + + ret = gpio_tlmm_config(GPIO_CFG + (vsync_gpio, + (mfd->use_mdp_vsync) ? 1 : 0, + GPIO_CFG_INPUT, + GPIO_CFG_PULL_DOWN, + GPIO_CFG_2MA), + GPIO_CFG_ENABLE); + if (ret) + goto err_handle; + + /* + * if use_mdp_vsync, then no interrupt need since + * mdp_vsync is feed directly to mdp to reset the + * write pointer counter. therefore no irq_handler + * need to reset write pointer counter. + */ + if (!mfd->use_mdp_vsync) { + mfd->channel_irq = MSM_GPIO_TO_INT(vsync_gpio); + if (request_irq + (mfd->channel_irq, + &mdp_hw_vsync_handler_proxy, + IRQF_TRIGGER_FALLING, "VSYNC_GPIO", + (void *)mfd)) { + MSM_FB_INFO + ("irq=%d failed! vsync_gpio=%d\n", + mfd->channel_irq, + vsync_gpio); + goto err_handle; + } + } + } +#endif + mdp_hw_vsync_clk_enable(mfd); + mdp_set_vsync((unsigned long)mfd); + } + + return; + +err_handle: + if (mfd->vsync_width_boundary) + vfree(mfd->vsync_width_boundary); + mfd->panel_info.lcd.vsync_enable = FALSE; + printk(KERN_ERR "%s: failed!\n", __func__); +} + +void mdp_vsync_resync_workqueue_handler(struct work_struct *work) +{ + struct msm_fb_data_type *mfd = NULL; + int vsync_fnc_enabled = FALSE; + struct msm_fb_panel_data *pdata = NULL; + + mfd = container_of(work, struct msm_fb_data_type, vsync_resync_worker); + + if (mfd) { + if (mfd->panel_power_on) { + pdata = + (struct msm_fb_panel_data *)mfd->pdev->dev. + platform_data; + + if (pdata->set_vsync_notifier != NULL) { + if (pdata->clk_func && !pdata->clk_func(2)) { + mfd->vsync_handler_pending = FALSE; + return; + } + + pdata->set_vsync_notifier( + mdp_vsync_handler, + (void *)mfd); + vsync_fnc_enabled = TRUE; + } + } + } + + if ((mfd) && (!vsync_fnc_enabled)) + mfd->vsync_handler_pending = FALSE; +} + +boolean mdp_hw_vsync_set_handler(msm_fb_vsync_handler_type handler, void *data) +{ + /* + * ToDo: tried enabling/disabling GPIO MDP HW VSYNC interrupt + * but getting inaccurate timing in mdp_vsync_handler() + * enable_irq(MDP_HW_VSYNC_IRQ); + */ + + return TRUE; +} + +uint32 mdp_get_lcd_line_counter(struct msm_fb_data_type *mfd) +{ + uint32 elapsed_usec_time; + uint32 lcd_line; + ktime_t last_vsync_timetick_local; + ktime_t curr_time; + unsigned long flag; + + if ((!mfd->panel_info.lcd.vsync_enable) || (!vsync_mode)) + return 0; + + spin_lock_irqsave(&mdp_spin_lock, flag); + last_vsync_timetick_local = mfd->last_vsync_timetick; + spin_unlock_irqrestore(&mdp_spin_lock, flag); + + curr_time = ktime_get_real(); + elapsed_usec_time = ktime_to_us(ktime_sub(curr_time, + last_vsync_timetick_local)); + + elapsed_usec_time = elapsed_usec_time % mfd->lcd_ref_usec_time; + + /* lcd line calculation referencing to line counter = 0 */ + lcd_line = + (elapsed_usec_time * mfd->total_lcd_lines) / mfd->lcd_ref_usec_time; + + /* lcd line adjusment referencing to the actual line counter at vsync */ + lcd_line = + (mfd->total_lcd_lines - mfd->panel_info.lcd.v_back_porch + + lcd_line) % (mfd->total_lcd_lines + 1); + + if (lcd_line > mfd->total_lcd_lines) { + MSM_FB_INFO + ("mdp_get_lcd_line_counter: mdp_lcd_rd_cnt >= mfd->total_lcd_lines error!\n"); + } + + return lcd_line; +} diff --git a/drivers/video/msm/mhl/mhl_8334.c b/drivers/video/msm/mhl/mhl_8334.c new file mode 100644 index 000000000000..46eb03bbafd6 --- /dev/null +++ b/drivers/video/msm/mhl/mhl_8334.c @@ -0,0 +1,849 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_fb.h" +#include "external_common.h" +#include "mhl_8334.h" +#include "mhl_i2c_utils.h" + +#define DEBUG + + +static struct i2c_device_id mhl_sii_i2c_id[] = { + { MHL_DRIVER_NAME, 0 }, + { } +}; + +struct mhl_msm_state_t *mhl_msm_state; +spinlock_t mhl_state_lock; + +static int mhl_i2c_probe(struct i2c_client *client,\ + const struct i2c_device_id *id); +static int mhl_i2c_remove(struct i2c_client *client); +static void force_usb_switch_open(void); +static void release_usb_switch_open(void); +static void switch_mode(enum mhl_st_type to_mode); +static irqreturn_t mhl_tx_isr(int irq, void *dev_id); + +static struct i2c_driver mhl_sii_i2c_driver = { + .driver = { + .name = MHL_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = mhl_i2c_probe, + /*.remove = __exit_p(mhl_i2c_remove),*/ + .remove = mhl_i2c_remove, + .id_table = mhl_sii_i2c_id, +}; + +bool mhl_is_connected(void) +{ + return true; +} + +static void cbus_reset(void) +{ + uint8_t i; + + /* + * REG_SRST + */ + mhl_i2c_reg_modify(TX_PAGE_3, 0x0000, BIT3, BIT3); + msleep(20); + mhl_i2c_reg_modify(TX_PAGE_3, 0x0000, BIT3, 0x00); + /* + * REG_INTR1 and REG_INTR4 + */ + mhl_i2c_reg_write(TX_PAGE_L0, 0x0075, BIT6 | BIT5); + mhl_i2c_reg_write(TX_PAGE_3, 0x0022, + BIT0 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6); + /* REG5 */ + if (mhl_msm_state->chip_rev_id < 1) + mhl_i2c_reg_write(TX_PAGE_3, 0x0024, BIT3 | BIT4); + else + /*REG5 Mask disabled due to auto FIFO reset ??*/ + mhl_i2c_reg_write(TX_PAGE_3, 0x0024, 0x00); + + /* Unmask CBUS1 Intrs */ + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0009, + BIT2 | BIT3 | BIT4 | BIT5 | BIT6); + + /* Unmask CBUS2 Intrs */ + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x001F, BIT2 | BIT3); + + for (i = 0; i < 4; i++) { + /* + * Enable WRITE_STAT interrupt for writes to + * all 4 MSC Status registers. + */ + mhl_i2c_reg_write(TX_PAGE_CBUS, (0xE0 + i), 0xFF); + + /* + * Enable SET_INT interrupt for writes to + * all 4 MSC Interrupt registers. + */ + mhl_i2c_reg_write(TX_PAGE_CBUS, (0xF0 + i), 0xFF); + } +} + +static void init_cbus_regs(void) +{ + uint8_t regval; + + /* Increase DDC translation layer timer*/ + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0007, 0xF2); + /* Drive High Time */ + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0036, 0x03); + /* Use programmed timing */ + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0039, 0x30); + /* CBUS Drive Strength */ + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0040, 0x03); + /* + * Write initial default settings + * to devcap regs: default settings + */ + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_DEV_STATE, + DEVCAP_VAL_DEV_STATE); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_MHL_VERSION, + DEVCAP_VAL_MHL_VERSION); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_DEV_CAT, + DEVCAP_VAL_DEV_CAT); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_ADOPTER_ID_H, + DEVCAP_VAL_ADOPTER_ID_H); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_ADOPTER_ID_L, + DEVCAP_VAL_ADOPTER_ID_L); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_VID_LINK_MODE, + DEVCAP_VAL_VID_LINK_MODE); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_AUD_LINK_MODE, + DEVCAP_VAL_AUD_LINK_MODE); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_VIDEO_TYPE, + DEVCAP_VAL_VIDEO_TYPE); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_LOG_DEV_MAP, + DEVCAP_VAL_LOG_DEV_MAP); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_BANDWIDTH, + DEVCAP_VAL_BANDWIDTH); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_FEATURE_FLAG, + DEVCAP_VAL_FEATURE_FLAG); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_DEVICE_ID_H, + DEVCAP_VAL_DEVICE_ID_H); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_DEVICE_ID_L, + DEVCAP_VAL_DEVICE_ID_L); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_SCRATCHPAD_SIZE, + DEVCAP_VAL_SCRATCHPAD_SIZE); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_INT_STAT_SIZE, + DEVCAP_VAL_INT_STAT_SIZE); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_RESERVED, + DEVCAP_VAL_RESERVED); + + /* Make bits 2,3 (initiator timeout) to 1,1 + * for register CBUS_LINK_CONTROL_2 + * REG_CBUS_LINK_CONTROL_2 + */ + regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x0031); + regval = (regval | 0x0C); + /* REG_CBUS_LINK_CONTROL_2 */ + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0031, regval); + /* REG_MSC_TIMEOUT_LIMIT */ + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0022, 0x0F); + /* REG_CBUS_LINK_CONTROL_1 */ + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0030, 0x01); + /* disallow vendor specific commands */ + mhl_i2c_reg_modify(TX_PAGE_CBUS, 0x002E, BIT4, BIT4); +} + +/* + * Configure the initial reg settings + */ +static void mhl_init_reg_settings(void) +{ + + /* + * ============================================ + * POWER UP + * ============================================ + */ + + /* Power up 1.2V core */ + mhl_i2c_reg_write(TX_PAGE_L1, 0x003D, 0x3F); + /* Enable Tx PLL Clock */ + mhl_i2c_reg_write(TX_PAGE_2, 0x0011, 0x01); + /* Enable Tx Clock Path and Equalizer */ + mhl_i2c_reg_write(TX_PAGE_2, 0x0012, 0x11); + /* Tx Source Termination ON */ + mhl_i2c_reg_write(TX_PAGE_3, 0x0030, 0x10); + /* Enable 1X MHL Clock output */ + mhl_i2c_reg_write(TX_PAGE_3, 0x0035, 0xAC); + /* Tx Differential Driver Config */ + mhl_i2c_reg_write(TX_PAGE_3, 0x0031, 0x3C); + mhl_i2c_reg_write(TX_PAGE_3, 0x0033, 0xD9); + /* PLL Bandwidth Control */ + mhl_i2c_reg_write(TX_PAGE_3, 0x0037, 0x02); + /* + * ============================================ + * Analog PLL Control + * ============================================ + */ + /* Enable Rx PLL clock */ + mhl_i2c_reg_write(TX_PAGE_L0, 0x0080, 0x00); + mhl_i2c_reg_write(TX_PAGE_L0, 0x00F8, 0x0C); + mhl_i2c_reg_write(TX_PAGE_L0, 0x0085, 0x02); + mhl_i2c_reg_write(TX_PAGE_2, 0x0000, 0x00); + mhl_i2c_reg_write(TX_PAGE_2, 0x0013, 0x60); + /* PLL Cal ref sel */ + mhl_i2c_reg_write(TX_PAGE_2, 0x0017, 0x03); + /* VCO Cal */ + mhl_i2c_reg_write(TX_PAGE_2, 0x001A, 0x20); + /* Auto EQ */ + mhl_i2c_reg_write(TX_PAGE_2, 0x0022, 0xE0); + mhl_i2c_reg_write(TX_PAGE_2, 0x0023, 0xC0); + mhl_i2c_reg_write(TX_PAGE_2, 0x0024, 0xA0); + mhl_i2c_reg_write(TX_PAGE_2, 0x0025, 0x80); + mhl_i2c_reg_write(TX_PAGE_2, 0x0026, 0x60); + mhl_i2c_reg_write(TX_PAGE_2, 0x0027, 0x40); + mhl_i2c_reg_write(TX_PAGE_2, 0x0028, 0x20); + mhl_i2c_reg_write(TX_PAGE_2, 0x0029, 0x00); + /* Rx PLL Bandwidth 4MHz */ + mhl_i2c_reg_write(TX_PAGE_2, 0x0031, 0x0A); + /* Rx PLL Bandwidth value from I2C */ + mhl_i2c_reg_write(TX_PAGE_2, 0x0045, 0x06); + mhl_i2c_reg_write(TX_PAGE_2, 0x004B, 0x06); + /* Manual zone control */ + mhl_i2c_reg_write(TX_PAGE_2, 0x004C, 0xE0); + /* PLL Mode value */ + mhl_i2c_reg_write(TX_PAGE_2, 0x004D, 0x00); + mhl_i2c_reg_write(TX_PAGE_L0, 0x0008, 0x35); + /* + * Discovery Control and Status regs + * Setting De-glitch time to 50 ms (default) + * Switch Control Disabled + */ + mhl_i2c_reg_write(TX_PAGE_3, 0x0011, 0xAD); + /* 1.8V CBUS VTH */ + mhl_i2c_reg_write(TX_PAGE_3, 0x0014, 0x55); + /* RGND and single Discovery attempt */ + mhl_i2c_reg_write(TX_PAGE_3, 0x0015, 0x11); + /* Ignore VBUS */ + mhl_i2c_reg_write(TX_PAGE_3, 0x0017, 0x82); + mhl_i2c_reg_write(TX_PAGE_3, 0x0018, 0x24); + /* Pull-up resistance off for IDLE state */ + mhl_i2c_reg_write(TX_PAGE_3, 0x0013, 0x84); + /* Enable CBUS Discovery */ + mhl_i2c_reg_write(TX_PAGE_3, 0x0010, 0x27); + mhl_i2c_reg_write(TX_PAGE_3, 0x0016, 0x20); + /* MHL CBUS Discovery - immediate comm. */ + mhl_i2c_reg_write(TX_PAGE_3, 0x0012, 0x86); + /* Do not force HPD to 0 during wake-up from D3 */ + if (mhl_msm_state->cur_state != POWER_STATE_D3) { + mhl_i2c_reg_modify(TX_PAGE_3, 0x0020, + BIT5 | BIT4, BIT4); + } + /* Enable Auto Soft RESET */ + mhl_i2c_reg_write(TX_PAGE_3, 0x0000, 0x084); + /* HDMI Transcode mode enable */ + mhl_i2c_reg_write(TX_PAGE_L0, 0x000D, 0x1C); + + cbus_reset(); + init_cbus_regs(); +} + +static int mhl_chip_init(void) +{ + /* Read the chip rev ID */ + mhl_msm_state->chip_rev_id = mhl_i2c_reg_read(TX_PAGE_L0, 0x04); + pr_debug("MHL: chip rev ID read=[%x]\n", mhl_msm_state->chip_rev_id); + + /* Reset the TX chip */ + mhl_msm_state->mhl_data->reset_pin(0); + msleep(20); + mhl_msm_state->mhl_data->reset_pin(1); + /* MHL spec requires a 100 ms wait here. */ + msleep(100); + + mhl_init_reg_settings(); + + /* + * Power down the chip to the + * D3 - a low power standby mode + * cable impedance measurement logic is operational + */ + switch_mode(POWER_STATE_D3); + return 0; +} + +/* + * I2C probe + */ +static int mhl_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + mhl_msm_state->mhl_data = kzalloc(sizeof(struct msm_mhl_platform_data), + GFP_KERNEL); + if (!(mhl_msm_state->mhl_data)) { + ret = -ENOMEM; + goto probe_exit; + } + pr_debug("Inside probe\n"); + mhl_msm_state->i2c_client = client; + + spin_lock_init(&mhl_state_lock); + + i2c_set_clientdata(client, mhl_msm_state); + mhl_msm_state->mhl_data = client->dev.platform_data; + + /* Init GPIO stuff here */ + ret = mhl_msm_state->mhl_data->gpio_setup(1); + if (ret == -1) { + pr_err("MHL: mhl_gpio_init has failed\n"); + ret = -ENODEV; + goto probe_exit; + } + return 0; + +probe_exit: + if (mhl_msm_state->mhl_data) { + /* free the gpios */ + mhl_msm_state->mhl_data->gpio_setup(0); + kfree(mhl_msm_state->mhl_data); + mhl_msm_state->mhl_data = NULL; + } + return ret; +} + +static int mhl_i2c_remove(struct i2c_client *client) +{ + pr_debug("inside i2c remove\n"); + mhl_msm_state->mhl_data->gpio_setup(0); + kfree(mhl_msm_state->mhl_data); + return 0; +} + +static int __init mhl_msm_init(void) +{ + int32_t ret; + + mhl_msm_state = kzalloc(sizeof(struct mhl_msm_state_t), GFP_KERNEL); + if (!mhl_msm_state) { + pr_err("mhl_msm_init FAILED: out of memory\n"); + ret = -ENOMEM; + goto init_exit; + } + + mhl_msm_state->i2c_client = NULL; + ret = i2c_add_driver(&mhl_sii_i2c_driver); + if (ret) { + pr_err("MHL: I2C driver add failed: %d\n", ret); + ret = -ENODEV; + goto init_exit; + } else { + if (mhl_msm_state->i2c_client == NULL) { + pr_err("JSR: I2C driver add failed\n"); + ret = -ENODEV; + goto init_exit; + } + pr_debug("MHL: I2C driver added\n"); + } + + /* Request IRQ stuff here */ + pr_debug("MHL: mhl_msm_state->mhl_data->irq=[%d]\n", + mhl_msm_state->mhl_data->irq); + ret = request_threaded_irq(mhl_msm_state->mhl_data->irq, NULL, + &mhl_tx_isr, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "mhl_tx_isr", mhl_msm_state); + if (ret != 0) { + pr_err("request_threaded_irq failed, status: %d\n", + ret); + ret = -EACCES; /* Error code???? */ + goto init_exit; + } + + mhl_msm_state->cur_state = POWER_STATE_D0_MHL; + + /* MHL SII 8334 chip specific init */ + mhl_chip_init(); + return 0; + +init_exit: + pr_err("Exiting from the init with err\n"); + i2c_del_driver(&mhl_sii_i2c_driver); + if (!mhl_msm_state) { + kfree(mhl_msm_state); + mhl_msm_state = NULL; + } + return ret; +} + +static void switch_mode(enum mhl_st_type to_mode) +{ + unsigned long flags; + + switch (to_mode) { + case POWER_STATE_D0_NO_MHL: + break; + case POWER_STATE_D0_MHL: + mhl_init_reg_settings(); + + /* REG_DISC_CTRL1 */ + mhl_i2c_reg_modify(TX_PAGE_3, 0x0010, BIT1, 0); + + /* + * TPI_DEVICE_POWER_STATE_CTRL_REG + * TX_POWER_STATE_MASK = BIT1 | BIT0 + */ + mhl_i2c_reg_modify(TX_PAGE_TPI, 0x001E, BIT1 | BIT0, 0x00); + break; + case POWER_STATE_D3: + if (mhl_msm_state->cur_state != POWER_STATE_D3) { + /* Force HPD to 0 when not in MHL mode. */ + mhl_i2c_reg_modify(TX_PAGE_3, 0x0020, + BIT5 | BIT4, BIT4); + + /* + * Change TMDS termination to high impedance + * on disconnection. + */ + mhl_i2c_reg_write(TX_PAGE_3, 0x0030, 0xD0); + mhl_i2c_reg_modify(TX_PAGE_L1, 0x003D, + BIT1 | BIT0, BIT0); + spin_lock_irqsave(&mhl_state_lock, flags); + mhl_msm_state->cur_state = POWER_STATE_D3; + spin_unlock_irqrestore(&mhl_state_lock, flags); + } + break; + default: + break; + } +} + +static void mhl_drive_hpd(uint8_t to_state) +{ + pr_debug("%s: To state=[0x%x]\n", __func__, to_state); + if (to_state == HPD_UP) { + /* + * Drive HPD to UP state + * + * The below two reg configs combined + * enable TMDS output. + */ + + /* Enable TMDS on TMDS_CCTRL */ + mhl_i2c_reg_modify(TX_PAGE_L0, 0x0080, BIT4, BIT4); + + /* + * Set HPD_OUT_OVR_EN = HPD State + * EDID read and Un-force HPD (from low) + * propogate to src let HPD float by clearing + * HPD OUT OVRRD EN + */ + mhl_i2c_reg_modify(TX_PAGE_3, 0x0020, BIT4, 0x00); + } else { + /* + * Drive HPD to DOWN state + * Disable TMDS Output on REG_TMDS_CCTRL + * Enable/Disable TMDS output (MHL TMDS output only) + */ + mhl_i2c_reg_modify(TX_PAGE_L0, 0x0080, BIT4, 0x00); + } + return; +} + +static void mhl_msm_connection(void) +{ + uint8_t val; + unsigned long flags; + + pr_err("%s: cur state = [0x%x]\n", __func__, mhl_msm_state->cur_state); + + if (mhl_msm_state->cur_state == POWER_STATE_D0_MHL) { + /* Already in D0 - MHL power state */ + return; + } + spin_lock_irqsave(&mhl_state_lock, flags); + mhl_msm_state->cur_state = POWER_STATE_D0_MHL; + spin_unlock_irqrestore(&mhl_state_lock, flags); + + mhl_i2c_reg_write(TX_PAGE_3, 0x30, 0x10); + + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x07, 0xF2); + + /* + * Keep the discovery enabled. Need RGND interrupt + * Possibly chip disables discovery after MHL_EST?? + * Need to re-enable here + */ + val = mhl_i2c_reg_read(TX_PAGE_3, 0x10); + mhl_i2c_reg_write(TX_PAGE_3, 0x10, val | BIT(0)); + + return; +} + +static void mhl_msm_disconnection(void) +{ + uint8_t reg; + + /* Clear interrupts - REG INTR4 */ + reg = mhl_i2c_reg_read(TX_PAGE_3, 0x0021); + mhl_i2c_reg_write(TX_PAGE_3, 0x0021, reg); + /* + * MHL TX CTL1 + * Disabling Tx termination + */ + mhl_i2c_reg_write(TX_PAGE_3, 0x30, 0xD0); + /* + * MSC REQUESTOR ABORT REASON + * Clear CBUS_HPD status + */ + mhl_i2c_reg_modify(TX_PAGE_CBUS, 0x000D, BIT6, 0x00); + /* Change HPD line to drive it low */ + mhl_drive_hpd(HPD_DOWN); + /* switch power state to D3 */ + switch_mode(POWER_STATE_D3); + return; +} + +/* + * If hardware detected a change in impedence and raised an INTR + * We check the range of this impedence to infer if the connected + * device is MHL or USB and take appropriate actions. + */ +static void mhl_msm_read_rgnd_int(void) +{ + uint8_t rgnd_imp; + + /* + * DISC STATUS REG 2 + * 1:0 RGND + * 00 - open (USB) + * 01 - 2 kOHM (USB) + * 10 - 1 kOHM ***(MHL)**** It's range 800 - 1200 OHM from MHL spec + * 11 - short (USB) + */ + rgnd_imp = mhl_i2c_reg_read(TX_PAGE_3, 0x001C); + pr_debug("Imp Range read = %02X\n", (int)rgnd_imp); + + + if (0x02 == rgnd_imp) { + pr_debug("MHL: MHL DEVICE!!!\n"); + /* + * Handling the MHL event in driver + */ + mhl_i2c_reg_modify(TX_PAGE_3, 0x0018, BIT0, BIT0); + } else { + pr_debug("MHL: NON-MHL DEVICE!!!\n"); + mhl_i2c_reg_modify(TX_PAGE_3, 0x0018, BIT3, BIT3); + } +} + +static void force_usb_switch_open(void) +{ + /*DISABLE_DISCOVERY*/ + mhl_i2c_reg_modify(TX_PAGE_3, 0x0010, BIT0, 0); + /* Force USB ID switch to open*/ + mhl_i2c_reg_modify(TX_PAGE_3, 0x0015, BIT6, BIT6); + mhl_i2c_reg_write(TX_PAGE_3, 0x0012, 0x86); + /* Force HPD to 0 when not in Mobile HD mode. */ + mhl_i2c_reg_modify(TX_PAGE_3, 0x0020, BIT5 | BIT4, BIT4); +} + +static void release_usb_switch_open(void) +{ + msleep(50); + mhl_i2c_reg_modify(TX_PAGE_3, 0x0015, BIT6, 0x00); + mhl_i2c_reg_modify(TX_PAGE_3, 0x0010, BIT0, BIT0); +} + +static void int_4_isr(void) +{ + uint8_t status; + + /* INTR_STATUS4 */ + status = mhl_i2c_reg_read(TX_PAGE_3, 0x0021); + + /* + * When I2C is inoperational (D3) and + * a previous interrupt brought us here, + * do nothing. + */ + pr_debug("MHL: MRR Interrupt status is = %02X\n", (int) status); + if (0xFF != status) { + if ((status & BIT0) && (mhl_msm_state->chip_rev_id < 1)) { + uint8_t tmds_cstat; + uint8_t mhl_fifo_status; + + /* TMDS CSTAT */ + tmds_cstat = mhl_i2c_reg_read(TX_PAGE_3, 0x0040); + + pr_debug("TMDS CSTAT: 0x%02x\n", tmds_cstat); + + if (tmds_cstat & 0x02) { + mhl_fifo_status = mhl_i2c_reg_read(TX_PAGE_3, + 0x0023); + pr_debug("MHL FIFO status: 0x%02x\n", + mhl_fifo_status); + if (mhl_fifo_status & 0x0C) { + mhl_i2c_reg_write(TX_PAGE_3, 0x0023, + 0x0C); + + pr_debug("Apply MHL FIFO Reset\n"); + mhl_i2c_reg_write(TX_PAGE_3, 0x0000, + 0x94); + mhl_i2c_reg_write(TX_PAGE_3, 0x0000, + 0x84); + } + } + } + + if (status & BIT1) + pr_err("MHL: INT4 BIT1 is set\n"); + + /* MHL_EST interrupt */ + if (status & BIT2) { + pr_err("MHL: Calling mhl_msm_connection() from ISR\n"); + mhl_msm_connection(); + pr_err("MHL Connect Drv: INT4 Status = %02X\n", + (int) status); + } else if (status & BIT3) { + pr_err("MHL: uUSB-A type device detected.\n"); + mhl_i2c_reg_write(TX_PAGE_3, 0x001C, 0x80); + switch_mode(POWER_STATE_D3); + } + + if (status & BIT5) { + mhl_msm_disconnection(); + pr_err("MHL Disconnect Drv: INT4 Status = %02X\n", + (int)status); + } + + if ((mhl_msm_state->cur_state != POWER_STATE_D0_MHL) &&\ + (status & BIT6)) { + /* RGND READY Intr */ + switch_mode(POWER_STATE_D0_MHL); + mhl_msm_read_rgnd_int(); + } + + /* Can't succeed at these in D3 */ + if (mhl_msm_state->cur_state != POWER_STATE_D3) { + /* CBUS Lockout interrupt? */ + /* + * Hardware detection mechanism figures that + * CBUS line is latched and raises this intr + * where we force usb switch open and release + */ + if (status & BIT4) { + force_usb_switch_open(); + release_usb_switch_open(); + } + } + } + pr_debug("MHL END Drv: INT4 Status = %02X\n", (int) status); + mhl_i2c_reg_write(TX_PAGE_3, 0x0021, status); + + return; +} + +static void int_5_isr(void) +{ + uint8_t intr_5_stat; + + /* + * Clear INT 5 ?? + * Probably need to revisit this later + * INTR5 is related to FIFO underflow/overflow reset + * which is handled in 8334 by auto FIFO reset + */ + intr_5_stat = mhl_i2c_reg_read(TX_PAGE_3, 0x0023); + mhl_i2c_reg_write(TX_PAGE_3, 0x0023, intr_5_stat); +} + + +static void int_1_isr(void) +{ + /* This ISR mainly handles the HPD status changes */ + uint8_t intr_1_stat; + uint8_t cbus_stat; + + /* INTR STATUS 1 */ + intr_1_stat = mhl_i2c_reg_read(TX_PAGE_L0, 0x0071); + + if (intr_1_stat) { + /* Clear interrupts */ + mhl_i2c_reg_write(TX_PAGE_L0, 0x0071, intr_1_stat); + if (BIT6 & intr_1_stat) { + /* + * HPD status change event is pending + * Read CBUS HPD status for this info + */ + + /* MSC REQ ABRT REASON */ + cbus_stat = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x0D); + if (BIT6 & cbus_stat) + mhl_drive_hpd(HPD_UP); + } + } + return; +} + +/* + * RCP, RAP messages - mandatory for compliance + * + */ +static void mhl_cbus_isr(void) +{ + uint8_t regval; + int req_done = FALSE; + uint8_t sub_cmd; + uint8_t cmd_data; + int msc_msg_recved = FALSE; + int rc = -1; + + regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x08); + if (regval == 0xff) + return; + + /* clear all interrupts that were raised even if we did not process */ + if (regval) + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x08, regval); + + pr_err("%s: CBUS_INT = %02x\n", __func__, regval); + + /* MSC_MSG (RCP/RAP) */ + if (regval & BIT(3)) { + sub_cmd = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x18); + cmd_data = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x19); + msc_msg_recved = TRUE; + } + + /* MSC_REQ_DONE */ + if (regval & BIT(4)) + req_done = TRUE; + + /* Now look for interrupts on CBUS_MSC_INT2 */ + regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x1E); + + /* clear all interrupts that were raised */ + /* even if we did not process */ + if (regval) + mhl_i2c_reg_write(TX_PAGE_CBUS, 0x1E, regval); + + pr_err("%s: CBUS_MSC_INT2 = %02x\n", __func__, regval); + + /* received SET_INT */ + if (regval & BIT(2)) { + uint8_t intr; + intr = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xA0); + pr_debug("%s: MHL_INT_0 = %02x\n", __func__, intr); + intr = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xA1); + pr_debug("%s: MHL_INT_1 = %02x\n", __func__, intr); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA0, 0xFF); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA1, 0xFF); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA2, 0xFF); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA3, 0xFF); + } + + /* received WRITE_STAT */ + if (regval & BIT(3)) { + uint8_t stat; + stat = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xB0); + pr_err("%s: MHL_STATUS_0 = %02x\n", __func__, stat); + stat = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xB1); + pr_err("%s: MHL_STATUS_1 = %02x\n", __func__, stat); + + mhl_i2c_reg_write(TX_PAGE_CBUS, 0xB0, 0xFF); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0xB1, 0xFF); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0xB2, 0xFF); + mhl_i2c_reg_write(TX_PAGE_CBUS, 0xB3, 0xFF); + } + + /* received MSC_MSG */ + if (msc_msg_recved) { + /*mhl msc recv msc msg*/ + if (rc) + pr_err("MHL: mhl msc recv msc msg failed(%d)!\n", rc); + } + + return; +} + +static irqreturn_t mhl_tx_isr(int irq, void *dev_id) +{ + /* + * Check discovery interrupt + * if not yet connected + */ + pr_debug("MHL: Current POWER state is [0x%x]\n", + mhl_msm_state->cur_state); + /* + * Check RGND, MHL_EST, CBUS_LOCKOUT, SCDT + * interrupts. In D3, we get only RGND + */ + int_4_isr(); + + pr_debug("MHL: Current POWER state is [0x%x]\n", + mhl_msm_state->cur_state); + if (mhl_msm_state->cur_state == POWER_STATE_D0_MHL) { + /* + * If int_4_isr() didn't move the tx to D3 + * on disconnect, continue to check other + * interrupt sources. + */ + int_5_isr(); + + /* + * Check for any peer messages for DCAP_CHG etc + * Dispatch to have the CBUS module working only + * once connected. + */ + mhl_cbus_isr(); + int_1_isr(); + } + return IRQ_HANDLED; +} + +static void __exit mhl_msm_exit(void) +{ + pr_warn("MHL: Exiting, Bye\n"); + /* + * Delete driver if i2c client structure is NULL + */ + i2c_del_driver(&mhl_sii_i2c_driver); + if (!mhl_msm_state) { + kfree(mhl_msm_state); + mhl_msm_state = NULL; + } +} + +module_init(mhl_msm_init); +module_exit(mhl_msm_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MHL SII 8334 TX driver"); diff --git a/drivers/video/msm/mhl/mhl_8334.h b/drivers/video/msm/mhl/mhl_8334.h new file mode 100644 index 000000000000..239d4d3936bc --- /dev/null +++ b/drivers/video/msm/mhl/mhl_8334.h @@ -0,0 +1,74 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __MHL_MSM_H__ +#define __MHL_MSM_H__ + +#include +#include +#include + +#include "mhl_devcap.h" +#include "mhl_defs.h" + +#define GPIO_MHL_RESET 15 +#define GPIO_MHL_INT 4 + +#define MHL_DEVICE_NAME "sii8334" +#define MHL_DRIVER_NAME "sii8334" + +#define HPD_UP 1 +#define HPD_DOWN 0 + +struct mhl_msm_state_t { + struct i2c_client *i2c_client; + struct i2c_driver *i2c_driver; + uint8_t cur_state; + uint8_t chip_rev_id; + struct msm_mhl_platform_data *mhl_data; +}; + +enum { + TX_PAGE_TPI = 0x00, + TX_PAGE_L0 = 0x01, + TX_PAGE_L1 = 0x02, + TX_PAGE_2 = 0x03, + TX_PAGE_3 = 0x04, + TX_PAGE_CBUS = 0x05, + TX_PAGE_DDC_EDID = 0x06, + TX_PAGE_DDC_SEGM = 0x07, +}; + +enum mhl_st_type { + POWER_STATE_D0_NO_MHL = 0, + POWER_STATE_D0_MHL = 2, + POWER_STATE_D3 = 3, +}; + +enum { + DEV_PAGE_TPI_0 = (0x72), + DEV_PAGE_TX_L0_0 = (0x72), + DEV_PAGE_TPI_1 = (0x76), + DEV_PAGE_TX_L0_1 = (0x76), + DEV_PAGE_TX_L1_0 = (0x7A), + DEV_PAGE_TX_L1_1 = (0x7E), + DEV_PAGE_TX_2_0 = (0x92), + DEV_PAGE_TX_2_1 = (0x96), + DEV_PAGE_TX_3_0 = (0x9A), + DEV_PAGE_TX_3_1 = (0x9E), + DEV_PAGE_CBUS = (0xC8), + DEV_PAGE_DDC_EDID = (0xA0), + DEV_PAGE_DDC_SEGM = (0x60), +}; + +#endif /* __MHL_MSM_H__ */ diff --git a/drivers/video/msm/mhl/mhl_defs.h b/drivers/video/msm/mhl/mhl_defs.h new file mode 100644 index 000000000000..9e85f07aec47 --- /dev/null +++ b/drivers/video/msm/mhl/mhl_defs.h @@ -0,0 +1,222 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __MHL_SPEC_DEFS_H__ +#define __MHL_SPEC_DEFS_H__ + +enum DevCapOffset_e { + DEVCAP_OFFSET_DEV_STATE = 0x00, + DEVCAP_OFFSET_MHL_VERSION = 0x01, + DEVCAP_OFFSET_DEV_CAT = 0x02, + DEVCAP_OFFSET_ADOPTER_ID_H = 0x03, + DEVCAP_OFFSET_ADOPTER_ID_L = 0x04, + DEVCAP_OFFSET_VID_LINK_MODE = 0x05, + DEVCAP_OFFSET_AUD_LINK_MODE = 0x06, + DEVCAP_OFFSET_VIDEO_TYPE = 0x07, + DEVCAP_OFFSET_LOG_DEV_MAP = 0x08, + DEVCAP_OFFSET_BANDWIDTH = 0x09, + DEVCAP_OFFSET_FEATURE_FLAG = 0x0A, + DEVCAP_OFFSET_DEVICE_ID_H = 0x0B, + DEVCAP_OFFSET_DEVICE_ID_L = 0x0C, + DEVCAP_OFFSET_SCRATCHPAD_SIZE = 0x0D, + DEVCAP_OFFSET_INT_STAT_SIZE = 0x0E, + DEVCAP_OFFSET_RESERVED = 0x0F, + /* this one must be last */ + DEVCAP_SIZE +}; + +#ifndef __MHL_MSM_8334_REGS_H__ +#define __MHL_MSM_8334_REGS_H__ + +#define BIT0 0x01 +#define BIT1 0x02 +#define BIT2 0x04 +#define BIT3 0x08 +#define BIT4 0x10 +#define BIT5 0x20 +#define BIT6 0x40 +#define BIT7 0x80 + +#define LOW 0 +#define HIGH 1 + +#define MAX_PAGES 8 +#endif + + +/* Version that this chip supports*/ +/* bits 4..7 */ +#define MHL_VER_MAJOR (0x01 << 4) +/* bits 0..3 */ +#define MHL_VER_MINOR 0x01 +#define MHL_VERSION (MHL_VER_MAJOR | MHL_VER_MINOR) + +/*Device Category*/ +#define MHL_DEV_CATEGORY_OFFSET DEVCAP_OFFSET_DEV_CAT +#define MHL_DEV_CATEGORY_POW_BIT (BIT4) + +#define MHL_DEV_CAT_SOURCE 0x02 + +/*Video Link Mode*/ +#define MHL_DEV_VID_LINK_SUPPRGB444 0x01 +#define MHL_DEV_VID_LINK_SUPPYCBCR444 0x02 +#define MHL_DEV_VID_LINK_SUPPYCBCR422 0x04 +#define MHL_DEV_VID_LINK_SUPP_PPIXEL 0x08 +#define MHL_DEV_VID_LINK_SUPP_ISLANDS 0x10 + +/*Audio Link Mode Support*/ +#define MHL_DEV_AUD_LINK_2CH 0x01 +#define MHL_DEV_AUD_LINK_8CH 0x02 + + +/*Feature Flag in the devcap*/ +#define MHL_DEV_FEATURE_FLAG_OFFSET DEVCAP_OFFSET_FEATURE_FLAG +/* Dongles have freedom to not support RCP */ +#define MHL_FEATURE_RCP_SUPPORT BIT0 +/* Dongles have freedom to not support RAP */ +#define MHL_FEATURE_RAP_SUPPORT BIT1 +/* Dongles have freedom to not support SCRATCHPAD */ +#define MHL_FEATURE_SP_SUPPORT BIT2 + +/*Logical Dev Map*/ +#define MHL_DEV_LD_DISPLAY (0x01 << 0) +#define MHL_DEV_LD_VIDEO (0x01 << 1) +#define MHL_DEV_LD_AUDIO (0x01 << 2) +#define MHL_DEV_LD_MEDIA (0x01 << 3) +#define MHL_DEV_LD_TUNER (0x01 << 4) +#define MHL_DEV_LD_RECORD (0x01 << 5) +#define MHL_DEV_LD_SPEAKER (0x01 << 6) +#define MHL_DEV_LD_GUI (0x01 << 7) + +/*Bandwidth*/ +/* 225 MHz */ +#define MHL_BANDWIDTH_LIMIT 22 + + +#define MHL_STATUS_REG_CONNECTED_RDY 0x30 +#define MHL_STATUS_REG_LINK_MODE 0x31 + +#define MHL_STATUS_DCAP_RDY BIT0 + +#define MHL_STATUS_CLK_MODE_MASK 0x07 +#define MHL_STATUS_CLK_MODE_PACKED_PIXEL 0x02 +#define MHL_STATUS_CLK_MODE_NORMAL 0x03 +#define MHL_STATUS_PATH_EN_MASK 0x08 +#define MHL_STATUS_PATH_ENABLED 0x08 +#define MHL_STATUS_PATH_DISABLED 0x00 +#define MHL_STATUS_MUTED_MASK 0x10 + +#define MHL_RCHANGE_INT 0x20 +#define MHL_DCHANGE_INT 0x21 + +#define MHL_INT_DCAP_CHG BIT0 +#define MHL_INT_DSCR_CHG BIT1 +#define MHL_INT_REQ_WRT BIT2 +#define MHL_INT_GRT_WRT BIT3 + +/* On INTR_1 the EDID_CHG is located at BIT 0*/ +#define MHL_INT_EDID_CHG BIT1 + +/* This contains one nibble each - max offset */ +#define MHL_INT_AND_STATUS_SIZE 0x33 +#define MHL_SCRATCHPAD_SIZE 16 +/* manually define highest number */ +#define MHL_MAX_BUFFER_SIZE MHL_SCRATCHPAD_SIZE + + + +enum { + /* RCP sub-command */ + MHL_MSC_MSG_RCP = 0x10, + /* RCP Acknowledge sub-command */ + MHL_MSC_MSG_RCPK = 0x11, + /* RCP Error sub-command */ + MHL_MSC_MSG_RCPE = 0x12, + /* Mode Change Warning sub-command */ + MHL_MSC_MSG_RAP = 0x20, + /* MCW Acknowledge sub-command */ + MHL_MSC_MSG_RAPK = 0x21, +}; + +#define RCPE_NO_ERROR 0x00 +#define RCPE_INEEFECTIVE_KEY_CODE 0x01 +#define RCPE_BUSY 0x02 +/* MHL spec related defines*/ +enum { + /* Command or Data byte acknowledge */ + MHL_ACK = 0x33, + /* Command or Data byte not acknowledge */ + MHL_NACK = 0x34, + /* Transaction abort */ + MHL_ABORT = 0x35, + /* 0xE0 - Write one status register strip top bit */ + MHL_WRITE_STAT = 0x60 | 0x80, + /* Write one interrupt register */ + MHL_SET_INT = 0x60, + /* Read one register */ + MHL_READ_DEVCAP = 0x61, + /* Read CBUS revision level from follower */ + MHL_GET_STATE = 0x62, + /* Read vendor ID value from follower. */ + MHL_GET_VENDOR_ID = 0x63, + /* Set Hot Plug Detect in follower */ + MHL_SET_HPD = 0x64, + /* Clear Hot Plug Detect in follower */ + MHL_CLR_HPD = 0x65, + /* Set Capture ID for downstream device. */ + MHL_SET_CAP_ID = 0x66, + /* Get Capture ID from downstream device. */ + MHL_GET_CAP_ID = 0x67, + /* VS command to send RCP sub-commands */ + MHL_MSC_MSG = 0x68, + /* Get Vendor-Specific command error code. */ + MHL_GET_SC1_ERRORCODE = 0x69, + /* Get DDC channel command error code. */ + MHL_GET_DDC_ERRORCODE = 0x6A, + /* Get MSC command error code. */ + MHL_GET_MSC_ERRORCODE = 0x6B, + /* Write 1-16 bytes to responder's scratchpad. */ + MHL_WRITE_BURST = 0x6C, + /* Get channel 3 command error code. */ + MHL_GET_SC3_ERRORCODE = 0x6D, +}; + +/* Turn content streaming ON. */ +#define MHL_RAP_CONTENT_ON 0x10 +/* Turn content streaming OFF. */ +#define MHL_RAP_CONTENT_OFF 0x11 + +/* + * + * MHL Timings applicable to this driver. + * + */ +/* 100 - 1000 milliseconds. Per MHL 1.0 Specs */ +#define T_SRC_VBUS_CBUS_TO_STABLE (200) +/* 20 milliseconds. Per MHL 1.0 Specs */ +#define T_SRC_WAKE_PULSE_WIDTH_1 (20) +/* 60 milliseconds. Per MHL 1.0 Specs */ +#define T_SRC_WAKE_PULSE_WIDTH_2 (60) + +/* 100 - 1000 milliseconds. Per MHL 1.0 Specs */ +#define T_SRC_WAKE_TO_DISCOVER (500) + +#define T_SRC_VBUS_CBUS_T0_STABLE (500) + +/* Allow RSEN to stay low this much before reacting.*/ +#define T_SRC_RSEN_DEGLITCH (100) + +/* Wait this much after connection before reacting to RSEN (300-500ms)*/ +/* Per specs between 300 to 500 ms*/ +#define T_SRC_RXSENSE_CHK (400) + +#endif /* __MHL_SPEC_DEFS_H__ */ diff --git a/drivers/video/msm/mhl/mhl_devcap.h b/drivers/video/msm/mhl/mhl_devcap.h new file mode 100644 index 000000000000..40a87fe73703 --- /dev/null +++ b/drivers/video/msm/mhl/mhl_devcap.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __MHL_DEVCAP_H__ +#define __MHL_DEVCAP_H__ + +#define SILICON_IMAGE_ADOPTER_ID 322 +#define TRANSCODER_DEVICE_ID 0x8334 + +#define MHL_DEV_LD_AUDIO (0x01 << 2) +#define MHL_DEV_LD_VIDEO (0x01 << 1) +#define MHL_DEV_LD_MEDIA (0x01 << 3) +#define MHL_DEV_LD_GUI (0x01 << 7) +#define MHL_LOGICAL_DEVICE_MAP (MHL_DEV_LD_AUDIO |\ + MHL_DEV_LD_VIDEO | MHL_DEV_LD_MEDIA | MHL_DEV_LD_GUI) + +#define DEVCAP_VAL_DEV_STATE 0 +#define DEVCAP_VAL_MHL_VERSION MHL_VERSION +#define DEVCAP_VAL_DEV_CAT (MHL_DEV_CAT_SOURCE |\ + MHL_DEV_CATEGORY_POW_BIT) +#define DEVCAP_VAL_ADOPTER_ID_H (uint8_t)(SILICON_IMAGE_ADOPTER_ID >> 8) +#define DEVCAP_VAL_ADOPTER_ID_L (uint8_t)(SILICON_IMAGE_ADOPTER_ID & 0xFF) +#define DEVCAP_VAL_VID_LINK_MODE MHL_DEV_VID_LINK_SUPPRGB444 +#define DEVCAP_VAL_AUD_LINK_MODE MHL_DEV_AUD_LINK_2CH +#define DEVCAP_VAL_VIDEO_TYPE 0 +#define DEVCAP_VAL_LOG_DEV_MAP MHL_LOGICAL_DEVICE_MAP +#define DEVCAP_VAL_BANDWIDTH 0 +#define DEVCAP_VAL_FEATURE_FLAG (MHL_FEATURE_RCP_SUPPORT |\ + MHL_FEATURE_RAP_SUPPORT | MHL_FEATURE_SP_SUPPORT) +#define DEVCAP_VAL_DEVICE_ID_H (uint8_t)(TRANSCODER_DEVICE_ID >> 8) +#define DEVCAP_VAL_DEVICE_ID_L (uint8_t)(TRANSCODER_DEVICE_ID & 0xFF) +#define DEVCAP_VAL_SCRATCHPAD_SIZE MHL_SCRATCHPAD_SIZE +#define DEVCAP_VAL_INT_STAT_SIZE MHL_INT_AND_STATUS_SIZE +#define DEVCAP_VAL_RESERVED 0 + +#endif /* __MHL_DEVCAP_H__ */ diff --git a/drivers/video/msm/mhl/mhl_i2c_utils.c b/drivers/video/msm/mhl/mhl_i2c_utils.c new file mode 100644 index 000000000000..c4728b4ddce9 --- /dev/null +++ b/drivers/video/msm/mhl/mhl_i2c_utils.c @@ -0,0 +1,107 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include + +#include "mhl_i2c_utils.h" +#include "mhl_8334.h" + +#define DEBUG + +uint8_t slave_addrs[MAX_PAGES] = { + DEV_PAGE_TPI_0 , + DEV_PAGE_TX_L0_0 , + DEV_PAGE_TX_L1_0 , + DEV_PAGE_TX_2_0 , + DEV_PAGE_TX_3_0 , + DEV_PAGE_CBUS , + DEV_PAGE_DDC_EDID , + DEV_PAGE_DDC_SEGM , +}; + +int mhl_i2c_reg_read(uint8_t slave_addr_index, uint8_t reg_offset) +{ + struct i2c_msg msgs[2]; + uint8_t buffer = 0; + int ret = -1; + + pr_debug("MRR: Reading from slave_addr_index=[%x] and offset=[%x]\n", + slave_addr_index, reg_offset); + pr_debug("MRR: Addr slave_addr_index=[%x]\n", + slave_addrs[slave_addr_index]); + + /* Slave addr */ + msgs[0].addr = slave_addrs[slave_addr_index] >> 1; + msgs[1].addr = slave_addrs[slave_addr_index] >> 1; + + /* Write Command */ + msgs[0].flags = 0; + msgs[1].flags = I2C_M_RD; + + /* Register offset for the next transaction */ + msgs[0].buf = ®_offset; + msgs[1].buf = &buffer; + + /* Offset is 1 Byte long */ + msgs[0].len = 1; + msgs[1].len = 1; + + ret = i2c_transfer(mhl_msm_state->i2c_client->adapter, msgs, 2); + if (ret < 1) { + pr_err("I2C READ FAILED=[%d]\n", ret); + return -EACCES; + } + pr_err("Buffer is [%x]\n", buffer); + return buffer; +} + + +int mhl_i2c_reg_write(uint8_t slave_addr_index, uint8_t reg_offset, + uint8_t value) +{ + return mhl_i2c_reg_write_cmds(slave_addr_index, reg_offset, &value, 1); +} + +int mhl_i2c_reg_write_cmds(uint8_t slave_addr_index, uint8_t reg_offset, + uint8_t *value, uint16_t count) +{ + struct i2c_msg msgs[1]; + uint8_t data[2]; + int status = -EACCES; + + msgs[0].addr = slave_addrs[slave_addr_index] >> 1; + msgs[0].flags = 0; + msgs[0].len = 2; + msgs[0].buf = data; + data[0] = reg_offset; + data[1] = *value; + + status = i2c_transfer(mhl_msm_state->i2c_client->adapter, msgs, 1); + if (status < 1) { + pr_err("I2C WRITE FAILED=[%d]\n", status); + return -EACCES; + } + + return status; +} + +void mhl_i2c_reg_modify(uint8_t slave_addr_index, uint8_t reg_offset, + uint8_t mask, uint8_t val) +{ + uint8_t temp; + + temp = mhl_i2c_reg_read(slave_addr_index, reg_offset); + temp &= (~mask); + temp |= (mask & val); + mhl_i2c_reg_write(slave_addr_index, reg_offset, temp); +} + diff --git a/drivers/video/msm/mhl/mhl_i2c_utils.h b/drivers/video/msm/mhl/mhl_i2c_utils.h new file mode 100644 index 000000000000..94daad7bec76 --- /dev/null +++ b/drivers/video/msm/mhl/mhl_i2c_utils.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __MHL_I2C_UTILS_H__ +#define __MHL_I2C_UTILS_H__ + +#include +#include + +#include "mhl_defs.h" + +/* + * I2C command to the adapter to append + * the buffer from next msg to this one. + */ +#define I2C_M_APPND_NXT_WR 0x0002 + +extern uint8_t slave_addrs[MAX_PAGES]; +extern struct mhl_msm_state_t *mhl_msm_state; + +int mhl_i2c_reg_read(uint8_t slave_addr_index, uint8_t reg_offset); +int mhl_i2c_reg_write(uint8_t slave_addr_index, uint8_t reg_offset, + uint8_t value); +int mhl_i2c_reg_write_cmds(uint8_t slave_addr_index, uint8_t reg_offset, + uint8_t *value, uint16_t count); +void mhl_i2c_reg_modify(uint8_t slave_addr_index, uint8_t reg_offset, + uint8_t mask, uint8_t val); + +#endif /* __MHL_I2C_UTILS_H__ */ diff --git a/drivers/video/msm/mhl_api.h b/drivers/video/msm/mhl_api.h new file mode 100644 index 000000000000..26037ce21dc4 --- /dev/null +++ b/drivers/video/msm/mhl_api.h @@ -0,0 +1,26 @@ + +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __MHL_API_H__ +#define __MHL_API_H__ + +#ifdef CONFIG_FB_MSM_HDMI_MHL_8334 +bool mhl_is_connected(void); +#else +static bool mhl_is_connected(void) +{ + return false; +} +#endif + +#endif /* __MHL_API_H__ */ diff --git a/drivers/video/msm/mipi_NT35510.c b/drivers/video/msm/mipi_NT35510.c new file mode 100644 index 000000000000..be3502ac599a --- /dev/null +++ b/drivers/video/msm/mipi_NT35510.c @@ -0,0 +1,609 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_NT35510.h" + +static struct msm_panel_common_pdata *mipi_nt35510_pdata; +static struct dsi_buf nt35510_tx_buf; +static struct dsi_buf nt35510_rx_buf; + +#define NT35510_SLEEP_OFF_DELAY 150 +#define NT35510_DISPLAY_ON_DELAY 150 + +/* common setting */ +static char exit_sleep[2] = {0x11, 0x00}; +static char display_on[2] = {0x29, 0x00}; +static char display_off[2] = {0x28, 0x00}; +static char enter_sleep[2] = {0x10, 0x00}; +static char write_ram[2] = {0x2c, 0x00}; /* write ram */ + +static struct dsi_cmd_desc nt35510_display_off_cmds[] = { + {DTYPE_DCS_WRITE, 1, 0, 0, 150, sizeof(display_off), display_off}, + {DTYPE_DCS_WRITE, 1, 0, 0, 150, sizeof(enter_sleep), enter_sleep} +}; + +static char cmd0[6] = { + 0xF0, 0x55, 0xAA, 0x52, + 0x08, 0x01, +}; +static char cmd1[4] = { + 0xBC, 0x00, 0xA0, 0x00, +}; +static char cmd2[4] = { + 0xBD, 0x00, 0xA0, 0x00, +}; +static char cmd3[3] = { + 0xBE, 0x00, 0x79, +}; +static char cmd4[53] = { + 0xD1, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x32, 0x00, + 0x4F, 0x00, 0x65, 0x00, + 0x8B, 0x00, 0xA8, 0x00, + 0xD5, 0x00, 0xF7, 0x01, + 0x2B, 0x01, 0x54, 0x01, + 0x8E, 0x01, 0xBB, 0x01, + 0xBC, 0x01, 0xE3, 0x02, + 0x08, 0x02, 0x1C, 0x02, + 0x39, 0x02, 0x4F, 0x02, + 0x76, 0x02, 0xA3, 0x02, + 0xE3, 0x03, 0x12, 0x03, + 0x4C, 0x03, 0x66, 0x03, + 0x9A, +}; +static char cmd5[53] = { + 0xD2, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x32, 0x00, + 0x4F, 0x00, 0x65, 0x00, + 0x8B, 0x00, 0xA8, 0x00, + 0xD5, 0x00, 0xF7, 0x01, + 0x2B, 0x01, 0x54, 0x01, + 0x8E, 0x01, 0xBB, 0x01, + 0xBC, 0x01, 0xE3, 0x02, + 0x08, 0x02, 0x1C, 0x02, + 0x39, 0x02, 0x4F, 0x02, + 0x76, 0x02, 0xA3, 0x02, + 0xE3, 0x03, 0x12, 0x03, + 0x4C, 0x03, 0x66, 0x03, + 0x9A, +}; +static char cmd6[53] = { + 0xD3, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x32, 0x00, + 0x4F, 0x00, 0x65, 0x00, + 0x8B, 0x00, 0xA8, 0x00, + 0xD5, 0x00, 0xF7, 0x01, + 0x2B, 0x01, 0x54, 0x01, + 0x8E, 0x01, 0xBB, 0x01, + 0xBC, 0x01, 0xE3, 0x02, + 0x08, 0x02, 0x1C, 0x02, + 0x39, 0x02, 0x4F, 0x02, + 0x76, 0x02, 0xA3, 0x02, + 0xE3, 0x03, 0x12, 0x03, + 0x4C, 0x03, 0x66, 0x03, + 0x9A, +}; +static char cmd7[53] = { + 0xD4, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x32, 0x00, + 0x4F, 0x00, 0x65, 0x00, + 0x8B, 0x00, 0xA8, 0x00, + 0xD5, 0x00, 0xF7, 0x01, + 0x2B, 0x01, 0x54, 0x01, + 0x8E, 0x01, 0xBB, 0x01, + 0xBC, 0x01, 0xE3, 0x02, + 0x08, 0x02, 0x1C, 0x02, + 0x39, 0x02, 0x4F, 0x02, + 0x76, 0x02, 0xA3, 0x02, + 0xE3, 0x03, 0x12, 0x03, + 0x4C, 0x03, 0x66, 0x03, + 0x9A, +}; +static char cmd8[53] = { + 0xD5, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x32, 0x00, + 0x4F, 0x00, 0x65, 0x00, + 0x8B, 0x00, 0xA8, 0x00, + 0xD5, 0x00, 0xF7, 0x01, + 0x2B, 0x01, 0x54, 0x01, + 0x8E, 0x01, 0xBB, 0x01, + 0xBC, 0x01, 0xE3, 0x02, + 0x08, 0x02, 0x1C, 0x02, + 0x39, 0x02, 0x4F, 0x02, + 0x76, 0x02, 0xA3, 0x02, + 0xE3, 0x03, 0x12, 0x03, + 0x4C, 0x03, 0x66, 0x03, + 0x9A, +}; +static char cmd9[53] = { + 0xD6, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x32, 0x00, + 0x4F, 0x00, 0x65, 0x00, + 0x8B, 0x00, 0xA8, 0x00, + 0xD5, 0x00, 0xF7, 0x01, + 0x2B, 0x01, 0x54, 0x01, + 0x8E, 0x01, 0xBB, 0x01, + 0xBC, 0x01, 0xE3, 0x02, + 0x08, 0x02, 0x1C, 0x02, + 0x39, 0x02, 0x4F, 0x02, + 0x76, 0x02, 0xA3, 0x02, + 0xE3, 0x03, 0x12, 0x03, + 0x4C, 0x03, 0x66, 0x03, + 0x9A, +}; +static char cmd10[4] = { + 0xB0, 0x0A, 0x0A, 0x0A, +}; +static char cmd11[4] = { + 0xB1, 0x0A, 0x0A, 0x0A, +}; +static char cmd12[4] = { + 0xBA, 0x24, 0x24, 0x24, +}; +static char cmd13[4] = { + 0xB9, 0x24, 0x24, 0x24, +}; +static char cmd14[4] = { + 0xB8, 0x24, 0x24, 0x24, +}; +static char cmd15[6] = { + 0xF0, 0x55, 0xAA, 0x52, + 0x08, 0x00, +}; +static char cmd16[2] = { + 0xB3, 0x00, +}; +static char cmd17[2] = { + 0xB4, 0x10, +}; +static char cmd18[2] = { + 0xB6, 0x02, +}; +static char cmd19[3] = { + 0xB1, 0xEC, 0x00, +}; +static char cmd20[4] = { + 0xBC, 0x05, 0x05, 0x05, +}; +static char cmd21[3] = { + 0xB7, 0x20, 0x20, +}; +static char cmd22[5] = { + 0xB8, 0x01, 0x03, 0x03, + 0x03, +}; +static char cmd23[19] = { + 0xC8, 0x01, 0x00, 0x78, + 0x50, 0x78, 0x50, 0x78, + 0x50, 0x78, 0x50, 0xC8, + 0x3C, 0x3C, 0xC8, 0xC8, + 0x3C, 0x3C, 0xC8, +}; +static char cmd24[6] = { + 0xBD, 0x01, 0x84, 0x07, + 0x31, 0x00, +}; +static char cmd25[6] = { + 0xBE, 0x01, 0x84, 0x07, + 0x31, 0x00, +}; +static char cmd26[6] = { + 0xBF, 0x01, 0x84, 0x07, + 0x31, 0x00, +}; +static char cmd27[2] = { + 0x35, 0x00, +}; +static char config_MADCTL[2] = {0x36, 0x00}; +static struct dsi_cmd_desc nt35510_cmd_display_on_cmds[] = { + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd0), cmd0}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd1), cmd1}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd2), cmd2}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd3), cmd3}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd4), cmd4}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd5), cmd5}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd6), cmd6}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd7), cmd7}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd8), cmd8}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd9), cmd9}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd10), cmd10}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd11), cmd11}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd12), cmd12}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd13), cmd13}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd14), cmd14}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd15), cmd15}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd16), cmd16}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd17), cmd17}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd18), cmd18}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd19), cmd19}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd20), cmd20}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd21), cmd21}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd22), cmd22}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd23), cmd23}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd24), cmd24}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd25), cmd25}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd26), cmd26}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(cmd27), cmd27}, + + {DTYPE_DCS_WRITE, 1, 0, 0, 150, sizeof(exit_sleep), exit_sleep}, + {DTYPE_DCS_WRITE, 1, 0, 0, 10, sizeof(display_on), display_on}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, 150, + sizeof(config_MADCTL), config_MADCTL}, + + {DTYPE_DCS_WRITE, 1, 0, 0, 10, sizeof(write_ram), write_ram}, +}; + +static char video0[6] = { + 0xF0, 0x55, 0xAA, 0x52, + 0x08, 0x01, +}; +static char video1[4] = { + 0xBC, 0x00, 0xA0, 0x00, +}; +static char video2[4] = { + 0xBD, 0x00, 0xA0, 0x00, +}; +static char video3[3] = { + 0xBE, 0x00, 0x79, +}; +static char video4[53] = { + 0xD1, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x32, 0x00, + 0x4F, 0x00, 0x65, 0x00, + 0x8B, 0x00, 0xA8, 0x00, + 0xD5, 0x00, 0xF7, 0x01, + 0x2B, 0x01, 0x54, 0x01, + 0x8E, 0x01, 0xBB, 0x01, + 0xBC, 0x01, 0xE3, 0x02, + 0x08, 0x02, 0x1C, 0x02, + 0x39, 0x02, 0x4F, 0x02, + 0x76, 0x02, 0xA3, 0x02, + 0xE3, 0x03, 0x12, 0x03, + 0x4C, 0x03, 0x66, 0x03, + 0x9A, +}; +static char video5[53] = { + 0xD2, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x32, 0x00, + 0x4F, 0x00, 0x65, 0x00, + 0x8B, 0x00, 0xA8, 0x00, + 0xD5, 0x00, 0xF7, 0x01, + 0x2B, 0x01, 0x54, 0x01, + 0x8E, 0x01, 0xBB, 0x01, + 0xBC, 0x01, 0xE3, 0x02, + 0x08, 0x02, 0x1C, 0x02, + 0x39, 0x02, 0x4F, 0x02, + 0x76, 0x02, 0xA3, 0x02, + 0xE3, 0x03, 0x12, 0x03, + 0x4C, 0x03, 0x66, 0x03, + 0x9A, +}; +static char video6[53] = { + 0xD3, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x32, 0x00, + 0x4F, 0x00, 0x65, 0x00, + 0x8B, 0x00, 0xA8, 0x00, + 0xD5, 0x00, 0xF7, 0x01, + 0x2B, 0x01, 0x54, 0x01, + 0x8E, 0x01, 0xBB, 0x01, + 0xBC, 0x01, 0xE3, 0x02, + 0x08, 0x02, 0x1C, 0x02, + 0x39, 0x02, 0x4F, 0x02, + 0x76, 0x02, 0xA3, 0x02, + 0xE3, 0x03, 0x12, 0x03, + 0x4C, 0x03, 0x66, 0x03, + 0x9A, +}; +static char video7[53] = { + 0xD4, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x32, 0x00, + 0x4F, 0x00, 0x65, 0x00, + 0x8B, 0x00, 0xA8, 0x00, + 0xD5, 0x00, 0xF7, 0x01, + 0x2B, 0x01, 0x54, 0x01, + 0x8E, 0x01, 0xBB, 0x01, + 0xBC, 0x01, 0xE3, 0x02, + 0x08, 0x02, 0x1C, 0x02, + 0x39, 0x02, 0x4F, 0x02, + 0x76, 0x02, 0xA3, 0x02, + 0xE3, 0x03, 0x12, 0x03, + 0x4C, 0x03, 0x66, 0x03, + 0x9A, +}; +static char video8[53] = { + 0xD5, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x32, 0x00, + 0x4F, 0x00, 0x65, 0x00, + 0x8B, 0x00, 0xA8, 0x00, + 0xD5, 0x00, 0xF7, 0x01, + 0x2B, 0x01, 0x54, 0x01, + 0x8E, 0x01, 0xBB, 0x01, + 0xBC, 0x01, 0xE3, 0x02, + 0x08, 0x02, 0x1C, 0x02, + 0x39, 0x02, 0x4F, 0x02, + 0x76, 0x02, 0xA3, 0x02, + 0xE3, 0x03, 0x12, 0x03, + 0x4C, 0x03, 0x66, 0x03, + 0x9A, +}; +static char video9[53] = { + 0xD6, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x32, 0x00, + 0x4F, 0x00, 0x65, 0x00, + 0x8B, 0x00, 0xA8, 0x00, + 0xD5, 0x00, 0xF7, 0x01, + 0x2B, 0x01, 0x54, 0x01, + 0x8E, 0x01, 0xBB, 0x01, + 0xBC, 0x01, 0xE3, 0x02, + 0x08, 0x02, 0x1C, 0x02, + 0x39, 0x02, 0x4F, 0x02, + 0x76, 0x02, 0xA3, 0x02, + 0xE3, 0x03, 0x12, 0x03, + 0x4C, 0x03, 0x66, 0x03, + 0x9A, +}; +static char video10[4] = { + 0xB0, 0x0A, 0x0A, 0x0A, +}; +static char video11[4] = { + 0xB1, 0x0A, 0x0A, 0x0A, +}; +static char video12[4] = { + 0xBA, 0x24, 0x24, 0x24, +}; +static char video13[4] = { + 0xB9, 0x24, 0x24, 0x24, +}; +static char video14[4] = { + 0xB8, 0x24, 0x24, 0x24, +}; +static char video15[6] = { + 0xF0, 0x55, 0xAA, 0x52, + 0x08, 0x00, +}; +static char video16[2] = { + 0xB3, 0x00, +}; +static char video17[2] = { + 0xB4, 0x10, +}; +static char video18[2] = { + 0xB6, 0x02, +}; +static char video19[3] = { + 0xB1, 0xFC, 0x00, +}; +static char video20[4] = { + 0xBC, 0x05, 0x05, 0x05, +}; +static char video21[3] = { + 0xB7, 0x20, 0x20, +}; +static char video22[5] = { + 0xB8, 0x01, 0x03, 0x03, + 0x03, +}; +static char video23[19] = { + 0xC8, 0x01, 0x00, 0x78, + 0x50, 0x78, 0x50, 0x78, + 0x50, 0x78, 0x50, 0xC8, + 0x3C, 0x3C, 0xC8, 0xC8, + 0x3C, 0x3C, 0xC8, +}; +static char video24[6] = { + 0xBD, 0x01, 0x84, 0x07, + 0x31, 0x00, +}; +static char video25[6] = { + 0xBE, 0x01, 0x84, 0x07, + 0x31, 0x00, +}; +static char video26[6] = { + 0xBF, 0x01, 0x84, 0x07, + 0x31, 0x00, +}; +static char video27[2] = { + 0x35, 0x00, +}; +static char config_video_MADCTL[2] = {0x36, 0xC0}; +static struct dsi_cmd_desc nt35510_video_display_on_cmds[] = { + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video0), video0}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video1), video1}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video2), video2}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video3), video3}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video4), video4}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video5), video5}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video6), video6}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video7), video7}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video8), video8}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video9), video9}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video10), video10}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video11), video11}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video12), video12}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video13), video13}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video14), video14}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video15), video15}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video16), video16}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video17), video17}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video18), video18}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video19), video19}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video20), video20}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video21), video21}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video22), video22}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video23), video23}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video24), video24}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video25), video25}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video26), video26}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video27), video27}, + {DTYPE_DCS_WRITE, 1, 0, 0, NT35510_SLEEP_OFF_DELAY, sizeof(exit_sleep), + exit_sleep}, + {DTYPE_DCS_WRITE, 1, 0, 0, NT35510_DISPLAY_ON_DELAY, sizeof(display_on), + display_on}, +}; + +static struct dsi_cmd_desc nt35510_video_display_on_cmds_rotate[] = { + {DTYPE_DCS_WRITE1, 1, 0, 0, 150, + sizeof(config_video_MADCTL), config_video_MADCTL}, +}; +static int mipi_nt35510_lcd_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct mipi_panel_info *mipi; + static int rotate; + mfd = platform_get_drvdata(pdev); + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + mipi = &mfd->panel_info.mipi; + + if (mipi_nt35510_pdata && mipi_nt35510_pdata->rotate_panel) + rotate = mipi_nt35510_pdata->rotate_panel(); + + if (mipi->mode == DSI_VIDEO_MODE) { + mipi_dsi_cmds_tx(mfd, &nt35510_tx_buf, + nt35510_video_display_on_cmds, + ARRAY_SIZE(nt35510_video_display_on_cmds)); + + if (rotate) { + mipi_dsi_cmds_tx(mfd, &nt35510_tx_buf, + nt35510_video_display_on_cmds_rotate, + ARRAY_SIZE(nt35510_video_display_on_cmds_rotate)); + } + } else if (mipi->mode == DSI_CMD_MODE) { + mipi_dsi_cmds_tx(mfd, &nt35510_tx_buf, + nt35510_cmd_display_on_cmds, + ARRAY_SIZE(nt35510_cmd_display_on_cmds)); + } + + return 0; +} + +static int mipi_nt35510_lcd_off(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + pr_debug("mipi_nt35510_lcd_off E\n"); + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + mipi_dsi_cmds_tx(mfd, &nt35510_tx_buf, nt35510_display_off_cmds, + ARRAY_SIZE(nt35510_display_off_cmds)); + + pr_debug("mipi_nt35510_lcd_off X\n"); + return 0; +} + +static int mipi_nt35510_lcd_probe(struct platform_device *pdev) +{ + pr_debug("%s\n", __func__); + + if (pdev->id == 0) { + mipi_nt35510_pdata = pdev->dev.platform_data; + if (mipi_nt35510_pdata->bl_lock) + spin_lock_init(&mipi_nt35510_pdata->bl_spinlock); + return 0; + } + + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = mipi_nt35510_lcd_probe, + .driver = { + .name = "mipi_NT35510", + }, +}; + +static void mipi_nt35510_set_backlight(struct msm_fb_data_type *mfd) +{ + int bl_level; + unsigned long flags; + bl_level = mfd->bl_level; + + if (mipi_nt35510_pdata->bl_lock) { + spin_lock_irqsave(&mipi_nt35510_pdata->bl_spinlock, flags); + mipi_nt35510_pdata->pmic_backlight(bl_level); + spin_unlock_irqrestore(&mipi_nt35510_pdata->bl_spinlock, flags); + } else + mipi_nt35510_pdata->pmic_backlight(bl_level); +} + +static struct msm_fb_panel_data nt35510_panel_data = { + .on = mipi_nt35510_lcd_on, + .off = mipi_nt35510_lcd_off, + .set_backlight = mipi_nt35510_set_backlight, +}; + +static int ch_used[3]; + +static int mipi_nt35510_lcd_init(void) +{ + mipi_dsi_buf_alloc(&nt35510_tx_buf, DSI_BUF_SIZE); + mipi_dsi_buf_alloc(&nt35510_rx_buf, DSI_BUF_SIZE); + + return platform_driver_register(&this_driver); +} +int mipi_nt35510_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel) +{ + struct platform_device *pdev = NULL; + int ret; + + if ((channel >= 3) || ch_used[channel]) + return -ENODEV; + + ch_used[channel] = TRUE; + + ret = mipi_nt35510_lcd_init(); + if (ret) { + pr_err("mipi_nt35510_lcd_init() failed with ret %u\n", ret); + return ret; + } + + pdev = platform_device_alloc("mipi_NT35510", (panel << 8)|channel); + if (!pdev) + return -ENOMEM; + + nt35510_panel_data.panel_info = *pinfo; + ret = platform_device_add_data(pdev, &nt35510_panel_data, + sizeof(nt35510_panel_data)); + if (ret) { + pr_debug("%s: platform_device_add_data failed!\n", __func__); + goto err_device_put; + } + + ret = platform_device_add(pdev); + if (ret) { + pr_debug("%s: platform_device_register failed!\n", __func__); + goto err_device_put; + } + + return 0; + +err_device_put: + platform_device_put(pdev); + return ret; +} diff --git a/drivers/video/msm/mipi_NT35510.h b/drivers/video/msm/mipi_NT35510.h new file mode 100644 index 000000000000..58ac05a54355 --- /dev/null +++ b/drivers/video/msm/mipi_NT35510.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef MIPI_NT35510_H +#define MIPI_NT35510_H + +int mipi_nt35510_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel); + +#endif /* MIPI_NT35510_H */ diff --git a/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c b/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c new file mode 100644 index 000000000000..d44b1c911a9f --- /dev/null +++ b/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c @@ -0,0 +1,98 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_NT35510.h" + +static struct msm_panel_info pinfo; + +static struct mipi_dsi_phy_ctrl dsi_cmd_mode_phy_db = { + /* DSI Bit Clock at 500 MHz, 2 lane, RGB888 */ + /* regulator */ + {0x03, 0x01, 0x01, 0x00}, + /* timing */ + {0xb9, 0x8e, 0x1f, 0x00, 0x98, 0x9c, 0x22, 0x90, + 0x18, 0x03, 0x04}, + /* phy ctrl */ + {0x7f, 0x00, 0x00, 0x00}, + /* strength */ + {0xbb, 0x02, 0x06, 0x00}, + /* pll control */ + {0x01, 0xec, 0x31, 0xd2, 0x00, 0x40, 0x37, 0x62, + 0x01, 0x0f, 0x07, + 0x05, 0x14, 0x03, 0x0, 0x0, 0x0, 0x20, 0x0, 0x02, 0x0}, +}; + +static int mipi_cmd_nt35510_wvga_pt_init(void) +{ + int ret; + + if (msm_fb_detect_client("mipi_cmd_nt35510_wvga")) + return 0; + + pinfo.xres = 480; + pinfo.yres = 800; + pinfo.type = MIPI_CMD_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.lcdc.h_back_porch = 100; + pinfo.lcdc.h_front_porch = 100; + pinfo.lcdc.h_pulse_width = 8; + pinfo.lcdc.v_back_porch = 20; + pinfo.lcdc.v_front_porch = 20; + pinfo.lcdc.v_pulse_width = 1; + + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + pinfo.bl_max = 31; + pinfo.bl_min = 1; + pinfo.fb_num = 2; + + pinfo.clk_rate = 499000000; + + pinfo.lcd.vsync_enable = TRUE; + pinfo.lcd.hw_vsync_mode = TRUE; + pinfo.lcd.refx100 = 6000; /* adjust refx100 to prevent tearing */ + + pinfo.mipi.mode = DSI_CMD_MODE; + pinfo.mipi.dst_format = DSI_CMD_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.rgb_swap = DSI_RGB_SWAP_RGB; + pinfo.mipi.data_lane0 = TRUE; + pinfo.mipi.data_lane1 = TRUE; + pinfo.mipi.t_clk_post = 0x20; + pinfo.mipi.t_clk_pre = 0x2F; + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.te_sel = 1; /* TE from vsync gpio */ + pinfo.mipi.interleave_max = 1; + pinfo.mipi.insert_dcs_cmd = TRUE; + pinfo.mipi.wr_mem_continue = 0x3c; + pinfo.mipi.wr_mem_start = 0x2c; + pinfo.mipi.dsi_phy_db = &dsi_cmd_mode_phy_db; + pinfo.mipi.tx_eot_append = 0x01; + pinfo.mipi.rx_eot_ignore = 0x0; + pinfo.mipi.dlane_swap = 0x01; + + ret = mipi_nt35510_device_register(&pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_WVGA_PT); + if (ret) + pr_err("%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mipi_cmd_nt35510_wvga_pt_init); diff --git a/drivers/video/msm/mipi_NT35510_video_wvga_pt.c b/drivers/video/msm/mipi_NT35510_video_wvga_pt.c new file mode 100644 index 000000000000..5b7a3cfbf0db --- /dev/null +++ b/drivers/video/msm/mipi_NT35510_video_wvga_pt.c @@ -0,0 +1,108 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_NT35510.h" + +static struct msm_panel_info pinfo; + +static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = { + /* DSI Bit Clock at 500 MHz, 2 lane, RGB888 */ + /* regulator */ + {0x03, 0x01, 0x01, 0x00}, + /* timing */ + {0xb9, 0x8e, 0x1f, 0x00, 0x98, 0x9c, 0x22, 0x90, + 0x18, 0x03, 0x04}, + /* phy ctrl */ + {0x7f, 0x00, 0x00, 0x00}, + /* strength */ + {0xbb, 0x02, 0x06, 0x00}, + /* pll control */ + {0x00, 0xec, 0x31, 0xd2, 0x00, 0x40, 0x37, 0x62, + 0x01, 0x0f, 0x07, + 0x05, 0x14, 0x03, 0x0, 0x0, 0x0, 0x20, 0x0, 0x02, 0x0}, +}; + +static int mipi_video_nt35510_wvga_pt_init(void) +{ + int ret; + + if (msm_fb_detect_client("mipi_video_nt35510_wvga")) + return 0; + + pinfo.xres = 480; + pinfo.yres = 800; + pinfo.type = MIPI_VIDEO_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.lcdc.h_back_porch = 100; + pinfo.lcdc.h_front_porch = 100; + pinfo.lcdc.h_pulse_width = 8; + pinfo.lcdc.v_back_porch = 20; + pinfo.lcdc.v_front_porch = 20; + pinfo.lcdc.v_pulse_width = 1; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + /* number of dot_clk cycles HSYNC active edge is + delayed from VSYNC active edge */ + pinfo.lcdc.hsync_skew = 0; + pinfo.clk_rate = 499000000; + pinfo.bl_max = 31; + pinfo.bl_min = 1; + pinfo.fb_num = 2; + + pinfo.mipi.mode = DSI_VIDEO_MODE; + /* send HSA and HE following VS/VE packet */ + pinfo.mipi.pulse_mode_hsa_he = TRUE; + pinfo.mipi.hfp_power_stop = TRUE; /* LP-11 during the HFP period */ + pinfo.mipi.hbp_power_stop = TRUE; /* LP-11 during the HBP period */ + pinfo.mipi.hsa_power_stop = TRUE; /* LP-11 during the HSA period */ + /* LP-11 or let Command Mode Engine send packets in + HS or LP mode for the BLLP of the last line of a frame */ + pinfo.mipi.eof_bllp_power_stop = TRUE; + /* LP-11 or let Command Mode Engine send packets in + HS or LP mode for packets sent during BLLP period */ + pinfo.mipi.bllp_power_stop = TRUE; + + pinfo.mipi.traffic_mode = DSI_BURST_MODE; + pinfo.mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.rgb_swap = DSI_RGB_SWAP_RGB; /* RGB */ + pinfo.mipi.data_lane0 = TRUE; + pinfo.mipi.data_lane1 = TRUE; + + pinfo.mipi.t_clk_post = 0x20; + pinfo.mipi.t_clk_pre = 0x2f; + + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_NONE; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.frame_rate = 60; /* FIXME */ + + pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db; + pinfo.mipi.dlane_swap = 0x01; + /* append EOT at the end of data burst */ + pinfo.mipi.tx_eot_append = 0x01; + + ret = mipi_nt35510_device_register(&pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_WVGA_PT); + + if (ret) + pr_err("%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mipi_video_nt35510_wvga_pt_init); diff --git a/drivers/video/msm/mipi_chimei_wuxga.c b/drivers/video/msm/mipi_chimei_wuxga.c new file mode 100644 index 000000000000..3645d61d0867 --- /dev/null +++ b/drivers/video/msm/mipi_chimei_wuxga.c @@ -0,0 +1,197 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * Chimei WUXGA LVDS Panel driver. + * The panel model is N101JSF-L21. + * + * The panel interface includes: + * 1. LVDS input for video (clock & data). + * 2. few configuration pins to control 3D module: Enable, Mode (2D/3D). + * 3. Backlight LED control (PWM 200 HZ). + * + * This panel is controled via the Toshiba DSI-to-LVDS bridge. + * + */ + +/* #define DEBUG 1 */ + +#include "msm_fb.h" +#include "msm_fb_panel.h" +#include "mipi_dsi.h" +#include "mipi_tc358764_dsi2lvds.h" + +#define MHZ (1000*1000) + +/** + * Panel info parameters. + * The panel info is passed to the mipi framebuffer driver. + */ +static struct msm_panel_info chimei_wuxga_pinfo; + +/** + * The mipi_dsi_phy_ctrl is calculated according to the + * "dsi_timing_program.xlsm" excel sheet. + * Output is based on: 1200x1920, RGB565, 4 lanes , 58 frames + * per second. + */ +static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = { + /* DSIPHY_REGULATOR_CTRL */ + .regulator = {0x03, 0x0a, 0x04, 0x00, 0x20}, /* common 8960 */ + /* DSIPHY_CTRL */ + .ctrl = {0x5f, 0x00, 0x00, 0x10}, /* common 8960 */ + /* DSIPHY_STRENGTH_CTRL */ + .strength = {0xff, 0x00, 0x06, 0x00}, /* common 8960 */ + /* DSIPHY_TIMING_CTRL */ + .timing = { 0xC9, 0x92, 0x29, /* panel specific */ + 0, /* DSIPHY_TIMING_CTRL_3 = 0 */ + 0x2D, 0x9B, 0x2B, 0x94, 0x2D, 0x03, 0x04}, /* panel specific */ + + /* DSIPHY_PLL_CTRL */ + .pll = { 0x00, /* common 8960 */ + /* VCO */ + 0x30, (0x01 | 0x30) , (0x19 | 0xC0), /* panel specific */ + 0x00, 0x50, 0x48, 0x63, + 0x77, 0x88, 0x99, /* Auto update by dsi-mipi driver */ + 0x00, 0x14, 0x03, 0x00, 0x02, /* common 8960 */ + 0x00, 0x20, 0x00, 0x01 }, /* common 8960 */ +}; + +/** + * Module init. + * + * Register the panel-info. + * + * Some parameters are from the panel datasheet + * and other are *calculated* by the "dsi_timing_program.xlsm" + * excel file + * + * @return int + */ +static int __init mipi_chimei_wuxga_init(void) +{ + int ret; + struct msm_panel_info *pinfo = &chimei_wuxga_pinfo; + + if (msm_fb_detect_client("mipi_video_chimei_wuxga")) + return 0; + + pr_info("mipi-dsi chimei wuxga (1200x1920) driver ver 1.0.\n"); + + /* Portrait */ + pinfo->xres = 1200; + pinfo->yres = 1920; + pinfo->type = MIPI_VIDEO_PANEL; + pinfo->pdest = DISPLAY_1; /* Primary Display */ + pinfo->wait_cycle = 0; + pinfo->bpp = 24; /* RGB565 requires 24 bits-per-pixel :-O */ + pinfo->fb_num = 2; /* using two frame buffers */ + + /* + * The CMI panel requires 80 MHZ LVDS-CLK. + * The D2L bridge drives the LVDS-CLK from the DSI-CLK. + * The DSI-CLK = bitclk/2, 640 MHZ/2= 320 MHZ. + * LVDS-CLK = DSI-CLK/4 , 320 MHZ/4= 80 MHZ. + */ + + pinfo->clk_rate = 635 * MHZ ; /* bitclk Calculated */ + + /* + * this panel is operated by DE, + * vsycn and hsync are ignored + */ + + pinfo->lcdc.h_front_porch = 160-48-32; /* thfp */ + pinfo->lcdc.h_back_porch = 48; /* thb */ + pinfo->lcdc.h_pulse_width = 32; /* thpw */ + + pinfo->lcdc.v_front_porch = 26-3-6; /* tvfp */ + pinfo->lcdc.v_back_porch = 3; /* tvb */ + pinfo->lcdc.v_pulse_width = 6; /* tvpw */ + + pinfo->lcdc.border_clr = 0; /* black */ + pinfo->lcdc.underflow_clr = 0xff; /* blue */ + + pinfo->lcdc.hsync_skew = 0; + + /* Backlight levels - controled via PMIC pwm gpio */ + pinfo->bl_max = PWM_LEVEL; + pinfo->bl_min = 1; + + /* mipi - general */ + pinfo->mipi.vc = 0; /* virtual channel */ + pinfo->mipi.rgb_swap = DSI_RGB_SWAP_RGB; + pinfo->mipi.tx_eot_append = true; + pinfo->mipi.t_clk_post = 34; /* Calculated */ + pinfo->mipi.t_clk_pre = 69; /* Calculated */ + + pinfo->mipi.dsi_phy_db = &dsi_video_mode_phy_db; + + /* Four lanes are recomended for 1920x1200 at 60 frames per second */ + pinfo->mipi.frame_rate = 60; + pinfo->mipi.data_lane0 = true; + pinfo->mipi.data_lane1 = true; + pinfo->mipi.data_lane2 = true; + pinfo->mipi.data_lane3 = true; + pinfo->mipi.esc_byte_ratio = 6; + + pinfo->mipi.mode = DSI_VIDEO_MODE; + /* + * Note: The CMI panel input is RGB888, + * thus the DSI-to-LVDS bridge output is RGB888. + * This parameter selects the DSI-Core output to the bridge. + */ + pinfo->mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB565; + + /* mipi - video mode */ + pinfo->mipi.traffic_mode = DSI_NON_BURST_SYNCH_EVENT; + pinfo->mipi.pulse_mode_hsa_he = false; /* sync mode */ + + pinfo->mipi.hfp_power_stop = false; + pinfo->mipi.hbp_power_stop = false; + pinfo->mipi.hsa_power_stop = false; + pinfo->mipi.eof_bllp_power_stop = false; + pinfo->mipi.bllp_power_stop = false; + + /* mipi - command mode */ + pinfo->mipi.te_sel = 1; /* TE from vsycn gpio */ + pinfo->mipi.interleave_max = 1; + /* The bridge supports only Generic Read/Write commands */ + pinfo->mipi.insert_dcs_cmd = false; + pinfo->mipi.wr_mem_continue = 0; + pinfo->mipi.wr_mem_start = 0; + pinfo->mipi.stream = false; /* dma_p */ + pinfo->mipi.mdp_trigger = DSI_CMD_TRIGGER_NONE; + pinfo->mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + /* + * toshiba d2l chip does not need max_pkt_size dcs cmd + * client reply len is directly configure through + * RDPKTLN register (0x0404) + */ + pinfo->mipi.no_max_pkt_size = 1; + pinfo->mipi.force_clk_lane_hs = 1; + + pinfo->is_3d_panel = FB_TYPE_3D_PANEL; + + ret = mipi_tc358764_dsi2lvds_register(pinfo, MIPI_DSI_PRIM, 1); + if (ret) + pr_err("%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mipi_chimei_wuxga_init); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Chimei WUXGA LVDS Panel driver"); +MODULE_AUTHOR("Amir Samuelov "); diff --git a/drivers/video/msm/mipi_chimei_wxga_pt.c b/drivers/video/msm/mipi_chimei_wxga_pt.c new file mode 100644 index 000000000000..8b1b828ce204 --- /dev/null +++ b/drivers/video/msm/mipi_chimei_wxga_pt.c @@ -0,0 +1,192 @@ +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * Chimei WXGA LVDS Panel driver. + * The panel model is N101BCG-L21. + * + * The panel interface includes: + * 1. LVDS input for video (clock & data). + * 2. few configuration pins: Up/Down scan, Left/Right scan etc. + * 3. Backlight LED control. + * 4. I2C interface for EEPROM access. + * + * The Panel is *internally* controlled by Novatek NT51009 controller. + * However, the "3-wire" SPI interface is not exposed on the panel interface. + * + * This panel is controled via the Toshiba DSI-to-LVDS bridge. + * + */ + +/* #define DEBUG 1 */ + +#include "msm_fb.h" +#include "msm_fb_panel.h" +#include "mipi_dsi.h" +#include "mipi_tc358764_dsi2lvds.h" + +#define MHZ (1000*1000) + +/** + * Panel info parameters. + * The panel info is passed to the mipi framebuffer driver. + */ +static struct msm_panel_info chimei_wxga_pinfo; + +/** + * The mipi_dsi_phy_ctrl is calculated according to the + * "DSI_panel_bring_up_guide_ver3.docm" using the excel sheet. + * Output is based on: 1366x768, RGB888, 4 lanes , 60 frames per second. + */ +static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = { + /* DSIPHY_REGULATOR_CTRL */ + .regulator = {0x03, 0x0a, 0x04, 0x00, 0x20}, /* common 8960 */ + /* DSIPHY_CTRL */ + .ctrl = {0x5f, 0x00, 0x00, 0x10}, /* common 8960 */ + /* DSIPHY_STRENGTH_CTRL */ + .strength = {0xff, 0x00, 0x06, 0x00}, /* common 8960 */ + /* DSIPHY_TIMING_CTRL */ + .timing = { 0xB6, 0x8D, 0x1E, /* panel specific */ + 0, /* DSIPHY_TIMING_CTRL_3 = 0 */ + 0x21, 0x95, 0x21, 0x8F, 0x21, 0x03, 0x04}, /* panel specific */ + + /* DSIPHY_PLL_CTRL */ + .pll = { 0x00, /* common 8960 */ + /* VCO */ + 0xC6, 0x01, 0x19, /* panel specific */ + 0x00, 0x50, 0x48, 0x63, + 0x77, 0x88, 0x99, /* Auto update by dsi-mipi driver */ + 0x00, 0x14, 0x03, 0x00, 0x02, /* common 8960 */ + 0x00, 0x20, 0x00, 0x01 }, /* common 8960 */ +}; + +/** + * Module init. + * + * Register the panel-info. + * + * Some parameters are from the panel datasheet + * and other are *calculated* according to the + * "DSI_panel_bring_up_guide_ver3.docm". + * + * @return int + */ +static int __init mipi_chimei_wxga_init(void) +{ + int ret; + struct msm_panel_info *pinfo = &chimei_wxga_pinfo; + + if (msm_fb_detect_client("mipi_video_chimei_wxga")) + return 0; + + pr_debug("mipi-dsi chimei wxga (1366x768) driver ver 1.0.\n"); + /* Landscape */ + pinfo->xres = 1366; + pinfo->yres = 768; + pinfo->type = MIPI_VIDEO_PANEL; + pinfo->pdest = DISPLAY_1; /* Primary Display */ + pinfo->wait_cycle = 0; + pinfo->bpp = 24; /* RGB888 = 24 bits-per-pixel */ + pinfo->fb_num = 2; /* using two frame buffers */ + + /* bitclk */ + pinfo->clk_rate = 473400000; /* 473.4 MHZ Calculated */ + + /* + * this panel is operated by DE, + * vsycn and hsync are ignored + */ + + pinfo->lcdc.h_front_porch = 96+2;/* thfp */ + pinfo->lcdc.h_back_porch = 88; /* thb */ + pinfo->lcdc.h_pulse_width = 40; /* thpw */ + + pinfo->lcdc.v_front_porch = 15; /* tvfp */ + pinfo->lcdc.v_back_porch = 23; /* tvb */ + pinfo->lcdc.v_pulse_width = 20; /* tvpw */ + + pinfo->lcdc.border_clr = 0; /* black */ + pinfo->lcdc.underflow_clr = 0xff; /* blue */ + + pinfo->lcdc.hsync_skew = 0; + + /* Backlight levels - controled via PMIC pwm gpio */ + pinfo->bl_max = PWM_LEVEL; + pinfo->bl_min = 1; + + /* mipi - general */ + pinfo->mipi.vc = 0; /* virtual channel */ + pinfo->mipi.rgb_swap = DSI_RGB_SWAP_RGB; + pinfo->mipi.tx_eot_append = true; + pinfo->mipi.t_clk_post = 34; /* Calculated */ + pinfo->mipi.t_clk_pre = 64; /* Calculated */ + pinfo->mipi.esc_byte_ratio = 4; + + pinfo->mipi.dsi_phy_db = &dsi_video_mode_phy_db; + + /* Four lanes are recomended for 1366x768 at 60 frames per second */ + pinfo->mipi.frame_rate = 60; /* 60 frames per second */ + pinfo->mipi.data_lane0 = true; + pinfo->mipi.data_lane1 = true; + pinfo->mipi.data_lane2 = true; + pinfo->mipi.data_lane3 = true; + + pinfo->mipi.mode = DSI_VIDEO_MODE; + /* + * Note: The CMI panel input is RGB888, + * thus the DSI-to-LVDS bridge output is RGB888. + * This parameter selects the DSI-Core output to the bridge. + */ + pinfo->mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888; + + /* mipi - video mode */ + pinfo->mipi.traffic_mode = DSI_NON_BURST_SYNCH_EVENT; + pinfo->mipi.pulse_mode_hsa_he = false; /* sync mode */ + + pinfo->mipi.hfp_power_stop = false; + pinfo->mipi.hbp_power_stop = false; + pinfo->mipi.hsa_power_stop = false; + pinfo->mipi.eof_bllp_power_stop = false; + pinfo->mipi.bllp_power_stop = false; + + /* mipi - command mode */ + pinfo->mipi.te_sel = 1; /* TE from vsycn gpio */ + pinfo->mipi.interleave_max = 1; + /* The bridge supports only Generic Read/Write commands */ + pinfo->mipi.insert_dcs_cmd = false; + pinfo->mipi.wr_mem_continue = 0; + pinfo->mipi.wr_mem_start = 0; + pinfo->mipi.stream = false; /* dma_p */ + pinfo->mipi.mdp_trigger = DSI_CMD_TRIGGER_NONE; + pinfo->mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + /* + * toshiba d2l chip does not need max_pkt_szie dcs cmd + * client reply len is directly configure through + * RDPKTLN register (0x0404) + */ + pinfo->mipi.no_max_pkt_size = 1; + pinfo->mipi.force_clk_lane_hs = 1; + + ret = mipi_tc358764_dsi2lvds_register(pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_WXGA); + if (ret) + pr_err("%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mipi_chimei_wxga_init); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Chimei WXGA LVDS Panel driver"); +MODULE_AUTHOR("Amir Samuelov "); diff --git a/drivers/video/msm/mipi_dsi.c b/drivers/video/msm/mipi_dsi.c new file mode 100644 index 000000000000..623f3311382c --- /dev/null +++ b/drivers/video/msm/mipi_dsi.c @@ -0,0 +1,639 @@ +/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mdp.h" +#include "mdp4.h" + +u32 dsi_irq; +u32 esc_byte_ratio; + +static boolean tlmm_settings = FALSE; + +static int mipi_dsi_probe(struct platform_device *pdev); +static int mipi_dsi_remove(struct platform_device *pdev); + +static int mipi_dsi_off(struct platform_device *pdev); +static int mipi_dsi_on(struct platform_device *pdev); + +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; +static struct mipi_dsi_platform_data *mipi_dsi_pdata; + +static int vsync_gpio = -1; + +static struct platform_driver mipi_dsi_driver = { + .probe = mipi_dsi_probe, + .remove = mipi_dsi_remove, + .shutdown = NULL, + .driver = { + .name = "mipi_dsi", + }, +}; + +struct device dsi_dev; + +static int mipi_dsi_off(struct platform_device *pdev) +{ + int ret = 0; + struct msm_fb_data_type *mfd; + struct msm_panel_info *pinfo; + + mfd = platform_get_drvdata(pdev); + pinfo = &mfd->panel_info; + + if (mdp_rev >= MDP_REV_41) + mutex_lock(&mfd->dma->ov_mutex); + else + down(&mfd->dma->mutex); + + mdp4_overlay_dsi_state_set(ST_DSI_SUSPEND); + + /* + * Description: dsi clock is need to perform shutdown. + * mdp4_dsi_cmd_dma_busy_wait() will enable dsi clock if disabled. + * also, wait until dma (overlay and dmap) finish. + */ + if (mfd->panel_info.type == MIPI_CMD_PANEL) { + if (mdp_rev >= MDP_REV_41) { + mdp4_dsi_cmd_dma_busy_wait(mfd); + mdp4_dsi_blt_dmap_busy_wait(mfd); + mipi_dsi_mdp_busy_wait(mfd); + } else { + mdp3_dsi_cmd_dma_busy_wait(mfd); + } + } else { + /* video mode, wait until fifo cleaned */ + mipi_dsi_controller_cfg(0); + } + + /* + * Desctiption: change to DSI_CMD_MODE since it needed to + * tx DCS dsiplay off comamnd to panel + */ + mipi_dsi_op_mode_config(DSI_CMD_MODE); + + if (mfd->panel_info.type == MIPI_CMD_PANEL) { + if (pinfo->lcd.vsync_enable) { + if (pinfo->lcd.hw_vsync_mode && vsync_gpio >= 0) { + if (MDP_REV_303 != mdp_rev) + gpio_free(vsync_gpio); + } + mipi_dsi_set_tear_off(mfd); + } + } + + ret = panel_next_off(pdev); + +#ifdef CONFIG_MSM_BUS_SCALING + mdp_bus_scale_update_request(0); +#endif + + local_bh_disable(); + mipi_dsi_clk_disable(); + local_bh_enable(); + + /* disbale dsi engine */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0000, 0); + + mipi_dsi_phy_ctrl(0); + + + local_bh_disable(); + mipi_dsi_ahb_ctrl(0); + local_bh_enable(); + + mipi_dsi_unprepare_clocks(); + if (mipi_dsi_pdata && mipi_dsi_pdata->dsi_power_save) + mipi_dsi_pdata->dsi_power_save(0); + + if (mdp_rev >= MDP_REV_41) + mutex_unlock(&mfd->dma->ov_mutex); + else + up(&mfd->dma->mutex); + + pr_debug("%s-:\n", __func__); + + return ret; +} + +static int mipi_dsi_on(struct platform_device *pdev) +{ + int ret = 0; + u32 clk_rate; + struct msm_fb_data_type *mfd; + struct fb_info *fbi; + struct fb_var_screeninfo *var; + struct msm_panel_info *pinfo; + struct mipi_panel_info *mipi; + u32 hbp, hfp, vbp, vfp, hspw, vspw, width, height; + u32 ystride, bpp, data; + u32 dummy_xres, dummy_yres; + int target_type = 0; + + mfd = platform_get_drvdata(pdev); + fbi = mfd->fbi; + var = &fbi->var; + pinfo = &mfd->panel_info; + esc_byte_ratio = pinfo->mipi.esc_byte_ratio; + + if (mipi_dsi_pdata && mipi_dsi_pdata->dsi_power_save) + mipi_dsi_pdata->dsi_power_save(1); + + cont_splash_clk_ctrl(0); + mipi_dsi_prepare_clocks(); + + local_bh_disable(); + mipi_dsi_ahb_ctrl(1); + local_bh_enable(); + + clk_rate = mfd->fbi->var.pixclock; + clk_rate = min(clk_rate, mfd->panel_info.clk_max); + + mipi_dsi_phy_ctrl(1); + + if (mdp_rev == MDP_REV_42 && mipi_dsi_pdata) + target_type = mipi_dsi_pdata->target_type; + + mipi_dsi_phy_init(0, &(mfd->panel_info), target_type); + + local_bh_disable(); + mipi_dsi_clk_enable(); + local_bh_enable(); + + MIPI_OUTP(MIPI_DSI_BASE + 0x114, 1); + MIPI_OUTP(MIPI_DSI_BASE + 0x114, 0); + + hbp = var->left_margin; + hfp = var->right_margin; + vbp = var->upper_margin; + vfp = var->lower_margin; + hspw = var->hsync_len; + vspw = var->vsync_len; + width = mfd->panel_info.xres; + height = mfd->panel_info.yres; + + mipi = &mfd->panel_info.mipi; + if (mfd->panel_info.type == MIPI_VIDEO_PANEL) { + dummy_xres = mfd->panel_info.lcdc.xres_pad; + dummy_yres = mfd->panel_info.lcdc.yres_pad; + + if (mdp_rev >= MDP_REV_41) { + MIPI_OUTP(MIPI_DSI_BASE + 0x20, + ((hspw + hbp + width + dummy_xres) << 16 | + (hspw + hbp))); + MIPI_OUTP(MIPI_DSI_BASE + 0x24, + ((vspw + vbp + height + dummy_yres) << 16 | + (vspw + vbp))); + MIPI_OUTP(MIPI_DSI_BASE + 0x28, + (vspw + vbp + height + dummy_yres + + vfp - 1) << 16 | (hspw + hbp + + width + dummy_xres + hfp - 1)); + } else { + /* DSI_LAN_SWAP_CTRL */ + MIPI_OUTP(MIPI_DSI_BASE + 0x00ac, mipi->dlane_swap); + + MIPI_OUTP(MIPI_DSI_BASE + 0x20, + ((hbp + width + dummy_xres) << 16 | (hbp))); + MIPI_OUTP(MIPI_DSI_BASE + 0x24, + ((vbp + height + dummy_yres) << 16 | (vbp))); + MIPI_OUTP(MIPI_DSI_BASE + 0x28, + (vbp + height + dummy_yres + vfp) << 16 | + (hbp + width + dummy_xres + hfp)); + } + + MIPI_OUTP(MIPI_DSI_BASE + 0x2c, (hspw << 16)); + MIPI_OUTP(MIPI_DSI_BASE + 0x30, 0); + MIPI_OUTP(MIPI_DSI_BASE + 0x34, (vspw << 16)); + + } else { /* command mode */ + if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888) + bpp = 3; + else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB666) + bpp = 3; + else if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565) + bpp = 2; + else + bpp = 3; /* Default format set to RGB888 */ + + ystride = width * bpp + 1; + + /* DSI_COMMAND_MODE_MDP_STREAM_CTRL */ + data = (ystride << 16) | (mipi->vc << 8) | DTYPE_DCS_LWRITE; + MIPI_OUTP(MIPI_DSI_BASE + 0x5c, data); + MIPI_OUTP(MIPI_DSI_BASE + 0x54, data); + + /* DSI_COMMAND_MODE_MDP_STREAM_TOTAL */ + data = height << 16 | width; + MIPI_OUTP(MIPI_DSI_BASE + 0x60, data); + MIPI_OUTP(MIPI_DSI_BASE + 0x58, data); + } + + mipi_dsi_host_init(mipi); + + if (mipi->force_clk_lane_hs) { + u32 tmp; + + tmp = MIPI_INP(MIPI_DSI_BASE + 0xA8); + tmp |= (1<<28); + MIPI_OUTP(MIPI_DSI_BASE + 0xA8, tmp); + wmb(); + } + + if (mdp_rev >= MDP_REV_41) + mutex_lock(&mfd->dma->ov_mutex); + else + down(&mfd->dma->mutex); + + ret = panel_next_on(pdev); + + mipi_dsi_op_mode_config(mipi->mode); + + if (mfd->panel_info.type == MIPI_CMD_PANEL) { + if (pinfo->lcd.vsync_enable) { + if (pinfo->lcd.hw_vsync_mode && vsync_gpio >= 0) { + if (mdp_rev >= MDP_REV_41) { + if (gpio_request(vsync_gpio, + "MDP_VSYNC") == 0) + gpio_direction_input( + vsync_gpio); + else + pr_err("%s: unable to \ + request gpio=%d\n", + __func__, vsync_gpio); + } else if (mdp_rev == MDP_REV_303) { + if (!tlmm_settings && gpio_request( + vsync_gpio, "MDP_VSYNC") == 0) { + ret = gpio_tlmm_config( + GPIO_CFG( + vsync_gpio, 1, + GPIO_CFG_INPUT, + GPIO_CFG_PULL_DOWN, + GPIO_CFG_2MA), + GPIO_CFG_ENABLE); + + if (ret) { + pr_err( + "%s: unable to config \ + tlmm = %d\n", + __func__, vsync_gpio); + } + tlmm_settings = TRUE; + + gpio_direction_input( + vsync_gpio); + } else { + if (!tlmm_settings) { + pr_err( + "%s: unable to request \ + gpio=%d\n", + __func__, vsync_gpio); + } + } + } + } + mipi_dsi_set_tear_on(mfd); + } + } + +#ifdef CONFIG_MSM_BUS_SCALING + mdp_bus_scale_update_request(2); +#endif + + mdp4_overlay_dsi_state_set(ST_DSI_RESUME); + + if (mdp_rev >= MDP_REV_41) + mutex_unlock(&mfd->dma->ov_mutex); + else + up(&mfd->dma->mutex); + + pr_debug("%s-:\n", __func__); + + return ret; +} + + +static int mipi_dsi_resource_initialized; + +static int mipi_dsi_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct fb_info *fbi; + struct msm_panel_info *pinfo; + struct mipi_panel_info *mipi; + struct platform_device *mdp_dev = NULL; + struct msm_fb_panel_data *pdata = NULL; + int rc; + uint8 lanes = 0, bpp; + uint32 h_period, v_period, dsi_pclk_rate; + + resource_size_t size ; + + if ((pdev->id == 1) && (pdev->num_resources >= 0)) { + mipi_dsi_pdata = pdev->dev.platform_data; + + size = resource_size(&pdev->resource[0]); + mipi_dsi_base = ioremap(pdev->resource[0].start, size); + + MSM_FB_INFO("mipi_dsi base phy_addr = 0x%x virt = 0x%x\n", + pdev->resource[0].start, (int) mipi_dsi_base); + + if (!mipi_dsi_base) + return -ENOMEM; + + if (mdp_rev >= MDP_REV_41) { + mmss_sfpb_base = ioremap(MMSS_SFPB_BASE_PHY, 0x100); + MSM_FB_INFO("mmss_sfpb base phy_addr = 0x%x," + "virt = 0x%x\n", MMSS_SFPB_BASE_PHY, + (int) mmss_sfpb_base); + + if (!mmss_sfpb_base) + return -ENOMEM; + } + + dsi_irq = platform_get_irq(pdev, 0); + if (dsi_irq < 0) { + pr_err("mipi_dsi: can not get mdp irq\n"); + return -ENOMEM; + } + + rc = request_irq(dsi_irq, mipi_dsi_isr, IRQF_DISABLED, + "MIPI_DSI", 0); + if (rc) { + pr_err("mipi_dsi_host request_irq() failed!\n"); + return rc; + } + + disable_irq(dsi_irq); + + if (mdp_rev == MDP_REV_42 && mipi_dsi_pdata && + mipi_dsi_pdata->target_type == 1) { + /* Target type is 1 for device with (De)serializer + * 0x4f00000 is the base for TV Encoder. + * Unused Offset 0x1000 is used for + * (de)serializer on emulation platform + */ + periph_base = ioremap(MMSS_SERDES_BASE_PHY, 0x100); + + if (periph_base) { + pr_debug("periph_base %p\n", periph_base); + writel(0x4, periph_base + 0x28); + writel(0xc, periph_base + 0x28); + } else { + pr_err("periph_base is NULL\n"); + free_irq(dsi_irq, 0); + return -ENOMEM; + } + } + + if (mipi_dsi_pdata) { + vsync_gpio = mipi_dsi_pdata->vsync_gpio; + pr_debug("%s: vsync_gpio=%d\n", __func__, vsync_gpio); + + if (mdp_rev == MDP_REV_303 && + mipi_dsi_pdata->dsi_client_reset) { + if (mipi_dsi_pdata->dsi_client_reset()) + pr_err("%s: DSI Client Reset failed!\n", + __func__); + else + pr_debug("%s: DSI Client Reset success\n", + __func__); + } + } + + if (mipi_dsi_clk_init(pdev)) + return -EPERM; + + if (mipi_dsi_pdata->splash_is_enabled && + !mipi_dsi_pdata->splash_is_enabled()) { + mipi_dsi_ahb_ctrl(1); + MIPI_OUTP(MIPI_DSI_BASE + 0x118, 0); + MIPI_OUTP(MIPI_DSI_BASE + 0x0, 0); + MIPI_OUTP(MIPI_DSI_BASE + 0x200, 0); + mipi_dsi_ahb_ctrl(0); + } + mipi_dsi_resource_initialized = 1; + + return 0; + } + + if (!mipi_dsi_resource_initialized) + return -EPERM; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) + return -ENOMEM; + + if (!mfd->cont_splash_done) + cont_splash_clk_ctrl(1); + + mdp_dev = platform_device_alloc("mdp", pdev->id); + if (!mdp_dev) + return -ENOMEM; + + /* + * link to the latest pdev + */ + mfd->pdev = mdp_dev; + + /* + * alloc panel device data + */ + if (platform_device_add_data + (mdp_dev, pdev->dev.platform_data, + sizeof(struct msm_fb_panel_data))) { + pr_err("mipi_dsi_probe: platform_device_add_data failed!\n"); + platform_device_put(mdp_dev); + return -ENOMEM; + } + /* + * data chain + */ + pdata = mdp_dev->dev.platform_data; + pdata->on = mipi_dsi_on; + pdata->off = mipi_dsi_off; + pdata->next = pdev; + + /* + * get/set panel specific fb info + */ + mfd->panel_info = pdata->panel_info; + pinfo = &mfd->panel_info; + + if (mfd->panel_info.type == MIPI_VIDEO_PANEL) + mfd->dest = DISPLAY_LCDC; + else + mfd->dest = DISPLAY_LCD; + + if (mdp_rev == MDP_REV_303 && + mipi_dsi_pdata->get_lane_config) { + if (mipi_dsi_pdata->get_lane_config() != 2) { + pr_info("Changing to DSI Single Mode Configuration\n"); +#ifdef CONFIG_FB_MSM_MDP303 + update_lane_config(pinfo); +#endif + } + } + + if (mfd->index == 0) + mfd->fb_imgType = MSMFB_DEFAULT_TYPE; + else + mfd->fb_imgType = MDP_RGB_565; + + fbi = mfd->fbi; + fbi->var.pixclock = mfd->panel_info.clk_rate; + fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch; + fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch; + fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch; + fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch; + fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width; + fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width; + + h_period = ((mfd->panel_info.lcdc.h_pulse_width) + + (mfd->panel_info.lcdc.h_back_porch) + + (mfd->panel_info.xres) + + (mfd->panel_info.lcdc.h_front_porch)); + + v_period = ((mfd->panel_info.lcdc.v_pulse_width) + + (mfd->panel_info.lcdc.v_back_porch) + + (mfd->panel_info.yres) + + (mfd->panel_info.lcdc.v_front_porch)); + + mipi = &mfd->panel_info.mipi; + + if (mipi->data_lane3) + lanes += 1; + if (mipi->data_lane2) + lanes += 1; + if (mipi->data_lane1) + lanes += 1; + if (mipi->data_lane0) + lanes += 1; + + if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888) + || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB888) + || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB666_LOOSE)) + bpp = 3; + else if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565) + || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB565)) + bpp = 2; + else + bpp = 3; /* Default format set to RGB888 */ + + if (mfd->panel_info.type == MIPI_VIDEO_PANEL && + !mfd->panel_info.clk_rate) { + h_period += mfd->panel_info.lcdc.xres_pad; + v_period += mfd->panel_info.lcdc.yres_pad; + + if (lanes > 0) { + mfd->panel_info.clk_rate = + ((h_period * v_period * (mipi->frame_rate) * bpp * 8) + / lanes); + } else { + pr_err("%s: forcing mipi_dsi lanes to 1\n", __func__); + mfd->panel_info.clk_rate = + (h_period * v_period + * (mipi->frame_rate) * bpp * 8); + } + } + pll_divider_config.clk_rate = mfd->panel_info.clk_rate; + + rc = mipi_dsi_clk_div_config(bpp, lanes, &dsi_pclk_rate); + if (rc) + goto mipi_dsi_probe_err; + + if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 103300000)) + dsi_pclk_rate = 35000000; + mipi->dsi_pclk_rate = dsi_pclk_rate; + + /* + * set driver data + */ + platform_set_drvdata(mdp_dev, mfd); + + /* + * register in mdp driver + */ + rc = platform_device_add(mdp_dev); + if (rc) + goto mipi_dsi_probe_err; + + pdev_list[pdev_list_cnt++] = pdev; + +return 0; + +mipi_dsi_probe_err: + platform_device_put(mdp_dev); + return rc; +} + +static int mipi_dsi_remove(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + iounmap(mipi_dsi_base); + return 0; +} + +static int mipi_dsi_register_driver(void) +{ + return platform_driver_register(&mipi_dsi_driver); +} + +static int __init mipi_dsi_driver_init(void) +{ + int ret; + + mipi_dsi_init(); + + ret = mipi_dsi_register_driver(); + + device_initialize(&dsi_dev); + + if (ret) { + pr_err("mipi_dsi_register_driver() failed!\n"); + return ret; + } + + return ret; +} + +module_init(mipi_dsi_driver_init); diff --git a/drivers/video/msm/mipi_dsi.h b/drivers/video/msm/mipi_dsi.h new file mode 100644 index 000000000000..3433d4391f60 --- /dev/null +++ b/drivers/video/msm/mipi_dsi.h @@ -0,0 +1,318 @@ +/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef MIPI_DSI_H +#define MIPI_DSI_H + +#include +#include + +#ifdef BIT +#undef BIT +#endif + +#define BIT(x) (1<<(x)) + +#define MMSS_CC_BASE_PHY 0x04000000 /* mmss clcok control */ +#define MMSS_SFPB_BASE_PHY 0x05700000 /* mmss SFPB CFG */ +#define MMSS_SERDES_BASE_PHY 0x04f01000 /* mmss (De)Serializer CFG */ + +#define MIPI_DSI_BASE mipi_dsi_base + +#define MIPI_OUTP(addr, data) writel((data), (addr)) +#define MIPI_INP(addr) readl(addr) + +#ifdef CONFIG_MSM_SECURE_IO +#define MIPI_OUTP_SECURE(addr, data) secure_writel((data), (addr)) +#define MIPI_INP_SECURE(addr) secure_readl(addr) +#else +#define MIPI_OUTP_SECURE(addr, data) writel((data), (addr)) +#define MIPI_INP_SECURE(addr) readl(addr) +#endif + +#define MIPI_DSI_PRIM 1 +#define MIPI_DSI_SECD 2 + +#define MIPI_DSI_PANEL_VGA 0 +#define MIPI_DSI_PANEL_WVGA 1 +#define MIPI_DSI_PANEL_WVGA_PT 2 +#define MIPI_DSI_PANEL_FWVGA_PT 3 +#define MIPI_DSI_PANEL_WSVGA_PT 4 +#define MIPI_DSI_PANEL_QHD_PT 5 +#define MIPI_DSI_PANEL_WXGA 6 +#define MIPI_DSI_PANEL_WUXGA 7 +#define MIPI_DSI_PANEL_720P_PT 8 +#define DSI_PANEL_MAX 8 + +enum { /* mipi dsi panel */ + DSI_VIDEO_MODE, + DSI_CMD_MODE, +}; + +enum { + ST_DSI_CLK_OFF, + ST_DSI_SUSPEND, + ST_DSI_RESUME, + ST_DSI_PLAYING, + ST_DSI_NUM +}; + +enum { + EV_DSI_UPDATE, + EV_DSI_DONE, + EV_DSI_TOUT, + EV_DSI_NUM +}; + +enum { + LANDSCAPE = 1, + PORTRAIT = 2, +}; + +enum dsi_trigger_type { + DSI_CMD_MODE_DMA, + DSI_CMD_MODE_MDP, +}; + +#define DSI_NON_BURST_SYNCH_PULSE 0 +#define DSI_NON_BURST_SYNCH_EVENT 1 +#define DSI_BURST_MODE 2 + + +#define DSI_RGB_SWAP_RGB 0 +#define DSI_RGB_SWAP_RBG 1 +#define DSI_RGB_SWAP_BGR 2 +#define DSI_RGB_SWAP_BRG 3 +#define DSI_RGB_SWAP_GRB 4 +#define DSI_RGB_SWAP_GBR 5 + +#define DSI_VIDEO_DST_FORMAT_RGB565 0 +#define DSI_VIDEO_DST_FORMAT_RGB666 1 +#define DSI_VIDEO_DST_FORMAT_RGB666_LOOSE 2 +#define DSI_VIDEO_DST_FORMAT_RGB888 3 + +#define DSI_CMD_DST_FORMAT_RGB111 0 +#define DSI_CMD_DST_FORMAT_RGB332 3 +#define DSI_CMD_DST_FORMAT_RGB444 4 +#define DSI_CMD_DST_FORMAT_RGB565 6 +#define DSI_CMD_DST_FORMAT_RGB666 7 +#define DSI_CMD_DST_FORMAT_RGB888 8 + +#define DSI_INTR_ERROR_MASK BIT(25) +#define DSI_INTR_ERROR BIT(24) +#define DSI_INTR_VIDEO_DONE_MASK BIT(17) +#define DSI_INTR_VIDEO_DONE BIT(16) +#define DSI_INTR_CMD_MDP_DONE_MASK BIT(9) +#define DSI_INTR_CMD_MDP_DONE BIT(8) +#define DSI_INTR_CMD_DMA_DONE_MASK BIT(1) +#define DSI_INTR_CMD_DMA_DONE BIT(0) + +#define DSI_CMD_TRIGGER_NONE 0x0 /* mdp trigger */ +#define DSI_CMD_TRIGGER_TE 0x02 +#define DSI_CMD_TRIGGER_SW 0x04 +#define DSI_CMD_TRIGGER_SW_SEOF 0x05 /* cmd dma only */ +#define DSI_CMD_TRIGGER_SW_TE 0x06 + +extern struct device dsi_dev; +extern int mipi_dsi_clk_on; +extern u32 dsi_irq; +extern u32 esc_byte_ratio; + +extern void __iomem *periph_base; +extern char *mmss_cc_base; /* mutimedia sub system clock control */ +extern char *mmss_sfpb_base; /* mutimedia sub system sfpb */ + +struct dsiphy_pll_divider_config { + u32 clk_rate; + u32 fb_divider; + u32 ref_divider_ratio; + u32 bit_clk_divider; /* oCLK1 */ + u32 byte_clk_divider; /* oCLK2 */ + u32 dsi_clk_divider; /* oCLK3 */ +}; + +extern struct dsiphy_pll_divider_config pll_divider_config; + +struct dsi_clk_mnd_table { + uint8 lanes; + uint8 bpp; + uint8 dsiclk_div; + uint8 dsiclk_m; + uint8 dsiclk_n; + uint8 dsiclk_d; + uint8 pclk_m; + uint8 pclk_n; + uint8 pclk_d; +}; + +static const struct dsi_clk_mnd_table mnd_table[] = { + { 1, 2, 8, 1, 1, 0, 1, 2, 1}, + { 1, 3, 8, 1, 1, 0, 1, 3, 2}, + { 2, 2, 4, 1, 1, 0, 1, 2, 1}, + { 2, 3, 4, 1, 1, 0, 1, 3, 2}, + { 3, 2, 1, 3, 8, 4, 3, 16, 8}, + { 3, 3, 1, 3, 8, 4, 1, 8, 4}, + { 4, 2, 2, 1, 1, 0, 1, 2, 1}, + { 4, 3, 2, 1, 1, 0, 1, 3, 2}, +}; + +struct dsi_clk_desc { + uint32 src; + uint32 m; + uint32 n; + uint32 d; + uint32 mnd_mode; + uint32 pre_div_func; +}; + +#define DSI_HOST_HDR_SIZE 4 +#define DSI_HDR_LAST BIT(31) +#define DSI_HDR_LONG_PKT BIT(30) +#define DSI_HDR_BTA BIT(29) +#define DSI_HDR_VC(vc) (((vc) & 0x03) << 22) +#define DSI_HDR_DTYPE(dtype) (((dtype) & 0x03f) << 16) +#define DSI_HDR_DATA2(data) (((data) & 0x0ff) << 8) +#define DSI_HDR_DATA1(data) ((data) & 0x0ff) +#define DSI_HDR_WC(wc) ((wc) & 0x0ffff) + +#define DSI_BUF_SIZE 1024 +#define MIPI_DSI_MRPS 0x04 /* Maximum Return Packet Size */ + +#define MIPI_DSI_LEN 8 /* 4 x 4 - 6 - 2, bytes dcs header+crc-align */ + +struct dsi_buf { + uint32 *hdr; /* dsi host header */ + char *start; /* buffer start addr */ + char *end; /* buffer end addr */ + int size; /* size of buffer */ + char *data; /* buffer */ + int len; /* data length */ + dma_addr_t dmap; /* mapped dma addr */ +}; + +/* dcs read/write */ +#define DTYPE_DCS_WRITE 0x05 /* short write, 0 parameter */ +#define DTYPE_DCS_WRITE1 0x15 /* short write, 1 parameter */ +#define DTYPE_DCS_READ 0x06 /* read */ +#define DTYPE_DCS_LWRITE 0x39 /* long write */ + +/* generic read/write */ +#define DTYPE_GEN_WRITE 0x03 /* short write, 0 parameter */ +#define DTYPE_GEN_WRITE1 0x13 /* short write, 1 parameter */ +#define DTYPE_GEN_WRITE2 0x23 /* short write, 2 parameter */ +#define DTYPE_GEN_LWRITE 0x29 /* long write */ +#define DTYPE_GEN_READ 0x04 /* long read, 0 parameter */ +#define DTYPE_GEN_READ1 0x14 /* long read, 1 parameter */ +#define DTYPE_GEN_READ2 0x24 /* long read, 2 parameter */ + +#define DTYPE_TEAR_ON 0x35 /* set tear on */ +#define DTYPE_MAX_PKTSIZE 0x37 /* set max packet size */ +#define DTYPE_NULL_PKT 0x09 /* null packet, no data */ +#define DTYPE_BLANK_PKT 0x19 /* blankiing packet, no data */ + +#define DTYPE_CM_ON 0x02 /* color mode off */ +#define DTYPE_CM_OFF 0x12 /* color mode on */ +#define DTYPE_PERIPHERAL_OFF 0x22 +#define DTYPE_PERIPHERAL_ON 0x32 + +/* + * dcs response + */ +#define DTYPE_ACK_ERR_RESP 0x02 +#define DTYPE_EOT_RESP 0x08 /* end of tx */ +#define DTYPE_GEN_READ1_RESP 0x11 /* 1 parameter, short */ +#define DTYPE_GEN_READ2_RESP 0x12 /* 2 parameter, short */ +#define DTYPE_GEN_LREAD_RESP 0x1a +#define DTYPE_DCS_LREAD_RESP 0x1c +#define DTYPE_DCS_READ1_RESP 0x21 /* 1 parameter, short */ +#define DTYPE_DCS_READ2_RESP 0x22 /* 2 parameter, short */ + +struct dsi_cmd_desc { + int dtype; + int last; + int vc; + int ack; /* ask ACK from peripheral */ + int wait; + int dlen; + char *payload; +}; + + +typedef void (*kickoff_act)(void *); + +struct dsi_kickoff_action { + struct list_head act_entry; + kickoff_act action; + void *data; +}; + + +char *mipi_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen); +char *mipi_dsi_buf_init(struct dsi_buf *dp); +void mipi_dsi_init(void); +void mipi_dsi_lane_cfg(void); +void mipi_dsi_bist_ctrl(void); +int mipi_dsi_buf_alloc(struct dsi_buf *, int size); +int mipi_dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm); +int mipi_dsi_cmds_tx(struct msm_fb_data_type *mfd, + struct dsi_buf *dp, struct dsi_cmd_desc *cmds, int cnt); + +int mipi_dsi_cmd_dma_tx(struct dsi_buf *dp); +int mipi_dsi_cmd_reg_tx(uint32 data); +int mipi_dsi_cmds_rx(struct msm_fb_data_type *mfd, + struct dsi_buf *tp, struct dsi_buf *rp, + struct dsi_cmd_desc *cmds, int len); +int mipi_dsi_cmd_dma_rx(struct dsi_buf *tp, int rlen); +void mipi_dsi_host_init(struct mipi_panel_info *pinfo); +void mipi_dsi_op_mode_config(int mode); +void mipi_dsi_cmd_mode_ctrl(int enable); +void mdp4_dsi_cmd_trigger(void); +void mipi_dsi_cmd_mdp_start(void); +void mipi_dsi_cmd_bta_sw_trigger(void); +void mipi_dsi_ack_err_status(void); +void mipi_dsi_set_tear_on(struct msm_fb_data_type *mfd); +void mipi_dsi_set_tear_off(struct msm_fb_data_type *mfd); +void mipi_dsi_clk_enable(void); +void mipi_dsi_clk_disable(void); +void mipi_dsi_pre_kickoff_action(void); +void mipi_dsi_post_kickoff_action(void); +void mipi_dsi_pre_kickoff_add(struct dsi_kickoff_action *act); +void mipi_dsi_post_kickoff_add(struct dsi_kickoff_action *act); +void mipi_dsi_pre_kickoff_del(struct dsi_kickoff_action *act); +void mipi_dsi_post_kickoff_del(struct dsi_kickoff_action *act); +void mipi_dsi_controller_cfg(int enable); +void mipi_dsi_sw_reset(void); +void mipi_dsi_mdp_busy_wait(struct msm_fb_data_type *mfd); + +irqreturn_t mipi_dsi_isr(int irq, void *ptr); + +void mipi_set_tx_power_mode(int mode); +void mipi_dsi_phy_ctrl(int on); +void mipi_dsi_phy_init(int panel_ndx, struct msm_panel_info const *panel_info, + int target_type); +int mipi_dsi_clk_div_config(uint8 bpp, uint8 lanes, + uint32 *expected_dsi_pclk); +int mipi_dsi_clk_init(struct platform_device *pdev); +void mipi_dsi_clk_deinit(struct device *dev); +void mipi_dsi_prepare_clocks(void); +void mipi_dsi_unprepare_clocks(void); +void mipi_dsi_ahb_ctrl(u32 enable); +void cont_splash_clk_ctrl(int enable); +void mipi_dsi_turn_on_clks(void); +void mipi_dsi_turn_off_clks(void); + +#ifdef CONFIG_FB_MSM_MDP303 +void update_lane_config(struct msm_panel_info *pinfo); +#endif + +#endif /* MIPI_DSI_H */ diff --git a/drivers/video/msm/mipi_dsi_host.c b/drivers/video/msm/mipi_dsi_host.c new file mode 100644 index 000000000000..c03c40c0b434 --- /dev/null +++ b/drivers/video/msm/mipi_dsi_host.c @@ -0,0 +1,1493 @@ + +/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mdp.h" +#include "mdp4.h" + +static struct completion dsi_dma_comp; +static struct completion dsi_mdp_comp; +static struct dsi_buf dsi_tx_buf; +static int dsi_irq_enabled; +static spinlock_t dsi_irq_lock; +static spinlock_t dsi_mdp_lock; +static int dsi_mdp_busy; + +static struct list_head pre_kickoff_list; +static struct list_head post_kickoff_list; + +enum { + STAT_DSI_START, + STAT_DSI_ERROR, + STAT_DSI_CMD, + STAT_DSI_MDP +}; + +#ifdef CONFIG_FB_MSM_MDP40 +void mipi_dsi_mdp_stat_inc(int which) +{ + switch (which) { + case STAT_DSI_START: + mdp4_stat.dsi_mdp_start++; + break; + case STAT_DSI_ERROR: + mdp4_stat.intr_dsi_err++; + break; + case STAT_DSI_CMD: + mdp4_stat.intr_dsi_cmd++; + break; + case STAT_DSI_MDP: + mdp4_stat.intr_dsi_mdp++; + break; + default: + break; + } +} +#else +void mipi_dsi_mdp_stat_inc(int which) +{ +} +#endif + +void mipi_dsi_init(void) +{ + init_completion(&dsi_dma_comp); + init_completion(&dsi_mdp_comp); + mipi_dsi_buf_alloc(&dsi_tx_buf, DSI_BUF_SIZE); + spin_lock_init(&dsi_irq_lock); + spin_lock_init(&dsi_mdp_lock); + + INIT_LIST_HEAD(&pre_kickoff_list); + INIT_LIST_HEAD(&post_kickoff_list); +} + +void mipi_dsi_enable_irq(void) +{ + unsigned long flags; + + spin_lock_irqsave(&dsi_irq_lock, flags); + if (dsi_irq_enabled) { + pr_debug("%s: IRQ aleady enabled\n", __func__); + spin_unlock_irqrestore(&dsi_irq_lock, flags); + return; + } + dsi_irq_enabled = 1; + enable_irq(dsi_irq); + spin_unlock_irqrestore(&dsi_irq_lock, flags); +} + +void mipi_dsi_disable_irq(void) +{ + unsigned long flags; + + spin_lock_irqsave(&dsi_irq_lock, flags); + if (dsi_irq_enabled == 0) { + pr_debug("%s: IRQ already disabled\n", __func__); + spin_unlock_irqrestore(&dsi_irq_lock, flags); + return; + } + + dsi_irq_enabled = 0; + disable_irq(dsi_irq); + spin_unlock_irqrestore(&dsi_irq_lock, flags); +} + +/* + * mipi_dsi_disale_irq_nosync() should be called + * from interrupt context + */ + void mipi_dsi_disable_irq_nosync(void) +{ + spin_lock(&dsi_irq_lock); + if (dsi_irq_enabled == 0) { + pr_debug("%s: IRQ cannot be disabled\n", __func__); + spin_unlock(&dsi_irq_lock); + return; + } + + dsi_irq_enabled = 0; + disable_irq_nosync(dsi_irq); + spin_unlock(&dsi_irq_lock); +} + +void mipi_dsi_turn_on_clks(void) +{ + local_bh_disable(); + mipi_dsi_ahb_ctrl(1); + mipi_dsi_clk_enable(); + local_bh_enable(); +} + +void mipi_dsi_turn_off_clks(void) +{ + local_bh_disable(); + mipi_dsi_clk_disable(); + mipi_dsi_ahb_ctrl(0); + local_bh_enable(); +} + +static void mipi_dsi_action(struct list_head *act_list) +{ + struct list_head *lp; + struct dsi_kickoff_action *act; + + list_for_each(lp, act_list) { + act = list_entry(lp, struct dsi_kickoff_action, act_entry); + if (act && act->action) + act->action(act->data); + } +} + +void mipi_dsi_pre_kickoff_action(void) +{ + mipi_dsi_action(&pre_kickoff_list); +} + +void mipi_dsi_post_kickoff_action(void) +{ + mipi_dsi_action(&post_kickoff_list); +} + +/* + * mipi_dsi_pre_kickoff_add: + * ov_mutex need to be acquired before call this function. + */ +void mipi_dsi_pre_kickoff_add(struct dsi_kickoff_action *act) +{ + if (act) + list_add_tail(&act->act_entry, &pre_kickoff_list); +} + +/* + * mipi_dsi_pre_kickoff_add: + * ov_mutex need to be acquired before call this function. + */ +void mipi_dsi_post_kickoff_add(struct dsi_kickoff_action *act) +{ + if (act) + list_add_tail(&act->act_entry, &post_kickoff_list); +} + +/* + * mipi_dsi_pre_kickoff_add: + * ov_mutex need to be acquired before call this function. + */ +void mipi_dsi_pre_kickoff_del(struct dsi_kickoff_action *act) +{ + if (!list_empty(&pre_kickoff_list) && act) + list_del(&act->act_entry); +} + +/* + * mipi_dsi_pre_kickoff_add: + * ov_mutex need to be acquired before call this function. + */ +void mipi_dsi_post_kickoff_del(struct dsi_kickoff_action *act) +{ + if (!list_empty(&post_kickoff_list) && act) + list_del(&act->act_entry); +} + +/* + * mipi dsi buf mechanism + */ +char *mipi_dsi_buf_reserve(struct dsi_buf *dp, int len) +{ + dp->data += len; + return dp->data; +} + +char *mipi_dsi_buf_unreserve(struct dsi_buf *dp, int len) +{ + dp->data -= len; + return dp->data; +} + +char *mipi_dsi_buf_push(struct dsi_buf *dp, int len) +{ + dp->data -= len; + dp->len += len; + return dp->data; +} + +char *mipi_dsi_buf_reserve_hdr(struct dsi_buf *dp, int hlen) +{ + dp->hdr = (uint32 *)dp->data; + return mipi_dsi_buf_reserve(dp, hlen); +} + +char *mipi_dsi_buf_init(struct dsi_buf *dp) +{ + int off; + + dp->data = dp->start; + off = (int)dp->data; + /* 8 byte align */ + off &= 0x07; + if (off) + off = 8 - off; + dp->data += off; + dp->len = 0; + return dp->data; +} + +int mipi_dsi_buf_alloc(struct dsi_buf *dp, int size) +{ + + dp->start = kmalloc(size, GFP_KERNEL); + if (dp->start == NULL) { + pr_err("%s:%u\n", __func__, __LINE__); + return -ENOMEM; + } + + dp->end = dp->start + size; + dp->size = size; + + if ((int)dp->start & 0x07) + pr_err("%s: buf NOT 8 bytes aligned\n", __func__); + + dp->data = dp->start; + dp->len = 0; + return size; +} + +/* + * mipi dsi gerneric long write + */ +static int mipi_dsi_generic_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm) +{ + char *bp; + uint32 *hp; + int i, len; + + bp = mipi_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE); + + /* fill up payload */ + if (cm->payload) { + len = cm->dlen; + len += 3; + len &= ~0x03; /* multipled by 4 */ + for (i = 0; i < cm->dlen; i++) + *bp++ = cm->payload[i]; + + /* append 0xff to the end */ + for (; i < len; i++) + *bp++ = 0xff; + + dp->len += len; + } + + /* fill up header */ + hp = dp->hdr; + *hp = 0; + *hp = DSI_HDR_WC(cm->dlen); + *hp |= DSI_HDR_VC(cm->vc); + *hp |= DSI_HDR_LONG_PKT; + *hp |= DSI_HDR_DTYPE(DTYPE_GEN_LWRITE); + if (cm->last) + *hp |= DSI_HDR_LAST; + + mipi_dsi_buf_push(dp, DSI_HOST_HDR_SIZE); + + return dp->len; +} + +/* + * mipi dsi gerneric short write with 0, 1 2 parameters + */ +static int mipi_dsi_generic_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm) +{ + uint32 *hp; + int len; + + if (cm->dlen && cm->payload == 0) { + pr_err("%s: NO payload error\n", __func__); + return 0; + } + + mipi_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE); + hp = dp->hdr; + *hp = 0; + *hp |= DSI_HDR_VC(cm->vc); + if (cm->last) + *hp |= DSI_HDR_LAST; + + + len = (cm->dlen > 2) ? 2 : cm->dlen; + + if (len == 1) { + *hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE1); + *hp |= DSI_HDR_DATA1(cm->payload[0]); + *hp |= DSI_HDR_DATA2(0); + } else if (len == 2) { + *hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE2); + *hp |= DSI_HDR_DATA1(cm->payload[0]); + *hp |= DSI_HDR_DATA2(cm->payload[1]); + } else { + *hp |= DSI_HDR_DTYPE(DTYPE_GEN_WRITE); + *hp |= DSI_HDR_DATA1(0); + *hp |= DSI_HDR_DATA2(0); + } + + mipi_dsi_buf_push(dp, DSI_HOST_HDR_SIZE); + + return dp->len; /* 4 bytes */ +} + +/* + * mipi dsi gerneric read with 0, 1 2 parameters + */ +static int mipi_dsi_generic_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm) +{ + uint32 *hp; + int len; + + if (cm->dlen && cm->payload == 0) { + pr_err("%s: NO payload error\n", __func__); + return 0; + } + + mipi_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE); + hp = dp->hdr; + *hp = 0; + *hp |= DSI_HDR_VC(cm->vc); + *hp |= DSI_HDR_BTA; + if (cm->last) + *hp |= DSI_HDR_LAST; + + len = (cm->dlen > 2) ? 2 : cm->dlen; + + if (len == 1) { + *hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ1); + *hp |= DSI_HDR_DATA1(cm->payload[0]); + *hp |= DSI_HDR_DATA2(0); + } else if (len == 2) { + *hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ2); + *hp |= DSI_HDR_DATA1(cm->payload[0]); + *hp |= DSI_HDR_DATA2(cm->payload[1]); + } else { + *hp |= DSI_HDR_DTYPE(DTYPE_GEN_READ); + *hp |= DSI_HDR_DATA1(0); + *hp |= DSI_HDR_DATA2(0); + } + + mipi_dsi_buf_push(dp, DSI_HOST_HDR_SIZE); + return dp->len; /* 4 bytes */ +} + +/* + * mipi dsi dcs long write + */ +static int mipi_dsi_dcs_lwrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm) +{ + char *bp; + uint32 *hp; + int i, len; + + bp = mipi_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE); + + /* + * fill up payload + * dcs command byte (first byte) followed by payload + */ + if (cm->payload) { + len = cm->dlen; + len += 3; + len &= ~0x03; /* multipled by 4 */ + for (i = 0; i < cm->dlen; i++) + *bp++ = cm->payload[i]; + + /* append 0xff to the end */ + for (; i < len; i++) + *bp++ = 0xff; + + dp->len += len; + } + + /* fill up header */ + hp = dp->hdr; + *hp = 0; + *hp = DSI_HDR_WC(cm->dlen); + *hp |= DSI_HDR_VC(cm->vc); + *hp |= DSI_HDR_LONG_PKT; + *hp |= DSI_HDR_DTYPE(DTYPE_DCS_LWRITE); + if (cm->last) + *hp |= DSI_HDR_LAST; + + mipi_dsi_buf_push(dp, DSI_HOST_HDR_SIZE); + + return dp->len; +} + +/* + * mipi dsi dcs short write with 0 parameters + */ +static int mipi_dsi_dcs_swrite(struct dsi_buf *dp, struct dsi_cmd_desc *cm) +{ + uint32 *hp; + int len; + + if (cm->payload == 0) { + pr_err("%s: NO payload error\n", __func__); + return -EINVAL; + } + + mipi_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE); + hp = dp->hdr; + *hp = 0; + *hp |= DSI_HDR_VC(cm->vc); + if (cm->ack) /* ask ACK trigger msg from peripeheral */ + *hp |= DSI_HDR_BTA; + if (cm->last) + *hp |= DSI_HDR_LAST; + + len = (cm->dlen > 1) ? 1 : cm->dlen; + + *hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE); + *hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */ + *hp |= DSI_HDR_DATA2(0); + + mipi_dsi_buf_push(dp, DSI_HOST_HDR_SIZE); + return dp->len; +} + +/* + * mipi dsi dcs short write with 1 parameters + */ +static int mipi_dsi_dcs_swrite1(struct dsi_buf *dp, struct dsi_cmd_desc *cm) +{ + uint32 *hp; + + if (cm->dlen < 2 || cm->payload == 0) { + pr_err("%s: NO payload error\n", __func__); + return -EINVAL; + } + + mipi_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE); + hp = dp->hdr; + *hp = 0; + *hp |= DSI_HDR_VC(cm->vc); + if (cm->ack) /* ask ACK trigger msg from peripeheral */ + *hp |= DSI_HDR_BTA; + if (cm->last) + *hp |= DSI_HDR_LAST; + + *hp |= DSI_HDR_DTYPE(DTYPE_DCS_WRITE1); + *hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs comamnd byte */ + *hp |= DSI_HDR_DATA2(cm->payload[1]); /* parameter */ + + mipi_dsi_buf_push(dp, DSI_HOST_HDR_SIZE); + + return dp->len; +} +/* + * mipi dsi dcs read with 0 parameters + */ + +static int mipi_dsi_dcs_read(struct dsi_buf *dp, struct dsi_cmd_desc *cm) +{ + uint32 *hp; + + if (cm->payload == 0) { + pr_err("%s: NO payload error\n", __func__); + return -EINVAL; + } + + mipi_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE); + hp = dp->hdr; + *hp = 0; + *hp |= DSI_HDR_VC(cm->vc); + *hp |= DSI_HDR_BTA; + *hp |= DSI_HDR_DTYPE(DTYPE_DCS_READ); + if (cm->last) + *hp |= DSI_HDR_LAST; + + *hp |= DSI_HDR_DATA1(cm->payload[0]); /* dcs command byte */ + *hp |= DSI_HDR_DATA2(0); + + mipi_dsi_buf_push(dp, DSI_HOST_HDR_SIZE); + + return dp->len; /* 4 bytes */ +} + +static int mipi_dsi_cm_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm) +{ + uint32 *hp; + + mipi_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE); + hp = dp->hdr; + *hp = 0; + *hp |= DSI_HDR_VC(cm->vc); + *hp |= DSI_HDR_DTYPE(DTYPE_CM_ON); + if (cm->last) + *hp |= DSI_HDR_LAST; + + mipi_dsi_buf_push(dp, DSI_HOST_HDR_SIZE); + + return dp->len; /* 4 bytes */ +} + +static int mipi_dsi_cm_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm) +{ + uint32 *hp; + + mipi_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE); + hp = dp->hdr; + *hp = 0; + *hp |= DSI_HDR_VC(cm->vc); + *hp |= DSI_HDR_DTYPE(DTYPE_CM_OFF); + if (cm->last) + *hp |= DSI_HDR_LAST; + + mipi_dsi_buf_push(dp, DSI_HOST_HDR_SIZE); + + return dp->len; /* 4 bytes */ +} + +static int mipi_dsi_peripheral_on(struct dsi_buf *dp, struct dsi_cmd_desc *cm) +{ + uint32 *hp; + + mipi_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE); + hp = dp->hdr; + *hp = 0; + *hp |= DSI_HDR_VC(cm->vc); + *hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_ON); + if (cm->last) + *hp |= DSI_HDR_LAST; + + mipi_dsi_buf_push(dp, DSI_HOST_HDR_SIZE); + + return dp->len; /* 4 bytes */ +} + +static int mipi_dsi_peripheral_off(struct dsi_buf *dp, struct dsi_cmd_desc *cm) +{ + uint32 *hp; + + mipi_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE); + hp = dp->hdr; + *hp = 0; + *hp |= DSI_HDR_VC(cm->vc); + *hp |= DSI_HDR_DTYPE(DTYPE_PERIPHERAL_OFF); + if (cm->last) + *hp |= DSI_HDR_LAST; + + mipi_dsi_buf_push(dp, DSI_HOST_HDR_SIZE); + + return dp->len; /* 4 bytes */ +} + +static int mipi_dsi_set_max_pktsize(struct dsi_buf *dp, struct dsi_cmd_desc *cm) +{ + uint32 *hp; + + if (cm->payload == 0) { + pr_err("%s: NO payload error\n", __func__); + return 0; + } + + mipi_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE); + hp = dp->hdr; + *hp = 0; + *hp |= DSI_HDR_VC(cm->vc); + *hp |= DSI_HDR_DTYPE(DTYPE_MAX_PKTSIZE); + if (cm->last) + *hp |= DSI_HDR_LAST; + + *hp |= DSI_HDR_DATA1(cm->payload[0]); + *hp |= DSI_HDR_DATA2(cm->payload[1]); + + mipi_dsi_buf_push(dp, DSI_HOST_HDR_SIZE); + + return dp->len; /* 4 bytes */ +} + +static int mipi_dsi_null_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm) +{ + uint32 *hp; + + mipi_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE); + hp = dp->hdr; + *hp = 0; + *hp = DSI_HDR_WC(cm->dlen); + *hp |= DSI_HDR_LONG_PKT; + *hp |= DSI_HDR_VC(cm->vc); + *hp |= DSI_HDR_DTYPE(DTYPE_NULL_PKT); + if (cm->last) + *hp |= DSI_HDR_LAST; + + mipi_dsi_buf_push(dp, DSI_HOST_HDR_SIZE); + + return dp->len; /* 4 bytes */ +} + +static int mipi_dsi_blank_pkt(struct dsi_buf *dp, struct dsi_cmd_desc *cm) +{ + uint32 *hp; + + mipi_dsi_buf_reserve_hdr(dp, DSI_HOST_HDR_SIZE); + hp = dp->hdr; + *hp = 0; + *hp = DSI_HDR_WC(cm->dlen); + *hp |= DSI_HDR_LONG_PKT; + *hp |= DSI_HDR_VC(cm->vc); + *hp |= DSI_HDR_DTYPE(DTYPE_BLANK_PKT); + if (cm->last) + *hp |= DSI_HDR_LAST; + + mipi_dsi_buf_push(dp, DSI_HOST_HDR_SIZE); + + return dp->len; /* 4 bytes */ +} + +/* + * prepare cmd buffer to be txed + */ +int mipi_dsi_cmd_dma_add(struct dsi_buf *dp, struct dsi_cmd_desc *cm) +{ + int len = 0; + + switch (cm->dtype) { + case DTYPE_GEN_WRITE: + case DTYPE_GEN_WRITE1: + case DTYPE_GEN_WRITE2: + len = mipi_dsi_generic_swrite(dp, cm); + break; + case DTYPE_GEN_LWRITE: + len = mipi_dsi_generic_lwrite(dp, cm); + break; + case DTYPE_GEN_READ: + case DTYPE_GEN_READ1: + case DTYPE_GEN_READ2: + len = mipi_dsi_generic_read(dp, cm); + break; + case DTYPE_DCS_LWRITE: + len = mipi_dsi_dcs_lwrite(dp, cm); + break; + case DTYPE_DCS_WRITE: + len = mipi_dsi_dcs_swrite(dp, cm); + break; + case DTYPE_DCS_WRITE1: + len = mipi_dsi_dcs_swrite1(dp, cm); + break; + case DTYPE_DCS_READ: + len = mipi_dsi_dcs_read(dp, cm); + break; + case DTYPE_MAX_PKTSIZE: + len = mipi_dsi_set_max_pktsize(dp, cm); + break; + case DTYPE_NULL_PKT: + len = mipi_dsi_null_pkt(dp, cm); + break; + case DTYPE_BLANK_PKT: + len = mipi_dsi_blank_pkt(dp, cm); + break; + case DTYPE_CM_ON: + len = mipi_dsi_cm_on(dp, cm); + break; + case DTYPE_CM_OFF: + len = mipi_dsi_cm_off(dp, cm); + break; + case DTYPE_PERIPHERAL_ON: + len = mipi_dsi_peripheral_on(dp, cm); + break; + case DTYPE_PERIPHERAL_OFF: + len = mipi_dsi_peripheral_off(dp, cm); + break; + default: + pr_debug("%s: dtype=%x NOT supported\n", + __func__, cm->dtype); + break; + + } + + return len; +} + +/* + * mipi_dsi_short_read1_resp: 1 parameter + */ +static int mipi_dsi_short_read1_resp(struct dsi_buf *rp) +{ + /* strip out dcs type */ + rp->data++; + rp->len = 1; + return rp->len; +} + +/* + * mipi_dsi_short_read2_resp: 2 parameter + */ +static int mipi_dsi_short_read2_resp(struct dsi_buf *rp) +{ + /* strip out dcs type */ + rp->data++; + rp->len = 2; + return rp->len; +} + +static int mipi_dsi_long_read_resp(struct dsi_buf *rp) +{ + short len; + + len = rp->data[2]; + len <<= 8; + len |= rp->data[1]; + /* strip out dcs header */ + rp->data += 4; + rp->len -= 4; + /* strip out 2 bytes of checksum */ + rp->len -= 2; + return len; +} + +void mipi_dsi_host_init(struct mipi_panel_info *pinfo) +{ + uint32 dsi_ctrl, intr_ctrl; + uint32 data; + + if (mdp_rev > MDP_REV_41 || mdp_rev == MDP_REV_303) + pinfo->rgb_swap = DSI_RGB_SWAP_RGB; + else + pinfo->rgb_swap = DSI_RGB_SWAP_BGR; + + if (pinfo->mode == DSI_VIDEO_MODE) { + data = 0; + if (pinfo->pulse_mode_hsa_he) + data |= BIT(28); + if (pinfo->hfp_power_stop) + data |= BIT(24); + if (pinfo->hbp_power_stop) + data |= BIT(20); + if (pinfo->hsa_power_stop) + data |= BIT(16); + if (pinfo->eof_bllp_power_stop) + data |= BIT(15); + if (pinfo->bllp_power_stop) + data |= BIT(12); + data |= ((pinfo->traffic_mode & 0x03) << 8); + data |= ((pinfo->dst_format & 0x03) << 4); /* 2 bits */ + data |= (pinfo->vc & 0x03); + MIPI_OUTP(MIPI_DSI_BASE + 0x000c, data); + + data = 0; + data |= ((pinfo->rgb_swap & 0x07) << 12); + if (pinfo->b_sel) + data |= BIT(8); + if (pinfo->g_sel) + data |= BIT(4); + if (pinfo->r_sel) + data |= BIT(0); + MIPI_OUTP(MIPI_DSI_BASE + 0x001c, data); + } else if (pinfo->mode == DSI_CMD_MODE) { + data = 0; + data |= ((pinfo->interleave_max & 0x0f) << 20); + data |= ((pinfo->rgb_swap & 0x07) << 16); + if (pinfo->b_sel) + data |= BIT(12); + if (pinfo->g_sel) + data |= BIT(8); + if (pinfo->r_sel) + data |= BIT(4); + data |= (pinfo->dst_format & 0x0f); /* 4 bits */ + MIPI_OUTP(MIPI_DSI_BASE + 0x003c, data); + + /* DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL */ + data = pinfo->wr_mem_continue & 0x0ff; + data <<= 8; + data |= (pinfo->wr_mem_start & 0x0ff); + if (pinfo->insert_dcs_cmd) + data |= BIT(16); + MIPI_OUTP(MIPI_DSI_BASE + 0x0040, data); + } else + pr_err("%s: Unknown DSI mode=%d\n", __func__, pinfo->mode); + + dsi_ctrl = BIT(8) | BIT(2); /* clock enable & cmd mode */ + intr_ctrl = 0; + intr_ctrl = (DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_CMD_MDP_DONE_MASK); + + if (pinfo->crc_check) + dsi_ctrl |= BIT(24); + if (pinfo->ecc_check) + dsi_ctrl |= BIT(20); + if (pinfo->data_lane3) + dsi_ctrl |= BIT(7); + if (pinfo->data_lane2) + dsi_ctrl |= BIT(6); + if (pinfo->data_lane1) + dsi_ctrl |= BIT(5); + if (pinfo->data_lane0) + dsi_ctrl |= BIT(4); + + /* from frame buffer, low power mode */ + /* DSI_COMMAND_MODE_DMA_CTRL */ + MIPI_OUTP(MIPI_DSI_BASE + 0x38, 0x14000000); + + data = 0; + if (pinfo->te_sel) + data |= BIT(31); + data |= pinfo->mdp_trigger << 4;/* cmd mdp trigger */ + data |= pinfo->dma_trigger; /* cmd dma trigger */ + data |= (pinfo->stream & 0x01) << 8; + MIPI_OUTP(MIPI_DSI_BASE + 0x0080, data); /* DSI_TRIG_CTRL */ + + /* DSI_LAN_SWAP_CTRL */ + MIPI_OUTP(MIPI_DSI_BASE + 0x00ac, pinfo->dlane_swap); + + /* clock out ctrl */ + data = pinfo->t_clk_post & 0x3f; /* 6 bits */ + data <<= 8; + data |= pinfo->t_clk_pre & 0x3f; /* 6 bits */ + MIPI_OUTP(MIPI_DSI_BASE + 0xc0, data); /* DSI_CLKOUT_TIMING_CTRL */ + + data = 0; + if (pinfo->rx_eot_ignore) + data |= BIT(4); + if (pinfo->tx_eot_append) + data |= BIT(0); + MIPI_OUTP(MIPI_DSI_BASE + 0x00c8, data); /* DSI_EOT_PACKET_CTRL */ + + + /* allow only ack-err-status to generate interrupt */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0108, 0x13ff3fe0); /* DSI_ERR_INT_MASK0 */ + + intr_ctrl |= DSI_INTR_ERROR_MASK; + MIPI_OUTP(MIPI_DSI_BASE + 0x010c, intr_ctrl); /* DSI_INTL_CTRL */ + + /* turn esc, byte, dsi, pclk, sclk, hclk on */ + if (mdp_rev >= MDP_REV_41) + MIPI_OUTP(MIPI_DSI_BASE + 0x118, 0x23f); /* DSI_CLK_CTRL */ + else + MIPI_OUTP(MIPI_DSI_BASE + 0x118, 0x33f); /* DSI_CLK_CTRL */ + + dsi_ctrl |= BIT(0); /* enable dsi */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0000, dsi_ctrl); + + wmb(); +} + +void mipi_set_tx_power_mode(int mode) +{ + uint32 data = MIPI_INP(MIPI_DSI_BASE + 0x38); + + if (mode == 0) + data &= ~BIT(26); + else + data |= BIT(26); + + MIPI_OUTP(MIPI_DSI_BASE + 0x38, data); +} + +void mipi_dsi_sw_reset(void) +{ + MIPI_OUTP(MIPI_DSI_BASE + 0x114, 0x01); + wmb(); + MIPI_OUTP(MIPI_DSI_BASE + 0x114, 0x00); + wmb(); +} + +void mipi_dsi_controller_cfg(int enable) +{ + + uint32 dsi_ctrl; + uint32 status; + int cnt; + + cnt = 16; + while (cnt--) { + status = MIPI_INP(MIPI_DSI_BASE + 0x0004); + status &= 0x02; /* CMD_MODE_DMA_BUSY */ + if (status == 0) + break; + usleep(1000); + } + if (cnt == 0) + pr_info("%s: DSI status=%x failed\n", __func__, status); + + cnt = 16; + while (cnt--) { + status = MIPI_INP(MIPI_DSI_BASE + 0x0008); + status &= 0x11111000; /* x_HS_FIFO_EMPTY */ + if (status == 0x11111000) /* all empty */ + break; + usleep(1000); + } + + if (cnt == 0) + pr_info("%s: FIFO status=%x failed\n", __func__, status); + + dsi_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x0000); + if (enable) + dsi_ctrl |= 0x01; + else + dsi_ctrl &= ~0x01; + + MIPI_OUTP(MIPI_DSI_BASE + 0x0000, dsi_ctrl); + wmb(); +} + +void mipi_dsi_op_mode_config(int mode) +{ + + uint32 dsi_ctrl, intr_ctrl; + + dsi_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x0000); + dsi_ctrl &= ~0x07; + if (mode == DSI_VIDEO_MODE) { + dsi_ctrl |= 0x03; + intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK; + } else { /* command mode */ + dsi_ctrl |= 0x05; + intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_ERROR_MASK | + DSI_INTR_CMD_MDP_DONE_MASK; + } + + pr_debug("%s: dsi_ctrl=%x intr=%x\n", __func__, dsi_ctrl, intr_ctrl); + + MIPI_OUTP(MIPI_DSI_BASE + 0x010c, intr_ctrl); /* DSI_INTL_CTRL */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0000, dsi_ctrl); + wmb(); +} + +void mipi_dsi_mdp_busy_wait(struct msm_fb_data_type *mfd) +{ + unsigned long flag; + int need_wait = 0; + + pr_debug("%s: start pid=%d\n", + __func__, current->pid); + spin_lock_irqsave(&dsi_mdp_lock, flag); + if (dsi_mdp_busy == TRUE) { + INIT_COMPLETION(dsi_mdp_comp); + need_wait++; + } + spin_unlock_irqrestore(&dsi_mdp_lock, flag); + + if (need_wait) { + /* wait until DMA finishes the current job */ + pr_debug("%s: pending pid=%d\n", + __func__, current->pid); + wait_for_completion(&dsi_mdp_comp); + } + pr_debug("%s: done pid=%d\n", + __func__, current->pid); +} + + +void mipi_dsi_cmd_mdp_start(void) +{ + unsigned long flag; + + + if (!in_interrupt()) + mipi_dsi_pre_kickoff_action(); + + mipi_dsi_mdp_stat_inc(STAT_DSI_START); + + spin_lock_irqsave(&dsi_mdp_lock, flag); + mipi_dsi_enable_irq(); + dsi_mdp_busy = TRUE; + spin_unlock_irqrestore(&dsi_mdp_lock, flag); +} + + +void mipi_dsi_cmd_bta_sw_trigger(void) +{ + uint32 data; + int cnt = 0; + + MIPI_OUTP(MIPI_DSI_BASE + 0x094, 0x01); /* trigger */ + wmb(); + + while (cnt < 10000) { + data = MIPI_INP(MIPI_DSI_BASE + 0x0004);/* DSI_STATUS */ + if ((data & 0x0010) == 0) + break; + cnt++; + } + + mipi_dsi_ack_err_status(); + + pr_debug("%s: BTA done, cnt=%d\n", __func__, cnt); +} + +static char set_tear_on[2] = {0x35, 0x00}; +static struct dsi_cmd_desc dsi_tear_on_cmd = { + DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(set_tear_on), set_tear_on}; + +static char set_tear_off[2] = {0x34, 0x00}; +static struct dsi_cmd_desc dsi_tear_off_cmd = { + DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(set_tear_off), set_tear_off}; + +void mipi_dsi_set_tear_on(struct msm_fb_data_type *mfd) +{ + mipi_dsi_buf_init(&dsi_tx_buf); + mipi_dsi_cmds_tx(mfd, &dsi_tx_buf, &dsi_tear_on_cmd, 1); +} + +void mipi_dsi_set_tear_off(struct msm_fb_data_type *mfd) +{ + mipi_dsi_buf_init(&dsi_tx_buf); + mipi_dsi_cmds_tx(mfd, &dsi_tx_buf, &dsi_tear_off_cmd, 1); +} + +int mipi_dsi_cmd_reg_tx(uint32 data) +{ +#ifdef DSI_HOST_DEBUG + int i; + char *bp; + + bp = (char *)&data; + pr_debug("%s: ", __func__); + for (i = 0; i < 4; i++) + pr_debug("%x ", *bp++); + + pr_debug("\n"); +#endif + + MIPI_OUTP(MIPI_DSI_BASE + 0x0080, 0x04);/* sw trigger */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0, 0x135); + + wmb(); + + MIPI_OUTP(MIPI_DSI_BASE + 0x038, data); + wmb(); + MIPI_OUTP(MIPI_DSI_BASE + 0x08c, 0x01); /* trigger */ + wmb(); + + udelay(300); + + return 4; +} + +/* + * mipi_dsi_cmds_tx: + * ov_mutex need to be acquired before call this function. + */ +int mipi_dsi_cmds_tx(struct msm_fb_data_type *mfd, + struct dsi_buf *tp, struct dsi_cmd_desc *cmds, int cnt) +{ + struct dsi_cmd_desc *cm; + uint32 dsi_ctrl, ctrl; + int i, video_mode; + unsigned long flag; + + /* turn on cmd mode + * for video mode, do not send cmds more than + * one pixel line, since it only transmit it + * during BLLP. + */ + dsi_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x0000); + video_mode = dsi_ctrl & 0x02; /* VIDEO_MODE_EN */ + if (video_mode) { + ctrl = dsi_ctrl | 0x04; /* CMD_MODE_EN */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0000, ctrl); + } else { /* cmd mode */ + /* + * during boot up, cmd mode is configured + * even it is video mode panel. + */ + /* make sure mdp dma is not txing pixel data */ + if (mfd->panel_info.type == MIPI_CMD_PANEL) { +#ifndef CONFIG_FB_MSM_MDP303 + mdp4_dsi_cmd_dma_busy_wait(mfd); +#else + mdp3_dsi_cmd_dma_busy_wait(mfd); +#endif + } + } + + spin_lock_irqsave(&dsi_mdp_lock, flag); + mipi_dsi_enable_irq(); + dsi_mdp_busy = TRUE; + spin_unlock_irqrestore(&dsi_mdp_lock, flag); + + cm = cmds; + mipi_dsi_buf_init(tp); + for (i = 0; i < cnt; i++) { + mipi_dsi_buf_init(tp); + mipi_dsi_cmd_dma_add(tp, cm); + mipi_dsi_cmd_dma_tx(tp); + if (cm->wait) + msleep(cm->wait); + cm++; + } + + spin_lock_irqsave(&dsi_mdp_lock, flag); + dsi_mdp_busy = FALSE; + mipi_dsi_disable_irq(); + complete(&dsi_mdp_comp); + spin_unlock_irqrestore(&dsi_mdp_lock, flag); + + if (video_mode) + MIPI_OUTP(MIPI_DSI_BASE + 0x0000, dsi_ctrl); /* restore */ + + return cnt; +} + +/* MIPI_DSI_MRPS, Maximum Return Packet Size */ +static char max_pktsize[2] = {0x00, 0x00}; /* LSB tx first, 10 bytes */ + +static struct dsi_cmd_desc pkt_size_cmd[] = { + {DTYPE_MAX_PKTSIZE, 1, 0, 0, 0, + sizeof(max_pktsize), max_pktsize} +}; + +/* + * DSI panel reply with MAX_RETURN_PACKET_SIZE bytes of data + * plus DCS header, ECC and CRC for DCS long read response + * mipi_dsi_controller only have 4x32 bits register ( 16 bytes) to + * hold data per transaction. + * MIPI_DSI_LEN equal to 8 + * len should be either 4 or 8 + * any return data more than MIPI_DSI_LEN need to be break down + * to multiple transactions. + * + * ov_mutex need to be acquired before call this function. + */ +int mipi_dsi_cmds_rx(struct msm_fb_data_type *mfd, + struct dsi_buf *tp, struct dsi_buf *rp, + struct dsi_cmd_desc *cmds, int rlen) +{ + int cnt, len, diff, pkt_size; + unsigned long flag; + char cmd; + + if (mfd->panel_info.mipi.no_max_pkt_size) { + /* Only support rlen = 4*n */ + rlen += 3; + rlen &= ~0x03; + } + + len = rlen; + diff = 0; + + if (len <= 2) + cnt = 4; /* short read */ + else { + if (len > MIPI_DSI_LEN) + len = MIPI_DSI_LEN; /* 8 bytes at most */ + + len = (len + 3) & ~0x03; /* len 4 bytes align */ + diff = len - rlen; + /* + * add extra 2 bytes to len to have overall + * packet size is multipe by 4. This also make + * sure 4 bytes dcs headerlocates within a + * 32 bits register after shift in. + * after all, len should be either 6 or 10. + */ + len += 2; + cnt = len + 6; /* 4 bytes header + 2 bytes crc */ + } + + if (mfd->panel_info.type == MIPI_CMD_PANEL) { + /* make sure mdp dma is not txing pixel data */ +#ifndef CONFIG_FB_MSM_MDP303 + mdp4_dsi_cmd_dma_busy_wait(mfd); +#else + mdp3_dsi_cmd_dma_busy_wait(mfd); +#endif + } + + spin_lock_irqsave(&dsi_mdp_lock, flag); + mipi_dsi_enable_irq(); + dsi_mdp_busy = TRUE; + spin_unlock_irqrestore(&dsi_mdp_lock, flag); + + if (!mfd->panel_info.mipi.no_max_pkt_size) { + /* packet size need to be set at every read */ + pkt_size = len; + max_pktsize[0] = pkt_size; + mipi_dsi_buf_init(tp); + mipi_dsi_cmd_dma_add(tp, pkt_size_cmd); + mipi_dsi_cmd_dma_tx(tp); + } + + mipi_dsi_buf_init(tp); + mipi_dsi_cmd_dma_add(tp, cmds); + + /* transmit read comamnd to client */ + mipi_dsi_cmd_dma_tx(tp); + /* + * once cmd_dma_done interrupt received, + * return data from client is ready and stored + * at RDBK_DATA register already + */ + mipi_dsi_buf_init(rp); + if (mfd->panel_info.mipi.no_max_pkt_size) { + /* + * expect rlen = n * 4 + * short alignement for start addr + */ + rp->data += 2; + } + + mipi_dsi_cmd_dma_rx(rp, cnt); + + spin_lock_irqsave(&dsi_mdp_lock, flag); + dsi_mdp_busy = FALSE; + mipi_dsi_disable_irq(); + complete(&dsi_mdp_comp); + spin_unlock_irqrestore(&dsi_mdp_lock, flag); + + if (mfd->panel_info.mipi.no_max_pkt_size) { + /* + * remove extra 2 bytes from previous + * rx transaction at shift register + * which was inserted during copy + * shift registers to rx buffer + * rx payload start from long alignment addr + */ + rp->data += 2; + } + + cmd = rp->data[0]; + switch (cmd) { + case DTYPE_ACK_ERR_RESP: + pr_debug("%s: rx ACK_ERR_PACLAGE\n", __func__); + break; + case DTYPE_GEN_READ1_RESP: + case DTYPE_DCS_READ1_RESP: + mipi_dsi_short_read1_resp(rp); + break; + case DTYPE_GEN_READ2_RESP: + case DTYPE_DCS_READ2_RESP: + mipi_dsi_short_read2_resp(rp); + break; + case DTYPE_GEN_LREAD_RESP: + case DTYPE_DCS_LREAD_RESP: + mipi_dsi_long_read_resp(rp); + rp->len -= 2; /* extra 2 bytes added */ + rp->len -= diff; /* align bytes */ + break; + default: + break; + } + + return rp->len; +} + +int mipi_dsi_cmd_dma_tx(struct dsi_buf *tp) +{ + int len; + +#ifdef DSI_HOST_DEBUG + int i; + char *bp; + + bp = tp->data; + + pr_debug("%s: ", __func__); + for (i = 0; i < tp->len; i++) + pr_debug("%x ", *bp++); + + pr_debug("\n"); +#endif + + len = tp->len; + len += 3; + len &= ~0x03; /* multipled by 4 */ + + tp->dmap = dma_map_single(&dsi_dev, tp->data, len, DMA_TO_DEVICE); + if (dma_mapping_error(&dsi_dev, tp->dmap)) + pr_err("%s: dmap mapp failed\n", __func__); + + INIT_COMPLETION(dsi_dma_comp); + + MIPI_OUTP(MIPI_DSI_BASE + 0x044, tp->dmap); + MIPI_OUTP(MIPI_DSI_BASE + 0x048, len); + wmb(); + MIPI_OUTP(MIPI_DSI_BASE + 0x08c, 0x01); /* trigger */ + wmb(); + + wait_for_completion(&dsi_dma_comp); + + dma_unmap_single(&dsi_dev, tp->dmap, len, DMA_TO_DEVICE); + tp->dmap = 0; + return tp->len; +} + +int mipi_dsi_cmd_dma_rx(struct dsi_buf *rp, int rlen) +{ + uint32 *lp, data; + int i, off, cnt; + + lp = (uint32 *)rp->data; + cnt = rlen; + cnt += 3; + cnt >>= 2; + + if (cnt > 4) + cnt = 4; /* 4 x 32 bits registers only */ + + off = 0x068; /* DSI_RDBK_DATA0 */ + off += ((cnt - 1) * 4); + + + for (i = 0; i < cnt; i++) { + data = (uint32)MIPI_INP(MIPI_DSI_BASE + off); + *lp++ = ntohl(data); /* to network byte order */ + off -= 4; + rp->len += sizeof(*lp); + } + + return rlen; +} + +void mipi_dsi_irq_set(uint32 mask, uint32 irq) +{ + uint32 data; + + data = MIPI_INP(MIPI_DSI_BASE + 0x010c);/* DSI_INTR_CTRL */ + data &= ~mask; + data |= irq; + MIPI_OUTP(MIPI_DSI_BASE + 0x010c, data); +} + + +void mipi_dsi_ack_err_status(void) +{ + uint32 status; + + status = MIPI_INP(MIPI_DSI_BASE + 0x0064);/* DSI_ACK_ERR_STATUS */ + + if (status) { + MIPI_OUTP(MIPI_DSI_BASE + 0x0064, status); + pr_debug("%s: status=%x\n", __func__, status); + } +} + +void mipi_dsi_timeout_status(void) +{ + uint32 status; + + status = MIPI_INP(MIPI_DSI_BASE + 0x00bc);/* DSI_TIMEOUT_STATUS */ + if (status & 0x0111) { + MIPI_OUTP(MIPI_DSI_BASE + 0x00bc, status); + pr_debug("%s: status=%x\n", __func__, status); + } +} + +void mipi_dsi_dln0_phy_err(void) +{ + uint32 status; + + status = MIPI_INP(MIPI_DSI_BASE + 0x00b0);/* DSI_DLN0_PHY_ERR */ + + if (status & 0x011111) { + MIPI_OUTP(MIPI_DSI_BASE + 0x00b0, status); + pr_debug("%s: status=%x\n", __func__, status); + } +} + +void mipi_dsi_fifo_status(void) +{ + uint32 status; + + status = MIPI_INP(MIPI_DSI_BASE + 0x0008);/* DSI_FIFO_STATUS */ + + if (status & 0x44444489) { + MIPI_OUTP(MIPI_DSI_BASE + 0x0008, status); + pr_debug("%s: status=%x\n", __func__, status); + } +} + +void mipi_dsi_status(void) +{ + uint32 status; + + status = MIPI_INP(MIPI_DSI_BASE + 0x0004);/* DSI_STATUS */ + + if (status & 0x80000000) { + MIPI_OUTP(MIPI_DSI_BASE + 0x0004, status); + pr_debug("%s: status=%x\n", __func__, status); + } +} + +void mipi_dsi_error(void) +{ + /* DSI_ERR_INT_MASK0 */ + mipi_dsi_ack_err_status(); /* mask0, 0x01f */ + mipi_dsi_timeout_status(); /* mask0, 0x0e0 */ + mipi_dsi_fifo_status(); /* mask0, 0x133d00 */ + mipi_dsi_status(); /* mask0, 0xc0100 */ + mipi_dsi_dln0_phy_err(); /* mask0, 0x3e00000 */ +} + + +irqreturn_t mipi_dsi_isr(int irq, void *ptr) +{ + uint32 isr; + + isr = MIPI_INP(MIPI_DSI_BASE + 0x010c);/* DSI_INTR_CTRL */ + MIPI_OUTP(MIPI_DSI_BASE + 0x010c, isr); + +#ifdef CONFIG_FB_MSM_MDP40 + mdp4_stat.intr_dsi++; +#endif + + if (isr & DSI_INTR_ERROR) { + mipi_dsi_mdp_stat_inc(STAT_DSI_ERROR); + mipi_dsi_error(); + } + + if (isr & DSI_INTR_VIDEO_DONE) { + /* + * do something here + */ + } + + if (isr & DSI_INTR_CMD_DMA_DONE) { + mipi_dsi_mdp_stat_inc(STAT_DSI_CMD); + complete(&dsi_dma_comp); + } + + if (isr & DSI_INTR_CMD_MDP_DONE) { + mipi_dsi_mdp_stat_inc(STAT_DSI_MDP); + spin_lock(&dsi_mdp_lock); + dsi_mdp_busy = FALSE; + mipi_dsi_disable_irq_nosync(); + spin_unlock(&dsi_mdp_lock); + complete(&dsi_mdp_comp); + mipi_dsi_post_kickoff_action(); + } + + + return IRQ_HANDLED; +} diff --git a/drivers/video/msm/mipi_novatek.c b/drivers/video/msm/mipi_novatek.c new file mode 100644 index 000000000000..d6e1e57bca53 --- /dev/null +++ b/drivers/video/msm/mipi_novatek.c @@ -0,0 +1,658 @@ +/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifdef CONFIG_SPI_QUP +#include +#endif +#include +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_novatek.h" +#include "mdp4.h" + + +static struct mipi_dsi_panel_platform_data *mipi_novatek_pdata; + +static struct dsi_buf novatek_tx_buf; +static struct dsi_buf novatek_rx_buf; +static int mipi_novatek_lcd_init(void); + +static int wled_trigger_initialized; + +#define MIPI_DSI_NOVATEK_SPI_DEVICE_NAME "dsi_novatek_3d_panel_spi" +#define HPCI_FPGA_READ_CMD 0x84 +#define HPCI_FPGA_WRITE_CMD 0x04 + +#ifdef CONFIG_SPI_QUP +static struct spi_device *panel_3d_spi_client; + +static void novatek_fpga_write(uint8 addr, uint16 value) +{ + char tx_buf[32]; + int rc; + struct spi_message m; + struct spi_transfer t; + u8 data[4] = {0x0, 0x0, 0x0, 0x0}; + + if (!panel_3d_spi_client) { + pr_err("%s panel_3d_spi_client is NULL\n", __func__); + return; + } + data[0] = HPCI_FPGA_WRITE_CMD; + data[1] = addr; + data[2] = ((value >> 8) & 0xFF); + data[3] = (value & 0xFF); + + memset(&t, 0, sizeof t); + memset(tx_buf, 0, sizeof tx_buf); + t.tx_buf = data; + t.len = 4; + spi_setup(panel_3d_spi_client); + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + rc = spi_sync(panel_3d_spi_client, &m); + if (rc) + pr_err("%s: SPI transfer failed\n", __func__); + + return; +} + +static void novatek_fpga_read(uint8 addr) +{ + char tx_buf[32]; + int rc; + struct spi_message m; + struct spi_transfer t; + struct spi_transfer rx; + char rx_value[2]; + u8 data[4] = {0x0, 0x0}; + + if (!panel_3d_spi_client) { + pr_err("%s panel_3d_spi_client is NULL\n", __func__); + return; + } + + data[0] = HPCI_FPGA_READ_CMD; + data[1] = addr; + + memset(&t, 0, sizeof t); + memset(tx_buf, 0, sizeof tx_buf); + memset(&rx, 0, sizeof rx); + memset(rx_value, 0, sizeof rx_value); + t.tx_buf = data; + t.len = 2; + rx.rx_buf = rx_value; + rx.len = 2; + spi_setup(panel_3d_spi_client); + spi_message_init(&m); + spi_message_add_tail(&t, &m); + spi_message_add_tail(&rx, &m); + + rc = spi_sync(panel_3d_spi_client, &m); + if (rc) + pr_err("%s: SPI transfer failed\n", __func__); + else + pr_info("%s: rx_value = 0x%x, 0x%x\n", __func__, + rx_value[0], rx_value[1]); + + return; +} + +static int panel_3d_spi_probe(struct spi_device *spi) +{ + panel_3d_spi_client = spi; + return 0; +} +static int panel_3d_spi_remove(struct spi_device *spi) +{ + panel_3d_spi_client = NULL; + return 0; +} +static struct spi_driver panel_3d_spi_driver = { + .probe = panel_3d_spi_probe, + .remove = panel_3d_spi_remove, + .driver = { + .name = "dsi_novatek_3d_panel_spi", + .owner = THIS_MODULE, + } +}; + +#else + +static void novatek_fpga_write(uint8 addr, uint16 value) +{ + return; +} + +static void novatek_fpga_read(uint8 addr) +{ + return; +} + +#endif + + +/* novatek blue panel */ + +#ifdef NOVETAK_COMMANDS_UNUSED +static char display_config_cmd_mode1[] = { + /* TYPE_DCS_LWRITE */ + 0x2A, 0x00, 0x00, 0x01, + 0x3F, 0xFF, 0xFF, 0xFF +}; + +static char display_config_cmd_mode2[] = { + /* DTYPE_DCS_LWRITE */ + 0x2B, 0x00, 0x00, 0x01, + 0xDF, 0xFF, 0xFF, 0xFF +}; + +static char display_config_cmd_mode3_666[] = { + /* DTYPE_DCS_WRITE1 */ + 0x3A, 0x66, 0x15, 0x80 /* 666 Packed (18-bits) */ +}; + +static char display_config_cmd_mode3_565[] = { + /* DTYPE_DCS_WRITE1 */ + 0x3A, 0x55, 0x15, 0x80 /* 565 mode */ +}; + +static char display_config_321[] = { + /* DTYPE_DCS_WRITE1 */ + 0x66, 0x2e, 0x15, 0x00 /* Reg 0x66 : 2E */ +}; + +static char display_config_323[] = { + /* DTYPE_DCS_WRITE */ + 0x13, 0x00, 0x05, 0x00 /* Reg 0x13 < Set for Normal Mode> */ +}; + +static char display_config_2lan[] = { + /* DTYPE_DCS_WRITE */ + 0x61, 0x01, 0x02, 0xff /* Reg 0x61 : 01,02 < Set for 2 Data Lane > */ +}; + +static char display_config_exit_sleep[] = { + /* DTYPE_DCS_WRITE */ + 0x11, 0x00, 0x05, 0x80 /* Reg 0x11 < exit sleep mode> */ +}; + +static char display_config_TE_ON[] = { + /* DTYPE_DCS_WRITE1 */ + 0x35, 0x00, 0x15, 0x80 +}; + +static char display_config_39H[] = { + /* DTYPE_DCS_WRITE */ + 0x39, 0x00, 0x05, 0x80 +}; + +static char display_config_set_tear_scanline[] = { + /* DTYPE_DCS_LWRITE */ + 0x44, 0x00, 0x00, 0xff +}; + +static char display_config_set_twolane[] = { + /* DTYPE_DCS_WRITE1 */ + 0xae, 0x03, 0x15, 0x80 +}; + +static char display_config_set_threelane[] = { + /* DTYPE_DCS_WRITE1 */ + 0xae, 0x05, 0x15, 0x80 +}; + +#else + +static char sw_reset[2] = {0x01, 0x00}; /* DTYPE_DCS_WRITE */ +static char enter_sleep[2] = {0x10, 0x00}; /* DTYPE_DCS_WRITE */ +static char exit_sleep[2] = {0x11, 0x00}; /* DTYPE_DCS_WRITE */ +static char display_off[2] = {0x28, 0x00}; /* DTYPE_DCS_WRITE */ +static char display_on[2] = {0x29, 0x00}; /* DTYPE_DCS_WRITE */ + + + +static char rgb_888[2] = {0x3A, 0x77}; /* DTYPE_DCS_WRITE1 */ + +#if defined(NOVATEK_TWO_LANE) +static char set_num_of_lanes[2] = {0xae, 0x03}; /* DTYPE_DCS_WRITE1 */ +#else /* 1 lane */ +static char set_num_of_lanes[2] = {0xae, 0x01}; /* DTYPE_DCS_WRITE1 */ +#endif +/* commands by Novatke */ +static char novatek_f4[2] = {0xf4, 0x55}; /* DTYPE_DCS_WRITE1 */ +static char novatek_8c[16] = { /* DTYPE_DCS_LWRITE */ + 0x8C, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x08, 0x00, 0x30, 0xC0, 0xB7, 0x37}; +static char novatek_ff[2] = {0xff, 0x55 }; /* DTYPE_DCS_WRITE1 */ + +static char set_width[5] = { /* DTYPE_DCS_LWRITE */ + 0x2A, 0x00, 0x00, 0x02, 0x1B}; /* 540 - 1 */ +static char set_height[5] = { /* DTYPE_DCS_LWRITE */ + 0x2B, 0x00, 0x00, 0x03, 0xBF}; /* 960 - 1 */ +#endif + +static char led_pwm1[2] = {0x51, 0x0}; /* DTYPE_DCS_WRITE1 */ +static char led_pwm2[2] = {0x53, 0x24}; /* DTYPE_DCS_WRITE1 */ +static char led_pwm3[2] = {0x55, 0x00}; /* DTYPE_DCS_WRITE1 */ + +static struct dsi_cmd_desc novatek_cmd_backlight_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(led_pwm1), led_pwm1}, +}; + +static struct dsi_cmd_desc novatek_video_on_cmds[] = { + {DTYPE_DCS_WRITE, 1, 0, 0, 50, + sizeof(sw_reset), sw_reset}, + {DTYPE_DCS_WRITE, 1, 0, 0, 10, + sizeof(exit_sleep), exit_sleep}, + {DTYPE_DCS_WRITE, 1, 0, 0, 10, + sizeof(display_on), display_on}, + {DTYPE_DCS_WRITE1, 1, 0, 0, 10, + sizeof(set_num_of_lanes), set_num_of_lanes}, + {DTYPE_DCS_WRITE1, 1, 0, 0, 10, + sizeof(rgb_888), rgb_888}, + {DTYPE_DCS_WRITE1, 1, 0, 0, 10, + sizeof(led_pwm2), led_pwm2}, + {DTYPE_DCS_WRITE1, 1, 0, 0, 10, + sizeof(led_pwm3), led_pwm3}, +}; + +static struct dsi_cmd_desc novatek_cmd_on_cmds[] = { + {DTYPE_DCS_WRITE, 1, 0, 0, 50, + sizeof(sw_reset), sw_reset}, + {DTYPE_DCS_WRITE, 1, 0, 0, 10, + sizeof(exit_sleep), exit_sleep}, + {DTYPE_DCS_WRITE, 1, 0, 0, 10, + sizeof(display_on), display_on}, + {DTYPE_DCS_WRITE1, 1, 0, 0, 50, + sizeof(novatek_f4), novatek_f4}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 50, + sizeof(novatek_8c), novatek_8c}, + {DTYPE_DCS_WRITE1, 1, 0, 0, 50, + sizeof(novatek_ff), novatek_ff}, + {DTYPE_DCS_WRITE1, 1, 0, 0, 10, + sizeof(set_num_of_lanes), set_num_of_lanes}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 50, + sizeof(set_width), set_width}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 50, + sizeof(set_height), set_height}, + {DTYPE_DCS_WRITE1, 1, 0, 0, 10, + sizeof(rgb_888), rgb_888}, + {DTYPE_DCS_WRITE1, 1, 0, 0, 1, + sizeof(led_pwm2), led_pwm2}, + {DTYPE_DCS_WRITE1, 1, 0, 0, 1, + sizeof(led_pwm3), led_pwm3}, +}; + +static struct dsi_cmd_desc novatek_display_off_cmds[] = { + {DTYPE_DCS_WRITE, 1, 0, 0, 10, + sizeof(display_off), display_off}, + {DTYPE_DCS_WRITE, 1, 0, 0, 120, + sizeof(enter_sleep), enter_sleep} +}; + +static char manufacture_id[2] = {0x04, 0x00}; /* DTYPE_DCS_READ */ + +static struct dsi_cmd_desc novatek_manufacture_id_cmd = { + DTYPE_DCS_READ, 1, 0, 1, 5, sizeof(manufacture_id), manufacture_id}; + +static uint32 mipi_novatek_manufacture_id(struct msm_fb_data_type *mfd) +{ + struct dsi_buf *rp, *tp; + struct dsi_cmd_desc *cmd; + uint32 *lp; + + tp = &novatek_tx_buf; + rp = &novatek_rx_buf; + cmd = &novatek_manufacture_id_cmd; + mipi_dsi_cmds_rx(mfd, tp, rp, cmd, 3); + lp = (uint32 *)rp->data; + pr_info("%s: manufacture_id=%x", __func__, *lp); + return *lp; +} + +static int fpga_addr; +static int fpga_access_mode; +static bool support_3d; + +static void mipi_novatek_3d_init(int addr, int mode) +{ + fpga_addr = addr; + fpga_access_mode = mode; +} + +static void mipi_dsi_enable_3d_barrier(int mode) +{ + void __iomem *fpga_ptr; + uint32_t ptr_value = 0; + + if (!fpga_addr && support_3d) { + pr_err("%s: fpga_addr not set. Failed to enable 3D barrier\n", + __func__); + return; + } + + if (fpga_access_mode == FPGA_SPI_INTF) { + if (mode == LANDSCAPE) + novatek_fpga_write(fpga_addr, 1); + else if (mode == PORTRAIT) + novatek_fpga_write(fpga_addr, 3); + else + novatek_fpga_write(fpga_addr, 0); + + mb(); + novatek_fpga_read(fpga_addr); + } else if (fpga_access_mode == FPGA_EBI2_INTF) { + fpga_ptr = ioremap_nocache(fpga_addr, sizeof(uint32_t)); + if (!fpga_ptr) { + pr_err("%s: FPGA ioremap failed." + "Failed to enable 3D barrier\n", + __func__); + return; + } + + ptr_value = readl_relaxed(fpga_ptr); + if (mode == LANDSCAPE) + writel_relaxed(((0xFFFF0000 & ptr_value) | 1), + fpga_ptr); + else if (mode == PORTRAIT) + writel_relaxed(((0xFFFF0000 & ptr_value) | 3), + fpga_ptr); + else + writel_relaxed((0xFFFF0000 & ptr_value), + fpga_ptr); + + mb(); + iounmap(fpga_ptr); + } else + pr_err("%s: 3D barrier not configured correctly\n", + __func__); +} + +static int mipi_novatek_lcd_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct mipi_panel_info *mipi; + struct msm_panel_info *pinfo; + + mfd = platform_get_drvdata(pdev); + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + pinfo = &mfd->panel_info; + if (pinfo->is_3d_panel) + support_3d = TRUE; + + mipi = &mfd->panel_info.mipi; + + if (mipi->mode == DSI_VIDEO_MODE) { + mipi_dsi_cmds_tx(mfd, &novatek_tx_buf, novatek_video_on_cmds, + ARRAY_SIZE(novatek_video_on_cmds)); + } else { + mipi_dsi_cmds_tx(mfd, &novatek_tx_buf, novatek_cmd_on_cmds, + ARRAY_SIZE(novatek_cmd_on_cmds)); + + mipi_dsi_cmd_bta_sw_trigger(); /* clean up ack_err_status */ + + mipi_novatek_manufacture_id(mfd); + } + + return 0; +} + +static int mipi_novatek_lcd_off(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + mipi_dsi_cmds_tx(mfd, &novatek_tx_buf, novatek_display_off_cmds, + ARRAY_SIZE(novatek_display_off_cmds)); + + return 0; +} + +DEFINE_LED_TRIGGER(bkl_led_trigger); + +static void mipi_novatek_set_backlight(struct msm_fb_data_type *mfd) +{ + struct mipi_panel_info *mipi; + + if ((mipi_novatek_pdata->enable_wled_bl_ctrl) + && (wled_trigger_initialized)) { + led_trigger_event(bkl_led_trigger, mfd->bl_level); + return; + } + mipi = &mfd->panel_info.mipi; + + mutex_lock(&mfd->dma->ov_mutex); + if (mdp4_overlay_dsi_state_get() <= ST_DSI_SUSPEND) { + mutex_unlock(&mfd->dma->ov_mutex); + return; + } + /* mdp4_dsi_cmd_busy_wait: will turn on dsi clock also */ + mdp4_dsi_cmd_dma_busy_wait(mfd); + mdp4_dsi_blt_dmap_busy_wait(mfd); + mipi_dsi_mdp_busy_wait(mfd); + + led_pwm1[1] = (unsigned char)(mfd->bl_level); + mipi_dsi_cmds_tx(mfd, &novatek_tx_buf, novatek_cmd_backlight_cmds, + ARRAY_SIZE(novatek_cmd_backlight_cmds)); + mutex_unlock(&mfd->dma->ov_mutex); + return; +} + +static int mipi_dsi_3d_barrier_sysfs_register(struct device *dev); +static int barrier_mode; + +static int mipi_novatek_lcd_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct mipi_panel_info *mipi; + struct platform_device *current_pdev; + static struct mipi_dsi_phy_ctrl *phy_settings; + static char dlane_swap; + + if (pdev->id == 0) { + mipi_novatek_pdata = pdev->dev.platform_data; + + if (mipi_novatek_pdata + && mipi_novatek_pdata->phy_ctrl_settings) { + phy_settings = (mipi_novatek_pdata->phy_ctrl_settings); + } + + if (mipi_novatek_pdata + && mipi_novatek_pdata->dlane_swap) { + dlane_swap = (mipi_novatek_pdata->dlane_swap); + } + + if (mipi_novatek_pdata + && mipi_novatek_pdata->fpga_3d_config_addr) + mipi_novatek_3d_init(mipi_novatek_pdata + ->fpga_3d_config_addr, mipi_novatek_pdata->fpga_ctrl_mode); + + /* create sysfs to control 3D barrier for the Sharp panel */ + if (mipi_dsi_3d_barrier_sysfs_register(&pdev->dev)) { + pr_err("%s: Failed to register 3d Barrier sysfs\n", + __func__); + return -ENODEV; + } + barrier_mode = 0; + + return 0; + } + + current_pdev = msm_fb_add_device(pdev); + + if (current_pdev) { + mfd = platform_get_drvdata(current_pdev); + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + mipi = &mfd->panel_info.mipi; + + if (phy_settings != NULL) + mipi->dsi_phy_db = phy_settings; + + if (dlane_swap) + mipi->dlane_swap = dlane_swap; + } + return 0; +} + +static struct platform_driver this_driver = { + .probe = mipi_novatek_lcd_probe, + .driver = { + .name = "mipi_novatek", + }, +}; + +static struct msm_fb_panel_data novatek_panel_data = { + .on = mipi_novatek_lcd_on, + .off = mipi_novatek_lcd_off, + .set_backlight = mipi_novatek_set_backlight, +}; + +static ssize_t mipi_dsi_3d_barrier_read(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf((char *)buf, sizeof(buf), "%u\n", barrier_mode); +} + +static ssize_t mipi_dsi_3d_barrier_write(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + int ret = -1; + u32 data = 0; + + if (sscanf((char *)buf, "%u", &data) != 1) { + dev_err(dev, "%s\n", __func__); + ret = -EINVAL; + } else { + barrier_mode = data; + if (data == 1) + mipi_dsi_enable_3d_barrier(LANDSCAPE); + else if (data == 2) + mipi_dsi_enable_3d_barrier(PORTRAIT); + else + mipi_dsi_enable_3d_barrier(0); + } + + return count; +} + +static struct device_attribute mipi_dsi_3d_barrier_attributes[] = { + __ATTR(enable_3d_barrier, 0664, mipi_dsi_3d_barrier_read, + mipi_dsi_3d_barrier_write), +}; + +static int mipi_dsi_3d_barrier_sysfs_register(struct device *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mipi_dsi_3d_barrier_attributes); i++) + if (device_create_file(dev, mipi_dsi_3d_barrier_attributes + i)) + goto error; + + return 0; + +error: + for (; i >= 0 ; i--) + device_remove_file(dev, mipi_dsi_3d_barrier_attributes + i); + pr_err("%s: Unable to create interface\n", __func__); + + return -ENODEV; +} + +static int ch_used[3]; + +int mipi_novatek_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel) +{ + struct platform_device *pdev = NULL; + int ret; + + if ((channel >= 3) || ch_used[channel]) + return -ENODEV; + + ch_used[channel] = TRUE; + + ret = mipi_novatek_lcd_init(); + if (ret) { + pr_err("mipi_novatek_lcd_init() failed with ret %u\n", ret); + return ret; + } + + pdev = platform_device_alloc("mipi_novatek", (panel << 8)|channel); + if (!pdev) + return -ENOMEM; + + novatek_panel_data.panel_info = *pinfo; + + ret = platform_device_add_data(pdev, &novatek_panel_data, + sizeof(novatek_panel_data)); + if (ret) { + printk(KERN_ERR + "%s: platform_device_add_data failed!\n", __func__); + goto err_device_put; + } + + ret = platform_device_add(pdev); + if (ret) { + printk(KERN_ERR + "%s: platform_device_register failed!\n", __func__); + goto err_device_put; + } + + return 0; + +err_device_put: + platform_device_put(pdev); + return ret; +} + +static int mipi_novatek_lcd_init(void) +{ +#ifdef CONFIG_SPI_QUP + int ret; + ret = spi_register_driver(&panel_3d_spi_driver); + + if (ret) { + pr_err("%s: spi register failed: rc=%d\n", __func__, ret); + platform_driver_unregister(&this_driver); + } else + pr_info("%s: SUCCESS (SPI)\n", __func__); +#endif + + led_trigger_register_simple("bkl_trigger", &bkl_led_trigger); + pr_info("%s: SUCCESS (WLED TRIGGER)\n", __func__); + wled_trigger_initialized = 1; + + mipi_dsi_buf_alloc(&novatek_tx_buf, DSI_BUF_SIZE); + mipi_dsi_buf_alloc(&novatek_rx_buf, DSI_BUF_SIZE); + + return platform_driver_register(&this_driver); +} diff --git a/drivers/video/msm/mipi_novatek.h b/drivers/video/msm/mipi_novatek.h new file mode 100644 index 000000000000..7abe86399bdc --- /dev/null +++ b/drivers/video/msm/mipi_novatek.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2010, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef MIPI_NOVATEK_BLUE_H +#define MIPI_NOVATEK_BLUE_H + +#define NOVATEK_TWO_LANE + +int mipi_novatek_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel); + +#endif /* MIPI_NOVATEK_BLUE_H */ diff --git a/drivers/video/msm/mipi_novatek_cmd_qhd_pt.c b/drivers/video/msm/mipi_novatek_cmd_qhd_pt.c new file mode 100644 index 000000000000..616622ec3829 --- /dev/null +++ b/drivers/video/msm/mipi_novatek_cmd_qhd_pt.c @@ -0,0 +1,100 @@ +/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_novatek.h" + +static struct msm_panel_info pinfo; + +static struct mipi_dsi_phy_ctrl dsi_cmd_mode_phy_db = { +/* DSI_BIT_CLK at 500MHz, 2 lane, RGB888 */ + {0x03, 0x01, 0x01, 0x00}, /* regulator */ + /* timing */ + {0xB4, 0x8D, 0x1D, 0x00, 0x20, 0x94, 0x20, + 0x8F, 0x20, 0x03, 0x04}, + {0x7f, 0x00, 0x00, 0x00}, /* phy ctrl */ + {0xee, 0x02, 0x86, 0x00}, /* strength */ + /* pll control */ + {0x40, 0xf9, 0xb0, 0xda, 0x00, 0x50, 0x48, 0x63, +#if defined(NOVATEK_TWO_LANE) + 0x30, 0x07, 0x03, +#else /* default set to 1 lane */ + 0x30, 0x07, 0x07, +#endif + 0x05, 0x14, 0x03, 0x0, 0x0, 0x54, 0x06, 0x10, 0x04, 0x0}, +}; + +static int __init mipi_cmd_novatek_blue_qhd_pt_init(void) +{ + int ret; + + if (msm_fb_detect_client("mipi_cmd_novatek_qhd")) + return 0; + + pinfo.xres = 540; + pinfo.yres = 960; + pinfo.type = MIPI_CMD_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.lcdc.h_back_porch = 50; + pinfo.lcdc.h_front_porch = 50; + pinfo.lcdc.h_pulse_width = 20; + pinfo.lcdc.v_back_porch = 11; + pinfo.lcdc.v_front_porch = 10; + pinfo.lcdc.v_pulse_width = 5; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + pinfo.bl_max = 255; + pinfo.bl_min = 1; + pinfo.fb_num = 2; + pinfo.clk_rate = 454000000; + pinfo.is_3d_panel = FB_TYPE_3D_PANEL; + pinfo.lcd.vsync_enable = TRUE; + pinfo.lcd.hw_vsync_mode = TRUE; + pinfo.lcd.refx100 = 6000; /* adjust refx100 to prevent tearing */ + pinfo.lcd.v_back_porch = 11; + pinfo.lcd.v_front_porch = 10; + pinfo.lcd.v_pulse_width = 5; + + pinfo.mipi.mode = DSI_CMD_MODE; + pinfo.mipi.dst_format = DSI_CMD_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.data_lane0 = TRUE; + pinfo.mipi.esc_byte_ratio = 4; +#if defined(NOVATEK_TWO_LANE) + pinfo.mipi.data_lane1 = TRUE; +#endif + pinfo.mipi.t_clk_post = 0x22; + pinfo.mipi.t_clk_pre = 0x3f; + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_NONE; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.te_sel = 1; /* TE from vsycn gpio */ + pinfo.mipi.interleave_max = 1; + pinfo.mipi.insert_dcs_cmd = TRUE; + pinfo.mipi.wr_mem_continue = 0x3c; + pinfo.mipi.wr_mem_start = 0x2c; + pinfo.mipi.dsi_phy_db = &dsi_cmd_mode_phy_db; + + ret = mipi_novatek_device_register(&pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_QHD_PT); + if (ret) + pr_err("%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mipi_cmd_novatek_blue_qhd_pt_init); diff --git a/drivers/video/msm/mipi_novatek_video_qhd_pt.c b/drivers/video/msm/mipi_novatek_video_qhd_pt.c new file mode 100644 index 000000000000..8881b60b20e9 --- /dev/null +++ b/drivers/video/msm/mipi_novatek_video_qhd_pt.c @@ -0,0 +1,97 @@ +/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_novatek.h" + +static struct msm_panel_info pinfo; + +static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = { +/* DSI_BIT_CLK at 500MHz, 2 lane, RGB888 */ + {0x03, 0x01, 0x01, 0x00}, /* regulator */ + /* timing */ + {0x82, 0x31, 0x13, 0x0, 0x42, 0x4D, 0x18, + 0x35, 0x21, 0x03, 0x04}, + {0x7f, 0x00, 0x00, 0x00}, /* phy ctrl */ + {0xee, 0x02, 0x86, 0x00}, /* strength */ + /* pll control */ + {0x40, 0xf9, 0xb0, 0xda, 0x00, 0x50, 0x48, 0x63, +#if defined(NOVATEK_TWO_LANE) + 0x30, 0x07, 0x03, +#else /* default set to 1 lane */ + 0x30, 0x07, 0x07, +#endif + 0x05, 0x14, 0x03, 0x0, 0x0, 0x54, 0x06, 0x10, 0x04, 0x0}, +}; + +static int __init mipi_video_novatek_qhd_pt_init(void) +{ + int ret; + + if (msm_fb_detect_client("mipi_video_novatek_qhd")) + return 0; + + pinfo.xres = 540; + pinfo.yres = 960; + pinfo.type = MIPI_VIDEO_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.lcdc.h_back_porch = 80; + pinfo.lcdc.h_front_porch = 24; + pinfo.lcdc.h_pulse_width = 8; + pinfo.lcdc.v_back_porch = 16; + pinfo.lcdc.v_front_porch = 8; + pinfo.lcdc.v_pulse_width = 1; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + pinfo.bl_max = 15; + pinfo.bl_min = 1; + pinfo.fb_num = 2; + + pinfo.mipi.mode = DSI_VIDEO_MODE; + pinfo.mipi.pulse_mode_hsa_he = TRUE; + pinfo.mipi.hfp_power_stop = FALSE; + pinfo.mipi.hbp_power_stop = FALSE; + pinfo.mipi.hsa_power_stop = FALSE; + pinfo.mipi.eof_bllp_power_stop = TRUE; + pinfo.mipi.bllp_power_stop = TRUE; + pinfo.mipi.traffic_mode = DSI_NON_BURST_SYNCH_PULSE; + pinfo.mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.rgb_swap = DSI_RGB_SWAP_BGR; + pinfo.mipi.data_lane0 = TRUE; + pinfo.mipi.esc_byte_ratio = 4; +#if defined(NOVATEK_TWO_LANE) + pinfo.mipi.data_lane1 = TRUE; +#endif + pinfo.mipi.tx_eot_append = TRUE; + pinfo.mipi.t_clk_post = 0x04; + pinfo.mipi.t_clk_pre = 0x1c; + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.frame_rate = 60; + pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db; + + ret = mipi_novatek_device_register(&pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_QHD_PT); + if (ret) + pr_err("%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mipi_video_novatek_qhd_pt_init); diff --git a/drivers/video/msm/mipi_orise.c b/drivers/video/msm/mipi_orise.c new file mode 100644 index 000000000000..2e2c373b659f --- /dev/null +++ b/drivers/video/msm/mipi_orise.c @@ -0,0 +1,194 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_orise.h" +#include "mdp4.h" + + +static struct mipi_dsi_panel_platform_data *mipi_orise_pdata; + +static struct dsi_buf orise_tx_buf; +static struct dsi_buf orise_rx_buf; + +static char enter_sleep[2] = {0x10, 0x00}; /* DTYPE_DCS_WRITE */ +static char exit_sleep[2] = {0x11, 0x00}; /* DTYPE_DCS_WRITE */ +static char display_off[2] = {0x28, 0x00}; /* DTYPE_DCS_WRITE */ +static char display_on[2] = {0x29, 0x00}; /* DTYPE_DCS_WRITE */ + +static struct dsi_cmd_desc orise_video_on_cmds[] = { + {DTYPE_DCS_WRITE, 1, 0, 0, 10, + sizeof(exit_sleep), exit_sleep}, + {DTYPE_DCS_WRITE, 1, 0, 0, 10, + sizeof(display_on), display_on}, +}; + +static struct dsi_cmd_desc orise_cmd_on_cmds[] = { + {DTYPE_DCS_WRITE, 1, 0, 0, 10, + sizeof(exit_sleep), exit_sleep}, + {DTYPE_DCS_WRITE, 1, 0, 0, 10, + sizeof(display_on), display_on}, +}; + +static struct dsi_cmd_desc orise_display_off_cmds[] = { + {DTYPE_DCS_WRITE, 1, 0, 0, 10, + sizeof(display_off), display_off}, + {DTYPE_DCS_WRITE, 1, 0, 0, 120, + sizeof(enter_sleep), enter_sleep} +}; + +static int mipi_orise_lcd_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct mipi_panel_info *mipi; + struct msm_panel_info *pinfo; + + mfd = platform_get_drvdata(pdev); + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + pinfo = &mfd->panel_info; + mipi = &mfd->panel_info.mipi; + + if (mipi->mode == DSI_VIDEO_MODE) { + mipi_dsi_cmds_tx(mfd, &orise_tx_buf, orise_video_on_cmds, + ARRAY_SIZE(orise_video_on_cmds)); + } else { + mipi_dsi_cmds_tx(mfd, &orise_tx_buf, orise_cmd_on_cmds, + ARRAY_SIZE(orise_cmd_on_cmds)); + + mipi_dsi_cmd_bta_sw_trigger(); /* clean up ack_err_status */ + } + + return 0; +} + +static int mipi_orise_lcd_off(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + mipi_dsi_cmds_tx(mfd, &orise_tx_buf, orise_display_off_cmds, + ARRAY_SIZE(orise_display_off_cmds)); + + return 0; +} + + + +static int mipi_orise_lcd_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct mipi_panel_info *mipi; + struct platform_device *current_pdev; + static struct mipi_dsi_phy_ctrl *phy_settings; + + if (pdev->id == 0) { + mipi_orise_pdata = pdev->dev.platform_data; + + if (mipi_orise_pdata + && mipi_orise_pdata->phy_ctrl_settings) { + phy_settings = (mipi_orise_pdata->phy_ctrl_settings); + } + + return 0; + } + + current_pdev = msm_fb_add_device(pdev); + + if (current_pdev) { + mfd = platform_get_drvdata(current_pdev); + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + mipi = &mfd->panel_info.mipi; + + if (phy_settings != NULL) + mipi->dsi_phy_db = phy_settings; + } + return 0; +} + +static struct platform_driver this_driver = { + .probe = mipi_orise_lcd_probe, + .driver = { + .name = "mipi_orise", + }, +}; + +static struct msm_fb_panel_data orise_panel_data = { + .on = mipi_orise_lcd_on, + .off = mipi_orise_lcd_off, +}; + +static int ch_used[3]; + +int mipi_orise_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel) +{ + struct platform_device *pdev = NULL; + int ret; + + if ((channel >= 3) || ch_used[channel]) + return -ENODEV; + + ch_used[channel] = TRUE; + + pdev = platform_device_alloc("mipi_orise", (panel << 8)|channel); + if (!pdev) + return -ENOMEM; + + orise_panel_data.panel_info = *pinfo; + + ret = platform_device_add_data(pdev, &orise_panel_data, + sizeof(orise_panel_data)); + if (ret) { + printk(KERN_ERR + "%s: platform_device_add_data failed!\n", __func__); + goto err_device_put; + } + + ret = platform_device_add(pdev); + if (ret) { + printk(KERN_ERR + "%s: platform_device_register failed!\n", __func__); + goto err_device_put; + } + + return 0; + +err_device_put: + platform_device_put(pdev); + return ret; +} + +static int __init mipi_orise_lcd_init(void) +{ + mipi_dsi_buf_alloc(&orise_tx_buf, DSI_BUF_SIZE); + mipi_dsi_buf_alloc(&orise_rx_buf, DSI_BUF_SIZE); + + return platform_driver_register(&this_driver); +} + +module_init(mipi_orise_lcd_init); diff --git a/drivers/video/msm/mipi_orise.h b/drivers/video/msm/mipi_orise.h new file mode 100644 index 000000000000..da4b59f2a5f2 --- /dev/null +++ b/drivers/video/msm/mipi_orise.h @@ -0,0 +1,21 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + + +#ifndef MIPI_ORISE_H +#define MIPI_ORISE_H + +int mipi_orise_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel); + +#endif /* MIPI_ORISE_H */ diff --git a/drivers/video/msm/mipi_orise_cmd_720p_pt.c b/drivers/video/msm/mipi_orise_cmd_720p_pt.c new file mode 100644 index 000000000000..9b7020ad498a --- /dev/null +++ b/drivers/video/msm/mipi_orise_cmd_720p_pt.c @@ -0,0 +1,96 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_orise.h" + +static struct msm_panel_info pinfo; + +static struct mipi_dsi_phy_ctrl dsi_cmd_mode_phy_db = { +/* DSI_BIT_CLK at 507MHz, 4 lane, RGB888 */ + {0x03, 0x0a, 0x04, 0x00, 0x20}, + /* timing */ + {0x8c, 0x34, 0x15, 0x00, 0x46, 0x50, 0x1a, 0x38, + 0x24, 0x03, 0x04, 0xa0}, + /* phy ctrl */ + {0x5f, 0x00, 0x00, 0x10}, + /* strength */ + {0xff, 0x00, 0x06, 0x00}, + /* pll control */ + {0x0, 0xf9, 0x30, 0xda, 0x00, 0x40, 0x03, 0x62, + 0x40, 0x07, 0x03, + 0x00, 0x1a, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x01 }, +}; + +static int __init mipi_cmd_orise_720p_pt_init(void) +{ + int ret; + + if (msm_fb_detect_client("mipi_cmd_orise_720p")) + return 0; + + pinfo.xres = 720; + pinfo.yres = 1280; + pinfo.type = MIPI_CMD_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.lcdc.h_back_porch = 160; + pinfo.lcdc.h_front_porch = 160; + pinfo.lcdc.h_pulse_width = 8; + pinfo.lcdc.v_back_porch = 32; + pinfo.lcdc.v_front_porch = 32; + pinfo.lcdc.v_pulse_width = 1; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + pinfo.bl_max = 200; + pinfo.bl_min = 1; + pinfo.fb_num = 2; + pinfo.clk_rate = 507000000; + pinfo.lcd.vsync_enable = TRUE; + pinfo.lcd.hw_vsync_mode = TRUE; + pinfo.lcd.refx100 = 6000; /* adjust refx100 to prevent tearing */ + pinfo.lcd.v_back_porch = 32; + pinfo.lcd.v_front_porch = 32; + pinfo.lcd.v_pulse_width = 1; + + pinfo.mipi.mode = DSI_CMD_MODE; + pinfo.mipi.dst_format = DSI_CMD_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.data_lane0 = TRUE; + pinfo.mipi.data_lane1 = TRUE; + pinfo.mipi.data_lane2 = TRUE; + pinfo.mipi.data_lane3 = TRUE; + pinfo.mipi.t_clk_post = 0x04; + pinfo.mipi.t_clk_pre = 0x1e; + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_NONE; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.te_sel = 1; /* TE from vsycn gpio */ + pinfo.mipi.interleave_max = 1; + pinfo.mipi.insert_dcs_cmd = TRUE; + pinfo.mipi.wr_mem_continue = 0x3c; + pinfo.mipi.wr_mem_start = 0x2c; + pinfo.mipi.dsi_phy_db = &dsi_cmd_mode_phy_db; + + ret = mipi_orise_device_register(&pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_720P_PT); + if (ret) + pr_err("%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mipi_cmd_orise_720p_pt_init); diff --git a/drivers/video/msm/mipi_orise_video_720p_pt.c b/drivers/video/msm/mipi_orise_video_720p_pt.c new file mode 100644 index 000000000000..1484576c99b2 --- /dev/null +++ b/drivers/video/msm/mipi_orise_video_720p_pt.c @@ -0,0 +1,98 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_orise.h" + +static struct msm_panel_info pinfo; + +static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = { + /* regulator */ + {0x03, 0x0a, 0x04, 0x00, 0x20}, + /* timing */ + {0x83, 0x31, 0x13, 0x00, 0x42, 0x4d, 0x18, 0x35, + 0x21, 0x03, 0x04, 0xa0}, + /* phy ctrl */ + {0x5f, 0x00, 0x00, 0x10}, + /* strength */ + {0xff, 0x00, 0x06, 0x00}, + /* pll control */ + {0x0, 0x0e, 0x30, 0xc0, 0x00, 0x40, 0x03, 0x62, + 0x40, 0x07, 0x07, + 0x00, 0x1a, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x01 }, +}; + +static int __init mipi_video_orise_720p_pt_init(void) +{ + int ret; + + if (msm_fb_detect_client("mipi_video_orise_720p")) + return 0; + + pinfo.xres = 720; + pinfo.yres = 1280; + pinfo.lcdc.xres_pad = 0; + pinfo.lcdc.yres_pad = 0; + + pinfo.type = MIPI_VIDEO_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.lcdc.h_back_porch = 160; + pinfo.lcdc.h_front_porch = 160; + pinfo.lcdc.h_pulse_width = 8; + pinfo.lcdc.v_back_porch = 32; + pinfo.lcdc.v_front_porch = 32; + pinfo.lcdc.v_pulse_width = 1; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + pinfo.bl_max = 200; + pinfo.bl_min = 1; + pinfo.fb_num = 2; + + pinfo.mipi.mode = DSI_VIDEO_MODE; + pinfo.mipi.pulse_mode_hsa_he = TRUE; + pinfo.mipi.hfp_power_stop = TRUE; + pinfo.mipi.hbp_power_stop = TRUE; + pinfo.mipi.hsa_power_stop = FALSE; + pinfo.mipi.eof_bllp_power_stop = TRUE; + pinfo.mipi.bllp_power_stop = TRUE; + pinfo.mipi.traffic_mode = DSI_NON_BURST_SYNCH_EVENT; + pinfo.mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.rgb_swap = DSI_RGB_SWAP_RGB; + pinfo.mipi.data_lane0 = TRUE; + pinfo.mipi.data_lane1 = TRUE; + pinfo.mipi.data_lane2 = TRUE; + pinfo.mipi.data_lane3 = TRUE; + pinfo.mipi.t_clk_post = 0x04; + pinfo.mipi.t_clk_pre = 0x1c; + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = 0; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.frame_rate = 55; + pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db; + pinfo.mipi.tx_eot_append = TRUE; + pinfo.mipi.esc_byte_ratio = 4; + + ret = mipi_orise_device_register(&pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_720P_PT); + if (ret) + printk(KERN_ERR "%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mipi_video_orise_720p_pt_init); diff --git a/drivers/video/msm/mipi_renesas.c b/drivers/video/msm/mipi_renesas.c new file mode 100644 index 000000000000..ff3bdae129af --- /dev/null +++ b/drivers/video/msm/mipi_renesas.c @@ -0,0 +1,1262 @@ +/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_renesas.h" +#include + +#define RENESAS_CMD_DELAY 0 /* 50 */ +#define RENESAS_SLEEP_OFF_DELAY 50 +static struct msm_panel_common_pdata *mipi_renesas_pdata; + +static struct dsi_buf renesas_tx_buf; +static struct dsi_buf renesas_rx_buf; + +static int mipi_renesas_lcd_init(void); + +static char config_sleep_out[2] = {0x11, 0x00}; +static char config_CMD_MODE[2] = {0x40, 0x01}; +static char config_WRTXHT[7] = {0x92, 0x16, 0x08, 0x08, 0x00, 0x01, 0xe0}; +static char config_WRTXVT[7] = {0x8b, 0x02, 0x02, 0x02, 0x00, 0x03, 0x60}; +static char config_PLL2NR[2] = {0xa0, 0x24}; +static char config_PLL2NF1[2] = {0xa2, 0xd0}; +static char config_PLL2NF2[2] = {0xa4, 0x00}; +static char config_PLL2BWADJ1[2] = {0xa6, 0xd0}; +static char config_PLL2BWADJ2[2] = {0xa8, 0x00}; +static char config_PLL2CTL[2] = {0xaa, 0x00}; +static char config_DBICBR[2] = {0x48, 0x03}; +static char config_DBICTYPE[2] = {0x49, 0x00}; +static char config_DBICSET1[2] = {0x4a, 0x1c}; +static char config_DBICADD[2] = {0x4b, 0x00}; +static char config_DBICCTL[2] = {0x4e, 0x01}; +/* static char config_COLMOD_565[2] = {0x3a, 0x05}; */ +/* static char config_COLMOD_666PACK[2] = {0x3a, 0x06}; */ +static char config_COLMOD_888[2] = {0x3a, 0x07}; +static char config_MADCTL[2] = {0x36, 0x00}; +static char config_DBIOC[2] = {0x82, 0x40}; +static char config_CASET[7] = {0x2a, 0x00, 0x00, 0x00, 0x00, 0x01, 0xdf }; +static char config_PASET[7] = {0x2b, 0x00, 0x00, 0x00, 0x00, 0x03, 0x5f }; +static char config_TXON[2] = {0x81, 0x00}; +static char config_BLSET_TM[2] = {0xff, 0x6c}; +static char config_DSIRXCTL[2] = {0x41, 0x01}; +static char config_TEON[2] = {0x35, 0x00}; +static char config_TEOFF[1] = {0x34}; + +static char config_AGCPSCTL_TM[2] = {0x56, 0x08}; + +static char config_DBICADD70[2] = {0x4b, 0x70}; +static char config_DBICSET_15[2] = {0x4a, 0x15}; +static char config_DBICADD72[2] = {0x4b, 0x72}; + +static char config_Power_Ctrl_2a_cmd[3] = {0x4c, 0x40, 0x10}; +static char config_Auto_Sequencer_Setting_a_cmd[3] = {0x4c, 0x00, 0x00}; +static char Driver_Output_Ctrl_indx[3] = {0x4c, 0x00, 0x01}; +static char Driver_Output_Ctrl_cmd[3] = {0x4c, 0x03, 0x10}; +static char config_LCD_drive_AC_Ctrl_indx[3] = {0x4c, 0x00, 0x02}; +static char config_LCD_drive_AC_Ctrl_cmd[3] = {0x4c, 0x01, 0x00}; +static char config_Entry_Mode_indx[3] = {0x4c, 0x00, 0x03}; +static char config_Entry_Mode_cmd[3] = {0x4c, 0x00, 0x00}; +static char config_Display_Ctrl_1_indx[3] = {0x4c, 0x00, 0x07}; +static char config_Display_Ctrl_1_cmd[3] = {0x4c, 0x00, 0x00}; +static char config_Display_Ctrl_2_indx[3] = {0x4c, 0x00, 0x08}; +static char config_Display_Ctrl_2_cmd[3] = {0x4c, 0x00, 0x04}; +static char config_Display_Ctrl_3_indx[3] = {0x4c, 0x00, 0x09}; +static char config_Display_Ctrl_3_cmd[3] = {0x4c, 0x00, 0x0c}; +static char config_Display_IF_Ctrl_1_indx[3] = {0x4c, 0x00, 0x0c}; +static char config_Display_IF_Ctrl_1_cmd[3] = {0x4c, 0x40, 0x10}; +static char config_Display_IF_Ctrl_2_indx[3] = {0x4c, 0x00, 0x0e}; +static char config_Display_IF_Ctrl_2_cmd[3] = {0x4c, 0x00, 0x00}; + +static char config_Panel_IF_Ctrl_1_indx[3] = {0x4c, 0x00, 0x20}; +static char config_Panel_IF_Ctrl_1_cmd[3] = {0x4c, 0x01, 0x3f}; +static char config_Panel_IF_Ctrl_3_indx[3] = {0x4c, 0x00, 0x22}; +static char config_Panel_IF_Ctrl_3_cmd[3] = {0x4c, 0x76, 0x00}; +static char config_Panel_IF_Ctrl_4_indx[3] = {0x4c, 0x00, 0x23}; +static char config_Panel_IF_Ctrl_4_cmd[3] = {0x4c, 0x1c, 0x0a}; +static char config_Panel_IF_Ctrl_5_indx[3] = {0x4c, 0x00, 0x24}; +static char config_Panel_IF_Ctrl_5_cmd[3] = {0x4c, 0x1c, 0x2c}; +static char config_Panel_IF_Ctrl_6_indx[3] = {0x4c, 0x00, 0x25}; +static char config_Panel_IF_Ctrl_6_cmd[3] = {0x4c, 0x1c, 0x4e}; +static char config_Panel_IF_Ctrl_8_indx[3] = {0x4c, 0x00, 0x27}; +static char config_Panel_IF_Ctrl_8_cmd[3] = {0x4c, 0x00, 0x00}; +static char config_Panel_IF_Ctrl_9_indx[3] = {0x4c, 0x00, 0x28}; +static char config_Panel_IF_Ctrl_9_cmd[3] = {0x4c, 0x76, 0x0c}; + + +static char config_gam_adjust_00_indx[3] = {0x4c, 0x03, 0x00}; +static char config_gam_adjust_00_cmd[3] = {0x4c, 0x00, 0x00}; +static char config_gam_adjust_01_indx[3] = {0x4c, 0x03, 0x01}; +static char config_gam_adjust_01_cmd[3] = {0x4c, 0x05, 0x02}; +static char config_gam_adjust_02_indx[3] = {0x4c, 0x03, 0x02}; +static char config_gam_adjust_02_cmd[3] = {0x4c, 0x07, 0x05}; +static char config_gam_adjust_03_indx[3] = {0x4c, 0x03, 0x03}; +static char config_gam_adjust_03_cmd[3] = {0x4c, 0x00, 0x00}; +static char config_gam_adjust_04_indx[3] = {0x4c, 0x03, 0x04}; +static char config_gam_adjust_04_cmd[3] = {0x4c, 0x02, 0x00}; +static char config_gam_adjust_05_indx[3] = {0x4c, 0x03, 0x05}; +static char config_gam_adjust_05_cmd[3] = {0x4c, 0x07, 0x07}; +static char config_gam_adjust_06_indx[3] = {0x4c, 0x03, 0x06}; +static char config_gam_adjust_06_cmd[3] = {0x4c, 0x10, 0x10}; +static char config_gam_adjust_07_indx[3] = {0x4c, 0x03, 0x07}; +static char config_gam_adjust_07_cmd[3] = {0x4c, 0x02, 0x02}; +static char config_gam_adjust_08_indx[3] = {0x4c, 0x03, 0x08}; +static char config_gam_adjust_08_cmd[3] = {0x4c, 0x07, 0x04}; +static char config_gam_adjust_09_indx[3] = {0x4c, 0x03, 0x09}; +static char config_gam_adjust_09_cmd[3] = {0x4c, 0x07, 0x07}; +static char config_gam_adjust_0A_indx[3] = {0x4c, 0x03, 0x0a}; +static char config_gam_adjust_0A_cmd[3] = {0x4c, 0x00, 0x00}; +static char config_gam_adjust_0B_indx[3] = {0x4c, 0x03, 0x0b}; +static char config_gam_adjust_0B_cmd[3] = {0x4c, 0x00, 0x00}; +static char config_gam_adjust_0C_indx[3] = {0x4c, 0x03, 0x0c}; +static char config_gam_adjust_0C_cmd[3] = {0x4c, 0x07, 0x07}; +static char config_gam_adjust_0D_indx[3] = {0x4c, 0x03, 0x0d}; +static char config_gam_adjust_0D_cmd[3] = {0x4c, 0x10, 0x10}; +static char config_gam_adjust_10_indx[3] = {0x4c, 0x03, 0x10}; +static char config_gam_adjust_10_cmd[3] = {0x4c, 0x01, 0x04}; +static char config_gam_adjust_11_indx[3] = {0x4c, 0x03, 0x11}; +static char config_gam_adjust_11_cmd[3] = {0x4c, 0x05, 0x03}; +static char config_gam_adjust_12_indx[3] = {0x4c, 0x03, 0x12}; +static char config_gam_adjust_12_cmd[3] = {0x4c, 0x03, 0x04}; +static char config_gam_adjust_15_indx[3] = {0x4c, 0x03, 0x15}; +static char config_gam_adjust_15_cmd[3] = {0x4c, 0x03, 0x04}; +static char config_gam_adjust_16_indx[3] = {0x4c, 0x03, 0x16}; +static char config_gam_adjust_16_cmd[3] = {0x4c, 0x03, 0x1c}; +static char config_gam_adjust_17_indx[3] = {0x4c, 0x03, 0x17}; +static char config_gam_adjust_17_cmd[3] = {0x4c, 0x02, 0x04}; +static char config_gam_adjust_18_indx[3] = {0x4c, 0x03, 0x18}; +static char config_gam_adjust_18_cmd[3] = {0x4c, 0x04, 0x02}; +static char config_gam_adjust_19_indx[3] = {0x4c, 0x03, 0x19}; +static char config_gam_adjust_19_cmd[3] = {0x4c, 0x03, 0x05}; +static char config_gam_adjust_1C_indx[3] = {0x4c, 0x03, 0x1c}; +static char config_gam_adjust_1C_cmd[3] = {0x4c, 0x07, 0x07}; +static char config_gam_adjust_1D_indx[3] = {0x4c, 0x03, 0x1D}; +static char config_gam_adjust_1D_cmd[3] = {0x4c, 0x02, 0x1f}; +static char config_gam_adjust_20_indx[3] = {0x4c, 0x03, 0x20}; +static char config_gam_adjust_20_cmd[3] = {0x4c, 0x05, 0x07}; +static char config_gam_adjust_21_indx[3] = {0x4c, 0x03, 0x21}; +static char config_gam_adjust_21_cmd[3] = {0x4c, 0x06, 0x04}; +static char config_gam_adjust_22_indx[3] = {0x4c, 0x03, 0x22}; +static char config_gam_adjust_22_cmd[3] = {0x4c, 0x04, 0x05}; +static char config_gam_adjust_27_indx[3] = {0x4c, 0x03, 0x27}; +static char config_gam_adjust_27_cmd[3] = {0x4c, 0x02, 0x03}; +static char config_gam_adjust_28_indx[3] = {0x4c, 0x03, 0x28}; +static char config_gam_adjust_28_cmd[3] = {0x4c, 0x03, 0x00}; +static char config_gam_adjust_29_indx[3] = {0x4c, 0x03, 0x29}; +static char config_gam_adjust_29_cmd[3] = {0x4c, 0x00, 0x02}; + +static char config_Power_Ctrl_1_indx[3] = {0x4c, 0x01, 0x00}; +static char config_Power_Ctrl_1b_cmd[3] = {0x4c, 0x36, 0x3c}; +static char config_Power_Ctrl_2_indx[3] = {0x4c, 0x01, 0x01}; +static char config_Power_Ctrl_2b_cmd[3] = {0x4c, 0x40, 0x03}; +static char config_Power_Ctrl_3_indx[3] = {0x4c, 0x01, 0x02}; +static char config_Power_Ctrl_3a_cmd[3] = {0x4c, 0x00, 0x01}; +static char config_Power_Ctrl_4_indx[3] = {0x4c, 0x01, 0x03}; +static char config_Power_Ctrl_4a_cmd[3] = {0x4c, 0x3c, 0x58}; +static char config_Power_Ctrl_6_indx[3] = {0x4c, 0x01, 0x0c}; +static char config_Power_Ctrl_6a_cmd[3] = {0x4c, 0x01, 0x35}; + +static char config_Auto_Sequencer_Setting_b_cmd[3] = {0x4c, 0x00, 0x02}; + +static char config_Panel_IF_Ctrl_10_indx[3] = {0x4c, 0x00, 0x29}; +static char config_Panel_IF_Ctrl_10a_cmd[3] = {0x4c, 0x03, 0xbf}; +static char config_Auto_Sequencer_Setting_indx[3] = {0x4c, 0x01, 0x06}; +static char config_Auto_Sequencer_Setting_c_cmd[3] = {0x4c, 0x00, 0x03}; +static char config_Power_Ctrl_2c_cmd[3] = {0x4c, 0x40, 0x10}; + +static char config_VIDEO[2] = {0x40, 0x00}; + +static char config_Panel_IF_Ctrl_10_indx_off[3] = {0x4C, 0x00, 0x29}; + +static char config_Panel_IF_Ctrl_10b_cmd_off[3] = {0x4C, 0x00, 0x02}; + +static char config_Power_Ctrl_1a_cmd[3] = {0x4C, 0x30, 0x00}; + +static struct dsi_cmd_desc renesas_sleep_off_cmds[] = { + {DTYPE_DCS_WRITE, 1, 0, 0, RENESAS_SLEEP_OFF_DELAY, + sizeof(config_sleep_out), config_sleep_out } +}; + +static struct dsi_cmd_desc renesas_display_off_cmds[] = { + /* Choosing Command Mode */ + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_CMD_MODE), config_CMD_MODE }, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Auto_Sequencer_Setting_indx), + config_Auto_Sequencer_Setting_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Auto_Sequencer_Setting_b_cmd), + config_Auto_Sequencer_Setting_b_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY * 2, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + /* After waiting >= 5 frames, turn OFF RGB signals + This is done by on DSI/MDP (depends on Vid/Cmd Mode. */ + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Auto_Sequencer_Setting_indx), + config_Auto_Sequencer_Setting_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Auto_Sequencer_Setting_a_cmd), + config_Auto_Sequencer_Setting_a_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Panel_IF_Ctrl_10_indx_off), + config_Panel_IF_Ctrl_10_indx_off}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Panel_IF_Ctrl_10b_cmd_off), + config_Panel_IF_Ctrl_10b_cmd_off}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Power_Ctrl_1_indx), + config_Power_Ctrl_1_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Power_Ctrl_1a_cmd), + config_Power_Ctrl_1a_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_TEOFF), config_TEOFF}, +}; + +static struct dsi_cmd_desc renesas_display_on_cmds[] = { + /* Choosing Command Mode */ + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_CMD_MODE), config_CMD_MODE }, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_WRTXHT), config_WRTXHT }, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_WRTXVT), config_WRTXVT }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_PLL2NR), config_PLL2NR }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_PLL2NF1), config_PLL2NF1 }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_PLL2NF2), config_PLL2NF2 }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_PLL2BWADJ1), config_PLL2BWADJ1}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_PLL2BWADJ2), config_PLL2BWADJ2}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_PLL2CTL), config_PLL2CTL}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICBR), config_DBICBR}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICTYPE), config_DBICTYPE}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET1), config_DBICSET1}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD), config_DBICADD}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICCTL), config_DBICCTL}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_COLMOD_888), config_COLMOD_888}, + /* Choose config_COLMOD_565 or config_COLMOD_666PACK for other modes */ + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_MADCTL), config_MADCTL}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBIOC), config_DBIOC}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_CASET), config_CASET}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_PASET), config_PASET}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DSIRXCTL), config_DSIRXCTL}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_TEON), config_TEON}, + {DTYPE_DCS_WRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_TXON), config_TXON}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_BLSET_TM), config_BLSET_TM}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_AGCPSCTL_TM), config_AGCPSCTL_TM}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Power_Ctrl_1_indx), config_Power_Ctrl_1_indx }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Power_Ctrl_1a_cmd), config_Power_Ctrl_1a_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Power_Ctrl_2_indx), config_Power_Ctrl_2_indx }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Power_Ctrl_2a_cmd), config_Power_Ctrl_2a_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Auto_Sequencer_Setting_indx), + config_Auto_Sequencer_Setting_indx }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Auto_Sequencer_Setting_a_cmd), + config_Auto_Sequencer_Setting_a_cmd }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(Driver_Output_Ctrl_indx), Driver_Output_Ctrl_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(Driver_Output_Ctrl_cmd), + Driver_Output_Ctrl_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_LCD_drive_AC_Ctrl_indx), + config_LCD_drive_AC_Ctrl_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_LCD_drive_AC_Ctrl_cmd), + config_LCD_drive_AC_Ctrl_cmd }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Entry_Mode_indx), + config_Entry_Mode_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Entry_Mode_cmd), + config_Entry_Mode_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Display_Ctrl_1_indx), + config_Display_Ctrl_1_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Display_Ctrl_1_cmd), + config_Display_Ctrl_1_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Display_Ctrl_2_indx), + config_Display_Ctrl_2_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Display_Ctrl_2_cmd), + config_Display_Ctrl_2_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Display_Ctrl_3_indx), + config_Display_Ctrl_3_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Display_Ctrl_3_cmd), + config_Display_Ctrl_3_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Display_IF_Ctrl_1_indx), + config_Display_IF_Ctrl_1_indx }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Display_IF_Ctrl_1_cmd), + config_Display_IF_Ctrl_1_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Display_IF_Ctrl_2_indx), + config_Display_IF_Ctrl_2_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Display_IF_Ctrl_2_cmd), + config_Display_IF_Ctrl_2_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Panel_IF_Ctrl_1_indx), + config_Panel_IF_Ctrl_1_indx }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Panel_IF_Ctrl_1_cmd), + config_Panel_IF_Ctrl_1_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Panel_IF_Ctrl_3_indx), + config_Panel_IF_Ctrl_3_indx }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Panel_IF_Ctrl_3_cmd), + config_Panel_IF_Ctrl_3_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Panel_IF_Ctrl_4_indx), + config_Panel_IF_Ctrl_4_indx }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Panel_IF_Ctrl_4_cmd), + config_Panel_IF_Ctrl_4_cmd }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Panel_IF_Ctrl_5_indx), + config_Panel_IF_Ctrl_5_indx }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Panel_IF_Ctrl_5_cmd), + config_Panel_IF_Ctrl_5_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Panel_IF_Ctrl_6_indx), + config_Panel_IF_Ctrl_6_indx }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Panel_IF_Ctrl_6_cmd), + config_Panel_IF_Ctrl_6_cmd }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Panel_IF_Ctrl_8_indx), + config_Panel_IF_Ctrl_8_indx }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Panel_IF_Ctrl_8_cmd), + config_Panel_IF_Ctrl_8_cmd }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Panel_IF_Ctrl_9_indx), + config_Panel_IF_Ctrl_9_indx }, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Panel_IF_Ctrl_9_cmd), + config_Panel_IF_Ctrl_9_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_00_indx), + config_gam_adjust_00_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_00_cmd), + config_gam_adjust_00_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_01_indx), + config_gam_adjust_01_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_01_cmd), + config_gam_adjust_01_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_02_indx), + config_gam_adjust_02_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_02_cmd), + config_gam_adjust_02_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_03_indx), + config_gam_adjust_03_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_03_cmd), + config_gam_adjust_03_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_04_indx), config_gam_adjust_04_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_04_cmd), config_gam_adjust_04_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_05_indx), config_gam_adjust_05_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_05_cmd), config_gam_adjust_05_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_06_indx), config_gam_adjust_06_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_06_cmd), config_gam_adjust_06_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_07_indx), config_gam_adjust_07_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_07_cmd), config_gam_adjust_07_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_08_indx), config_gam_adjust_08_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_08_cmd), config_gam_adjust_08_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_09_indx), config_gam_adjust_09_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_09_cmd), config_gam_adjust_09_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_0A_indx), config_gam_adjust_0A_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_0A_cmd), config_gam_adjust_0A_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_0B_indx), config_gam_adjust_0B_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_0B_cmd), config_gam_adjust_0B_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_0C_indx), config_gam_adjust_0C_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_0C_cmd), config_gam_adjust_0C_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_0D_indx), config_gam_adjust_0D_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_0D_cmd), config_gam_adjust_0D_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_10_indx), config_gam_adjust_10_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_10_cmd), config_gam_adjust_10_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_11_indx), config_gam_adjust_11_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_11_cmd), config_gam_adjust_11_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_12_indx), config_gam_adjust_12_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_12_cmd), config_gam_adjust_12_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_15_indx), config_gam_adjust_15_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_15_cmd), config_gam_adjust_15_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_16_indx), config_gam_adjust_16_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_16_cmd), config_gam_adjust_16_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_17_indx), config_gam_adjust_17_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_17_cmd), config_gam_adjust_17_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_18_indx), config_gam_adjust_18_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_18_cmd), config_gam_adjust_18_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_19_indx), config_gam_adjust_19_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_19_cmd), config_gam_adjust_19_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_1C_indx), config_gam_adjust_1C_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_1C_cmd), config_gam_adjust_1C_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_1D_indx), config_gam_adjust_1D_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_1D_cmd), config_gam_adjust_1D_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_20_indx), config_gam_adjust_20_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_20_cmd), config_gam_adjust_20_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_21_indx), config_gam_adjust_21_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_21_cmd), config_gam_adjust_21_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_22_indx), config_gam_adjust_22_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_22_cmd), config_gam_adjust_22_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_27_indx), config_gam_adjust_27_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_27_cmd), config_gam_adjust_27_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_28_indx), config_gam_adjust_28_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_28_cmd), config_gam_adjust_28_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_29_indx), config_gam_adjust_29_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_gam_adjust_29_cmd), config_gam_adjust_29_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Power_Ctrl_1_indx), config_Power_Ctrl_1_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Power_Ctrl_1b_cmd), config_Power_Ctrl_1b_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Power_Ctrl_2_indx), config_Power_Ctrl_2_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Power_Ctrl_2b_cmd), config_Power_Ctrl_2b_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Power_Ctrl_3_indx), config_Power_Ctrl_3_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Power_Ctrl_3a_cmd), config_Power_Ctrl_3a_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Power_Ctrl_4_indx), config_Power_Ctrl_4_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Power_Ctrl_4a_cmd), config_Power_Ctrl_4a_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Power_Ctrl_6_indx), config_Power_Ctrl_6_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Power_Ctrl_6a_cmd), config_Power_Ctrl_6a_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Auto_Sequencer_Setting_indx), + config_Auto_Sequencer_Setting_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Auto_Sequencer_Setting_b_cmd), + config_Auto_Sequencer_Setting_b_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Panel_IF_Ctrl_10_indx), + config_Panel_IF_Ctrl_10_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Panel_IF_Ctrl_10a_cmd), + config_Panel_IF_Ctrl_10a_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Auto_Sequencer_Setting_indx), + config_Auto_Sequencer_Setting_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Auto_Sequencer_Setting_c_cmd), + config_Auto_Sequencer_Setting_c_cmd}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD70), config_DBICADD70}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Power_Ctrl_2_indx), + config_Power_Ctrl_2_indx}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICSET_15), config_DBICSET_15}, + {DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_DBICADD72), config_DBICADD72}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_Power_Ctrl_2c_cmd), + config_Power_Ctrl_2c_cmd}, + + {DTYPE_DCS_WRITE1, 1, 0, 0, 0/* RENESAS_CMD_DELAY */, + sizeof(config_DBICSET_15), config_DBICSET_15}, + +}; + +static char config_WRTXHT2[7] = {0x92, 0x15, 0x05, 0x0F, 0x00, 0x01, 0xe0}; +static char config_WRTXVT2[7] = {0x8b, 0x14, 0x01, 0x14, 0x00, 0x03, 0x60}; + +static struct dsi_cmd_desc renesas_hvga_on_cmds[] = { + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_WRTXHT2), config_WRTXHT2}, + {DTYPE_DCS_LWRITE, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_WRTXVT2), config_WRTXVT2}, +}; + +static struct dsi_cmd_desc renesas_video_on_cmds[] = { +{DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_VIDEO), config_VIDEO} +}; + +static struct dsi_cmd_desc renesas_cmd_on_cmds[] = { +{DTYPE_DCS_WRITE1, 1, 0, 0, RENESAS_CMD_DELAY, + sizeof(config_CMD_MODE), config_CMD_MODE}, +}; + +static int mipi_renesas_lcd_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct mipi_panel_info *mipi; + + mfd = platform_get_drvdata(pdev); + mipi = &mfd->panel_info.mipi; + + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + mipi_dsi_cmds_tx(mfd, &renesas_tx_buf, renesas_sleep_off_cmds, + ARRAY_SIZE(renesas_sleep_off_cmds)); + + mipi_set_tx_power_mode(1); + mipi_dsi_cmds_tx(mfd, &renesas_tx_buf, renesas_display_on_cmds, + ARRAY_SIZE(renesas_display_on_cmds)); + + if (cpu_is_msm7x25a() || cpu_is_msm7x25aa() || cpu_is_msm7x25ab()) { + mipi_dsi_cmds_tx(mfd, &renesas_tx_buf, renesas_hvga_on_cmds, + ARRAY_SIZE(renesas_hvga_on_cmds)); + } + + if (mipi->mode == DSI_VIDEO_MODE) + mipi_dsi_cmds_tx(mfd, &renesas_tx_buf, renesas_video_on_cmds, + ARRAY_SIZE(renesas_video_on_cmds)); + else + mipi_dsi_cmds_tx(mfd, &renesas_tx_buf, renesas_cmd_on_cmds, + ARRAY_SIZE(renesas_cmd_on_cmds)); + mipi_set_tx_power_mode(0); + + return 0; +} + +static int mipi_renesas_lcd_off(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + mipi_dsi_cmds_tx(mfd, &renesas_tx_buf, renesas_display_off_cmds, + ARRAY_SIZE(renesas_display_off_cmds)); + + return 0; +} + +static int mipi_renesas_lcd_probe(struct platform_device *pdev) +{ + if (pdev->id == 0) { + mipi_renesas_pdata = pdev->dev.platform_data; + return 0; + } + + msm_fb_add_device(pdev); + + return 0; +} + +static void mipi_renesas_set_backlight(struct msm_fb_data_type *mfd) +{ + int ret = -EPERM; + int bl_level; + + bl_level = mfd->bl_level; + + if (mipi_renesas_pdata && mipi_renesas_pdata->pmic_backlight) + ret = mipi_renesas_pdata->pmic_backlight(bl_level); + else + pr_err("%s(): Backlight level set failed", __func__); +} + +static struct platform_driver this_driver = { + .probe = mipi_renesas_lcd_probe, + .driver = { + .name = "mipi_renesas", + }, +}; + +static struct msm_fb_panel_data renesas_panel_data = { + .on = mipi_renesas_lcd_on, + .off = mipi_renesas_lcd_off, + .set_backlight = mipi_renesas_set_backlight, +}; + +static int ch_used[3]; + +int mipi_renesas_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel) +{ + struct platform_device *pdev = NULL; + int ret; + if ((channel >= 3) || ch_used[channel]) + return -ENODEV; + + ch_used[channel] = TRUE; + + ret = mipi_renesas_lcd_init(); + if (ret) { + pr_err("mipi_renesas_lcd_init() failed with ret %u\n", ret); + return ret; + } + + pdev = platform_device_alloc("mipi_renesas", (panel << 8)|channel); + if (!pdev) + return -ENOMEM; + + renesas_panel_data.panel_info = *pinfo; + + ret = platform_device_add_data(pdev, &renesas_panel_data, + sizeof(renesas_panel_data)); + if (ret) { + pr_err("%s: platform_device_add_data failed!\n", __func__); + goto err_device_put; + } + + ret = platform_device_add(pdev); + if (ret) { + pr_err("%s: platform_device_register failed!\n", __func__); + goto err_device_put; + } + + return 0; + +err_device_put: + platform_device_put(pdev); + return ret; +} + +static int mipi_renesas_lcd_init(void) +{ + mipi_dsi_buf_alloc(&renesas_tx_buf, DSI_BUF_SIZE); + mipi_dsi_buf_alloc(&renesas_rx_buf, DSI_BUF_SIZE); + + return platform_driver_register(&this_driver); +} diff --git a/drivers/video/msm/mipi_renesas.h b/drivers/video/msm/mipi_renesas.h new file mode 100644 index 000000000000..67f777fef564 --- /dev/null +++ b/drivers/video/msm/mipi_renesas.h @@ -0,0 +1,21 @@ +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef MIPI_RENESAS_H +#define MIPI_RENESAS_H + +#define RENESAS_FWVGA_TWO_LANE + +int mipi_renesas_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel); + +#endif /* MIPI_RENESAS_H */ diff --git a/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c b/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c new file mode 100644 index 000000000000..1f796ab10692 --- /dev/null +++ b/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c @@ -0,0 +1,157 @@ +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_renesas.h" + +static struct msm_panel_info pinfo; + +static struct mipi_dsi_phy_ctrl dsi_cmd_mode_phy_db = { +#ifdef CONFIG_FB_MSM_MDP303 + /* DSI Bit Clock at 500 MHz, 2 lane, RGB888 */ + /* regulator */ + {0x03, 0x01, 0x01, 0x00}, + /* timing */ + {0xb9, 0x8e, 0x1f, 0x00, 0x98, 0x9c, 0x22, 0x90, + 0x18, 0x03, 0x04}, + /* phy ctrl */ + {0x7f, 0x00, 0x00, 0x00}, + /* strength */ + {0xbb, 0x02, 0x06, 0x00}, + /* pll control */ + {0x01, 0xec, 0x31, 0xd2, 0x00, 0x40, 0x37, 0x62, + 0x01, 0x0f, 0x07, + 0x05, 0x14, 0x03, 0x0, 0x0, 0x0, 0x20, 0x0, 0x02, 0x0}, +#else + /* DSI_BIT_CLK at 400MHz, 1 lane, RGB888 */ + {0x03, 0x01, 0x01, 0x00}, /* regulator */ + /* timing */ + {0x22, 0x0c, 0x7, 0x00, 0x10, 0x20, 0x10, + 0xd, 0x8, 0x2, 0x3}, + /* phy ctrl */ + {0x7f, 0x00, 0x00, 0x00}, + /* strength */ + {0xee, 0x00, 0x6, 0x00}, + /* pll control */ + {0x40, 0x2f, 0xb1, 0xda, 0x00, 0x50, 0x48, 0x63, +#if defined(RENESAS_FWVGA_TWO_LANE) + 0x33, 0x1f, 0x07, +#else /* default set to 1 lane */ + 0x30, 0x07, 0x07, +#endif + 0x05, 0x14, 0x03, 0x0, 0x0, 0x54, 0x06, 0x10, 0x04, 0x0}, +#endif +}; + +static int __init mipi_cmd_renesas_fwvga_pt_init(void) +{ + int ret; + + if (msm_fb_detect_client("mipi_cmd_renesas_fwvga")) + return 0; + + pinfo.xres = 480; + pinfo.yres = 864; + pinfo.type = MIPI_CMD_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; +#ifdef CONFIG_FB_MSM_MDP303 + pinfo.lcdc.h_back_porch = 100; + pinfo.lcdc.h_front_porch = 100; + pinfo.lcdc.h_pulse_width = 8; + pinfo.lcdc.v_back_porch = 20; + pinfo.lcdc.v_front_porch = 20; + pinfo.lcdc.v_pulse_width = 1; +#else + pinfo.lcdc.h_front_porch = 50; +#if defined(RENESAS_FWVGA_TWO_LANE) + pinfo.lcdc.h_back_porch = 400; + pinfo.lcdc.h_pulse_width = 5; + pinfo.lcdc.v_back_porch = 75; + pinfo.lcdc.v_front_porch = 5; + pinfo.lcdc.v_pulse_width = 1; +#else + pinfo.lcdc.h_back_porch = 50; + pinfo.lcdc.h_pulse_width = 20; + pinfo.lcdc.v_back_porch = 10; + pinfo.lcdc.v_front_porch = 10; + pinfo.lcdc.v_pulse_width = 5; +#endif + +#endif /* CONFIG_FB_MSM_MDP303 */ + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + pinfo.bl_max = 100; + pinfo.bl_min = 1; + pinfo.fb_num = 2; + +#ifdef CONFIG_FB_MSM_MDP303 + pinfo.clk_rate = 499000000; +#else + pinfo.clk_rate = 152000000; +#endif + pinfo.lcd.refx100 = 6000; /* adjust refx100 to prevent tearing */ + + pinfo.mipi.mode = DSI_CMD_MODE; + pinfo.mipi.dst_format = DSI_CMD_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.rgb_swap = DSI_RGB_SWAP_RGB; + pinfo.mipi.data_lane0 = TRUE; +#ifdef CONFIG_FB_MSM_MDP303 + pinfo.lcd.vsync_enable = TRUE; + pinfo.lcd.hw_vsync_mode = TRUE; + pinfo.mipi.data_lane1 = TRUE; + pinfo.mipi.t_clk_post = 0x20; + pinfo.mipi.t_clk_pre = 0x2F; + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.te_sel = 1; /* TE from vsync gpio */ + pinfo.mipi.interleave_max = 1; + pinfo.mipi.insert_dcs_cmd = TRUE; + pinfo.mipi.wr_mem_continue = 0x3c; + pinfo.mipi.wr_mem_start = 0x2c; + pinfo.mipi.dsi_phy_db = &dsi_cmd_mode_phy_db; + pinfo.mipi.tx_eot_append = 0x01; + pinfo.mipi.rx_eot_ignore = 0; + pinfo.mipi.dlane_swap = 0x01; +#else +#if defined(RENESAS_FWVGA_TWO_LANE) + pinfo.mipi.data_lane1 = TRUE; +#else + pinfo.mipi.data_lane1 = FALSE; +#endif + pinfo.mipi.t_clk_post = 0x18; + pinfo.mipi.t_clk_pre = 0x14; + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.te_sel = 1; /* TE from vsycn gpio */ + pinfo.mipi.interleave_max = 1; + pinfo.mipi.insert_dcs_cmd = TRUE; + pinfo.mipi.wr_mem_continue = 0x3c; + pinfo.mipi.wr_mem_start = 0x2c; + pinfo.mipi.dsi_phy_db = &dsi_cmd_mode_phy_db; +#endif /* CONFIG_FB_MSM_MDP303 */ + + ret = mipi_renesas_device_register(&pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_FWVGA_PT); + if (ret) + pr_err("%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mipi_cmd_renesas_fwvga_pt_init); diff --git a/drivers/video/msm/mipi_renesas_video_fwvga_pt.c b/drivers/video/msm/mipi_renesas_video_fwvga_pt.c new file mode 100644 index 000000000000..a8baca61da40 --- /dev/null +++ b/drivers/video/msm/mipi_renesas_video_fwvga_pt.c @@ -0,0 +1,163 @@ +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_renesas.h" + +static struct msm_panel_info pinfo; + +static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = { +#ifdef CONFIG_FB_MSM_MDP303 + /* DSI Bit Clock at 500 MHz, 2 lane, RGB888 */ + /* regulator */ + {0x03, 0x01, 0x01, 0x00}, + /* timing */ + {0xb9, 0x8e, 0x1f, 0x00, 0x98, 0x9c, 0x22, 0x90, + 0x18, 0x03, 0x04}, + /* phy ctrl */ + {0x7f, 0x00, 0x00, 0x00}, + /* strength */ + {0xbb, 0x02, 0x06, 0x00}, + /* pll control */ + {0x00, 0xec, 0x31, 0xd2, 0x00, 0x40, 0x37, 0x62, + 0x01, 0x0f, 0x07, + 0x05, 0x14, 0x03, 0x0, 0x0, 0x0, 0x20, 0x0, 0x02, 0x0}, +#else + /* DSI_BIT_CLK at 400MHz, 1 lane, RGB888 */ + /* regulator */ + {0x03, 0x01, 0x01, 0x00}, + /* timing */ + {0xaa, 0x3b, 0x1b, 0x00, 0x52, 0x58, 0x20, 0x3f, + 0x2e, 0x03, 0x04}, + /* phy ctrl */ + {0x7f, 0x00, 0x00, 0x00}, + /* strength */ + {0xee, 0x00, 0x86, 0x00}, + /* pll control */ + {0x40, 0xc7, 0xb0, 0xda, 0x00, 0x50, 0x48, 0x63, +#if defined(RENESAS_FWVGA_TWO_LANE) + 0x30, 0x07, 0x03, +#else + /* default set to 1 lane */ + 0x30, 0x07, 0x07, +#endif + 0x05, 0x14, 0x03, 0x0, 0x0, 0x54, 0x06, 0x10, 0x04, 0x0}, +#endif +}; + +static int __init mipi_video_renesas_fwvga_pt_init(void) +{ + int ret; + + if (msm_fb_detect_client("mipi_video_renesas_fwvga")) + return 0; + + pinfo.xres = 480; + pinfo.yres = 864; + pinfo.type = MIPI_VIDEO_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; +#ifdef CONFIG_FB_MSM_MDP303 + pinfo.lcdc.h_back_porch = 100; + pinfo.lcdc.h_front_porch = 100; + pinfo.lcdc.h_pulse_width = 8; + pinfo.lcdc.v_back_porch = 20; + pinfo.lcdc.v_front_porch = 20; + pinfo.lcdc.v_pulse_width = 1; + pinfo.clk_rate = 499000000; +#else + +#if defined(RENESAS_FWVGA_TWO_LANE) + pinfo.lcdc.h_back_porch = 400; +#else + pinfo.lcdc.h_back_porch = 50; +#endif + pinfo.lcdc.h_front_porch = 50; + +#if defined(RENESAS_FWVGA_TWO_LANE) + pinfo.lcdc.h_pulse_width = 5; +#else + pinfo.lcdc.h_pulse_width = 20; +#endif + +#if defined(RENESAS_FWVGA_TWO_LANE) + pinfo.lcdc.v_back_porch = 75; + pinfo.lcdc.v_front_porch = 5; + pinfo.lcdc.v_pulse_width = 1; +#else + pinfo.lcdc.v_back_porch = 10; + pinfo.lcdc.v_front_porch = 10; + pinfo.lcdc.v_pulse_width = 5; +#endif + +#endif + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + pinfo.bl_max = 100; + pinfo.bl_min = 1; + pinfo.fb_num = 2; + + pinfo.mipi.mode = DSI_VIDEO_MODE; + pinfo.mipi.pulse_mode_hsa_he = TRUE; + pinfo.mipi.hfp_power_stop = TRUE; + pinfo.mipi.hbp_power_stop = TRUE; + pinfo.mipi.hsa_power_stop = TRUE; + pinfo.mipi.eof_bllp_power_stop = TRUE; + pinfo.mipi.bllp_power_stop = TRUE; +#ifdef CONFIG_FB_MSM_MDP303 + pinfo.mipi.traffic_mode = DSI_BURST_MODE; + pinfo.mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.rgb_swap = DSI_RGB_SWAP_RGB; + pinfo.mipi.data_lane0 = TRUE; + pinfo.mipi.data_lane1 = TRUE; + pinfo.mipi.t_clk_post = 0x20; + pinfo.mipi.t_clk_pre = 0x2F; + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_NONE; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.frame_rate = 60; + pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db; + pinfo.mipi.dlane_swap = 0x01; + pinfo.mipi.tx_eot_append = 0x01; +#else + pinfo.mipi.traffic_mode = DSI_NON_BURST_SYNCH_PULSE; + pinfo.mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.rgb_swap = DSI_RGB_SWAP_BGR; + pinfo.mipi.data_lane0 = TRUE; +#if defined(RENESAS_FWVGA_TWO_LANE) + pinfo.mipi.data_lane1 = TRUE; +#else + pinfo.mipi.data_lane1 = FALSE; +#endif + pinfo.mipi.t_clk_post = 0x03; + pinfo.mipi.t_clk_pre = 0x24; + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.frame_rate = 60; + pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db; +#endif + + ret = mipi_renesas_device_register(&pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_FWVGA_PT); + if (ret) + pr_err("%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mipi_video_renesas_fwvga_pt_init); diff --git a/drivers/video/msm/mipi_simulator.c b/drivers/video/msm/mipi_simulator.c new file mode 100644 index 000000000000..998e7dea2542 --- /dev/null +++ b/drivers/video/msm/mipi_simulator.c @@ -0,0 +1,167 @@ +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_simulator.h" + +static struct dsi_buf simulator_tx_buf; +static struct dsi_buf simulator_rx_buf; +static struct msm_panel_common_pdata *mipi_simulator_pdata; + +static int mipi_simulator_lcd_init(void); + +static char display_on[2] = {0x00, 0x00}; +static char display_off[2] = {0x00, 0x00}; + +static struct dsi_cmd_desc display_on_cmds[] = { + {DTYPE_PERIPHERAL_ON, 1, 0, 0, 0, sizeof(display_on), + display_on} +}; +static struct dsi_cmd_desc display_off_cmds[] = { + {DTYPE_PERIPHERAL_OFF, 1, 0, 0, 0, sizeof(display_off), + display_off} +}; + +static int mipi_simulator_lcd_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct mipi_panel_info *mipi; + + mfd = platform_get_drvdata(pdev); + mipi = &mfd->panel_info.mipi; + + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + pr_debug("%s:%d, debug info (mode) : %d", __func__, __LINE__, + mipi->mode); + + if (mipi->mode == DSI_VIDEO_MODE) { + mipi_dsi_cmds_tx(mfd, &simulator_tx_buf, display_on_cmds, + ARRAY_SIZE(display_on_cmds)); + } else { + pr_err("%s:%d, CMD MODE NOT SUPPORTED", __func__, __LINE__); + return -EINVAL; + } + + return 0; +} + +static int mipi_simulator_lcd_off(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct mipi_panel_info *mipi; + + mfd = platform_get_drvdata(pdev); + mipi = &mfd->panel_info.mipi; + + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + pr_debug("%s:%d, debug info", __func__, __LINE__); + + if (mipi->mode == DSI_VIDEO_MODE) { + mipi_dsi_cmds_tx(mfd, &simulator_tx_buf, display_off_cmds, + ARRAY_SIZE(display_off_cmds)); + } else { + pr_debug("%s:%d, DONT REACH HERE", __func__, __LINE__); + return -EINVAL; + } + + return 0; +} + +static int mipi_simulator_lcd_probe(struct platform_device *pdev) +{ + if (pdev->id == 0) { + mipi_simulator_pdata = pdev->dev.platform_data; + return 0; + } + pr_debug("%s:%d, debug info", __func__, __LINE__); + + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = mipi_simulator_lcd_probe, + .driver = { + .name = "mipi_simulator", + }, +}; + +static struct msm_fb_panel_data simulator_panel_data = { + .on = mipi_simulator_lcd_on, + .off = mipi_simulator_lcd_off, +}; + +static int ch_used[3]; + +int mipi_simulator_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel) +{ + struct platform_device *pdev = NULL; + int ret; + + if ((channel >= 3) || ch_used[channel]) + return -ENODEV; + + ch_used[channel] = TRUE; + + pr_debug("%s:%d, debug info", __func__, __LINE__); + ret = mipi_simulator_lcd_init(); + if (ret) { + pr_err("mipi_simulator_lcd_init() failed with ret %u\n", ret); + return ret; + } + + pdev = platform_device_alloc("mipi_simulator", (panel << 8)|channel); + if (!pdev) + return -ENOMEM; + + simulator_panel_data.panel_info = *pinfo; + + ret = platform_device_add_data(pdev, &simulator_panel_data, + sizeof(simulator_panel_data)); + if (ret) { + pr_err(KERN_ERR + "%s: platform_device_add_data failed!\n", __func__); + goto err_device_put; + } + + ret = platform_device_add(pdev); + if (ret) { + pr_err(KERN_ERR + "%s: platform_device_register failed!\n", __func__); + goto err_device_put; + } + + return 0; + +err_device_put: + platform_device_put(pdev); + return ret; +} + +static int mipi_simulator_lcd_init(void) +{ + mipi_dsi_buf_alloc(&simulator_tx_buf, DSI_BUF_SIZE); + mipi_dsi_buf_alloc(&simulator_rx_buf, DSI_BUF_SIZE); + + return platform_driver_register(&this_driver); +} diff --git a/drivers/video/msm/mipi_simulator.h b/drivers/video/msm/mipi_simulator.h new file mode 100644 index 000000000000..6c0a60c105fa --- /dev/null +++ b/drivers/video/msm/mipi_simulator.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef MIPI_SIMULATOR_H +#define MIPI_SIMULATOR_H + +int mipi_simulator_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel); + +#endif /* MIPI_SIMULATOR_H */ diff --git a/drivers/video/msm/mipi_simulator_video.c b/drivers/video/msm/mipi_simulator_video.c new file mode 100644 index 000000000000..258a7ecabe5c --- /dev/null +++ b/drivers/video/msm/mipi_simulator_video.c @@ -0,0 +1,86 @@ +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_simulator.h" + +static struct msm_panel_info pinfo; + +static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = { + {0x03, 0x01, 0x01, 0x00}, + {0xaa, 0x3b, 0x1b, 0x00, 0x52, 0x58, 0x20, 0x3f, + 0x2e, 0x03, 0x04}, + {0x7f, 0x00, 0x00, 0x00}, + {0xee, 0x00, 0x86, 0x00}, + {0x40, 0xc7, 0xb0, 0xda, 0x00, 0x50, 0x48, 0x63, + 0x30, 0x07, 0x03, + 0x05, 0x14, 0x03, 0x0, 0x0, 0x54, 0x06, 0x10, 0x04, 0x0}, +}; + +static int __init mipi_video_simulator_init(void) +{ + int ret; + + if (msm_fb_detect_client("mipi_video_simulator_vga")) + return 0; + pinfo.xres = 640; + pinfo.yres = 480; + pinfo.type = MIPI_VIDEO_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + + pinfo.lcdc.h_back_porch = 6; + pinfo.lcdc.h_front_porch = 6; + pinfo.lcdc.h_pulse_width = 2; + pinfo.lcdc.v_back_porch = 6; + pinfo.lcdc.v_front_porch = 6; + pinfo.lcdc.v_pulse_width = 2; + + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + pinfo.bl_max = 15; + pinfo.bl_min = 1; + pinfo.fb_num = 2; + + pinfo.mipi.mode = DSI_VIDEO_MODE; + pinfo.mipi.pulse_mode_hsa_he = TRUE; + pinfo.mipi.hfp_power_stop = TRUE; + pinfo.mipi.hbp_power_stop = TRUE; + pinfo.mipi.hsa_power_stop = TRUE; + pinfo.mipi.eof_bllp_power_stop = TRUE; + pinfo.mipi.bllp_power_stop = TRUE; + pinfo.mipi.traffic_mode = DSI_NON_BURST_SYNCH_PULSE; + pinfo.mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.rgb_swap = DSI_RGB_SWAP_RGB; + pinfo.mipi.data_lane0 = TRUE; + pinfo.mipi.data_lane1 = TRUE; + pinfo.mipi.t_clk_post = 0x03; + pinfo.mipi.t_clk_pre = 0x24; + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.frame_rate = 60; + pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db; + + ret = mipi_simulator_device_register(&pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_VGA); + if (ret) + pr_err("%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mipi_video_simulator_init); diff --git a/drivers/video/msm/mipi_tc358764_dsi2lvds.c b/drivers/video/msm/mipi_tc358764_dsi2lvds.c new file mode 100644 index 000000000000..0d44a3048853 --- /dev/null +++ b/drivers/video/msm/mipi_tc358764_dsi2lvds.c @@ -0,0 +1,997 @@ +/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * Toshiba MIPI-DSI-to-LVDS Bridge driver. + * Device Model TC358764XBG/65XBG. + * Reference document: TC358764XBG_65XBG_V119.pdf + * + * The Host sends a DSI Generic Long Write packet (Data ID = 0x29) over the + * DSI link for each write access transaction to the chip configuration + * registers. + * Payload of this packet is 16-bit register address and 32-bit data. + * Multiple data values are allowed for sequential addresses. + * + * The Host sends a DSI Generic Read packet (Data ID = 0x24) over the DSI + * link for each read request transaction to the chip configuration + * registers. Payload of this packet is further defined as follows: + * 16-bit address followed by a 32-bit value (Generic Long Read Response + * packet). + * + * The bridge supports 5 GPIO lines controlled via the GPC register. + * + * The bridge support I2C Master/Slave. + * The I2C slave can be used for read/write to the bridge register instead of + * using the DSI interface. + * I2C slave address is 0x0F (read/write 0x1F/0x1E). + * The I2C Master can be used for communication with the panel if + * it has an I2C slave. + * + * NOTE: The I2C interface is not used in this driver. + * Only the DSI interface is used for read/write the bridge registers. + * + * Pixel data can be transmitted in non-burst or burst fashion. + * Non-burst refers to pixel data packet transmission time on DSI link + * being roughly the same (to account for packet overhead time) + * as active video line time on LVDS output (i.e. DE = 1). + * And burst refers to pixel data packet transmission time on DSI link + * being less than the active video line time on LVDS output. + * Video mode transmission is further differentiated by the types of + * timing events being transmitted. + * Video pulse mode refers to the case where both sync start and sync end + * events (for frame and line) are transmitted. + * Video event mode refers to the case where only sync start events + * are transmitted. + * This is configured via register bit VPCTRL.EVTMODE. + * + */ + +/* #define DEBUG 1 */ + +/** + * Use the I2C master to control the panel. + */ +/* #define TC358764_USE_I2C_MASTER */ + +#define DRV_NAME "mipi_tc358764" + +#include +#include +#include +#include +#include "msm_fb.h" +#include "mdp4.h" +#include "mipi_dsi.h" +#include "mipi_tc358764_dsi2lvds.h" + +/* Registers definition */ + +/* DSI D-PHY Layer Registers */ +#define D0W_DPHYCONTTX 0x0004 /* Data Lane 0 DPHY Tx Control */ +#define CLW_DPHYCONTRX 0x0020 /* Clock Lane DPHY Rx Control */ +#define D0W_DPHYCONTRX 0x0024 /* Data Lane 0 DPHY Rx Control */ +#define D1W_DPHYCONTRX 0x0028 /* Data Lane 1 DPHY Rx Control */ +#define D2W_DPHYCONTRX 0x002C /* Data Lane 2 DPHY Rx Control */ +#define D3W_DPHYCONTRX 0x0030 /* Data Lane 3 DPHY Rx Control */ +#define COM_DPHYCONTRX 0x0038 /* DPHY Rx Common Control */ +#define CLW_CNTRL 0x0040 /* Clock Lane Control */ +#define D0W_CNTRL 0x0044 /* Data Lane 0 Control */ +#define D1W_CNTRL 0x0048 /* Data Lane 1 Control */ +#define D2W_CNTRL 0x004C /* Data Lane 2 Control */ +#define D3W_CNTRL 0x0050 /* Data Lane 3 Control */ +#define DFTMODE_CNTRL 0x0054 /* DFT Mode Control */ + +/* DSI PPI Layer Registers */ +#define PPI_STARTPPI 0x0104 /* START control bit of PPI-TX function. */ +#define PPI_BUSYPPI 0x0108 +#define PPI_LINEINITCNT 0x0110 /* Line Initialization Wait Counter */ +#define PPI_LPTXTIMECNT 0x0114 +#define PPI_LANEENABLE 0x0134 /* Enables each lane at the PPI layer. */ +#define PPI_TX_RX_TA 0x013C /* DSI Bus Turn Around timing parameters */ + +/* Analog timer function enable */ +#define PPI_CLS_ATMR 0x0140 /* Delay for Clock Lane in LPRX */ +#define PPI_D0S_ATMR 0x0144 /* Delay for Data Lane 0 in LPRX */ +#define PPI_D1S_ATMR 0x0148 /* Delay for Data Lane 1 in LPRX */ +#define PPI_D2S_ATMR 0x014C /* Delay for Data Lane 2 in LPRX */ +#define PPI_D3S_ATMR 0x0150 /* Delay for Data Lane 3 in LPRX */ +#define PPI_D0S_CLRSIPOCOUNT 0x0164 + +#define PPI_D1S_CLRSIPOCOUNT 0x0168 /* For lane 1 */ +#define PPI_D2S_CLRSIPOCOUNT 0x016C /* For lane 2 */ +#define PPI_D3S_CLRSIPOCOUNT 0x0170 /* For lane 3 */ + +#define CLS_PRE 0x0180 /* Digital Counter inside of PHY IO */ +#define D0S_PRE 0x0184 /* Digital Counter inside of PHY IO */ +#define D1S_PRE 0x0188 /* Digital Counter inside of PHY IO */ +#define D2S_PRE 0x018C /* Digital Counter inside of PHY IO */ +#define D3S_PRE 0x0190 /* Digital Counter inside of PHY IO */ +#define CLS_PREP 0x01A0 /* Digital Counter inside of PHY IO */ +#define D0S_PREP 0x01A4 /* Digital Counter inside of PHY IO */ +#define D1S_PREP 0x01A8 /* Digital Counter inside of PHY IO */ +#define D2S_PREP 0x01AC /* Digital Counter inside of PHY IO */ +#define D3S_PREP 0x01B0 /* Digital Counter inside of PHY IO */ +#define CLS_ZERO 0x01C0 /* Digital Counter inside of PHY IO */ +#define D0S_ZERO 0x01C4 /* Digital Counter inside of PHY IO */ +#define D1S_ZERO 0x01C8 /* Digital Counter inside of PHY IO */ +#define D2S_ZERO 0x01CC /* Digital Counter inside of PHY IO */ +#define D3S_ZERO 0x01D0 /* Digital Counter inside of PHY IO */ + +#define PPI_CLRFLG 0x01E0 /* PRE Counters has reached set values */ +#define PPI_CLRSIPO 0x01E4 /* Clear SIPO values, Slave mode use only. */ +#define HSTIMEOUT 0x01F0 /* HS Rx Time Out Counter */ +#define HSTIMEOUTENABLE 0x01F4 /* Enable HS Rx Time Out Counter */ +#define DSI_STARTDSI 0x0204 /* START control bit of DSI-TX function */ +#define DSI_BUSYDSI 0x0208 +#define DSI_LANEENABLE 0x0210 /* Enables each lane at the Protocol layer. */ +#define DSI_LANESTATUS0 0x0214 /* Displays lane is in HS RX mode. */ +#define DSI_LANESTATUS1 0x0218 /* Displays lane is in ULPS or STOP state */ + +#define DSI_INTSTATUS 0x0220 /* Interrupt Status */ +#define DSI_INTMASK 0x0224 /* Interrupt Mask */ +#define DSI_INTCLR 0x0228 /* Interrupt Clear */ +#define DSI_LPTXTO 0x0230 /* Low Power Tx Time Out Counter */ + +#define DSIERRCNT 0x0300 /* DSI Error Count */ +#define APLCTRL 0x0400 /* Application Layer Control */ +#define RDPKTLN 0x0404 /* Command Read Packet Length */ +#define VPCTRL 0x0450 /* Video Path Control */ +#define HTIM1 0x0454 /* Horizontal Timing Control 1 */ +#define HTIM2 0x0458 /* Horizontal Timing Control 2 */ +#define VTIM1 0x045C /* Vertical Timing Control 1 */ +#define VTIM2 0x0460 /* Vertical Timing Control 2 */ +#define VFUEN 0x0464 /* Video Frame Timing Update Enable */ + +/* Mux Input Select for LVDS LINK Input */ +#define LVMX0003 0x0480 /* Bit 0 to 3 */ +#define LVMX0407 0x0484 /* Bit 4 to 7 */ +#define LVMX0811 0x0488 /* Bit 8 to 11 */ +#define LVMX1215 0x048C /* Bit 12 to 15 */ +#define LVMX1619 0x0490 /* Bit 16 to 19 */ +#define LVMX2023 0x0494 /* Bit 20 to 23 */ +#define LVMX2427 0x0498 /* Bit 24 to 27 */ + +#define LVCFG 0x049C /* LVDS Configuration */ +#define LVPHY0 0x04A0 /* LVDS PHY 0 */ +#define LVPHY1 0x04A4 /* LVDS PHY 1 */ +#define SYSSTAT 0x0500 /* System Status */ +#define SYSRST 0x0504 /* System Reset */ + +/* GPIO Registers */ +#define GPIOC 0x0520 /* GPIO Control */ +#define GPIOO 0x0524 /* GPIO Output */ +#define GPIOI 0x0528 /* GPIO Input */ + +/* I2C Registers */ +#define I2CTIMCTRL 0x0540 /* I2C IF Timing and Enable Control */ +#define I2CMADDR 0x0544 /* I2C Master Addressing */ +#define WDATAQ 0x0548 /* Write Data Queue */ +#define RDATAQ 0x054C /* Read Data Queue */ + +/* Chip ID and Revision ID Register */ +#define IDREG 0x0580 + +#define TC358764XBG_ID 0x00006500 + +/* Debug Registers */ +#define DEBUG00 0x05A0 /* Debug */ +#define DEBUG01 0x05A4 /* LVDS Data */ + +/* PWM */ +static u32 d2l_pwm_freq_hz = (3.921*1000); + +#define PWM_FREQ_HZ (d2l_pwm_freq_hz) +#define PWM_PERIOD_USEC (USEC_PER_SEC / PWM_FREQ_HZ) +#define PWM_DUTY_LEVEL (PWM_PERIOD_USEC / PWM_LEVEL) + +#define CMD_DELAY 100 +#define DSI_MAX_LANES 4 +#define KHZ 1000 +#define MHZ (1000*1000) + +/** + * Command payload for DTYPE_GEN_LWRITE (0x29) / DTYPE_GEN_READ2 (0x24). + */ +struct wr_cmd_payload { + u16 addr; + u32 data; +} __packed; + +/* + * Driver state. + */ +static struct msm_panel_common_pdata *d2l_common_pdata; +struct msm_fb_data_type *d2l_mfd; +static struct dsi_buf d2l_tx_buf; +static struct dsi_buf d2l_rx_buf; +static int led_pwm; +static struct pwm_device *bl_pwm; +static struct pwm_device *tn_pwm; +static int bl_level; +static u32 d2l_gpio_out_mask; +static u32 d2l_gpio_out_val; +static u32 d2l_3d_gpio_enable; +static u32 d2l_3d_gpio_mode; +static int d2l_enable_3d; +static struct i2c_client *d2l_i2c_client; +static struct i2c_driver d2l_i2c_slave_driver; + +static int mipi_d2l_init(void); +static int mipi_d2l_enable_3d(struct msm_fb_data_type *mfd, + bool enable, bool mode); +static u32 d2l_i2c_read_reg(struct i2c_client *client, u16 reg); +static u32 d2l_i2c_write_reg(struct i2c_client *client, u16 reg, u32 val); + +/** + * Read a bridge register + * + * @param mfd + * + * @return register data value + */ +static u32 mipi_d2l_read_reg(struct msm_fb_data_type *mfd, u16 reg) +{ + u32 data; + int len = 4; + struct dsi_cmd_desc cmd_read_reg = { + DTYPE_GEN_READ2, 1, 0, 1, 0, /* cmd 0x24 */ + sizeof(reg), (char *) ®}; + + mipi_dsi_buf_init(&d2l_tx_buf); + mipi_dsi_buf_init(&d2l_rx_buf); + + /* mutex had been acquired at mipi_dsi_on */ + len = mipi_dsi_cmds_rx(mfd, &d2l_tx_buf, &d2l_rx_buf, + &cmd_read_reg, len); + + data = *(u32 *)d2l_rx_buf.data; + + if (len != 4) + pr_err("%s: invalid rlen=%d, expecting 4.\n", __func__, len); + + pr_debug("%s: reg=0x%x.data=0x%08x.\n", __func__, reg, data); + + return data; +} + +/** + * Write a bridge register + * + * @param mfd + * + * @return int + */ +static int mipi_d2l_write_reg(struct msm_fb_data_type *mfd, u16 reg, u32 data) +{ + struct wr_cmd_payload payload; + struct dsi_cmd_desc cmd_write_reg = { + DTYPE_GEN_LWRITE, 1, 0, 0, 0, + sizeof(payload), (char *)&payload}; + + payload.addr = reg; + payload.data = data; + + /* mutex had been acquired at mipi_dsi_on */ + mipi_dsi_cmds_tx(mfd, &d2l_tx_buf, &cmd_write_reg, 1); + + pr_debug("%s: reg=0x%x. data=0x%x.\n", __func__, reg, data); + + return 0; +} + +static void mipi_d2l_read_status(struct msm_fb_data_type *mfd) +{ + mipi_d2l_read_reg(mfd, DSI_LANESTATUS0); /* 0x214 */ + mipi_d2l_read_reg(mfd, DSI_LANESTATUS1); /* 0x218 */ + mipi_d2l_read_reg(mfd, DSI_INTSTATUS); /* 0x220 */ + mipi_d2l_read_reg(mfd, SYSSTAT); /* 0x500 */ +} + +static void mipi_d2l_read_status_via_i2c(struct i2c_client *client) +{ + u32 tmp = 0; + + tmp = d2l_i2c_read_reg(client, DSIERRCNT); + d2l_i2c_write_reg(client, DSIERRCNT, 0xFFFF0000); + + d2l_i2c_read_reg(client, DSI_LANESTATUS0); /* 0x214 */ + d2l_i2c_read_reg(client, DSI_LANESTATUS1); /* 0x218 */ + d2l_i2c_read_reg(client, DSI_INTSTATUS); /* 0x220 */ + d2l_i2c_read_reg(client, SYSSTAT); /* 0x500 */ + + d2l_i2c_write_reg(client, DSIERRCNT, tmp); +} +/** + * Init the D2L bridge via the DSI interface for Video. + * + * VPCTRL.EVTMODE (0x20) configuration bit is needed to determine whether + * video timing information is delivered in pulse mode or event mode. + * In pulse mode, both Sync Start and End packets are required. + * In event mode, only Sync Start packets are required. + * + * @param mfd + * + * @return int + */ +static int mipi_d2l_dsi_init_sequence(struct msm_fb_data_type *mfd) +{ + struct mipi_panel_info *mipi = &mfd->panel_info.mipi; + u32 lanes_enable; + u32 vpctrl; + u32 htime1; + u32 vtime1; + u32 htime2; + u32 vtime2; + u32 ppi_tx_rx_ta; /* BTA Bus-Turn-Around */ + u32 lvcfg; + u32 hbpr; /* Horizontal Back Porch */ + u32 hpw; /* Horizontal Pulse Width */ + u32 vbpr; /* Vertical Back Porch */ + u32 vpw; /* Vertical Pulse Width */ + + u32 hfpr; /* Horizontal Front Porch */ + u32 hsize; /* Horizontal Active size */ + u32 vfpr; /* Vertical Front Porch */ + u32 vsize; /* Vertical Active size */ + bool vesa_rgb888 = false; + + lanes_enable = 0x01; /* clock-lane enable */ + lanes_enable |= (mipi->data_lane0 << 1); + lanes_enable |= (mipi->data_lane1 << 2); + lanes_enable |= (mipi->data_lane2 << 3); + lanes_enable |= (mipi->data_lane3 << 4); + + if (mipi->traffic_mode == DSI_NON_BURST_SYNCH_EVENT) + vpctrl = 0x01000120; + else if (mipi->traffic_mode == DSI_NON_BURST_SYNCH_PULSE) + vpctrl = 0x01000100; + else { + pr_err("%s.unsupported traffic_mode %d.\n", + __func__, mipi->traffic_mode); + return -EINVAL; + } + + if (mfd->panel_info.clk_rate > 800*1000*1000) { + pr_err("%s.unsupported clk_rate %d.\n", + __func__, mfd->panel_info.clk_rate); + return -EINVAL; + } + + pr_debug("%s.xres=%d.yres=%d.fps=%d.dst_format=%d.\n", + __func__, + mfd->panel_info.xres, + mfd->panel_info.yres, + mfd->panel_info.mipi.frame_rate, + mfd->panel_info.mipi.dst_format); + + hbpr = mfd->panel_info.lcdc.h_back_porch; + hpw = mfd->panel_info.lcdc.h_pulse_width; + vbpr = mfd->panel_info.lcdc.v_back_porch; + vpw = mfd->panel_info.lcdc.v_pulse_width; + + htime1 = (hbpr << 16) + hpw; + vtime1 = (vbpr << 16) + vpw; + + hfpr = mfd->panel_info.lcdc.h_front_porch; + hsize = mfd->panel_info.xres; + vfpr = mfd->panel_info.lcdc.v_front_porch; + vsize = mfd->panel_info.yres; + + htime2 = (hfpr << 16) + hsize; + vtime2 = (vfpr << 16) + vsize; + + lvcfg = 0x0003; /* PCLK=DCLK/3, Dual Link, LVEN */ + vpctrl = 0x01000120; /* Output RGB888 , Event-Mode , */ + ppi_tx_rx_ta = 0x00040004; + + if (mfd->panel_info.xres == 1366) { + ppi_tx_rx_ta = 0x00040004; + lvcfg = 0x01; /* LVEN */ + vesa_rgb888 = true; + } + + if (mfd->panel_info.xres == 1200) { + lvcfg = 0x0103; /* PCLK=DCLK/4, Dual Link, LVEN */ + vesa_rgb888 = true; + } + + pr_debug("%s.htime1=0x%x.\n", __func__, htime1); + pr_debug("%s.vtime1=0x%x.\n", __func__, vtime1); + pr_debug("%s.vpctrl=0x%x.\n", __func__, vpctrl); + pr_debug("%s.lvcfg=0x%x.\n", __func__, lvcfg); + + mipi_d2l_write_reg(mfd, SYSRST, 0xFF); + msleep(30); + + if (vesa_rgb888) { + /* VESA format instead of JEIDA format for RGB888 */ + mipi_d2l_write_reg(mfd, LVMX0003, 0x03020100); + mipi_d2l_write_reg(mfd, LVMX0407, 0x08050704); + mipi_d2l_write_reg(mfd, LVMX0811, 0x0F0E0A09); + mipi_d2l_write_reg(mfd, LVMX1215, 0x100D0C0B); + mipi_d2l_write_reg(mfd, LVMX1619, 0x12111716); + mipi_d2l_write_reg(mfd, LVMX2023, 0x1B151413); + mipi_d2l_write_reg(mfd, LVMX2427, 0x061A1918); + } + + mipi_d2l_write_reg(mfd, PPI_TX_RX_TA, ppi_tx_rx_ta); /* BTA */ + mipi_d2l_write_reg(mfd, PPI_LPTXTIMECNT, 0x00000004); + mipi_d2l_write_reg(mfd, PPI_D0S_CLRSIPOCOUNT, 0x00000003); + mipi_d2l_write_reg(mfd, PPI_D1S_CLRSIPOCOUNT, 0x00000003); + mipi_d2l_write_reg(mfd, PPI_D2S_CLRSIPOCOUNT, 0x00000003); + mipi_d2l_write_reg(mfd, PPI_D3S_CLRSIPOCOUNT, 0x00000003); + mipi_d2l_write_reg(mfd, PPI_LANEENABLE, lanes_enable); + mipi_d2l_write_reg(mfd, DSI_LANEENABLE, lanes_enable); + mipi_d2l_write_reg(mfd, PPI_STARTPPI, 0x00000001); + mipi_d2l_write_reg(mfd, DSI_STARTDSI, 0x00000001); + + mipi_d2l_write_reg(mfd, VPCTRL, vpctrl); /* RGB888 + Event mode */ + mipi_d2l_write_reg(mfd, HTIM1, htime1); + mipi_d2l_write_reg(mfd, VTIM1, vtime1); + mipi_d2l_write_reg(mfd, HTIM2, htime2); + mipi_d2l_write_reg(mfd, VTIM2, vtime2); + mipi_d2l_write_reg(mfd, VFUEN, 0x00000001); + mipi_d2l_write_reg(mfd, LVCFG, lvcfg); /* Enables LVDS tx */ + + return 0; +} + +/** + * Set Backlight level. + * + * @param pwm + * @param level + * + * @return int + */ +static int mipi_d2l_set_backlight_level(struct pwm_device *pwm, int level) +{ + int ret = 0; + + pr_debug("%s: level=%d.\n", __func__, level); + + if ((pwm == NULL) || (level > PWM_LEVEL) || (level < 0)) { + pr_err("%s.pwm=NULL.\n", __func__); + return -EINVAL; + } + + ret = pwm_config(pwm, PWM_DUTY_LEVEL * level, PWM_PERIOD_USEC); + if (ret) { + pr_err("%s: pwm_config() failed err=%d.\n", __func__, ret); + return ret; + } + + ret = pwm_enable(pwm); + if (ret) { + pr_err("%s: pwm_enable() failed err=%d\n", + __func__, ret); + return ret; + } + + return 0; +} + +/** + * Set TN CLK. + * + * @param pwm + * @param level + * + * @return int + */ +static int mipi_d2l_set_tn_clk(struct pwm_device *pwm, u32 usec) +{ + int ret = 0; + + pr_debug("%s: usec=%d.\n", __func__, usec); + + ret = pwm_config(pwm, usec/2 , usec); + if (ret) { + pr_err("%s: pwm_config() failed err=%d.\n", __func__, ret); + return ret; + } + + ret = pwm_enable(pwm); + if (ret) { + pr_err("%s: pwm_enable() failed err=%d\n", + __func__, ret); + return ret; + } + + return 0; +} + +/** + * LCD ON. + * + * Set LCD On via MIPI interface or I2C-Slave interface. + * Set Backlight on. + * + * @param pdev + * + * @return int + */ +static int mipi_d2l_lcd_on(struct platform_device *pdev) +{ + int ret = 0; + u32 chip_id; + struct msm_fb_data_type *mfd; + + pr_info("%s.\n", __func__); + + /* wait for valid clock before sending data over DSI or I2C. */ + msleep(30); + + mfd = platform_get_drvdata(pdev); + d2l_mfd = mfd; + + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + chip_id = mipi_d2l_read_reg(mfd, IDREG); + + + if (chip_id != TC358764XBG_ID) { + pr_err("%s: invalid chip_id=0x%x", __func__, chip_id); + return -ENODEV; + } + + ret = mipi_d2l_dsi_init_sequence(mfd); + if (ret) + return ret; + + mipi_d2l_write_reg(mfd, GPIOC, d2l_gpio_out_mask); + /* Set gpio#4=U/D=0, gpio#3=L/R=1 , gpio#2,1=CABC=0, gpio#0=NA. */ + mipi_d2l_write_reg(mfd, GPIOO, d2l_gpio_out_val); + + d2l_pwm_freq_hz = (3.921*1000); + + if (bl_level == 0) + bl_level = PWM_LEVEL * 2 / 3 ; /* Default ON value */ + + /* Set backlight via PWM */ + if (bl_pwm) { + ret = mipi_d2l_set_backlight_level(bl_pwm, bl_level); + if (ret) + pr_err("%s.mipi_d2l_set_backlight_level.ret=%d", + __func__, ret); + } + + mipi_d2l_read_status(mfd); + + mipi_d2l_enable_3d(mfd, false, false); + + /* Add I2C driver only after DSI-CLK is running */ + i2c_add_driver(&d2l_i2c_slave_driver); + + pr_info("%s.ret=%d.\n", __func__, ret); + + return ret; +} + +/** + * LCD OFF. + * + * @param pdev + * + * @return int + */ +static int mipi_d2l_lcd_off(struct platform_device *pdev) +{ + int ret; + struct msm_fb_data_type *mfd; + + pr_info("%s.\n", __func__); + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + ret = mipi_d2l_set_backlight_level(bl_pwm, 1); + + pr_info("%s.ret=%d.\n", __func__, ret); + + return ret; +} + +static void mipi_d2l_set_backlight(struct msm_fb_data_type *mfd) +{ + int level = mfd->bl_level; + + pr_debug("%s.lvl=%d.\n", __func__, level); + + mipi_d2l_set_backlight_level(bl_pwm, level); + + bl_level = level; +} + +static struct msm_fb_panel_data d2l_panel_data = { + .on = mipi_d2l_lcd_on, + .off = mipi_d2l_lcd_off, + .set_backlight = mipi_d2l_set_backlight, +}; + +static u32 d2l_i2c_read_reg(struct i2c_client *client, u16 reg) +{ + int rc; + u32 val = 0; + u8 buf[6]; + + if (client == NULL) { + pr_err("%s.invalid i2c client.\n", __func__); + return -EINVAL; + } + + buf[0] = reg >> 8; + buf[1] = reg & 0xFF; + + rc = i2c_master_send(client, buf, sizeof(reg)); + rc = i2c_master_recv(client, buf, 4); + + if (rc >= 0) { + val = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24); + pr_debug("%s.reg=0x%x.val=0x%x.\n", __func__, reg, val); + } else + pr_err("%s.fail.reg=0x%x.\n", __func__, reg); + + return val; +} + +static u32 d2l_i2c_write_reg(struct i2c_client *client, u16 reg, u32 val) +{ + int rc; + u8 buf[6]; + + if (client == NULL) { + pr_err("%s.invalid i2c client.\n", __func__); + return -EINVAL; + } + + buf[0] = reg >> 8; + buf[1] = reg & 0xFF; + + buf[2] = (val >> 0) & 0xFF; + buf[3] = (val >> 8) & 0xFF; + buf[4] = (val >> 16) & 0xFF; + buf[5] = (val >> 24) & 0xFF; + + rc = i2c_master_send(client, buf, sizeof(buf)); + + if (rc >= 0) + pr_debug("%s.reg=0x%x.val=0x%x.\n", __func__, reg, val); + else + pr_err("%s.fail.reg=0x%x.\n", __func__, reg); + + return val; +} + +static int d2l_i2c_slave_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + static const u32 i2c_funcs = I2C_FUNC_I2C; + + d2l_i2c_client = client; + + if (!i2c_check_functionality(client->adapter, i2c_funcs)) { + pr_err("%s.i2c_check_functionality failed.\n", __func__); + return -ENOSYS; + } else { + pr_debug("%s.i2c_check_functionality OK.\n", __func__); + } + + d2l_i2c_read_reg(client, IDREG); + + mipi_d2l_read_status_via_i2c(d2l_i2c_client); + + return 0; +} + +static int d2l_i2c_slave_remove(struct i2c_client *client) +{ + d2l_i2c_client = NULL; + + return 0; +} + +static const struct i2c_device_id d2l_i2c_id[] = { + {"tc358764-i2c", 0}, + {} +}; + +static struct i2c_driver d2l_i2c_slave_driver = { + .driver = { + .name = "tc358764-i2c", + .owner = THIS_MODULE + }, + .probe = d2l_i2c_slave_probe, + .remove = d2l_i2c_slave_remove, + .id_table = d2l_i2c_id, +}; + +static int mipi_d2l_enable_3d(struct msm_fb_data_type *mfd, + bool enable, bool mode) +{ + u32 tn_usec = 1000000 / 66; /* 66 HZ */ + + pr_debug("%s.enable=%d.mode=%d.\n", __func__, enable, mode); + + gpio_direction_output(d2l_3d_gpio_enable, enable); + gpio_direction_output(d2l_3d_gpio_mode, mode); + + mipi_d2l_set_tn_clk(tn_pwm, tn_usec); + + return 0; +} + +static ssize_t mipi_d2l_enable_3d_read(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf((char *)buf, sizeof(buf), "%u\n", d2l_enable_3d); +} + +static ssize_t mipi_d2l_enable_3d_write(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + int ret = -1; + u32 data = 0; + + if (sscanf((char *)buf, "%u", &data) != 1) { + dev_err(dev, "%s. Invalid input.\n", __func__); + ret = -EINVAL; + } else { + d2l_enable_3d = data; + if (data == 1) /* LANDSCAPE */ + mipi_d2l_enable_3d(d2l_mfd, true, true); + else if (data == 2) /* PORTRAIT */ + mipi_d2l_enable_3d(d2l_mfd, true, false); + else if (data == 0) + mipi_d2l_enable_3d(d2l_mfd, false, false); + else if (data == 9) + mipi_d2l_read_status_via_i2c(d2l_i2c_client); + else + pr_err("%s.Invalid value=%d.\n", __func__, data); + } + + return count; +} + +static struct device_attribute mipi_d2l_3d_barrier_attributes[] = { + __ATTR(enable_3d_barrier, 0666, + mipi_d2l_enable_3d_read, + mipi_d2l_enable_3d_write), +}; + +static int mipi_dsi_3d_barrier_sysfs_register(struct device *dev) +{ + int ret; + + pr_debug("%s.d2l_3d_gpio_enable=%d.\n", __func__, d2l_3d_gpio_enable); + pr_debug("%s.d2l_3d_gpio_mode=%d.\n", __func__, d2l_3d_gpio_mode); + + ret = device_create_file(dev, mipi_d2l_3d_barrier_attributes); + if (ret) { + pr_err("%s.failed to create 3D sysfs.\n", __func__); + goto err_device_create_file; + } + + ret = gpio_request(d2l_3d_gpio_enable, "d2l_3d_gpio_enable"); + if (ret) { + pr_err("%s.failed to get d2l_3d_gpio_enable=%d.\n", + __func__, d2l_3d_gpio_enable); + goto err_d2l_3d_gpio_enable; + } + + ret = gpio_request(d2l_3d_gpio_mode, "d2l_3d_gpio_mode"); + if (ret) { + pr_err("%s.failed to get d2l_3d_gpio_mode=%d.\n", + __func__, d2l_3d_gpio_mode); + goto err_d2l_3d_gpio_mode; + } + + return 0; + +err_d2l_3d_gpio_mode: + gpio_free(d2l_3d_gpio_enable); +err_d2l_3d_gpio_enable: + device_remove_file(dev, mipi_d2l_3d_barrier_attributes); +err_device_create_file: + + return ret; +} + +/** + * Probe for device. + * + * Both the "target" and "panel" device use the same probe function. + * "Target" device has id=0, "Panel" devic has non-zero id. + * Target device should register first, passing msm_panel_common_pdata. + * Panel device passing msm_panel_info. + * + * @param pdev + * + * @return int + */ +static int mipi_d2l_probe(struct platform_device *pdev) +{ + int ret = 0; + struct msm_panel_info *pinfo = NULL; + + pr_debug("%s.id=%d.\n", __func__, pdev->id); + + if (pdev->id == 0) { + d2l_common_pdata = pdev->dev.platform_data; + + if (d2l_common_pdata == NULL) { + pr_err("%s: no PWM gpio specified.\n", __func__); + return 0; + } + + led_pwm = d2l_common_pdata->gpio_num[0]; + d2l_gpio_out_mask = d2l_common_pdata->gpio_num[1] >> 8; + d2l_gpio_out_val = d2l_common_pdata->gpio_num[1] & 0xFF; + d2l_3d_gpio_enable = d2l_common_pdata->gpio_num[2]; + d2l_3d_gpio_mode = d2l_common_pdata->gpio_num[3]; + + mipi_dsi_buf_alloc(&d2l_tx_buf, DSI_BUF_SIZE); + mipi_dsi_buf_alloc(&d2l_rx_buf, DSI_BUF_SIZE); + + return 0; + } + + if (d2l_common_pdata == NULL) { + pr_err("%s: d2l_common_pdata is NULL.\n", __func__); + return -ENODEV; + } + + bl_pwm = NULL; + if (led_pwm >= 0) { + bl_pwm = pwm_request(led_pwm, "lcd-backlight"); + if (bl_pwm == NULL || IS_ERR(bl_pwm)) { + pr_err("%s pwm_request() failed.id=%d.bl_pwm=%d.\n", + __func__, led_pwm, (int) bl_pwm); + bl_pwm = NULL; + return -EIO; + } else { + pr_debug("%s.pwm_request() ok.pwm-id=%d.\n", + __func__, led_pwm); + + } + } else { + pr_err("%s. led_pwm is invalid.\n", __func__); + } + + tn_pwm = pwm_request(1, "3D_TN_clk"); + if (tn_pwm == NULL || IS_ERR(tn_pwm)) { + pr_err("%s pwm_request() failed.id=%d.tn_pwm=%d.\n", + __func__, 1, (int) tn_pwm); + tn_pwm = NULL; + return -EIO; + } else { + pr_debug("%s.pwm_request() ok.pwm-id=%d.\n", __func__, 1); + + } + + pinfo = pdev->dev.platform_data; + + if (pinfo == NULL) { + pr_err("%s: pinfo is NULL.\n", __func__); + return -ENODEV; + } + + d2l_panel_data.panel_info = *pinfo; + + pdev->dev.platform_data = &d2l_panel_data; + + msm_fb_add_device(pdev); + + if (pinfo->is_3d_panel) + mipi_dsi_3d_barrier_sysfs_register(&(pdev->dev)); + + return ret; +} + +/** + * Device removal notification handler. + * + * @param pdev + * + * @return int + */ +static int mipi_d2l_remove(struct platform_device *pdev) +{ + /* Note: There are no APIs to remove fb device and free DSI buf. */ + pr_debug("%s.\n", __func__); + + if (bl_pwm) { + pwm_free(bl_pwm); + bl_pwm = NULL; + } + + return 0; +} + +/** + * Register the panel device. + * + * @param pinfo + * @param channel_id + * @param panel_id + * + * @return int + */ +int mipi_tc358764_dsi2lvds_register(struct msm_panel_info *pinfo, + u32 channel_id, u32 panel_id) +{ + struct platform_device *pdev = NULL; + int ret; + /* Use DSI-to-LVDS bridge */ + const char driver_name[] = "mipi_tc358764"; + + pr_debug("%s.\n", __func__); + ret = mipi_d2l_init(); + if (ret) { + pr_err("mipi_d2l_init() failed with ret %u\n", ret); + return ret; + } + + /* Note: the device id should be non-zero */ + pdev = platform_device_alloc(driver_name, (panel_id << 8)|channel_id); + if (pdev == NULL) + return -ENOMEM; + + pdev->dev.platform_data = pinfo; + + ret = platform_device_add(pdev); + if (ret) { + pr_err("%s: platform_device_register failed!\n", __func__); + goto err_device_put; + } + + return 0; + +err_device_put: + platform_device_put(pdev); + return ret; +} + +static struct platform_driver d2l_driver = { + .probe = mipi_d2l_probe, + .remove = mipi_d2l_remove, + .driver = { + .name = DRV_NAME, + }, +}; + +/** + * Module Init + * + * @return int + */ +static int mipi_d2l_init(void) +{ + pr_debug("%s.\n", __func__); + + return platform_driver_register(&d2l_driver); +} + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Toshiba MIPI-DSI-to-LVDS bridge driver"); +MODULE_AUTHOR("Amir Samuelov "); diff --git a/drivers/video/msm/mipi_tc358764_dsi2lvds.h b/drivers/video/msm/mipi_tc358764_dsi2lvds.h new file mode 100644 index 000000000000..671c191d52ac --- /dev/null +++ b/drivers/video/msm/mipi_tc358764_dsi2lvds.h @@ -0,0 +1,21 @@ +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef MIPI_TC358764_DSI2LVDS_H +#define MIPI_TC358764_DSI2LVDS_H + +#define PWM_LEVEL 255 + +int mipi_tc358764_dsi2lvds_register(struct msm_panel_info *pinfo, + u32 channel_id, u32 panel_id); +#endif /* MIPI_TC358764_DSI2LVDS_H */ diff --git a/drivers/video/msm/mipi_toshiba.c b/drivers/video/msm/mipi_toshiba.c new file mode 100644 index 000000000000..41c50984f1f1 --- /dev/null +++ b/drivers/video/msm/mipi_toshiba.c @@ -0,0 +1,355 @@ +/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_toshiba.h" + +static struct pwm_device *bl_lpm; +static struct mipi_dsi_panel_platform_data *mipi_toshiba_pdata; + +#define TM_GET_PID(id) (((id) & 0xff00)>>8) + +static struct dsi_buf toshiba_tx_buf; +static struct dsi_buf toshiba_rx_buf; +static int mipi_toshiba_lcd_init(void); + +#ifdef TOSHIBA_CMDS_UNUSED +static char one_lane[3] = {0xEF, 0x60, 0x62}; +static char dmode_wqvga[2] = {0xB3, 0x01}; +static char intern_wr_clk1_wqvga[3] = {0xef, 0x2f, 0x22}; +static char intern_wr_clk2_wqvga[3] = {0xef, 0x6e, 0x33}; +static char hor_addr_2A_wqvga[5] = {0x2A, 0x00, 0x00, 0x00, 0xef}; +static char hor_addr_2B_wqvga[5] = {0x2B, 0x00, 0x00, 0x01, 0xaa}; +static char if_sel_cmd[2] = {0x53, 0x00}; +#endif + +static char exit_sleep[2] = {0x11, 0x00}; +static char display_on[2] = {0x29, 0x00}; +static char display_off[2] = {0x28, 0x00}; +static char enter_sleep[2] = {0x10, 0x00}; + +static char mcap_off[2] = {0xb2, 0x00}; +static char ena_test_reg[3] = {0xEF, 0x01, 0x01}; +static char two_lane[3] = {0xEF, 0x60, 0x63}; +static char non_burst_sync_pulse[3] = {0xef, 0x61, 0x09}; +static char dmode_wvga[2] = {0xB3, 0x00}; +static char intern_wr_clk1_wvga[3] = {0xef, 0x2f, 0xcc}; +static char intern_wr_clk2_wvga[3] = {0xef, 0x6e, 0xdd}; +static char hor_addr_2A_wvga[5] = {0x2A, 0x00, 0x00, 0x01, 0xdf}; +static char hor_addr_2B_wvga[5] = {0x2B, 0x00, 0x00, 0x03, 0x55}; +static char if_sel_video[2] = {0x53, 0x01}; + +static struct dsi_cmd_desc toshiba_wvga_display_on_cmds[] = { + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(mcap_off), mcap_off}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(ena_test_reg), ena_test_reg}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(two_lane), two_lane}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(non_burst_sync_pulse), + non_burst_sync_pulse}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(dmode_wvga), dmode_wvga}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(intern_wr_clk1_wvga), + intern_wr_clk1_wvga}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(intern_wr_clk2_wvga), + intern_wr_clk2_wvga}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, sizeof(hor_addr_2A_wvga), + hor_addr_2A_wvga}, + {DTYPE_DCS_LWRITE, 1, 0, 0, 0, sizeof(hor_addr_2B_wvga), + hor_addr_2B_wvga}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(if_sel_video), if_sel_video}, + {DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(exit_sleep), exit_sleep}, + {DTYPE_DCS_WRITE, 1, 0, 0, 0, sizeof(display_on), display_on} +}; + +static char mcap_start[2] = {0xb0, 0x04}; +static char num_out_pixelform[3] = {0xb3, 0x00, 0x87}; +static char dsi_ctrl[3] = {0xb6, 0x30, 0x83}; +static char panel_driving[7] = {0xc0, 0x01, 0x00, 0x85, 0x00, 0x00, 0x00}; +static char dispV_timing[5] = {0xc1, 0x00, 0x10, 0x00, 0x01}; +static char dispCtrl[3] = {0xc3, 0x00, 0x19}; +static char test_mode_c4[2] = {0xc4, 0x03}; +static char dispH_timing[15] = { + /* TYPE_DCS_LWRITE */ + 0xc5, 0x00, 0x01, 0x05, + 0x04, 0x5e, 0x00, 0x00, + 0x00, 0x00, 0x0b, 0x17, + 0x05, 0x00, 0x00 +}; +static char test_mode_c6[2] = {0xc6, 0x00}; +static char gamma_setA[13] = { + 0xc8, 0x0a, 0x15, 0x18, + 0x1b, 0x1c, 0x0d, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00 +}; +static char gamma_setB[13] = { + 0xc9, 0x0d, 0x1d, 0x1f, + 0x1f, 0x1f, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00 +}; +static char gamma_setC[13] = { + 0xca, 0x1e, 0x1f, 0x1e, + 0x1d, 0x1d, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00 +}; +static char powerSet_ChrgPmp[5] = {0xd0, 0x02, 0x00, 0xa3, 0xb8}; +static char testMode_d1[6] = {0xd1, 0x10, 0x14, 0x53, 0x64, 0x00}; +static char powerSet_SrcAmp[3] = {0xd2, 0xb3, 0x00}; +static char powerInt_PS[3] = {0xd3, 0x33, 0x03}; +static char vreg[2] = {0xd5, 0x00}; +static char test_mode_d6[2] = {0xd6, 0x01}; +static char timingCtrl_d7[9] = { + 0xd7, 0x09, 0x00, 0x84, + 0x81, 0x61, 0xbc, 0xb5, + 0x05 +}; +static char timingCtrl_d8[7] = { + 0xd8, 0x04, 0x25, 0x90, + 0x4c, 0x92, 0x00 +}; +static char timingCtrl_d9[4] = {0xd9, 0x5b, 0x7f, 0x05}; +static char white_balance[6] = {0xcb, 0x00, 0x00, 0x00, 0x1c, 0x00}; +static char vcs_settings[2] = {0xdd, 0x53}; +static char vcom_dc_settings[2] = {0xde, 0x43}; +static char testMode_e3[5] = {0xe3, 0x00, 0x00, 0x00, 0x00}; +static char testMode_e4[6] = {0xe4, 0x00, 0x00, 0x22, 0xaa, 0x00}; +static char testMode_e5[2] = {0xe5, 0x00}; +static char testMode_fa[4] = {0xfa, 0x00, 0x00, 0x00}; +static char testMode_fd[5] = {0xfd, 0x00, 0x00, 0x00, 0x00}; +static char testMode_fe[5] = {0xfe, 0x00, 0x00, 0x00, 0x00}; +static char mcap_end[2] = {0xb0, 0x03}; +static char set_add_mode[2] = {0x36, 0x0}; +static char set_pixel_format[2] = {0x3a, 0x70}; + + +static struct dsi_cmd_desc toshiba_wsvga_display_on_cmds[] = { + {DTYPE_GEN_WRITE2, 1, 0, 0, 10, sizeof(mcap_start), mcap_start}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 10, sizeof(num_out_pixelform), + num_out_pixelform}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 10, sizeof(dsi_ctrl), dsi_ctrl}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(panel_driving), panel_driving}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(dispV_timing), dispV_timing}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(dispCtrl), dispCtrl}, + {DTYPE_GEN_WRITE2, 1, 0, 0, 0, sizeof(test_mode_c4), test_mode_c4}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(dispH_timing), dispH_timing}, + {DTYPE_GEN_WRITE2, 1, 0, 0, 0, sizeof(test_mode_c6), test_mode_c6}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(gamma_setA), gamma_setA}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(gamma_setB), gamma_setB}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(gamma_setC), gamma_setC}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(powerSet_ChrgPmp), + powerSet_ChrgPmp}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(testMode_d1), testMode_d1}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(powerSet_SrcAmp), + powerSet_SrcAmp}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(powerInt_PS), powerInt_PS}, + {DTYPE_GEN_WRITE2, 1, 0, 0, 0, sizeof(vreg), vreg}, + {DTYPE_GEN_WRITE2, 1, 0, 0, 0, sizeof(test_mode_d6), test_mode_d6}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(timingCtrl_d7), timingCtrl_d7}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(timingCtrl_d8), timingCtrl_d8}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(timingCtrl_d9), timingCtrl_d9}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(white_balance), white_balance}, + {DTYPE_GEN_WRITE2, 1, 0, 0, 0, sizeof(vcs_settings), vcs_settings}, + {DTYPE_GEN_WRITE2, 1, 0, 0, 0, sizeof(vcom_dc_settings), + vcom_dc_settings}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(testMode_e3), testMode_e3}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(testMode_e4), testMode_e4}, + {DTYPE_GEN_WRITE2, 1, 0, 0, 0, sizeof(testMode_e5), testMode_e5}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(testMode_fa), testMode_fa}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(testMode_fd), testMode_fd}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(testMode_fe), testMode_fe}, + {DTYPE_GEN_WRITE2, 1, 0, 0, 0, sizeof(mcap_end), mcap_end}, + {DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(set_add_mode), set_add_mode}, + {DTYPE_DCS_WRITE1, 1, 0, 0, 0, sizeof(set_pixel_format), + set_pixel_format}, + {DTYPE_DCS_WRITE, 1, 0, 0, 120, sizeof(exit_sleep), exit_sleep}, + {DTYPE_DCS_WRITE, 1, 0, 0, 50, sizeof(display_on), display_on} +}; + +static struct dsi_cmd_desc toshiba_display_off_cmds[] = { + {DTYPE_DCS_WRITE, 1, 0, 0, 50, sizeof(display_off), display_off}, + {DTYPE_DCS_WRITE, 1, 0, 0, 120, sizeof(enter_sleep), enter_sleep} +}; + +static int mipi_toshiba_lcd_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (TM_GET_PID(mfd->panel.id) == MIPI_DSI_PANEL_WVGA_PT) + mipi_dsi_cmds_tx(mfd, &toshiba_tx_buf, + toshiba_wvga_display_on_cmds, + ARRAY_SIZE(toshiba_wvga_display_on_cmds)); + else if (TM_GET_PID(mfd->panel.id) == MIPI_DSI_PANEL_WSVGA_PT || + TM_GET_PID(mfd->panel.id) == MIPI_DSI_PANEL_WUXGA) + mipi_dsi_cmds_tx(mfd, &toshiba_tx_buf, + toshiba_wsvga_display_on_cmds, + ARRAY_SIZE(toshiba_wsvga_display_on_cmds)); + else + return -EINVAL; + + return 0; +} + +static int mipi_toshiba_lcd_off(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + mipi_dsi_cmds_tx(mfd, &toshiba_tx_buf, toshiba_display_off_cmds, + ARRAY_SIZE(toshiba_display_off_cmds)); + + return 0; +} + +void mipi_bklight_pwm_cfg(void) +{ + if (mipi_toshiba_pdata && mipi_toshiba_pdata->dsi_pwm_cfg) + mipi_toshiba_pdata->dsi_pwm_cfg(); +} + +static void mipi_toshiba_set_backlight(struct msm_fb_data_type *mfd) +{ + int ret; + static int bklight_pwm_cfg; + + if (bklight_pwm_cfg == 0) { + mipi_bklight_pwm_cfg(); + bklight_pwm_cfg++; + } + + if (bl_lpm) { + ret = pwm_config(bl_lpm, MIPI_TOSHIBA_PWM_DUTY_LEVEL * + mfd->bl_level, MIPI_TOSHIBA_PWM_PERIOD_USEC); + if (ret) { + pr_err("pwm_config on lpm failed %d\n", ret); + return; + } + if (mfd->bl_level) { + ret = pwm_enable(bl_lpm); + if (ret) + pr_err("pwm enable/disable on lpm failed" + "for bl %d\n", mfd->bl_level); + } else { + pwm_disable(bl_lpm); + } + } +} + +static int mipi_toshiba_lcd_probe(struct platform_device *pdev) +{ + if (pdev->id == 0) { + mipi_toshiba_pdata = pdev->dev.platform_data; + return 0; + } + + if (mipi_toshiba_pdata == NULL) { + pr_err("%s.invalid platform data.\n", __func__); + return -ENODEV; + } + + if (mipi_toshiba_pdata != NULL) + bl_lpm = pwm_request(mipi_toshiba_pdata->gpio[0], + "backlight"); + + if (bl_lpm == NULL || IS_ERR(bl_lpm)) { + pr_err("%s pwm_request() failed\n", __func__); + bl_lpm = NULL; + } + pr_debug("bl_lpm = %p lpm = %d\n", bl_lpm, + mipi_toshiba_pdata->gpio[0]); + + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = mipi_toshiba_lcd_probe, + .driver = { + .name = "mipi_toshiba", + }, +}; + +static struct msm_fb_panel_data toshiba_panel_data = { + .on = mipi_toshiba_lcd_on, + .off = mipi_toshiba_lcd_off, + .set_backlight = mipi_toshiba_set_backlight, +}; + +static int ch_used[3]; + +int mipi_toshiba_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel) +{ + struct platform_device *pdev = NULL; + int ret; + + if ((channel >= 3) || ch_used[channel]) + return -ENODEV; + + ch_used[channel] = TRUE; + + ret = mipi_toshiba_lcd_init(); + if (ret) { + pr_err("mipi_toshiba_lcd_init() failed with ret %u\n", ret); + return ret; + } + + pdev = platform_device_alloc("mipi_toshiba", (panel << 8)|channel); + if (!pdev) + return -ENOMEM; + + toshiba_panel_data.panel_info = *pinfo; + + ret = platform_device_add_data(pdev, &toshiba_panel_data, + sizeof(toshiba_panel_data)); + if (ret) { + printk(KERN_ERR + "%s: platform_device_add_data failed!\n", __func__); + goto err_device_put; + } + + ret = platform_device_add(pdev); + if (ret) { + printk(KERN_ERR + "%s: platform_device_register failed!\n", __func__); + goto err_device_put; + } + + return 0; + +err_device_put: + platform_device_put(pdev); + return ret; +} + +static int mipi_toshiba_lcd_init(void) +{ + mipi_dsi_buf_alloc(&toshiba_tx_buf, DSI_BUF_SIZE); + mipi_dsi_buf_alloc(&toshiba_rx_buf, DSI_BUF_SIZE); + + return platform_driver_register(&this_driver); +} diff --git a/drivers/video/msm/mipi_toshiba.h b/drivers/video/msm/mipi_toshiba.h new file mode 100644 index 000000000000..ea7fddd2308b --- /dev/null +++ b/drivers/video/msm/mipi_toshiba.h @@ -0,0 +1,30 @@ + +/* Copyright (c) 2009-2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef MIPI_TOSHIBA_H +#define MIPI_TOSHIBA_H + +#include +#include + +int mipi_toshiba_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel); + +#define MIPI_TOSHIBA_PWM_FREQ_HZ 3921 +#define MIPI_TOSHIBA_PWM_PERIOD_USEC (USEC_PER_SEC / MIPI_TOSHIBA_PWM_FREQ_HZ) +#define MIPI_TOSHIBA_PWM_LEVEL 255 +#define MIPI_TOSHIBA_PWM_DUTY_LEVEL \ + (MIPI_TOSHIBA_PWM_PERIOD_USEC / MIPI_TOSHIBA_PWM_LEVEL) + +#endif /* MIPI_TOSHIBA_H */ diff --git a/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c b/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c new file mode 100644 index 000000000000..2a36d94cf724 --- /dev/null +++ b/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c @@ -0,0 +1,105 @@ +/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_toshiba.h" + +static struct msm_panel_info pinfo; + +static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = { + /* 600*1024, RGB888, 3 Lane 55 fps video mode */ + /* regulator */ + {0x09, 0x08, 0x05, 0x00, 0x20}, + /* timing */ + {0xab, 0x8a, 0x18, 0x00, 0x92, 0x97, 0x1b, 0x8c, + 0x0c, 0x03, 0x04, 0xa0}, + /* phy ctrl */ + {0x5f, 0x00, 0x00, 0x10}, + /* strength */ + {0xff, 0x00, 0x06, 0x00}, + /* pll control */ + {0x0, 0x7f, 0x31, 0xda, 0x00, 0x50, 0x48, 0x63, + 0x41, 0x0f, 0x01, + 0x00, 0x14, 0x03, 0x00, 0x02, 0x00, 0x20, 0x00, 0x01 }, +}; + +static int __init mipi_video_toshiba_wsvga_pt_init(void) +{ + int ret; + + if (msm_fb_detect_client("mipi_video_toshiba_wsvga")) + return 0; + + pinfo.xres = 600; + pinfo.yres = 1024; + /* + * + * Panel's Horizontal input timing requirement is to + * include dummy(pad) data of 200 clk in addition to + * width and porch/sync width values + */ + pinfo.lcdc.xres_pad = 200; + pinfo.lcdc.yres_pad = 0; + + pinfo.type = MIPI_VIDEO_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.lcdc.h_back_porch = 16; + pinfo.lcdc.h_front_porch = 23; + pinfo.lcdc.h_pulse_width = 8; + pinfo.lcdc.v_back_porch = 2; + pinfo.lcdc.v_front_porch = 7; + pinfo.lcdc.v_pulse_width = 2; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + pinfo.bl_max = MIPI_TOSHIBA_PWM_LEVEL; + pinfo.bl_min = 1; + pinfo.fb_num = 2; + pinfo.clk_rate = 384000000; + + pinfo.mipi.mode = DSI_VIDEO_MODE; + pinfo.mipi.pulse_mode_hsa_he = FALSE; + pinfo.mipi.hfp_power_stop = FALSE; + pinfo.mipi.hbp_power_stop = FALSE; + pinfo.mipi.hsa_power_stop = FALSE; + pinfo.mipi.eof_bllp_power_stop = FALSE; + pinfo.mipi.bllp_power_stop = FALSE; + pinfo.mipi.traffic_mode = DSI_NON_BURST_SYNCH_EVENT; + pinfo.mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.rgb_swap = DSI_RGB_SWAP_RGB; + pinfo.mipi.data_lane0 = TRUE; + pinfo.mipi.data_lane1 = TRUE; + pinfo.mipi.data_lane2 = TRUE; + pinfo.mipi.t_clk_post = 0x20; + pinfo.mipi.t_clk_pre = 0x2d; + pinfo.mipi.esc_byte_ratio = 4; + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = 0; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.frame_rate = 55; + pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db; + pinfo.mipi.tx_eot_append = TRUE; + + ret = mipi_toshiba_device_register(&pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_WSVGA_PT); + if (ret) + printk(KERN_ERR "%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mipi_video_toshiba_wsvga_pt_init); diff --git a/drivers/video/msm/mipi_toshiba_video_wuxga.c b/drivers/video/msm/mipi_toshiba_video_wuxga.c new file mode 100644 index 000000000000..ed7895ec37a0 --- /dev/null +++ b/drivers/video/msm/mipi_toshiba_video_wuxga.c @@ -0,0 +1,98 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_toshiba.h" + +static struct msm_panel_info pinfo; + +static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = { + /* 1920*1200, RGB888, 4 Lane 60 fps video mode */ + /* regulator */ + {0x03, 0x0a, 0x04, 0x00, 0x20}, + /* timing */ + {0x66, 0x26, 0x1F, 0x00, 0x55, 0x9C, 0x16, 0x90, + 0x23, 0x03, 0x04, 0xa0}, + /* phy ctrl */ + {0x5f, 0x00, 0x00, 0x10}, + /* strength */ + {0xff, 0x00, 0x06, 0x00}, + /* pll control */ + {0x0, 0xD7, 0x1, 0x19, 0x00, 0x50, 0x48, 0x63, + 0x41, 0x0f, 0x01, + 0x00, 0x14, 0x03, 0x00, 0x02, 0x00, 0x20, 0x00, 0x01 }, +}; + +static int __init mipi_video_toshiba_wuxga_init(void) +{ + int ret; + + if (msm_fb_detect_client("mipi_video_toshiba_wuxga")) + return 0; + + pinfo.xres = 1920; + pinfo.yres = 1200; + + pinfo.type = MIPI_VIDEO_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.lcdc.h_back_porch = 50; + pinfo.lcdc.h_front_porch = 50; + pinfo.lcdc.h_pulse_width = 170; + pinfo.lcdc.v_back_porch = 7; + pinfo.lcdc.v_front_porch = 8; + pinfo.lcdc.v_pulse_width = 30; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + pinfo.bl_max = MIPI_TOSHIBA_PWM_LEVEL; + pinfo.bl_min = 1; + pinfo.fb_num = 2; + pinfo.clk_rate = 981560000; + + pinfo.mipi.mode = DSI_VIDEO_MODE; + pinfo.mipi.pulse_mode_hsa_he = TRUE; + pinfo.mipi.hfp_power_stop = FALSE; + pinfo.mipi.hbp_power_stop = FALSE; + pinfo.mipi.hsa_power_stop = FALSE; + pinfo.mipi.eof_bllp_power_stop = TRUE; + pinfo.mipi.bllp_power_stop = TRUE; + pinfo.mipi.traffic_mode = DSI_NON_BURST_SYNCH_PULSE; + pinfo.mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.rgb_swap = DSI_RGB_SWAP_BGR; + pinfo.mipi.data_lane0 = TRUE; + pinfo.mipi.data_lane1 = TRUE; + pinfo.mipi.data_lane2 = TRUE; + pinfo.mipi.data_lane3 = TRUE; + pinfo.mipi.tx_eot_append = TRUE; + pinfo.mipi.t_clk_post = 0x04; + pinfo.mipi.t_clk_pre = 0x1c; + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.frame_rate = 60; + pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db; + pinfo.mipi.esc_byte_ratio = 9; + + ret = mipi_toshiba_device_register(&pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_WUXGA); + if (ret) + printk(KERN_ERR "%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mipi_video_toshiba_wuxga_init); diff --git a/drivers/video/msm/mipi_toshiba_video_wvga_pt.c b/drivers/video/msm/mipi_toshiba_video_wvga_pt.c new file mode 100644 index 000000000000..fdd4d1c4d321 --- /dev/null +++ b/drivers/video/msm/mipi_toshiba_video_wvga_pt.c @@ -0,0 +1,106 @@ +/* Copyright (c) 2009-2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_toshiba.h" + +static struct msm_panel_info pinfo; + +static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = { + /* 480*854, RGB888, 2 Lane 60 fps video mode */ + {0x03, 0x01, 0x01, 0x00}, /* regulator */ + /* timing */ + {0x6a, 0x22, 0x0f, 0x00, 0x30, 0x38, 0x13, 0x26, + 0x1b, 0x03, 0x04}, + {0x7f, 0x00, 0x00, 0x00}, /* phy ctrl */ + {0xee, 0x03, 0x86, 0x03}, /* strength */ + /* pll control */ + +#define DSI_BIT_CLK_380MHZ + +#if defined(DSI_BIT_CLK_366MHZ) + {0x41, 0xdb, 0xb2, 0xf5, 0x00, 0x50, 0x48, 0x63, + 0x31, 0x0f, 0x07, + 0x05, 0x14, 0x03, 0x03, 0x03, 0x54, 0x06, 0x10, 0x04, 0x03 }, +#elif defined(DSI_BIT_CLK_380MHZ) + {0x41, 0xf7, 0xb2, 0xf5, 0x00, 0x50, 0x48, 0x63, + 0x31, 0x0f, 0x07, + 0x05, 0x14, 0x03, 0x03, 0x03, 0x54, 0x06, 0x10, 0x04, 0x03 }, +#elif defined(DSI_BIT_CLK_400MHZ) + {0x41, 0x8f, 0xb1, 0xda, 0x00, 0x50, 0x48, 0x63, + 0x31, 0x0f, 0x07, + 0x05, 0x14, 0x03, 0x03, 0x03, 0x54, 0x06, 0x10, 0x04, 0x03 }, +#else /* 200 mhz */ + {0x41, 0x8f, 0xb1, 0xda, 0x00, 0x50, 0x48, 0x63, + 0x33, 0x1f, 0x0f, + 0x05, 0x14, 0x03, 0x03, 0x03, 0x54, 0x06, 0x10, 0x04, 0x03 }, +#endif +}; + +static int __init mipi_video_toshiba_wvga_pt_init(void) +{ + int ret; + + if (msm_fb_detect_client("mipi_video_toshiba_wvga")) + return 0; + + pinfo.xres = 480; + pinfo.yres = 864; /* 856 for V1 surf */ + pinfo.type = MIPI_VIDEO_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.lcdc.h_back_porch = 64; + pinfo.lcdc.h_front_porch = 64; + pinfo.lcdc.h_pulse_width = 16; + pinfo.lcdc.v_back_porch = 8; + pinfo.lcdc.v_front_porch = 4; + pinfo.lcdc.v_pulse_width = 1; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + pinfo.bl_max = 15; + pinfo.bl_min = 1; + pinfo.fb_num = 2; + + pinfo.mipi.mode = DSI_VIDEO_MODE; + pinfo.mipi.pulse_mode_hsa_he = TRUE; + pinfo.mipi.hfp_power_stop = FALSE; + pinfo.mipi.hbp_power_stop = FALSE; + pinfo.mipi.hsa_power_stop = FALSE; + pinfo.mipi.eof_bllp_power_stop = TRUE; + pinfo.mipi.bllp_power_stop = TRUE; + pinfo.mipi.traffic_mode = DSI_NON_BURST_SYNCH_PULSE; + pinfo.mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.rgb_swap = DSI_RGB_SWAP_BGR; + pinfo.mipi.data_lane0 = TRUE; + pinfo.mipi.data_lane1 = TRUE; + pinfo.mipi.t_clk_post = 0x04; + pinfo.mipi.t_clk_pre = 0x17; + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.frame_rate = 60; + pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db; + + ret = mipi_toshiba_device_register(&pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_WVGA_PT); + if (ret) + printk(KERN_ERR "%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mipi_video_toshiba_wvga_pt_init); diff --git a/drivers/video/msm/mipi_truly.c b/drivers/video/msm/mipi_truly.c new file mode 100644 index 000000000000..fa42e4f17252 --- /dev/null +++ b/drivers/video/msm/mipi_truly.c @@ -0,0 +1,259 @@ +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_truly.h" + +static struct msm_panel_common_pdata *mipi_truly_pdata; +static struct dsi_buf truly_tx_buf; +static struct dsi_buf truly_rx_buf; + +#define TRULY_CMD_DELAY 0 +#define TRULY_SLEEP_OFF_DELAY 150 +#define TRULY_DISPLAY_ON_DELAY 150 +#define GPIO_TRULY_LCD_RESET 129 + +static int prev_bl = 17; + +static char extend_cmd_enable[4] = {0xB9, 0xFF, 0x83, 0x69}; +static char display_setting[16] = { + 0xB2, 0x00, 0x23, 0x62, + 0x62, 0x70, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, + 0x03, 0x03, 0x00, 0x01, +}; +static char wave_cycle_setting[6] = {0xB4, 0x00, 0x1D, 0x5F, 0x0E, 0x06}; +static char gip_setting[27] = { + 0xD5, 0x00, 0x04, 0x03, + 0x00, 0x01, 0x05, 0x1C, + 0x70, 0x01, 0x03, 0x00, + 0x00, 0x40, 0x06, 0x51, + 0x07, 0x00, 0x00, 0x41, + 0x06, 0x50, 0x07, 0x07, + 0x0F, 0x04, 0x00, +}; +static char power_setting[20] = { + 0xB1, 0x01, 0x00, 0x34, + 0x06, 0x00, 0x0F, 0x0F, + 0x2A, 0x32, 0x3F, 0x3F, + 0x07, 0x3A, 0x01, 0xE6, + 0xE6, 0xE6, 0xE6, 0xE6, +}; +static char vcom_setting[3] = {0xB6, 0x56, 0x56}; +static char pannel_setting[2] = {0xCC, 0x02}; +static char gamma_setting[35] = { + 0xE0, 0x00, 0x1D, 0x22, + 0x38, 0x3D, 0x3F, 0x2E, + 0x4A, 0x06, 0x0D, 0x0F, + 0x13, 0x15, 0x13, 0x16, + 0x10, 0x19, 0x00, 0x1D, + 0x22, 0x38, 0x3D, 0x3F, + 0x2E, 0x4A, 0x06, 0x0D, + 0x0F, 0x13, 0x15, 0x13, + 0x16, 0x10, 0x19, +}; +static char mipi_setting[14] = { + 0xBA, 0x00, 0xA0, 0xC6, + 0x00, 0x0A, 0x00, 0x10, + 0x30, 0x6F, 0x02, 0x11, + 0x18, 0x40, +}; +static char exit_sleep[2] = {0x11, 0x00}; +static char display_on[2] = {0x29, 0x00}; +static char display_off[2] = {0x28, 0x00}; +static char enter_sleep[2] = {0x10, 0x00}; + +static struct dsi_cmd_desc truly_display_off_cmds[] = { + {DTYPE_DCS_WRITE, 1, 0, 0, 10, sizeof(display_off), display_off}, + {DTYPE_DCS_WRITE, 1, 0, 0, 120, sizeof(enter_sleep), enter_sleep} +}; + +static struct dsi_cmd_desc truly_display_on_cmds[] = { + {DTYPE_GEN_LWRITE, 1, 0, 0, TRULY_CMD_DELAY, + sizeof(extend_cmd_enable), extend_cmd_enable}, + {DTYPE_GEN_LWRITE, 1, 0, 0, TRULY_CMD_DELAY, + sizeof(display_setting), display_setting}, + {DTYPE_GEN_LWRITE, 1, 0, 0, TRULY_CMD_DELAY, + sizeof(wave_cycle_setting), wave_cycle_setting}, + {DTYPE_GEN_LWRITE, 1, 0, 0, TRULY_CMD_DELAY, + sizeof(gip_setting), gip_setting}, + {DTYPE_GEN_LWRITE, 1, 0, 0, TRULY_CMD_DELAY, + sizeof(power_setting), power_setting}, + {DTYPE_GEN_LWRITE, 1, 0, 0, TRULY_CMD_DELAY, + sizeof(vcom_setting), vcom_setting}, + {DTYPE_GEN_LWRITE, 1, 0, 0, TRULY_CMD_DELAY, + sizeof(pannel_setting), pannel_setting}, + {DTYPE_GEN_LWRITE, 1, 0, 0, TRULY_CMD_DELAY, + sizeof(gamma_setting), gamma_setting}, + {DTYPE_GEN_LWRITE, 1, 0, 0, TRULY_CMD_DELAY, + sizeof(mipi_setting), mipi_setting}, + {DTYPE_DCS_WRITE, 1, 0, 0, TRULY_SLEEP_OFF_DELAY, + sizeof(exit_sleep), exit_sleep}, + {DTYPE_DCS_WRITE, 1, 0, 0, TRULY_DISPLAY_ON_DELAY, + sizeof(display_on), display_on}, +}; + +static int mipi_truly_lcd_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + msleep(20); + mipi_dsi_cmds_tx(mfd, &truly_tx_buf, truly_display_on_cmds, + ARRAY_SIZE(truly_display_on_cmds)); + + return 0; +} + +static int mipi_truly_lcd_off(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + mipi_dsi_cmds_tx(mfd, &truly_tx_buf, truly_display_off_cmds, + ARRAY_SIZE(truly_display_off_cmds)); + + return 0; +} + +#define BL_LEVEL 17 +static void mipi_truly_set_backlight(struct msm_fb_data_type *mfd) +{ + int step = 0, i = 0; + int bl_level = mfd->bl_level; + + /* real backlight level, 1 - max, 16 - min, 17 - off */ + bl_level = BL_LEVEL - bl_level; + + if (bl_level > prev_bl) { + step = bl_level - prev_bl; + if (bl_level == BL_LEVEL) + step--; + } else if (bl_level < prev_bl) { + step = bl_level + 16 - prev_bl; + } else { + pr_debug("%s: no change\n", __func__); + return; + } + + if (bl_level == BL_LEVEL) { + /* turn off backlight */ + mipi_truly_pdata->pmic_backlight(0); + } else { + if (prev_bl == BL_LEVEL) { + /* turn on backlight */ + mipi_truly_pdata->pmic_backlight(1); + udelay(30); + } + /* adjust backlight level */ + for (i = 0; i < step; i++) { + mipi_truly_pdata->pmic_backlight(0); + udelay(1); + mipi_truly_pdata->pmic_backlight(1); + udelay(1); + } + } + msleep(20); + prev_bl = bl_level; + + return; +} + +static int mipi_truly_lcd_probe(struct platform_device *pdev) +{ + if (pdev->id == 0) { + mipi_truly_pdata = pdev->dev.platform_data; + return 0; + } + + msm_fb_add_device(pdev); + + return 0; +} + +static struct platform_driver this_driver = { + .probe = mipi_truly_lcd_probe, + .driver = { + .name = "mipi_truly", + }, +}; + +static struct msm_fb_panel_data truly_panel_data = { + .on = mipi_truly_lcd_on, + .off = mipi_truly_lcd_off, + .set_backlight = mipi_truly_set_backlight, +}; + +static int ch_used[3]; + +int mipi_truly_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel) +{ + struct platform_device *pdev = NULL; + int ret; + + if ((channel >= 3) || ch_used[channel]) + return -ENODEV; + + ch_used[channel] = TRUE; + + pdev = platform_device_alloc("mipi_truly", (panel << 8)|channel); + + if (!pdev) + return -ENOMEM; + + truly_panel_data.panel_info = *pinfo; + + ret = platform_device_add_data(pdev, &truly_panel_data, + sizeof(truly_panel_data)); + if (ret) { + pr_err("%s: platform_device_add_data failed!\n", __func__); + goto err_device_put; + } + + ret = platform_device_add(pdev); + + if (ret) { + pr_err("%s: platform_device_register failed!\n", __func__); + goto err_device_put; + } + + return 0; + +err_device_put: + platform_device_put(pdev); + return ret; +} + +static int __init mipi_truly_lcd_init(void) +{ + mipi_dsi_buf_alloc(&truly_tx_buf, DSI_BUF_SIZE); + mipi_dsi_buf_alloc(&truly_rx_buf, DSI_BUF_SIZE); + + return platform_driver_register(&this_driver); +} + +module_init(mipi_truly_lcd_init); diff --git a/drivers/video/msm/mipi_truly.h b/drivers/video/msm/mipi_truly.h new file mode 100644 index 000000000000..4c12ff997550 --- /dev/null +++ b/drivers/video/msm/mipi_truly.h @@ -0,0 +1,21 @@ +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef MIPI_TRULY_H +#define MIPI_TRULY_H + +/* #define MIPI_TRULY_FAKE_PANEL */ /* FAKE PANEL for test */ + +int mipi_truly_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel); + +#endif /* MIPI_TRULY_H */ diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e.c b/drivers/video/msm/mipi_truly_tft540960_1_e.c new file mode 100644 index 000000000000..6de37381ac1e --- /dev/null +++ b/drivers/video/msm/mipi_truly_tft540960_1_e.c @@ -0,0 +1,817 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_truly_tft540960_1_e.h" + +static struct msm_panel_common_pdata *mipi_truly_pdata; +static struct dsi_buf truly_tx_buf; +static struct dsi_buf truly_rx_buf; + +#define TRULY_CMD_DELAY 0 +#define MIPI_SETTING_DELAY 10 +#define TRULY_SLEEP_OFF_DELAY 150 +#define TRULY_DISPLAY_ON_DELAY 150 + +/* common setting */ +static char exit_sleep[2] = {0x11, 0x00}; +static char display_on[2] = {0x29, 0x00}; +static char display_off[2] = {0x28, 0x00}; +static char enter_sleep[2] = {0x10, 0x00}; +static char write_ram[2] = {0x2c, 0x00}; /* write ram */ + +static struct dsi_cmd_desc truly_display_off_cmds[] = { + {DTYPE_DCS_WRITE, 1, 0, 0, 150, sizeof(display_off), display_off}, + {DTYPE_DCS_WRITE, 1, 0, 0, 150, sizeof(enter_sleep), enter_sleep} +}; + + +/* TFT540960_1_E CMD mode */ +static char cmd0[5] = { + 0xFF, 0xAA, 0x55, 0x25, + 0x01, +}; + +static char cmd2[5] = { + 0xF3, 0x02, 0x03, 0x07, + 0x45, +}; + +static char cmd3[6] = { + 0xF0, 0x55, 0xAA, 0x52, + 0x08, 0x00, +}; + +static char cmd4[2] = { + 0xB1, 0xeC, +}; + +/* add 0X BD command */ +static char cmd26_2[6] = { + 0xBD, 0x01, 0x48, 0x10, 0x38, 0x01 /* 59 HZ */ +}; + +static char cmd5[5] = { + 0xB8, 0x01, 0x02, 0x02, + 0x02, +}; + +static char cmd6[4] = { + 0xBC, 0x05, 0x05, 0x05, +}; + +static char cmd7[2] = { + 0x4C, 0x11, +}; + +static char cmd8[6] = { + 0xF0, 0x55, 0xAA, 0x52, + 0x08, 0x01, +}; + +static char cmd9[4] = { + 0xB0, 0x05, 0x05, 0x05, +}; + +static char cmd10[4] = { + 0xB6, 0x44, 0x44, 0x44, +}; +static char cmd11[4] = { + 0xB1, 0x05, 0x05, 0x05, +}; + +static char cmd12[4] = { + 0xB7, 0x34, 0x34, 0x34, +}; + +static char cmd13[4] = { + 0xB3, 0x10, 0x10, 0x10, +}; + +static char cmd14[4] = { + 0xB9, 0x34, 0x34, 0x34, +}; + +static char cmd15[4] = { + 0xB4, 0x0A, 0x0A, 0x0A, +}; + +static char cmd16[4] = { + 0xBA, 0x14, 0x14, 0x14, +}; +static char cmd17[4] = { + 0xBC, 0x00, 0xA0, 0x00, +}; + +static char cmd18[4] = { + 0xBD, 0x00, 0xA0, 0x00, +}; + +static char cmd19[2] = { + 0xBE, 0x45, +}; + +static char cmd20[17] = { + 0xD1, 0x00, 0x32, 0x00, + 0x41, 0x00, 0x54, 0x00, + 0x67, 0x00, 0x7A, 0x00, + 0x98, 0x00, 0xB0, 0x00, + 0xDB, +}; + +static char cmd21[17] = { + 0xD2, 0x01, 0x01, 0x01, + 0x3F, 0x01, 0x70, 0x01, + 0xB4, 0x01, 0xEC, 0x01, + 0xED, 0x02, 0x1E, 0x02, + 0x51, +}; + +static char cmd22[17] = { + 0xD3, 0x02, 0x6C, 0x02, + 0x8D, 0x02, 0xA5, 0x02, + 0xC9, 0x02, 0xEA, 0x03, + 0x19, 0x03, 0x45, 0x03, + 0x7A, +}; + +static char cmd23[5] = { + 0xD4, 0x03, 0xB0, 0x03, + 0xF4, +}; + +static char cmd24[17] = { + 0xD5, 0x00, 0x32, 0x00, + 0x41, 0x00, 0x54, 0x00, + 0x67, 0x00, 0x7A, 0x00, + 0x98, 0x00, 0xB0, 0x00, + 0xDB, +}; +static char cmd25[17] = { + 0xD6, 0x01, 0x01, 0x01, + 0x3F, 0x01, 0x70, 0x01, + 0xB4, 0x01, 0xEC, 0x01, + 0xED, 0x02, 0x1E, 0x02, + 0x51, +}; + +static char cmd26[17] = { + 0xD7, 0x02, 0x6C, 0x02, + 0x8D, 0x02, 0xA5, 0x02, + 0xC9, 0x02, 0xEA, 0x03, + 0x19, 0x03, 0x45, 0x03, + 0x7A, +}; +static char cmd27[5] = { + 0xD8, 0x03, 0xB0, 0x03, + 0xF4, +}; + + +static char cmd28[17] = { + 0xD9, 0x00, 0x32, 0x00, + 0x41, 0x00, 0x54, 0x00, + 0x67, 0x00, 0x7A, 0x00, + 0x98, 0x00, 0xB0, 0x00, + 0xDB, +}; + +static char cmd29[17] = { + 0xDD, 0x01, 0x01, 0x01, + 0x3F, 0x01, 0x70, 0x01, + 0xB4, 0x01, 0xEC, 0x01, + 0xED, 0x02, 0x1E, 0x02, + 0x51, +}; +static char cmd30[17] = { + 0xDE, 0x02, 0x6C, 0x02, + 0x8D, 0x02, 0xA5, 0x02, + 0xC9, 0x02, 0xEA, 0x03, + 0x19, 0x03, 0x45, 0x03, + 0x7A, +}; + +static char cmd31[5] = { + 0xDF, 0x03, 0xB0, 0x03, + 0xF4, +}; + +static char cmd32[17] = { + 0xE0, 0x00, 0x32, 0x00, + 0x41, 0x00, 0x54, 0x00, + 0x67, 0x00, 0x7A, 0x00, + 0x98, 0x00, 0xB0, 0x00, + 0xDB, +}; + +static char cmd33[17] = { + 0xE1, 0x01, 0x01, 0x01, + 0x3F, 0x01, 0x70, 0x01, + 0xB4, 0x01, 0xEC, 0x01, + 0xED, 0x02, 0x1E, 0x02, + 0x51, +}; + +static char cmd34[17] = { + 0xE2, 0x02, 0x6C, 0x02, + 0x8D, 0x02, 0xA5, 0x02, + 0xC9, 0x02, 0xEA, 0x03, + 0x19, 0x03, 0x45, 0x03, + 0x7A, +}; + +static char cmd35[5] = { + 0xE3, 0x03, 0xB0, 0x03, + 0xF4, +}; + +static char cmd36[17] = { + 0xE4, 0x00, 0x32, 0x00, + 0x41, 0x00, 0x54, 0x00, + 0x67, 0x00, 0x7A, 0x00, + 0x98, 0x00, 0xB0, 0x00, + 0xDB, +}; +static char cmd37[17] = { + 0xE5, 0x01, 0x01, 0x01, + 0x3F, 0x01, 0x70, 0x01, + 0xB4, 0x01, 0xEC, 0x01, + 0xED, 0x02, 0x1E, 0x02, + 0x51, +}; + +static char cmd38[17] = { + 0xE6, 0x02, 0x6C, 0x02, + 0x8D, 0x02, 0xA5, 0x02, + 0xC9, 0x02, 0xEA, 0x03, + 0x19, 0x03, 0x45, 0x03, + 0x7A, +}; + +static char cmd39[5] = { + 0xE7, 0x03, 0xB0, 0x03, + 0xF4, +}; + +static char cmd40[17] = { + 0xE8, 0x00, 0x32, 0x00, + 0x41, 0x00, 0x54, 0x00, + 0x67, 0x00, 0x7A, 0x00, + 0x98, 0x00, 0xB0, 0x00, + 0xDB, +}; + +static char cmd41[17] = { + 0xE9, 0x01, 0x01, 0x01, + 0x3F, 0x01, 0x70, 0x01, + 0xB4, 0x01, 0xEC, 0x01, + 0xED, 0x02, 0x1E, 0x02, + 0x51, +}; + +static char cmd42[17] = { + 0xEA, 0x02, 0x6C, 0x02, + 0x8D, 0x02, 0xA5, 0x02, + 0xC9, 0x02, 0xEA, 0x03, + 0x19, 0x03, 0x45, 0x03, + 0x7A, +}; + +static char cmd43[5] = { + 0xEB, 0x03, 0xB0, 0x03, + 0xF4, +}; + +static char cmd44[2] = { + 0x3A, 0x07, +}; + +static char cmd45[2] = { + 0x35, 0x00, +}; + + +static struct dsi_cmd_desc truly_cmd_display_on_cmds[] = { + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd0), cmd0}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd2), cmd2}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd3), cmd3}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd4), cmd4}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd26_2), cmd26_2}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd5), cmd5}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd6), cmd6}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd7), cmd7}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd8), cmd8}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd9), cmd9}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd10), cmd10}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd11), cmd11}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd12), cmd12}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd13), cmd13}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd14), cmd14}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd15), cmd15}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd16), cmd16}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd17), cmd17}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd18), cmd18}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd19), cmd19}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd20), cmd20}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd21), cmd21}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd22), cmd22}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd23), cmd23}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd24), cmd24}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd25), cmd25}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd26), cmd26}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd27), cmd27}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd28), cmd28}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd29), cmd29}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd30), cmd30}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd31), cmd31}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd32), cmd32}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd33), cmd33}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd34), cmd34}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd35), cmd35}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd36), cmd36}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd37), cmd37}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd38), cmd38}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd39), cmd39}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd40), cmd40}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd41), cmd41}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd42), cmd42}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd43), cmd43}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd44), cmd44}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(cmd45), cmd45}, + {DTYPE_DCS_WRITE, 1, 0, 0, TRULY_SLEEP_OFF_DELAY, sizeof(exit_sleep), + exit_sleep}, + {DTYPE_DCS_WRITE, 1, 0, 0, TRULY_CMD_DELAY, sizeof(display_on), + display_on}, + {DTYPE_DCS_WRITE, 1, 0, 0, TRULY_CMD_DELAY, sizeof(write_ram), + write_ram}, + +}; + +/* TFT540960_1_E VIDEO mode */ +static char video0[5] = { + 0xFF, 0xAA, 0x55, 0x25, + 0x01, +}; + +static char video2[5] = { + 0xF3, 0x02, 0x03, 0x07, + 0x15, +}; + +static char video3[6] = { + 0xF0, 0x55, 0xAA, 0x52, + 0x08, 0x00, +}; + +static char video4[2] = { + 0xB1, 0xFC, +}; + +static char video5[5] = { + 0xB8, 0x01, 0x02, 0x02, + 0x02, +}; + +static char video6[4] = { + 0xBC, 0x05, 0x05, 0x05, +}; + +static char video7[2] = { + 0x4C, 0x11, +}; + +static char video8[6] = { + 0xF0, 0x55, 0xAA, 0x52, + 0x08, 0x01, +}; + +static char video9[4] = { + 0xB0, 0x05, 0x05, 0x05, +}; + +static char video10[4] = { + 0xB6, 0x44, 0x44, 0x44, +}; + +static char video11[4] = { + 0xB1, 0x05, 0x05, 0x05, +}; + +static char video12[4] = { + 0xB7, 0x34, 0x34, 0x34, +}; + +static char video13[4] = { + 0xB3, 0x10, 0x10, 0x10, +}; + +static char video14[4] = { + 0xB9, 0x34, 0x34, 0x34, +}; + +static char video15[4] = { + 0xB4, 0x0A, 0x0A, 0x0A, +}; + +static char video16[4] = { + 0xBA, 0x14, 0x14, 0x14, +}; + +static char video17[4] = { + 0xBC, 0x00, 0xA0, 0x00, +}; + +static char video18[4] = { + 0xBD, 0x00, 0xA0, 0x00, +}; + +static char video19[2] = { + 0xBE, 0x45, +}; + +static char video20[17] = { + 0xD1, 0x00, 0x32, 0x00, + 0x41, 0x00, 0x54, 0x00, + 0x67, 0x00, 0x7A, 0x00, + 0x98, 0x00, 0xB0, 0x00, + 0xDB, +}; + +static char video21[17] = { + 0xD2, 0x01, 0x01, 0x01, + 0x3F, 0x01, 0x70, 0x01, + 0xB4, 0x01, 0xEC, 0x01, + 0xED, 0x02, 0x1E, 0x02, + 0x51, +}; + +static char video22[17] = { + 0xD3, 0x02, 0x6C, 0x02, + 0x8D, 0x02, 0xA5, 0x02, + 0xC9, 0x02, 0xEA, 0x03, + 0x19, 0x03, 0x45, 0x03, + 0x7A, +}; + +static char video23[5] = { + 0xD4, 0x03, 0xB0, 0x03, + 0xF4, +}; + +static char video24[17] = { + 0xD5, 0x00, 0x32, 0x00, + 0x41, 0x00, 0x54, 0x00, + 0x67, 0x00, 0x7A, 0x00, + 0x98, 0x00, 0xB0, 0x00, + 0xDB, +}; + +static char video25[17] = { + 0xD6, 0x01, 0x01, 0x01, + 0x3F, 0x01, 0x70, 0x01, + 0xB4, 0x01, 0xEC, 0x01, + 0xED, 0x02, 0x1E, 0x02, + 0x51, +}; + +static char video26[17] = { + 0xD7, 0x02, 0x6C, 0x02, + 0x8D, 0x02, 0xA5, 0x02, + 0xC9, 0x02, 0xEA, 0x03, + 0x19, 0x03, 0x45, 0x03, + 0x7A, +}; + +static char video27[5] = { + 0xD8, 0x03, 0xB0, 0x03, + 0xF4, +}; + +static char video28[17] = { + 0xD9, 0x00, 0x32, 0x00, + 0x41, 0x00, 0x54, 0x00, + 0x67, 0x00, 0x7A, 0x00, + 0x98, 0x00, 0xB0, 0x00, + 0xDB, +}; + +static char video29[17] = { + 0xDD, 0x01, 0x01, 0x01, + 0x3F, 0x01, 0x70, 0x01, + 0xB4, 0x01, 0xEC, 0x01, + 0xED, 0x02, 0x1E, 0x02, + 0x51, +}; + +static char video30[17] = { + 0xDE, 0x02, 0x6C, 0x02, + 0x8D, 0x02, 0xA5, 0x02, + 0xC9, 0x02, 0xEA, 0x03, + 0x19, 0x03, 0x45, 0x03, + 0x7A, +}; + +static char video31[5] = { + 0xDF, 0x03, 0xB0, 0x03, + 0xF4, +}; + +static char video32[17] = { + 0xE0, 0x00, 0x32, 0x00, + 0x41, 0x00, 0x54, 0x00, + 0x67, 0x00, 0x7A, 0x00, + 0x98, 0x00, 0xB0, 0x00, + 0xDB, +}; + +static char video33[17] = { + 0xE1, 0x01, 0x01, 0x01, + 0x3F, 0x01, 0x70, 0x01, + 0xB4, 0x01, 0xEC, 0x01, + 0xED, 0x02, 0x1E, 0x02, + 0x51, +}; + +static char video34[17] = { + 0xE2, 0x02, 0x6C, 0x02, + 0x8D, 0x02, 0xA5, 0x02, + 0xC9, 0x02, 0xEA, 0x03, + 0x19, 0x03, 0x45, 0x03, + 0x7A, +}; + +static char video35[5] = { + 0xE3, 0x03, 0xB0, 0x03, + 0xF4, +}; + +static char video36[17] = { + 0xE4, 0x00, 0x32, 0x00, + 0x41, 0x00, 0x54, 0x00, + 0x67, 0x00, 0x7A, 0x00, + 0x98, 0x00, 0xB0, 0x00, + 0xDB, +}; + +static char video37[17] = { + 0xE5, 0x01, 0x01, 0x01, + 0x3F, 0x01, 0x70, 0x01, + 0xB4, 0x01, 0xEC, 0x01, + 0xED, 0x02, 0x1E, 0x02, + 0x51, +}; + +static char video38[17] = { + 0xE6, 0x02, 0x6C, 0x02, + 0x8D, 0x02, 0xA5, 0x02, + 0xC9, 0x02, 0xEA, 0x03, + 0x19, 0x03, 0x45, 0x03, + 0x7A, +}; + +static char video39[5] = { + 0xE7, 0x03, 0xB0, 0x03, + 0xF4, +}; + +static char video40[17] = { + 0xE8, 0x00, 0x32, 0x00, + 0x41, 0x00, 0x54, 0x00, + 0x67, 0x00, 0x7A, 0x00, + 0x98, 0x00, 0xB0, 0x00, + 0xDB, +}; + +static char video41[17] = { + 0xE9, 0x01, 0x01, 0x01, + 0x3F, 0x01, 0x70, 0x01, + 0xB4, 0x01, 0xEC, 0x01, + 0xED, 0x02, 0x1E, 0x02, + 0x51, +}; + +static char video42[17] = { + 0xEA, 0x02, 0x6C, 0x02, + 0x8D, 0x02, 0xA5, 0x02, + 0xC9, 0x02, 0xEA, 0x03, + 0x19, 0x03, 0x45, 0x03, + 0x7A, +}; + +static char video43[5] = { + 0xEB, 0x03, 0xB0, 0x03, + 0xF4, +}; + +static char video44[2] = { + 0x3A, 0x07, +}; + +static char video45[2] = { + 0x35, 0x00, +}; + +static struct dsi_cmd_desc truly_video_display_on_cmds[] = { + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video0), video0}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video2), video2}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video3), video3}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video4), video4}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video5), video5}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video6), video6}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video7), video7}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video8), video8}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video9), video9}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video10), video10}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video11), video11}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video12), video12}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video13), video13}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video14), video14}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video15), video15}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video16), video16}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video17), video17}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video18), video18}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video19), video19}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video20), video20}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video21), video21}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video22), video22}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video23), video23}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video24), video24}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video25), video25}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video26), video26}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video27), video27}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video28), video28}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video29), video29}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video30), video30}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video31), video31}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video32), video32}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video33), video33}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video34), video34}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video35), video35}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video36), video36}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video37), video37}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video38), video38}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video39), video39}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video40), video40}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video41), video41}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video42), video42}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video43), video43}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video44), video44}, + {DTYPE_GEN_LWRITE, 1, 0, 0, 0, sizeof(video45), video45}, + + {DTYPE_DCS_WRITE, 1, 0, 0, 150, sizeof(exit_sleep), exit_sleep}, + {DTYPE_DCS_WRITE, 1, 0, 0, 50, sizeof(display_on), display_on}, +}; + +static int mipi_truly_lcd_on(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct mipi_panel_info *mipi; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + mipi = &mfd->panel_info.mipi; + pr_info("%s: mode = %d\n", __func__, mipi->mode); + msleep(120); + + if (mipi->mode == DSI_VIDEO_MODE) { + mipi_dsi_cmds_tx(mfd, &truly_tx_buf, + truly_video_display_on_cmds, + ARRAY_SIZE(truly_video_display_on_cmds)); + } else if (mipi->mode == DSI_CMD_MODE) { + mipi_dsi_cmds_tx(mfd, &truly_tx_buf, + truly_cmd_display_on_cmds, + ARRAY_SIZE(truly_cmd_display_on_cmds)); + } + + return 0; +} + +static int mipi_truly_lcd_off(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + if (mfd->key != MFD_KEY) + return -EINVAL; + + mipi_dsi_cmds_tx(mfd, &truly_tx_buf, truly_display_off_cmds, + ARRAY_SIZE(truly_display_off_cmds)); + + return 0; +} + +static int mipi_truly_lcd_probe(struct platform_device *pdev) +{ + int rc = 0; + + if (pdev->id == 0) { + mipi_truly_pdata = pdev->dev.platform_data; + if (mipi_truly_pdata->bl_lock) + spin_lock_init(&mipi_truly_pdata->bl_spinlock); + return rc; + } + + msm_fb_add_device(pdev); + + return rc; +} + +static struct platform_driver this_driver = { + .probe = mipi_truly_lcd_probe, + .driver = { + .name = "mipi_truly_tft540960_1_e", + }, +}; + +static void mipi_truly_set_backlight(struct msm_fb_data_type *mfd) +{ + int bl_level; + unsigned long flags; + bl_level = mfd->bl_level; + + if (mipi_truly_pdata->bl_lock) { + spin_lock_irqsave(&mipi_truly_pdata->bl_spinlock, flags); + mipi_truly_pdata->pmic_backlight(bl_level); + spin_unlock_irqrestore(&mipi_truly_pdata->bl_spinlock, flags); + } else + mipi_truly_pdata->pmic_backlight(bl_level); +} + +static struct msm_fb_panel_data truly_panel_data = { + .on = mipi_truly_lcd_on, + .off = mipi_truly_lcd_off, + .set_backlight = mipi_truly_set_backlight, +}; + +static int ch_used[3]; + +static int mipi_truly_tft540960_1_e_lcd_init(void) +{ + mipi_dsi_buf_alloc(&truly_tx_buf, DSI_BUF_SIZE); + mipi_dsi_buf_alloc(&truly_rx_buf, DSI_BUF_SIZE); + + return platform_driver_register(&this_driver); +} +int mipi_truly_tft540960_1_e_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel) +{ + struct platform_device *pdev = NULL; + int ret; + + if ((channel >= 3) || ch_used[channel]) + return -ENODEV; + + ch_used[channel] = TRUE; + + ret = mipi_truly_tft540960_1_e_lcd_init(); + if (ret) { + pr_err("%s: platform_device_register failed!\n", __func__); + return ret; + } + + pdev = platform_device_alloc("mipi_truly_tft540960_1_e", + (panel << 8)|channel); + if (!pdev) + return -ENOMEM; + + truly_panel_data.panel_info = *pinfo; + + ret = platform_device_add_data(pdev, &truly_panel_data, + sizeof(truly_panel_data)); + if (ret) { + pr_err("%s: platform_device_add_data failed!\n", __func__); + goto err_device_put; + } + + ret = platform_device_add(pdev); + if (ret) { + pr_err("%s: platform_device_register failed!\n", __func__); + goto err_device_put; + } + + return 0; + +err_device_put: + platform_device_put(pdev); + return ret; +} diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e.h b/drivers/video/msm/mipi_truly_tft540960_1_e.h new file mode 100644 index 000000000000..d7329d6a8148 --- /dev/null +++ b/drivers/video/msm/mipi_truly_tft540960_1_e.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef MIPI_TRULY_H +#define MIPI_TRULY_H + +int mipi_truly_tft540960_1_e_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel); + +#endif /* MIPI_TRULY_H */ diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c b/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c new file mode 100644 index 000000000000..1e42c9b56aff --- /dev/null +++ b/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c @@ -0,0 +1,98 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_truly_tft540960_1_e.h" + +static struct msm_panel_info pinfo; + +static struct mipi_dsi_phy_ctrl dsi_cmd_mode_phy_db = { + /* DSI Bit Clock at 500 MHz, 2 lane, RGB888 */ + /* regulator */ + {0x03, 0x01, 0x01, 0x00}, + /* timing */ + {0xb9, 0x8e, 0x1f, 0x00, 0x98, 0x9c, 0x22, 0x90, + 0x18, 0x03, 0x04}, + /* phy ctrl */ + {0x7f, 0x00, 0x00, 0x00}, + /* strength */ + {0xbb, 0x02, 0x06, 0x00}, + /* pll control */ + {0x01, 0xec, 0x31, 0xd2, 0x00, 0x40, 0x37, 0x62, + 0x01, 0x0f, 0x07, + 0x05, 0x14, 0x03, 0x0, 0x0, 0x0, 0x20, 0x0, 0x02, 0x0}, +}; + +static int mipi_cmd_truly_qhd_pt_init(void) +{ + int ret; + if (msm_fb_detect_client("mipi_cmd_truly_qhd")) + return 0; + + pinfo.xres = 540; + pinfo.yres = 960; + pinfo.type = MIPI_CMD_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.lcdc.h_back_porch = 100; + pinfo.lcdc.h_front_porch = 100; + pinfo.lcdc.h_pulse_width = 8; + pinfo.lcdc.v_back_porch = 20; + pinfo.lcdc.v_front_porch = 20; + pinfo.lcdc.v_pulse_width = 1; + + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + pinfo.lcdc.hsync_skew = 0; + pinfo.bl_max = 31; + pinfo.bl_min = 1; + pinfo.fb_num = 2; + + pinfo.clk_rate = 499000000; + + pinfo.lcd.vsync_enable = TRUE; + pinfo.lcd.hw_vsync_mode = TRUE; + pinfo.lcd.refx100 = 6100; /* adjust refx100 to prevent tearing */ + + pinfo.mipi.mode = DSI_CMD_MODE; + pinfo.mipi.dst_format = DSI_CMD_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.rgb_swap = DSI_RGB_SWAP_RGB; + pinfo.mipi.data_lane0 = TRUE; + pinfo.mipi.data_lane1 = TRUE; + pinfo.mipi.t_clk_post = 0x20; + pinfo.mipi.t_clk_pre = 0x2F; + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_SW_TE; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.te_sel = 1; /* TE from vsync gpio */ + pinfo.mipi.interleave_max = 1; + pinfo.mipi.insert_dcs_cmd = TRUE; + pinfo.mipi.wr_mem_continue = 0x3c; + pinfo.mipi.wr_mem_start = 0x2c; + pinfo.mipi.dsi_phy_db = &dsi_cmd_mode_phy_db; + pinfo.mipi.tx_eot_append = 0x01; + pinfo.mipi.rx_eot_ignore = 0x0; + pinfo.mipi.dlane_swap = 0x01; + + ret = mipi_truly_tft540960_1_e_device_register(&pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_WVGA_PT); + if (ret) + pr_err("%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mipi_cmd_truly_qhd_pt_init); diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c b/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c new file mode 100644 index 000000000000..2c5ccad2c9b1 --- /dev/null +++ b/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c @@ -0,0 +1,107 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_truly_tft540960_1_e.h" + +static struct msm_panel_info pinfo; + +static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = { + /* DSI Bit Clock at 500 MHz, 2 lane, RGB888 */ + /* regulator */ + {0x03, 0x01, 0x01, 0x00}, + /* timing */ + {0xb9, 0x8e, 0x1f, 0x00, 0x98, 0x9c, 0x22, 0x90, + 0x18, 0x03, 0x04}, + /* phy ctrl */ + {0x7f, 0x00, 0x00, 0x00}, + /* strength */ + {0xbb, 0x02, 0x06, 0x00}, + /* pll control */ + {0x00, 0xec, 0x31, 0xd2, 0x00, 0x40, 0x37, 0x62, + 0x01, 0x0f, 0x07, + 0x05, 0x14, 0x03, 0x0, 0x0, 0x0, 0x20, 0x0, 0x02, 0x0}, +}; + +static int mipi_video_truly_qhd_pt_init(void) +{ + int ret; + if (msm_fb_detect_client("mipi_video_truly_qhd")) + return 0; + + pinfo.xres = 540; + pinfo.yres = 960; + pinfo.type = MIPI_VIDEO_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.lcdc.h_back_porch = 100; + pinfo.lcdc.h_front_porch = 100; + pinfo.lcdc.h_pulse_width = 8; + pinfo.lcdc.v_back_porch = 20; + pinfo.lcdc.v_front_porch = 20; + pinfo.lcdc.v_pulse_width = 1; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + /* number of dot_clk cycles HSYNC active edge + is delayed from VSYNC active edge */ + pinfo.lcdc.hsync_skew = 0; + pinfo.clk_rate = 699000000; + pinfo.lcd.refx100 = 6000; /* FB driver calc FPS based on this value */ + pinfo.bl_max = 31; + pinfo.bl_min = 1; + pinfo.fb_num = 2; + + pinfo.mipi.mode = DSI_VIDEO_MODE; + /* send HSA and HE following VS/VE packet */ + pinfo.mipi.pulse_mode_hsa_he = TRUE; + pinfo.mipi.hfp_power_stop = TRUE; /* LP-11 during the HFP period */ + pinfo.mipi.hbp_power_stop = TRUE; /* LP-11 during the HBP period */ + pinfo.mipi.hsa_power_stop = TRUE; /* LP-11 during the HSA period */ + /* LP-11 or let Command Mode Engine send packets in + HS or LP mode for the BLLP of the last line of a frame */ + pinfo.mipi.eof_bllp_power_stop = TRUE; + /* LP-11 or let Command Mode Engine send packets in + HS or LP mode for packets sent during BLLP period */ + pinfo.mipi.bllp_power_stop = TRUE; + + pinfo.mipi.traffic_mode = DSI_BURST_MODE; + pinfo.mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.rgb_swap = DSI_RGB_SWAP_RGB; /* RGB */ + pinfo.mipi.data_lane0 = TRUE; + pinfo.mipi.data_lane1 = TRUE; + + pinfo.mipi.t_clk_post = 0x20; + pinfo.mipi.t_clk_pre = 0x2f; + + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_NONE; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.frame_rate = 60; + + pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db; + pinfo.mipi.dlane_swap = 0x01; + /* append EOT at the end of data burst */ + pinfo.mipi.tx_eot_append = 0x01; + + ret = mipi_truly_tft540960_1_e_device_register(&pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_WVGA_PT); + if (ret) + pr_err("%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mipi_video_truly_qhd_pt_init); diff --git a/drivers/video/msm/mipi_truly_video_wvga_pt.c b/drivers/video/msm/mipi_truly_video_wvga_pt.c new file mode 100644 index 000000000000..3fc14d2e8782 --- /dev/null +++ b/drivers/video/msm/mipi_truly_video_wvga_pt.c @@ -0,0 +1,108 @@ +/* Copyright (c) 2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "mipi_truly.h" + +static struct msm_panel_info pinfo; + +static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = { + /* DSI Bit Clock at 500 MHz, 2 lane, RGB888 */ + /* regulator */ + {0x03, 0x01, 0x01, 0x00}, + /* timing */ + {0xb9, 0x8e, 0x1f, 0x00, 0x98, 0x9c, 0x22, 0x90, + 0x18, 0x03, 0x04}, + /* phy ctrl */ + {0x7f, 0x00, 0x00, 0x00}, + /* strength */ + {0xbb, 0x02, 0x06, 0x00}, + /* pll control */ + {0x00, 0xec, 0x31, 0xd2, 0x00, 0x40, 0x37, 0x62, + 0x01, 0x0f, 0x07, + 0x05, 0x14, 0x03, 0x0, 0x0, 0x0, 0x20, 0x0, 0x02, 0x0}, +}; + +static int __init mipi_video_truly_wvga_pt_init(void) +{ + int ret; + + if (msm_fb_detect_client("mipi_video_truly_wvga")) + return 0; + + pinfo.xres = 480; + pinfo.yres = 800; + pinfo.type = MIPI_VIDEO_PANEL; + pinfo.pdest = DISPLAY_1; + pinfo.wait_cycle = 0; + pinfo.bpp = 24; + pinfo.lcdc.h_back_porch = 100; + pinfo.lcdc.h_front_porch = 100; + pinfo.lcdc.h_pulse_width = 8; + pinfo.lcdc.v_back_porch = 20; + pinfo.lcdc.v_front_porch = 20; + pinfo.lcdc.v_pulse_width = 1; + pinfo.lcdc.border_clr = 0; /* blk */ + pinfo.lcdc.underflow_clr = 0xff; /* blue */ + /* number of dot_clk cycles HSYNC active edge + is delayed from VSYNC active edge */ + pinfo.lcdc.hsync_skew = 0; + pinfo.clk_rate = 499000000; + pinfo.bl_max = 15; + pinfo.bl_min = 1; + pinfo.fb_num = 2; + + pinfo.mipi.mode = DSI_VIDEO_MODE; + pinfo.mipi.pulse_mode_hsa_he = TRUE; /* send HSA and HE following + VS/VE packet */ + pinfo.mipi.hfp_power_stop = TRUE; /* LP-11 during the HFP period */ + pinfo.mipi.hbp_power_stop = TRUE; /* LP-11 during the HBP period */ + pinfo.mipi.hsa_power_stop = TRUE; /* LP-11 during the HSA period */ + /* LP-11 or let Command Mode Engine send packets in + HS or LP mode for the BLLP of the last line of a frame */ + pinfo.mipi.eof_bllp_power_stop = TRUE; + /* LP-11 or let Command Mode Engine send packets in + HS or LP mode for packets sent during BLLP period */ + pinfo.mipi.bllp_power_stop = TRUE; + + pinfo.mipi.traffic_mode = DSI_BURST_MODE; + pinfo.mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888; + pinfo.mipi.vc = 0; + pinfo.mipi.rgb_swap = DSI_RGB_SWAP_RGB; /* RGB */ + pinfo.mipi.data_lane0 = TRUE; + pinfo.mipi.data_lane1 = TRUE; + + pinfo.mipi.t_clk_post = 0x20; + pinfo.mipi.t_clk_pre = 0x2f; + + pinfo.mipi.stream = 0; /* dma_p */ + pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_NONE; + pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; + pinfo.mipi.frame_rate = 60; /* FIXME */ + + pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db; + pinfo.mipi.dlane_swap = 0x01; + pinfo.mipi.tx_eot_append = 0x01; /* append EOT at the end + of data burst */ + + ret = mipi_truly_device_register(&pinfo, MIPI_DSI_PRIM, + MIPI_DSI_PANEL_WVGA_PT); + + if (ret) + pr_err("%s: failed to register device!\n", __func__); + + return ret; +} + +module_init(mipi_video_truly_wvga_pt_init); diff --git a/drivers/video/msm/msm_dss_io_7x27a.c b/drivers/video/msm/msm_dss_io_7x27a.c new file mode 100644 index 000000000000..436c12a1eee3 --- /dev/null +++ b/drivers/video/msm/msm_dss_io_7x27a.c @@ -0,0 +1,470 @@ +/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include "msm_fb.h" +#include "mipi_dsi.h" + +/* multimedia sub system sfpb */ +char *mmss_sfpb_base; +void __iomem *periph_base; + +static struct dsi_clk_desc dsicore_clk; +static struct dsi_clk_desc dsi_pclk; + +static struct clk *dsi_byte_div_clk; +static struct clk *dsi_esc_clk; +static struct clk *dsi_pixel_clk; +static struct clk *dsi_clk; +static struct clk *dsi_ref_clk; +static struct clk *mdp_dsi_pclk; +static struct clk *ahb_m_clk; +static struct clk *ahb_s_clk; +static struct clk *ebi1_dsi_clk; +int mipi_dsi_clk_on; + +int mipi_dsi_clk_init(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + dsi_esc_clk = clk_get(dev, "esc_clk"); + if (IS_ERR_OR_NULL(dsi_esc_clk)) { + printk(KERN_ERR "can't find dsi_esc_clk\n"); + dsi_esc_clk = NULL; + goto mipi_dsi_clk_err; + } + + dsi_byte_div_clk = clk_get(dev, "byte_clk"); + if (IS_ERR_OR_NULL(dsi_byte_div_clk)) { + pr_err("can't find dsi_byte_div_clk\n"); + dsi_byte_div_clk = NULL; + goto mipi_dsi_clk_err; + } + + dsi_pixel_clk = clk_get(dev, "pixel_clk"); + if (IS_ERR_OR_NULL(dsi_pixel_clk)) { + pr_err("can't find dsi_pixel_clk\n"); + dsi_pixel_clk = NULL; + goto mipi_dsi_clk_err; + } + + dsi_clk = clk_get(dev, "core_clk"); + if (IS_ERR_OR_NULL(dsi_clk)) { + pr_err("can't find dsi_clk\n"); + dsi_clk = NULL; + goto mipi_dsi_clk_err; + } + + dsi_ref_clk = clk_get(dev, "ref_clk"); + if (IS_ERR_OR_NULL(dsi_ref_clk)) { + pr_err("can't find dsi_ref_clk\n"); + dsi_ref_clk = NULL; + goto mipi_dsi_clk_err; + } + + mdp_dsi_pclk = clk_get(dev, "mdp_clk"); + if (IS_ERR_OR_NULL(mdp_dsi_pclk)) { + pr_err("can't find mdp_dsi_pclk\n"); + mdp_dsi_pclk = NULL; + goto mipi_dsi_clk_err; + } + + ahb_m_clk = clk_get(dev, "master_iface_clk"); + if (IS_ERR_OR_NULL(ahb_m_clk)) { + pr_err("can't find ahb_m_clk\n"); + ahb_m_clk = NULL; + goto mipi_dsi_clk_err; + } + + ahb_s_clk = clk_get(dev, "slave_iface_clk"); + if (IS_ERR_OR_NULL(ahb_s_clk)) { + pr_err("can't find ahb_s_clk\n"); + ahb_s_clk = NULL; + goto mipi_dsi_clk_err; + } + + ebi1_dsi_clk = clk_get(dev, "mem_clk"); + if (IS_ERR_OR_NULL(ebi1_dsi_clk)) { + pr_err("can't find ebi1_dsi_clk\n"); + ebi1_dsi_clk = NULL; + goto mipi_dsi_clk_err; + } + + return 0; + +mipi_dsi_clk_err: + mipi_dsi_clk_deinit(NULL); + return -EPERM; +} + +void mipi_dsi_clk_deinit(struct device *dev) +{ + if (mdp_dsi_pclk) + clk_put(mdp_dsi_pclk); + if (ahb_m_clk) + clk_put(ahb_m_clk); + if (ahb_s_clk) + clk_put(ahb_s_clk); + if (dsi_ref_clk) + clk_put(dsi_ref_clk); + if (dsi_byte_div_clk) + clk_put(dsi_byte_div_clk); + if (dsi_esc_clk) + clk_put(dsi_esc_clk); + if (ebi1_dsi_clk) + clk_put(ebi1_dsi_clk); +} + +static void mipi_dsi_clk_ctrl(struct dsi_clk_desc *clk, int clk_en) +{ + uint32 data; + if (clk_en) { + data = (clk->pre_div_func) << 24 | + (clk->m) << 16 | (clk->n) << 8 | + ((clk->d) * 2); + clk_set_rate(dsi_clk, data); + clk_enable(dsi_clk); + } else + clk_disable(dsi_clk); +} + +static void mipi_dsi_pclk_ctrl(struct dsi_clk_desc *clk, int clk_en) +{ + uint32 data; + + if (clk_en) { + data = (clk->pre_div_func) << 24 | (clk->m) << 16 + | (clk->n) << 8 | ((clk->d) * 2); + if ((clk_set_rate(dsi_pixel_clk, data)) < 0) + pr_err("%s: pixel clk set rate failed\n", __func__); + if (clk_enable(dsi_pixel_clk)) + pr_err("%s clk enable failed\n", __func__); + } else { + clk_disable(dsi_pixel_clk); + } +} + +static void mipi_dsi_calibration(void) +{ + MIPI_OUTP(MIPI_DSI_BASE + 0xf8, 0x00a105a1); /* cal_hw_ctrl */ +} + +#define PREF_DIV_RATIO 19 +struct dsiphy_pll_divider_config pll_divider_config; + +int mipi_dsi_clk_div_config(uint8 bpp, uint8 lanes, + uint32 *expected_dsi_pclk) +{ + u32 fb_divider, rate, vco; + u32 div_ratio = 0; + struct dsi_clk_mnd_table const *mnd_entry = mnd_table; + if (pll_divider_config.clk_rate == 0) + pll_divider_config.clk_rate = 454000000; + + rate = pll_divider_config.clk_rate / 1000000; /* In Mhz */ + + if (rate < 125) { + vco = rate * 8; + div_ratio = 8; + } else if (rate < 250) { + vco = rate * 4; + div_ratio = 4; + } else if (rate < 500) { + vco = rate * 2; + div_ratio = 2; + } else { + vco = rate * 1; + div_ratio = 1; + } + + /* find the mnd settings from mnd_table entry */ + for (; mnd_entry != mnd_table + ARRAY_SIZE(mnd_table); ++mnd_entry) { + if (((mnd_entry->lanes) == lanes) && + ((mnd_entry->bpp) == bpp)) + break; + } + + if (mnd_entry == mnd_table + ARRAY_SIZE(mnd_table)) { + pr_err("%s: requested Lanes, %u & BPP, %u, not supported\n", + __func__, lanes, bpp); + return -EINVAL; + } + fb_divider = ((vco * PREF_DIV_RATIO) / 27); + pll_divider_config.fb_divider = fb_divider; + pll_divider_config.ref_divider_ratio = PREF_DIV_RATIO; + pll_divider_config.bit_clk_divider = div_ratio; + pll_divider_config.byte_clk_divider = + pll_divider_config.bit_clk_divider * 8; + pll_divider_config.dsi_clk_divider = + (mnd_entry->dsiclk_div) * div_ratio; + + if ((mnd_entry->dsiclk_d == 0) + || (mnd_entry->dsiclk_m == 1)) { + dsicore_clk.mnd_mode = 0; + dsicore_clk.src = 0x3; + dsicore_clk.pre_div_func = (mnd_entry->dsiclk_n - 1); + } else { + dsicore_clk.mnd_mode = 2; + dsicore_clk.src = 0x3; + dsicore_clk.m = mnd_entry->dsiclk_m; + dsicore_clk.n = mnd_entry->dsiclk_n; + dsicore_clk.d = mnd_entry->dsiclk_d; + } + + if ((mnd_entry->pclk_d == 0) + || (mnd_entry->pclk_m == 1)) { + dsi_pclk.mnd_mode = 0; + dsi_pclk.src = 0x3; + dsi_pclk.pre_div_func = (mnd_entry->pclk_n - 1); + *expected_dsi_pclk = ((vco * 1000000) / + ((pll_divider_config.dsi_clk_divider) + * (mnd_entry->pclk_n))); + } else { + dsi_pclk.mnd_mode = 2; + dsi_pclk.src = 0x3; + dsi_pclk.m = mnd_entry->pclk_m; + dsi_pclk.n = mnd_entry->pclk_n; + dsi_pclk.d = mnd_entry->pclk_d; + *expected_dsi_pclk = ((vco * 1000000 * dsi_pclk.m) / + ((pll_divider_config.dsi_clk_divider) + * (mnd_entry->pclk_n))); + } + dsicore_clk.m = 1; + dsicore_clk.n = 1; + dsicore_clk.d = 2; + dsicore_clk.pre_div_func = 0; + + dsi_pclk.m = 1; + dsi_pclk.n = 3; + dsi_pclk.d = 2; + dsi_pclk.pre_div_func = 0; + return 0; +} + +void mipi_dsi_phy_init(int panel_ndx, struct msm_panel_info const *panel_info, + int target_type) +{ + struct mipi_dsi_phy_ctrl *pd; + int i, off; + + MIPI_OUTP(MIPI_DSI_BASE + 0x128, 0x0001);/* start phy sw reset */ + wmb(); + usleep(1000); + MIPI_OUTP(MIPI_DSI_BASE + 0x128, 0x0000);/* end phy w reset */ + wmb(); + usleep(1000); + MIPI_OUTP(MIPI_DSI_BASE + 0x2cc, 0x0003);/* regulator_ctrl_0 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x2d0, 0x0001);/* regulator_ctrl_1 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x2d4, 0x0001);/* regulator_ctrl_2 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x2d8, 0x0000);/* regulator_ctrl_3 */ +#ifdef DSI_POWER + MIPI_OUTP(MIPI_DSI_BASE + 0x2dc, 0x0100);/* regulator_ctrl_4 */ +#endif + + pd = (panel_info->mipi).dsi_phy_db; + + off = 0x02cc; /* regulator ctrl 0 */ + for (i = 0; i < 4; i++) { + MIPI_OUTP(MIPI_DSI_BASE + off, pd->regulator[i]); + wmb(); + off += 4; + } + + off = 0x0260; /* phy timig ctrl 0 */ + for (i = 0; i < 11; i++) { + MIPI_OUTP(MIPI_DSI_BASE + off, pd->timing[i]); + wmb(); + off += 4; + } + + off = 0x0290; /* ctrl 0 */ + for (i = 0; i < 4; i++) { + MIPI_OUTP(MIPI_DSI_BASE + off, pd->ctrl[i]); + wmb(); + off += 4; + } + + off = 0x02a0; /* strength 0 */ + for (i = 0; i < 4; i++) { + MIPI_OUTP(MIPI_DSI_BASE + off, pd->strength[i]); + wmb(); + off += 4; + } + + mipi_dsi_calibration(); + + off = 0x0204; /* pll ctrl 1, skip 0 */ + for (i = 1; i < 21; i++) { + MIPI_OUTP(MIPI_DSI_BASE + off, pd->pll[i]); + wmb(); + off += 4; + } + + MIPI_OUTP(MIPI_DSI_BASE + 0x100, 0x67); + + /* pll ctrl 0 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0200, pd->pll[0]); + wmb(); +} + +void cont_splash_clk_ctrl(int enable) +{ +} + +void mipi_dsi_prepare_clocks(void) +{ + clk_prepare(dsi_ref_clk); + clk_prepare(ahb_m_clk); + clk_prepare(ahb_s_clk); + clk_prepare(ebi1_dsi_clk); + clk_prepare(mdp_dsi_pclk); + clk_prepare(dsi_byte_div_clk); + clk_prepare(dsi_esc_clk); + clk_prepare(dsi_clk); + clk_prepare(dsi_pixel_clk); +} + +void mipi_dsi_unprepare_clocks(void) +{ + clk_unprepare(dsi_esc_clk); + clk_unprepare(dsi_byte_div_clk); + clk_unprepare(mdp_dsi_pclk); + clk_unprepare(ebi1_dsi_clk); + clk_unprepare(ahb_m_clk); + clk_unprepare(ahb_s_clk); + clk_unprepare(dsi_ref_clk); + clk_unprepare(dsi_clk); + clk_unprepare(dsi_pixel_clk); +} + +void mipi_dsi_ahb_ctrl(u32 enable) +{ + static int ahb_ctrl_done; + if (enable) { + if (ahb_ctrl_done) { + pr_info("%s: ahb clks already ON\n", __func__); + return; + } + clk_enable(dsi_ref_clk); + clk_enable(ahb_m_clk); + clk_enable(ahb_s_clk); + ahb_ctrl_done = 1; + } else { + if (ahb_ctrl_done == 0) { + pr_info("%s: ahb clks already OFF\n", __func__); + return; + } + clk_disable(ahb_m_clk); + clk_disable(ahb_s_clk); + clk_disable(dsi_ref_clk); + ahb_ctrl_done = 0; + } +} + +void mipi_dsi_clk_enable(void) +{ + unsigned data = 0; + uint32 pll_ctrl; + + if (mipi_dsi_clk_on) { + pr_info("%s: mipi_dsi_clks already ON\n", __func__); + return; + } + if (clk_set_rate(ebi1_dsi_clk, 65000000)) /* 65 MHz */ + pr_err("%s: ebi1_dsi_clk set rate failed\n", __func__); + clk_enable(ebi1_dsi_clk); + + pll_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x0200); + MIPI_OUTP(MIPI_DSI_BASE + 0x0200, pll_ctrl | 0x01); + mb(); + + clk_set_rate(dsi_byte_div_clk, data); + clk_set_rate(dsi_esc_clk, data); + clk_enable(mdp_dsi_pclk); + clk_enable(dsi_byte_div_clk); + clk_enable(dsi_esc_clk); + mipi_dsi_pclk_ctrl(&dsi_pclk, 1); + mipi_dsi_clk_ctrl(&dsicore_clk, 1); + mipi_dsi_clk_on = 1; +} + +void mipi_dsi_clk_disable(void) +{ + if (mipi_dsi_clk_on == 0) { + pr_info("%s: mipi_dsi_clks already OFF\n", __func__); + return; + } + mipi_dsi_pclk_ctrl(&dsi_pclk, 0); + mipi_dsi_clk_ctrl(&dsicore_clk, 0); + clk_disable(dsi_esc_clk); + clk_disable(dsi_byte_div_clk); + clk_disable(mdp_dsi_pclk); + /* DSIPHY_PLL_CTRL_0, disable dsi pll */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0200, 0x40); + if (clk_set_rate(ebi1_dsi_clk, 0)) + pr_err("%s: ebi1_dsi_clk set rate failed\n", __func__); + clk_disable(ebi1_dsi_clk); + mipi_dsi_clk_on = 0; +} + +void mipi_dsi_phy_ctrl(int on) +{ + if (on) { + /* DSIPHY_PLL_CTRL_5 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0214, 0x050); + + /* DSIPHY_TPA_CTRL_1 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0258, 0x00f); + + /* DSIPHY_TPA_CTRL_2 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x025c, 0x000); + } else { + /* DSIPHY_PLL_CTRL_5 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0214, 0x05f); + + /* DSIPHY_TPA_CTRL_1 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0258, 0x08f); + + /* DSIPHY_TPA_CTRL_2 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x025c, 0x001); + + /* DSIPHY_REGULATOR_CTRL_0 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x02cc, 0x02); + + /* DSIPHY_CTRL_0 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0290, 0x00); + + /* DSIPHY_CTRL_1 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0294, 0x7f); + + /* disable dsi clk */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0118, 0); + } +} + +#ifdef CONFIG_FB_MSM_MDP303 +void update_lane_config(struct msm_panel_info *pinfo) +{ + struct mipi_dsi_phy_ctrl *pd; + + pd = (pinfo->mipi).dsi_phy_db; + pinfo->mipi.data_lane1 = FALSE; + pd->pll[10] |= 0x08; + + pinfo->yres = 320; + pinfo->lcdc.h_back_porch = 15; + pinfo->lcdc.h_front_porch = 21; + pinfo->lcdc.h_pulse_width = 5; + pinfo->lcdc.v_back_porch = 50; + pinfo->lcdc.v_front_porch = 101; + pinfo->lcdc.v_pulse_width = 50; +} +#endif diff --git a/drivers/video/msm/msm_dss_io_8960.c b/drivers/video/msm/msm_dss_io_8960.c new file mode 100644 index 000000000000..c2220688f431 --- /dev/null +++ b/drivers/video/msm/msm_dss_io_8960.c @@ -0,0 +1,830 @@ +/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include "msm_fb.h" +#include "mdp.h" +#include "mdp4.h" +#include "mipi_dsi.h" +#include "hdmi_msm.h" +#include + +/* HDMI PHY macros */ +#define HDMI_PHY_REG_0 (0x00000400) +#define HDMI_PHY_REG_1 (0x00000404) +#define HDMI_PHY_REG_2 (0x00000408) +#define HDMI_PHY_REG_3 (0x0000040c) +#define HDMI_PHY_REG_4 (0x00000410) +#define HDMI_PHY_REG_5 (0x00000414) +#define HDMI_PHY_REG_6 (0x00000418) +#define HDMI_PHY_REG_7 (0x0000041c) +#define HDMI_PHY_REG_8 (0x00000420) +#define HDMI_PHY_REG_9 (0x00000424) +#define HDMI_PHY_REG_10 (0x00000428) +#define HDMI_PHY_REG_11 (0x0000042c) +#define HDMI_PHY_REG_12 (0x00000430) +#define HDMI_PHY_REG_BIST_CFG (0x00000434) +#define HDMI_PHY_DEBUG_BUS_SEL (0x00000438) +#define HDMI_PHY_REG_MISC0 (0x0000043c) +#define HDMI_PHY_REG_13 (0x00000440) +#define HDMI_PHY_REG_14 (0x00000444) +#define HDMI_PHY_REG_15 (0x00000448) +#define HDMI_PHY_CTRL (0x000002D4) + +/* HDMI PHY/PLL bit field macros */ +#define HDMI_PHY_PLL_STATUS0 (0x00000598) +#define SW_RESET BIT(2) +#define SW_RESET_PLL BIT(0) +#define PWRDN_B BIT(7) + +/* multimedia sub system clock control */ +char *mmss_cc_base = MSM_MMSS_CLK_CTL_BASE; +/* multimedia sub system sfpb */ +char *mmss_sfpb_base; +void __iomem *periph_base; + +static struct dsi_clk_desc dsicore_clk; +static struct dsi_clk_desc dsi_pclk; + +static struct clk *dsi_byte_div_clk; +static struct clk *dsi_esc_clk; +static struct clk *dsi_m_pclk; +static struct clk *dsi_s_pclk; + +static struct clk *amp_pclk; +int mipi_dsi_clk_on; + +int mipi_dsi_clk_init(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct device *dev = &pdev->dev; + + mfd = platform_get_drvdata(pdev); + + amp_pclk = clk_get(dev, "arb_clk"); + if (IS_ERR_OR_NULL(amp_pclk)) { + pr_err("can't find amp_pclk\n"); + amp_pclk = NULL; + goto mipi_dsi_clk_err; + } + + dsi_m_pclk = clk_get(dev, "master_iface_clk"); + if (IS_ERR_OR_NULL(dsi_m_pclk)) { + pr_err("can't find dsi_m_pclk\n"); + dsi_m_pclk = NULL; + goto mipi_dsi_clk_err; + } + + dsi_s_pclk = clk_get(dev, "slave_iface_clk"); + if (IS_ERR_OR_NULL(dsi_s_pclk)) { + pr_err("can't find dsi_s_pclk\n"); + dsi_s_pclk = NULL; + goto mipi_dsi_clk_err; + } + + dsi_byte_div_clk = clk_get(dev, "byte_clk"); + if (IS_ERR(dsi_byte_div_clk)) { + pr_err("can't find dsi_byte_div_clk\n"); + dsi_byte_div_clk = NULL; + goto mipi_dsi_clk_err; + } + + dsi_esc_clk = clk_get(dev, "esc_clk"); + if (IS_ERR(dsi_esc_clk)) { + printk(KERN_ERR "can't find dsi_esc_clk\n"); + dsi_esc_clk = NULL; + goto mipi_dsi_clk_err; + } + + return 0; + +mipi_dsi_clk_err: + mipi_dsi_clk_deinit(dev); + return -EPERM; +} + +void mipi_dsi_clk_deinit(struct device *dev) +{ + if (amp_pclk) + clk_put(amp_pclk); + if (amp_pclk) + clk_put(dsi_m_pclk); + if (dsi_s_pclk) + clk_put(dsi_s_pclk); + if (dsi_byte_div_clk) + clk_put(dsi_byte_div_clk); + if (dsi_esc_clk) + clk_put(dsi_esc_clk); +} + +static void mipi_dsi_clk_ctrl(struct dsi_clk_desc *clk, int clk_en) +{ + char *cc, *ns, *md; + int pmxo_sel = 0; + char mnd_en = 1, root_en = 1; + uint32 data, val; + + cc = mmss_cc_base + 0x004c; + md = mmss_cc_base + 0x0050; + ns = mmss_cc_base + 0x0054; + + if (clk_en) { + if (clk->mnd_mode == 0) { + data = clk->pre_div_func << 14; + data |= clk->src; + MIPI_OUTP_SECURE(ns, data); + MIPI_OUTP_SECURE(cc, ((pmxo_sel << 8) + | (clk->mnd_mode << 6) + | (root_en << 2) | clk_en)); + } else { + val = clk->d * 2; + data = (~val) & 0x0ff; + data |= clk->m << 8; + MIPI_OUTP_SECURE(md, data); + + val = clk->n - clk->m; + data = (~val) & 0x0ff; + data <<= 24; + data |= clk->src; + MIPI_OUTP_SECURE(ns, data); + + MIPI_OUTP_SECURE(cc, ((pmxo_sel << 8) + | (clk->mnd_mode << 6) + | (mnd_en << 5) + | (root_en << 2) | clk_en)); + } + } else + MIPI_OUTP_SECURE(cc, 0); + + wmb(); +} + +static void mipi_dsi_sfpb_cfg(void) +{ + char *sfpb; + int data; + + sfpb = mmss_sfpb_base + 0x058; + + data = MIPI_INP(sfpb); + data |= 0x01800; + MIPI_OUTP(sfpb, data); + wmb(); +} + +static void mipi_dsi_pclk_ctrl(struct dsi_clk_desc *clk, int clk_en) +{ + char *cc, *ns, *md; + char mnd_en = 1, root_en = 1; + uint32 data, val; + + cc = mmss_cc_base + 0x0130; + md = mmss_cc_base + 0x0134; + ns = mmss_cc_base + 0x0138; + + if (clk_en) { + if (clk->mnd_mode == 0) { + data = clk->pre_div_func << 12; + data |= clk->src; + MIPI_OUTP_SECURE(ns, data); + MIPI_OUTP_SECURE(cc, ((clk->mnd_mode << 6) + | (root_en << 2) | clk_en)); + } else { + val = clk->d * 2; + data = (~val) & 0x0ff; + data |= clk->m << 8; + MIPI_OUTP_SECURE(md, data); + + val = clk->n - clk->m; + data = (~val) & 0x0ff; + data <<= 24; + data |= clk->src; + MIPI_OUTP_SECURE(ns, data); + + MIPI_OUTP_SECURE(cc, ((clk->mnd_mode << 6) + | (mnd_en << 5) + | (root_en << 2) | clk_en)); + } + } else + MIPI_OUTP_SECURE(cc, 0); + + wmb(); +} + +static void mipi_dsi_ahb_en(void) +{ + char *ahb; + + ahb = mmss_cc_base + 0x08; + + pr_debug("%s: ahb=%x %x\n", + __func__, (int) ahb, MIPI_INP_SECURE(ahb)); +} + +void mipi_dsi_lane_cfg(void) +{ + int i, ln_offset; + + ln_offset = 0x300; + for (i = 0; i < 4; i++) { + /* DSI1_DSIPHY_LN_CFG0 */ + MIPI_OUTP(MIPI_DSI_BASE + ln_offset, 0x80); + /* DSI1_DSIPHY_LN_CFG1 */ + MIPI_OUTP(MIPI_DSI_BASE + ln_offset + 0x04, 0x45); + /* DSI1_DSIPHY_LN_CFG2 */ + MIPI_OUTP(MIPI_DSI_BASE + ln_offset + 0x08, 0x0); + /* DSI1_DSIPHY_LN_TEST_DATAPATH */ + MIPI_OUTP(MIPI_DSI_BASE + ln_offset + 0x0c, 0x0); + /* DSI1_DSIPHY_LN_TEST_STR0 */ + MIPI_OUTP(MIPI_DSI_BASE + ln_offset + 0x14, 0x1); + /* DSI1_DSIPHY_LN_TEST_STR1 */ + MIPI_OUTP(MIPI_DSI_BASE + ln_offset + 0x18, 0x66); + ln_offset += 0x40; + } + + MIPI_OUTP(MIPI_DSI_BASE + 0x0400, 0x40); /* DSI1_DSIPHY_LNCK_CFG0 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0404, 0x67); /* DSI1_DSIPHY_LNCK_CFG1 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0408, 0x0); /* DSI1_DSIPHY_LNCK_CFG2 */ + /* DSI1_DSIPHY_LNCK_TEST_DATAPATH */ + MIPI_OUTP(MIPI_DSI_BASE + 0x040c, 0x0); + MIPI_OUTP(MIPI_DSI_BASE + 0x0414, 0x1); /* DSI1_DSIPHY_LNCK_TEST_STR0 */ + /* DSI1_DSIPHY_LNCK_TEST_STR1 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0418, 0x88); +} + +void mipi_dsi_bist_ctrl(void) +{ + MIPI_OUTP(MIPI_DSI_BASE + 0x049c, 0x0f); /* DSI1_DSIPHY_BIST_CTRL4 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0490, 0x03); /* DSI1_DSIPHY_BIST_CTRL1 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x048c, 0x03); /* DSI1_DSIPHY_BIST_CTRL0 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x049c, 0x0); /* DSI1_DSIPHY_BIST_CTRL4 */ +} + +static void mipi_dsi_calibration(void) +{ + int i = 0; + uint32 term_cnt = 5000; + int cal_busy = MIPI_INP(MIPI_DSI_BASE + 0x550); + + /* DSI1_DSIPHY_REGULATOR_CAL_PWR_CFG */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0518, 0x03); + + /* DSI1_DSIPHY_CAL_SW_CFG2 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0534, 0x0); + /* DSI1_DSIPHY_CAL_HW_CFG1 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x053c, 0x5a); + /* DSI1_DSIPHY_CAL_HW_CFG3 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0544, 0x10); + /* DSI1_DSIPHY_CAL_HW_CFG4 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0548, 0x01); + /* DSI1_DSIPHY_CAL_HW_CFG0 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0538, 0x01); + + /* DSI1_DSIPHY_CAL_HW_TRIGGER */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0528, 0x01); + usleep_range(5000, 5000); + /* DSI1_DSIPHY_CAL_HW_TRIGGER */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0528, 0x00); + + cal_busy = MIPI_INP(MIPI_DSI_BASE + 0x550); + while (cal_busy & 0x10) { + i++; + if (i > term_cnt) { + pr_err("DSI1 PHY REGULATOR NOT READY," + "exceeded polling TIMEOUT!\n"); + break; + } + cal_busy = MIPI_INP(MIPI_DSI_BASE + 0x550); + } +} + +void mipi_dsi_phy_rdy_poll(void) +{ + uint32 phy_pll_busy; + uint32 i = 0; + uint32 term_cnt = 0xFFFFFF; + + phy_pll_busy = MIPI_INP(MIPI_DSI_BASE + 0x280); + while (!(phy_pll_busy & 0x1)) { + i++; + if (i > term_cnt) { + pr_err("DSI1 PHY NOT READY, exceeded polling TIMEOUT!\n"); + break; + } + phy_pll_busy = MIPI_INP(MIPI_DSI_BASE + 0x280); + } +} + +#define PREF_DIV_RATIO 27 +struct dsiphy_pll_divider_config pll_divider_config; + +int mipi_dsi_phy_pll_config(u32 clk_rate) +{ + struct dsiphy_pll_divider_config *dividers; + u32 fb_divider, tmp; + dividers = &pll_divider_config; + + /* DSIPHY_PLL_CTRL_x: 1 2 3 8 9 10 */ + /* masks 0xff 0x07 0x3f 0x0f 0xff 0xff */ + + /* DSIPHY_PLL_CTRL_1 */ + fb_divider = ((dividers->fb_divider) / 2) - 1; + MIPI_OUTP(MIPI_DSI_BASE + 0x204, fb_divider & 0xff); + + /* DSIPHY_PLL_CTRL_2 */ + tmp = MIPI_INP(MIPI_DSI_BASE + 0x208); + tmp &= ~0x07; + tmp |= (fb_divider >> 8) & 0x07; + MIPI_OUTP(MIPI_DSI_BASE + 0x208, tmp); + + /* DSIPHY_PLL_CTRL_3 */ + tmp = MIPI_INP(MIPI_DSI_BASE + 0x20c); + tmp &= ~0x3f; + tmp |= (dividers->ref_divider_ratio - 1) & 0x3f; + MIPI_OUTP(MIPI_DSI_BASE + 0x20c, tmp); + + /* DSIPHY_PLL_CTRL_8 */ + tmp = MIPI_INP(MIPI_DSI_BASE + 0x220); + tmp &= ~0x0f; + tmp |= (dividers->bit_clk_divider - 1) & 0x0f; + MIPI_OUTP(MIPI_DSI_BASE + 0x220, tmp); + + /* DSIPHY_PLL_CTRL_9 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x224, (dividers->byte_clk_divider - 1)); + + /* DSIPHY_PLL_CTRL_10 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x228, (dividers->dsi_clk_divider - 1)); + + return 0; +} + +int mipi_dsi_clk_div_config(uint8 bpp, uint8 lanes, + uint32 *expected_dsi_pclk) +{ + u32 fb_divider, rate, vco; + u32 div_ratio = 0; + struct dsi_clk_mnd_table const *mnd_entry = mnd_table; + if (pll_divider_config.clk_rate == 0) + pll_divider_config.clk_rate = 454000000; + + rate = pll_divider_config.clk_rate / 1000000; /* In Mhz */ + + if (rate < 125) { + vco = rate * 8; + div_ratio = 8; + } else if (rate < 250) { + vco = rate * 4; + div_ratio = 4; + } else if (rate < 600) { + vco = rate * 2; + div_ratio = 2; + } else { + vco = rate * 1; + div_ratio = 1; + } + + /* find the mnd settings from mnd_table entry */ + for (; mnd_entry != mnd_table + ARRAY_SIZE(mnd_table); ++mnd_entry) { + if (((mnd_entry->lanes) == lanes) && + ((mnd_entry->bpp) == bpp)) + break; + } + + if (mnd_entry == mnd_table + ARRAY_SIZE(mnd_table)) { + pr_err("%s: requested Lanes, %u & BPP, %u, not supported\n", + __func__, lanes, bpp); + return -EINVAL; + } + fb_divider = ((vco * PREF_DIV_RATIO) / 27); + pll_divider_config.fb_divider = fb_divider; + pll_divider_config.ref_divider_ratio = PREF_DIV_RATIO; + pll_divider_config.bit_clk_divider = div_ratio; + pll_divider_config.byte_clk_divider = + pll_divider_config.bit_clk_divider * 8; + pll_divider_config.dsi_clk_divider = + (mnd_entry->dsiclk_div) * div_ratio; + + if (mnd_entry->dsiclk_d == 0) { + dsicore_clk.mnd_mode = 0; + dsicore_clk.src = 0x3; + dsicore_clk.pre_div_func = (mnd_entry->dsiclk_n - 1); + } else { + dsicore_clk.mnd_mode = 2; + dsicore_clk.src = 0x3; + dsicore_clk.m = mnd_entry->dsiclk_m; + dsicore_clk.n = mnd_entry->dsiclk_n; + dsicore_clk.d = mnd_entry->dsiclk_d; + } + + if ((mnd_entry->pclk_d == 0) + || (mnd_entry->pclk_m == 1)) { + dsi_pclk.mnd_mode = 0; + dsi_pclk.src = 0x3; + dsi_pclk.pre_div_func = (mnd_entry->pclk_n - 1); + *expected_dsi_pclk = ((vco * 1000000) / + ((pll_divider_config.dsi_clk_divider) + * (mnd_entry->pclk_n))); + } else { + dsi_pclk.mnd_mode = 2; + dsi_pclk.src = 0x3; + dsi_pclk.m = mnd_entry->pclk_m; + dsi_pclk.n = mnd_entry->pclk_n; + dsi_pclk.d = mnd_entry->pclk_d; + *expected_dsi_pclk = ((vco * 1000000 * dsi_pclk.m) / + ((pll_divider_config.dsi_clk_divider) + * (mnd_entry->pclk_n))); + } + return 0; +} + +static void mipi_dsi_configure_serdes(void) +{ + void __iomem *cc; + + /* PHY registers programemd thru S2P interface */ + if (periph_base) { + MIPI_OUTP(periph_base + 0x2c, 0x000000b6); + MIPI_OUTP(periph_base + 0x2c, 0x000001b5); + MIPI_OUTP(periph_base + 0x2c, 0x000001b4); + MIPI_OUTP(periph_base + 0x2c, 0x000003b3); + MIPI_OUTP(periph_base + 0x2c, 0x000003a2); + MIPI_OUTP(periph_base + 0x2c, 0x000002a1); + MIPI_OUTP(periph_base + 0x2c, 0x000008a0); + MIPI_OUTP(periph_base + 0x2c, 0x00000d9f); + MIPI_OUTP(periph_base + 0x2c, 0x0000109e); + MIPI_OUTP(periph_base + 0x2c, 0x0000209d); + MIPI_OUTP(periph_base + 0x2c, 0x0000109c); + MIPI_OUTP(periph_base + 0x2c, 0x0000079a); + MIPI_OUTP(periph_base + 0x2c, 0x00000c99); + MIPI_OUTP(periph_base + 0x2c, 0x00002298); + MIPI_OUTP(periph_base + 0x2c, 0x000000a7); + MIPI_OUTP(periph_base + 0x2c, 0x000000a6); + MIPI_OUTP(periph_base + 0x2c, 0x000000a5); + MIPI_OUTP(periph_base + 0x2c, 0x00007fa4); + MIPI_OUTP(periph_base + 0x2c, 0x0000eea8); + MIPI_OUTP(periph_base + 0x2c, 0x000006aa); + MIPI_OUTP(periph_base + 0x2c, 0x00002095); + MIPI_OUTP(periph_base + 0x2c, 0x00000493); + MIPI_OUTP(periph_base + 0x2c, 0x00001092); + MIPI_OUTP(periph_base + 0x2c, 0x00000691); + MIPI_OUTP(periph_base + 0x2c, 0x00005490); + MIPI_OUTP(periph_base + 0x2c, 0x0000038d); + MIPI_OUTP(periph_base + 0x2c, 0x0000148c); + MIPI_OUTP(periph_base + 0x2c, 0x0000058b); + MIPI_OUTP(periph_base + 0x2c, 0x0000078a); + MIPI_OUTP(periph_base + 0x2c, 0x00001f89); + MIPI_OUTP(periph_base + 0x2c, 0x00003388); + MIPI_OUTP(periph_base + 0x2c, 0x00006387); + MIPI_OUTP(periph_base + 0x2c, 0x00004886); + MIPI_OUTP(periph_base + 0x2c, 0x00005085); + MIPI_OUTP(periph_base + 0x2c, 0x00000084); + MIPI_OUTP(periph_base + 0x2c, 0x0000da83); + MIPI_OUTP(periph_base + 0x2c, 0x0000b182); + MIPI_OUTP(periph_base + 0x2c, 0x00002f81); + MIPI_OUTP(periph_base + 0x2c, 0x00004080); + MIPI_OUTP(periph_base + 0x2c, 0x00004180); + MIPI_OUTP(periph_base + 0x2c, 0x000006aa); + } + + cc = MIPI_DSI_BASE + 0x0130; + MIPI_OUTP(cc, 0x806c11c8); + MIPI_OUTP(cc, 0x804c11c8); + MIPI_OUTP(cc, 0x806d0080); + MIPI_OUTP(cc, 0x804d0080); + MIPI_OUTP(cc, 0x00000000); + MIPI_OUTP(cc, 0x807b1597); + MIPI_OUTP(cc, 0x805b1597); + MIPI_OUTP(cc, 0x807c0080); + MIPI_OUTP(cc, 0x805c0080); + MIPI_OUTP(cc, 0x00000000); + MIPI_OUTP(cc, 0x807911c8); + MIPI_OUTP(cc, 0x805911c8); + MIPI_OUTP(cc, 0x807a0080); + MIPI_OUTP(cc, 0x805a0080); + MIPI_OUTP(cc, 0x00000000); + MIPI_OUTP(cc, 0x80721555); + MIPI_OUTP(cc, 0x80521555); + MIPI_OUTP(cc, 0x80730000); + MIPI_OUTP(cc, 0x80530000); + MIPI_OUTP(cc, 0x00000000); +} + +void mipi_dsi_phy_init(int panel_ndx, struct msm_panel_info const *panel_info, + int target_type) +{ + struct mipi_dsi_phy_ctrl *pd; + int i, off; + + MIPI_OUTP(MIPI_DSI_BASE + 0x128, 0x0001);/* start phy sw reset */ + wmb(); + usleep(1); + MIPI_OUTP(MIPI_DSI_BASE + 0x128, 0x0000);/* end phy w reset */ + wmb(); + usleep(1); + MIPI_OUTP(MIPI_DSI_BASE + 0x500, 0x0003);/* regulator_ctrl_0 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x504, 0x0001);/* regulator_ctrl_1 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x508, 0x0001);/* regulator_ctrl_2 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x50c, 0x0000);/* regulator_ctrl_3 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x510, 0x0100);/* regulator_ctrl_4 */ + + MIPI_OUTP(MIPI_DSI_BASE + 0x4b0, 0x04);/* DSIPHY_LDO_CNTRL */ + + pd = (panel_info->mipi).dsi_phy_db; + + off = 0x0480; /* strength 0 - 2 */ + for (i = 0; i < 3; i++) { + MIPI_OUTP(MIPI_DSI_BASE + off, pd->strength[i]); + wmb(); + off += 4; + } + + off = 0x0470; /* ctrl 0 - 3 */ + for (i = 0; i < 4; i++) { + MIPI_OUTP(MIPI_DSI_BASE + off, pd->ctrl[i]); + wmb(); + off += 4; + } + + off = 0x0500; /* regulator ctrl 0 - 4 */ + for (i = 0; i < 5; i++) { + MIPI_OUTP(MIPI_DSI_BASE + off, pd->regulator[i]); + wmb(); + off += 4; + } + mipi_dsi_calibration(); + mipi_dsi_lane_cfg(); /* lane cfgs */ + mipi_dsi_bist_ctrl(); /* bist ctrl */ + + off = 0x0204; /* pll ctrl 1 - 19, skip 0 */ + for (i = 1; i < 20; i++) { + MIPI_OUTP(MIPI_DSI_BASE + off, pd->pll[i]); + wmb(); + off += 4; + } + + if (panel_info) + mipi_dsi_phy_pll_config(panel_info->clk_rate); + + /* pll ctrl 0 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x200, pd->pll[0]); + wmb(); + + off = 0x0440; /* phy timing ctrl 0 - 11 */ + for (i = 0; i < 12; i++) { + MIPI_OUTP(MIPI_DSI_BASE + off, pd->timing[i]); + wmb(); + off += 4; + } + + if (target_type == 1) + mipi_dsi_configure_serdes(); +} + +void cont_splash_clk_ctrl(int enable) +{ + static int cont_splash_clks_enabled; + if (enable && !cont_splash_clks_enabled) { + clk_prepare_enable(dsi_byte_div_clk); + clk_prepare_enable(dsi_esc_clk); + cont_splash_clks_enabled = 1; + } else if (!enable && cont_splash_clks_enabled) { + clk_disable_unprepare(dsi_byte_div_clk); + clk_disable_unprepare(dsi_esc_clk); + cont_splash_clks_enabled = 0; + } +} + +void mipi_dsi_prepare_clocks(void) +{ + clk_prepare(amp_pclk); + clk_prepare(dsi_m_pclk); + clk_prepare(dsi_s_pclk); + clk_prepare(dsi_byte_div_clk); + clk_prepare(dsi_esc_clk); +} + +void mipi_dsi_unprepare_clocks(void) +{ + clk_unprepare(dsi_esc_clk); + clk_unprepare(dsi_byte_div_clk); + clk_unprepare(dsi_m_pclk); + clk_unprepare(dsi_s_pclk); + clk_unprepare(amp_pclk); +} + +void mipi_dsi_ahb_ctrl(u32 enable) +{ + static int ahb_ctrl_done; + if (enable) { + if (ahb_ctrl_done) { + pr_info("%s: ahb clks already ON\n", __func__); + return; + } + clk_enable(amp_pclk); /* clock for AHB-master to AXI */ + clk_enable(dsi_m_pclk); + clk_enable(dsi_s_pclk); + mipi_dsi_ahb_en(); + mipi_dsi_sfpb_cfg(); + ahb_ctrl_done = 1; + } else { + if (ahb_ctrl_done == 0) { + pr_info("%s: ahb clks already OFF\n", __func__); + return; + } + clk_disable(dsi_m_pclk); + clk_disable(dsi_s_pclk); + clk_disable(amp_pclk); /* clock for AHB-master to AXI */ + ahb_ctrl_done = 0; + } +} + +void mipi_dsi_clk_enable(void) +{ + u32 pll_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x0200); + if (mipi_dsi_clk_on) { + pr_info("%s: mipi_dsi_clks already ON\n", __func__); + return; + } + MIPI_OUTP(MIPI_DSI_BASE + 0x0200, pll_ctrl | 0x01); + mipi_dsi_phy_rdy_poll(); + + if (clk_set_rate(dsi_byte_div_clk, 1) < 0) /* divided by 1 */ + pr_err("%s: dsi_byte_div_clk - " + "clk_set_rate failed\n", __func__); + if (clk_set_rate(dsi_esc_clk, esc_byte_ratio) < 0) /* divided by esc */ + pr_err("%s: dsi_esc_clk - " /* clk ratio */ + "clk_set_rate failed\n", __func__); + mipi_dsi_pclk_ctrl(&dsi_pclk, 1); + mipi_dsi_clk_ctrl(&dsicore_clk, 1); + clk_enable(dsi_byte_div_clk); + clk_enable(dsi_esc_clk); + mipi_dsi_clk_on = 1; + mdp4_stat.dsi_clk_on++; +} + +void mipi_dsi_clk_disable(void) +{ + if (mipi_dsi_clk_on == 0) { + pr_info("%s: mipi_dsi_clks already OFF\n", __func__); + return; + } + clk_disable(dsi_esc_clk); + clk_disable(dsi_byte_div_clk); + mipi_dsi_pclk_ctrl(&dsi_pclk, 0); + mipi_dsi_clk_ctrl(&dsicore_clk, 0); + /* DSIPHY_PLL_CTRL_0, disable dsi pll */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0200, 0x0); + mipi_dsi_clk_on = 0; + mdp4_stat.dsi_clk_off++; +} + +void mipi_dsi_phy_ctrl(int on) +{ + if (on) { + /* DSIPHY_PLL_CTRL_5 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0214, 0x050); + } else { + /* DSIPHY_PLL_CTRL_5 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0214, 0x05f); + + /* DSIPHY_REGULATOR_CTRL_0 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0500, 0x02); + + /* DSIPHY_CTRL_0 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0470, 0x00); + + /* DSIPHY_CTRL_1 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0474, 0x7f); + + /* disable dsi clk */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0118, 0); + } +} + +#ifdef CONFIG_FB_MSM_HDMI_COMMON +void hdmi_phy_reset(void) +{ + unsigned int phy_reset_polarity = 0x0; + unsigned int pll_reset_polarity = 0x0; + + unsigned int val = HDMI_INP_ND(HDMI_PHY_CTRL); + + phy_reset_polarity = val >> 3 & 0x1; + pll_reset_polarity = val >> 1 & 0x1; + + if (phy_reset_polarity == 0) + HDMI_OUTP(HDMI_PHY_CTRL, val | SW_RESET); + else + HDMI_OUTP(HDMI_PHY_CTRL, val & (~SW_RESET)); + + if (pll_reset_polarity == 0) + HDMI_OUTP(HDMI_PHY_CTRL, val | SW_RESET_PLL); + else + HDMI_OUTP(HDMI_PHY_CTRL, val & (~SW_RESET_PLL)); + + msleep(100); + + if (phy_reset_polarity == 0) + HDMI_OUTP(HDMI_PHY_CTRL, val & (~SW_RESET)); + else + HDMI_OUTP(HDMI_PHY_CTRL, val | SW_RESET); + + if (pll_reset_polarity == 0) + HDMI_OUTP(HDMI_PHY_CTRL, val & (~SW_RESET_PLL)); + else + HDMI_OUTP(HDMI_PHY_CTRL, val | SW_RESET_PLL); +} + +void hdmi_msm_reset_core(void) +{ + hdmi_msm_set_mode(FALSE); + hdmi_msm_clk(0); + udelay(5); + hdmi_msm_clk(1); + + clk_reset(hdmi_msm_state->hdmi_app_clk, CLK_RESET_ASSERT); + udelay(20); + clk_reset(hdmi_msm_state->hdmi_app_clk, CLK_RESET_DEASSERT); +} + +void hdmi_msm_init_phy(int video_format) +{ + uint32 offset; + pr_err("Video format is : %u\n", video_format); + + HDMI_OUTP(HDMI_PHY_REG_0, 0x1B); + HDMI_OUTP(HDMI_PHY_REG_1, 0xf2); + + offset = HDMI_PHY_REG_4; + while (offset <= HDMI_PHY_REG_11) { + HDMI_OUTP(offset, 0x0); + offset += 0x4; + } + + HDMI_OUTP(HDMI_PHY_REG_3, 0x20); +} + +void hdmi_msm_powerdown_phy(void) +{ + /* Power down PHY */ + HDMI_OUTP_ND(HDMI_PHY_REG_2, 0x7F); /*0b01111111*/ +} + +void hdmi_frame_ctrl_cfg(const struct hdmi_disp_mode_timing_type *timing) +{ + /* 0x02C8 HDMI_FRAME_CTRL + * 31 INTERLACED_EN Interlaced or progressive enable bit + * 0: Frame in progressive + * 1: Frame is interlaced + * 29 HSYNC_HDMI_POL HSYNC polarity fed to HDMI core + * 0: Active Hi Hsync, detect the rising edge of hsync + * 1: Active lo Hsync, Detect the falling edge of Hsync + * 28 VSYNC_HDMI_POL VSYNC polarity fed to HDMI core + * 0: Active Hi Vsync, detect the rising edge of vsync + * 1: Active Lo Vsync, Detect the falling edge of Vsync + * 12 RGB_MUX_SEL ALPHA mdp4 input is RGB, mdp4 input is BGR + */ + HDMI_OUTP(0x02C8, + ((timing->interlaced << 31) & 0x80000000) + | ((timing->active_low_h << 29) & 0x20000000) + | ((timing->active_low_v << 28) & 0x10000000)); +} + +void hdmi_msm_phy_status_poll(void) +{ + unsigned int lock_det, phy_ready; + lock_det = 0x1 & HDMI_INP_ND(HDMI_PHY_PLL_STATUS0); + if (lock_det) { + pr_debug("HDMI Phy PLL Lock Detect Bit is set\n"); + } else { + pr_debug("HDMI Phy Lock Detect Bit is not set," + "waiting for lock detection\n"); + do { + lock_det = 0x1 & \ + HDMI_INP_ND(HDMI_PHY_PLL_STATUS0); + } while (!lock_det); + } + + phy_ready = 0x1 & HDMI_INP_ND(HDMI_PHY_REG_15); + if (phy_ready) { + pr_debug("HDMI Phy Status bit is set and ready\n"); + } else { + pr_debug("HDMI Phy Status bit is not set," + "waiting for ready status\n"); + do { + phy_ready = 0x1 & HDMI_INP_ND(HDMI_PHY_REG_15); + } while (!phy_ready); + } +} + +#endif diff --git a/drivers/video/msm/msm_dss_io_8x60.c b/drivers/video/msm/msm_dss_io_8x60.c new file mode 100644 index 000000000000..360b60bb5c92 --- /dev/null +++ b/drivers/video/msm/msm_dss_io_8x60.c @@ -0,0 +1,690 @@ +/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include "msm_fb.h" +#include "mipi_dsi.h" +#include "hdmi_msm.h" +#include + +/* multimedia sub system clock control */ +char *mmss_cc_base = MSM_MMSS_CLK_CTL_BASE; +/* multimedia sub system sfpb */ +char *mmss_sfpb_base; +void __iomem *periph_base; + +static struct dsi_clk_desc dsicore_clk; +static struct dsi_clk_desc dsi_pclk; + +static struct clk *dsi_byte_div_clk; +static struct clk *dsi_esc_clk; +static struct clk *dsi_m_pclk; +static struct clk *dsi_s_pclk; + +static struct clk *amp_pclk; +int mipi_dsi_clk_on; + +int mipi_dsi_clk_init(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + amp_pclk = clk_get(dev, "arb_clk"); + if (IS_ERR_OR_NULL(amp_pclk)) { + pr_err("can't find amp_pclk\n"); + amp_pclk = NULL; + goto mipi_dsi_clk_err; + } + + dsi_m_pclk = clk_get(dev, "master_iface_clk"); + if (IS_ERR_OR_NULL(dsi_m_pclk)) { + pr_err("can't find dsi_m_pclk\n"); + dsi_m_pclk = NULL; + goto mipi_dsi_clk_err; + } + + dsi_s_pclk = clk_get(dev, "slave_iface_clk"); + if (IS_ERR_OR_NULL(dsi_s_pclk)) { + pr_err("can't find dsi_s_pclk\n"); + dsi_s_pclk = NULL; + goto mipi_dsi_clk_err; + } + + dsi_byte_div_clk = clk_get(dev, "byte_clk"); + if (IS_ERR_OR_NULL(dsi_byte_div_clk)) { + pr_err("can't find dsi_byte_div_clk\n"); + dsi_byte_div_clk = NULL; + goto mipi_dsi_clk_err; + } + + dsi_esc_clk = clk_get(dev, "esc_clk"); + if (IS_ERR_OR_NULL(dsi_esc_clk)) { + printk(KERN_ERR "can't find dsi_esc_clk\n"); + dsi_esc_clk = NULL; + goto mipi_dsi_clk_err; + } + + return 0; + +mipi_dsi_clk_err: + mipi_dsi_clk_deinit(NULL); + return -EPERM; +} + +void mipi_dsi_clk_deinit(struct device *dev) +{ + if (amp_pclk) + clk_put(amp_pclk); + if (dsi_m_pclk) + clk_put(dsi_m_pclk); + if (dsi_s_pclk) + clk_put(dsi_s_pclk); + if (dsi_byte_div_clk) + clk_put(dsi_byte_div_clk); + if (dsi_esc_clk) + clk_put(dsi_esc_clk); +} + +static void mipi_dsi_clk_ctrl(struct dsi_clk_desc *clk, int clk_en) +{ + char *cc, *ns, *md; + int pmxo_sel = 0; + char mnd_en = 1, root_en = 1; + uint32 data, val; + + cc = mmss_cc_base + 0x004c; + md = mmss_cc_base + 0x0050; + ns = mmss_cc_base + 0x0054; + + if (clk_en) { + if (clk->mnd_mode == 0) { + data = clk->pre_div_func << 14; + data |= clk->src; + MIPI_OUTP_SECURE(ns, data); + MIPI_OUTP_SECURE(cc, ((pmxo_sel << 8) + | (clk->mnd_mode << 6) + | (root_en << 2) | clk_en)); + } else { + val = clk->d * 2; + data = (~val) & 0x0ff; + data |= clk->m << 8; + MIPI_OUTP_SECURE(md, data); + + val = clk->n - clk->m; + data = (~val) & 0x0ff; + data <<= 24; + data |= clk->src; + MIPI_OUTP_SECURE(ns, data); + + MIPI_OUTP_SECURE(cc, ((pmxo_sel << 8) + | (clk->mnd_mode << 6) + | (mnd_en << 5) + | (root_en << 2) | clk_en)); + } + + } else + MIPI_OUTP_SECURE(cc, 0); + + wmb(); +} + +static void mipi_dsi_sfpb_cfg(void) +{ + char *sfpb; + int data; + + sfpb = mmss_sfpb_base + 0x058; + + data = MIPI_INP(sfpb); + data |= 0x01800; + MIPI_OUTP(sfpb, data); + wmb(); +} + +static void mipi_dsi_pclk_ctrl(struct dsi_clk_desc *clk, int clk_en) +{ + char *cc, *ns, *md; + char mnd_en = 1, root_en = 1; + uint32 data, val; + + cc = mmss_cc_base + 0x0130; + md = mmss_cc_base + 0x0134; + ns = mmss_cc_base + 0x0138; + + if (clk_en) { + if (clk->mnd_mode == 0) { + data = clk->pre_div_func << 12; + data |= clk->src; + MIPI_OUTP_SECURE(ns, data); + MIPI_OUTP_SECURE(cc, ((clk->mnd_mode << 6) + | (root_en << 2) | clk_en)); + } else { + val = clk->d * 2; + data = (~val) & 0x0ff; + data |= clk->m << 8; + MIPI_OUTP_SECURE(md, data); + + val = clk->n - clk->m; + data = (~val) & 0x0ff; + data <<= 24; + data |= clk->src; + MIPI_OUTP_SECURE(ns, data); + + MIPI_OUTP_SECURE(cc, ((clk->mnd_mode << 6) + | (mnd_en << 5) + | (root_en << 2) | clk_en)); + } + + } else + MIPI_OUTP_SECURE(cc, 0); + + wmb(); +} + +static void mipi_dsi_ahb_en(void) +{ + char *ahb; + + ahb = mmss_cc_base + 0x08; + + pr_debug("%s: ahb=%x %x\n", + __func__, (int) ahb, MIPI_INP_SECURE(ahb)); +} + +static void mipi_dsi_calibration(void) +{ + uint32 data; + + MIPI_OUTP(MIPI_DSI_BASE + 0xf4, 0x0000ff11); /* cal_ctrl */ + MIPI_OUTP(MIPI_DSI_BASE + 0xf0, 0x01); /* cal_hw_trigger */ + + while (1) { + data = MIPI_INP(MIPI_DSI_BASE + 0xfc); /* cal_status */ + if ((data & 0x10000000) == 0) + break; + + udelay(10); + } +} + +#define PREF_DIV_RATIO 27 +struct dsiphy_pll_divider_config pll_divider_config; + + +int mipi_dsi_phy_pll_config(u32 clk_rate) +{ + struct dsiphy_pll_divider_config *dividers; + u32 fb_divider, tmp; + dividers = &pll_divider_config; + + /* DSIPHY_PLL_CTRL_x: 1 2 3 8 9 10 */ + /* masks 0xff 0x07 0x3f 0x0f 0xff 0xff */ + + /* DSIPHY_PLL_CTRL_1 */ + fb_divider = ((dividers->fb_divider) / 2) - 1; + MIPI_OUTP(MIPI_DSI_BASE + 0x204, fb_divider & 0xff); + + /* DSIPHY_PLL_CTRL_2 */ + tmp = MIPI_INP(MIPI_DSI_BASE + 0x208); + tmp &= ~0x07; + tmp |= (fb_divider >> 8) & 0x07; + MIPI_OUTP(MIPI_DSI_BASE + 0x208, tmp); + + /* DSIPHY_PLL_CTRL_3 */ + tmp = MIPI_INP(MIPI_DSI_BASE + 0x20c); + tmp &= ~0x3f; + tmp |= (dividers->ref_divider_ratio - 1) & 0x3f; + MIPI_OUTP(MIPI_DSI_BASE + 0x20c, tmp); + + /* DSIPHY_PLL_CTRL_8 */ + tmp = MIPI_INP(MIPI_DSI_BASE + 0x220); + tmp &= ~0x0f; + tmp |= (dividers->bit_clk_divider - 1) & 0x0f; + MIPI_OUTP(MIPI_DSI_BASE + 0x220, tmp); + + /* DSIPHY_PLL_CTRL_9 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x224, (dividers->byte_clk_divider - 1)); + + /* DSIPHY_PLL_CTRL_10 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x228, (dividers->dsi_clk_divider - 1)); + + return 0; +} + +int mipi_dsi_clk_div_config(uint8 bpp, uint8 lanes, + uint32 *expected_dsi_pclk) +{ + u32 fb_divider, rate, vco; + u32 div_ratio = 0; + struct dsi_clk_mnd_table const *mnd_entry = mnd_table; + if (pll_divider_config.clk_rate == 0) + pll_divider_config.clk_rate = 454000000; + + rate = pll_divider_config.clk_rate / 1000000; /* In Mhz */ + + if (rate < 125) { + vco = rate * 8; + div_ratio = 8; + } else if (rate < 250) { + vco = rate * 4; + div_ratio = 4; + } else if (rate < 500) { + vco = rate * 2; + div_ratio = 2; + } else { + vco = rate * 1; + div_ratio = 1; + } + + /* find the mnd settings from mnd_table entry */ + for (; mnd_entry != mnd_table + ARRAY_SIZE(mnd_table); ++mnd_entry) { + if (((mnd_entry->lanes) == lanes) && + ((mnd_entry->bpp) == bpp)) + break; + } + + if (mnd_entry == mnd_table + ARRAY_SIZE(mnd_table)) { + pr_err("%s: requested Lanes, %u & BPP, %u, not supported\n", + __func__, lanes, bpp); + return -EINVAL; + } + fb_divider = ((vco * PREF_DIV_RATIO) / 27); + pll_divider_config.fb_divider = fb_divider; + pll_divider_config.ref_divider_ratio = PREF_DIV_RATIO; + pll_divider_config.bit_clk_divider = div_ratio; + pll_divider_config.byte_clk_divider = + pll_divider_config.bit_clk_divider * 8; + pll_divider_config.dsi_clk_divider = + (mnd_entry->dsiclk_div) * div_ratio; + + if ((mnd_entry->dsiclk_d == 0) + || (mnd_entry->dsiclk_m == 1)) { + dsicore_clk.mnd_mode = 0; + dsicore_clk.src = 0x3; + dsicore_clk.pre_div_func = (mnd_entry->dsiclk_n - 1); + } else { + dsicore_clk.mnd_mode = 2; + dsicore_clk.src = 0x3; + dsicore_clk.m = mnd_entry->dsiclk_m; + dsicore_clk.n = mnd_entry->dsiclk_n; + dsicore_clk.d = mnd_entry->dsiclk_d; + } + + if ((mnd_entry->pclk_d == 0) + || (mnd_entry->pclk_m == 1)) { + dsi_pclk.mnd_mode = 0; + dsi_pclk.src = 0x3; + dsi_pclk.pre_div_func = (mnd_entry->pclk_n - 1); + *expected_dsi_pclk = ((vco * 1000000) / + ((pll_divider_config.dsi_clk_divider) + * (mnd_entry->pclk_n))); + } else { + dsi_pclk.mnd_mode = 2; + dsi_pclk.src = 0x3; + dsi_pclk.m = mnd_entry->pclk_m; + dsi_pclk.n = mnd_entry->pclk_n; + dsi_pclk.d = mnd_entry->pclk_d; + *expected_dsi_pclk = ((vco * 1000000 * dsi_pclk.m) / + ((pll_divider_config.dsi_clk_divider) + * (mnd_entry->pclk_n))); + } + return 0; +} + +void mipi_dsi_phy_init(int panel_ndx, struct msm_panel_info const *panel_info, + int target_type) +{ + struct mipi_dsi_phy_ctrl *pd; + int i, off; + + MIPI_OUTP(MIPI_DSI_BASE + 0x128, 0x0001);/* start phy sw reset */ + wmb(); + usleep(1); + MIPI_OUTP(MIPI_DSI_BASE + 0x128, 0x0000);/* end phy w reset */ + wmb(); + usleep(1); + MIPI_OUTP(MIPI_DSI_BASE + 0x2cc, 0x0003);/* regulator_ctrl_0 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x2d0, 0x0001);/* regulator_ctrl_1 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x2d4, 0x0001);/* regulator_ctrl_2 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x2d8, 0x0000);/* regulator_ctrl_3 */ +#ifdef DSI_POWER + MIPI_OUTP(MIPI_DSI_BASE + 0x2dc, 0x0100);/* regulator_ctrl_4 */ +#endif + + pd = (panel_info->mipi).dsi_phy_db; + + off = 0x02cc; /* regulator ctrl 0 */ + for (i = 0; i < 4; i++) { + MIPI_OUTP(MIPI_DSI_BASE + off, pd->regulator[i]); + wmb(); + off += 4; + } + + off = 0x0260; /* phy timig ctrl 0 */ + for (i = 0; i < 11; i++) { + MIPI_OUTP(MIPI_DSI_BASE + off, pd->timing[i]); + wmb(); + off += 4; + } + + off = 0x0290; /* ctrl 0 */ + for (i = 0; i < 4; i++) { + MIPI_OUTP(MIPI_DSI_BASE + off, pd->ctrl[i]); + wmb(); + off += 4; + } + + off = 0x02a0; /* strength 0 */ + for (i = 0; i < 4; i++) { + MIPI_OUTP(MIPI_DSI_BASE + off, pd->strength[i]); + wmb(); + off += 4; + } + + mipi_dsi_calibration(); + + off = 0x0204; /* pll ctrl 1, skip 0 */ + for (i = 1; i < 21; i++) { + MIPI_OUTP(MIPI_DSI_BASE + off, pd->pll[i]); + wmb(); + off += 4; + } + + if (panel_info) + mipi_dsi_phy_pll_config(panel_info->clk_rate); + + /* pll ctrl 0 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x200, pd->pll[0]); + wmb(); +} + +void cont_splash_clk_ctrl(int enable) +{ +} + +void mipi_dsi_prepare_clocks(void) +{ + clk_prepare(amp_pclk); + clk_prepare(dsi_m_pclk); + clk_prepare(dsi_s_pclk); + clk_prepare(dsi_byte_div_clk); + clk_prepare(dsi_esc_clk); +} + +void mipi_dsi_unprepare_clocks(void) +{ + clk_unprepare(dsi_esc_clk); + clk_unprepare(dsi_byte_div_clk); + clk_unprepare(dsi_m_pclk); + clk_unprepare(dsi_s_pclk); + clk_unprepare(amp_pclk); +} + +void mipi_dsi_ahb_ctrl(u32 enable) +{ + static int ahb_ctrl_done; + if (enable) { + if (ahb_ctrl_done) { + pr_info("%s: ahb clks already ON\n", __func__); + return; + } + clk_enable(amp_pclk); /* clock for AHB-master to AXI */ + clk_enable(dsi_m_pclk); + clk_enable(dsi_s_pclk); + mipi_dsi_ahb_en(); + mipi_dsi_sfpb_cfg(); + ahb_ctrl_done = 1; + } else { + if (ahb_ctrl_done == 0) { + pr_info("%s: ahb clks already OFF\n", __func__); + return; + } + clk_disable(dsi_m_pclk); + clk_disable(dsi_s_pclk); + clk_disable(amp_pclk); /* clock for AHB-master to AXI */ + ahb_ctrl_done = 0; + } +} + +void mipi_dsi_clk_enable(void) +{ + u32 pll_ctrl = MIPI_INP(MIPI_DSI_BASE + 0x0200); + if (mipi_dsi_clk_on) { + pr_info("%s: mipi_dsi_clks already ON\n", __func__); + return; + } + MIPI_OUTP(MIPI_DSI_BASE + 0x0200, pll_ctrl | 0x01); + mb(); + + if (clk_set_rate(dsi_byte_div_clk, 1) < 0) /* divided by 1 */ + pr_err("%s: clk_set_rate failed\n", __func__); + mipi_dsi_pclk_ctrl(&dsi_pclk, 1); + mipi_dsi_clk_ctrl(&dsicore_clk, 1); + clk_enable(dsi_byte_div_clk); + clk_enable(dsi_esc_clk); + mipi_dsi_clk_on = 1; +} + +void mipi_dsi_clk_disable(void) +{ + if (mipi_dsi_clk_on == 0) { + pr_info("%s: mipi_dsi_clks already OFF\n", __func__); + return; + } + clk_disable(dsi_esc_clk); + clk_disable(dsi_byte_div_clk); + + mipi_dsi_pclk_ctrl(&dsi_pclk, 0); + mipi_dsi_clk_ctrl(&dsicore_clk, 0); + /* DSIPHY_PLL_CTRL_0, disable dsi pll */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0200, 0x40); + mipi_dsi_clk_on = 0; +} + +void mipi_dsi_phy_ctrl(int on) +{ + if (on) { + /* DSIPHY_PLL_CTRL_5 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0214, 0x050); + + /* DSIPHY_TPA_CTRL_1 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0258, 0x00f); + + /* DSIPHY_TPA_CTRL_2 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x025c, 0x000); + } else { + /* DSIPHY_PLL_CTRL_5 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0214, 0x05f); + + /* DSIPHY_TPA_CTRL_1 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0258, 0x08f); + + /* DSIPHY_TPA_CTRL_2 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x025c, 0x001); + + /* DSIPHY_REGULATOR_CTRL_0 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x02cc, 0x02); + + /* DSIPHY_CTRL_0 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0290, 0x00); + + /* DSIPHY_CTRL_1 */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0294, 0x7f); + + /* disable dsi clk */ + MIPI_OUTP(MIPI_DSI_BASE + 0x0118, 0); + } +} + +#ifdef CONFIG_FB_MSM_HDMI_COMMON +#define SW_RESET BIT(2) +void hdmi_phy_reset(void) +{ + unsigned int phy_reset_polarity = 0x0; + unsigned int val = HDMI_INP_ND(0x2D4); + + phy_reset_polarity = val >> 3 & 0x1; + + if (phy_reset_polarity == 0) + HDMI_OUTP(0x2D4, val | SW_RESET); + else + HDMI_OUTP(0x2D4, val & (~SW_RESET)); + + msleep(100); + + if (phy_reset_polarity == 0) + HDMI_OUTP(0x2D4, val & (~SW_RESET)); + else + HDMI_OUTP(0x2D4, val | SW_RESET); +} + +void hdmi_msm_reset_core(void) +{ + hdmi_msm_set_mode(FALSE); + hdmi_msm_clk(0); + udelay(5); + hdmi_msm_clk(1); + + clk_reset(hdmi_msm_state->hdmi_app_clk, CLK_RESET_ASSERT); + clk_reset(hdmi_msm_state->hdmi_m_pclk, CLK_RESET_ASSERT); + clk_reset(hdmi_msm_state->hdmi_s_pclk, CLK_RESET_ASSERT); + udelay(20); + clk_reset(hdmi_msm_state->hdmi_app_clk, CLK_RESET_DEASSERT); + clk_reset(hdmi_msm_state->hdmi_m_pclk, CLK_RESET_DEASSERT); + clk_reset(hdmi_msm_state->hdmi_s_pclk, CLK_RESET_DEASSERT); +} + +void hdmi_msm_init_phy(int video_format) +{ + uint32 offset; + /* De-serializer delay D/C for non-lbk mode + * PHY REG0 = (DESER_SEL(0) | DESER_DEL_CTRL(3) + * | AMUX_OUT_SEL(0)) + */ + HDMI_OUTP_ND(0x0300, 0x0C); /*0b00001100*/ + + if (video_format == HDMI_VFRMT_720x480p60_16_9) { + /* PHY REG1 = DTEST_MUX_SEL(5) | PLL_GAIN_SEL(0) + * | OUTVOL_SWING_CTRL(3) + */ + HDMI_OUTP_ND(0x0304, 0x53); /*0b01010011*/ + } else { + /* If the freq. is less than 120MHz, use low gain 0 + * for board with termination + * PHY REG1 = DTEST_MUX_SEL(5) | PLL_GAIN_SEL(0) + * | OUTVOL_SWING_CTRL(4) + */ + HDMI_OUTP_ND(0x0304, 0x54); /*0b01010100*/ + } + + /* No matter what, start from the power down mode + * PHY REG2 = PD_PWRGEN | PD_PLL | PD_DRIVE_4 | PD_DRIVE_3 + * | PD_DRIVE_2 | PD_DRIVE_1 | PD_DESER + */ + HDMI_OUTP_ND(0x0308, 0x7F); /*0b01111111*/ + + /* Turn PowerGen on + * PHY REG2 = PD_PLL | PD_DRIVE_4 | PD_DRIVE_3 + * | PD_DRIVE_2 | PD_DRIVE_1 | PD_DESER + */ + HDMI_OUTP_ND(0x0308, 0x3F); /*0b00111111*/ + + /* Turn PLL power on + * PHY REG2 = PD_DRIVE_4 | PD_DRIVE_3 + * | PD_DRIVE_2 | PD_DRIVE_1 | PD_DESER + */ + HDMI_OUTP_ND(0x0308, 0x1F); /*0b00011111*/ + + /* Write to HIGH after PLL power down de-assert + * PHY REG3 = PLL_ENABLE + */ + HDMI_OUTP_ND(0x030C, 0x01); + /* ASIC power on; PHY REG9 = 0 */ + HDMI_OUTP_ND(0x0324, 0x00); + /* Enable PLL lock detect, PLL lock det will go high after lock + * Enable the re-time logic + * PHY REG12 = PLL_LOCK_DETECT_EN | RETIMING_ENABLE + */ + HDMI_OUTP_ND(0x0330, 0x03); /*0b00000011*/ + + /* Drivers are on + * PHY REG2 = PD_DESER + */ + HDMI_OUTP_ND(0x0308, 0x01); /*0b00000001*/ + /* If the RX detector is needed + * PHY REG2 = RCV_SENSE_EN | PD_DESER + */ + HDMI_OUTP_ND(0x0308, 0x81); /*0b10000001*/ + + offset = 0x0310; + while (offset <= 0x032C) { + HDMI_OUTP(offset, 0x0); + offset += 0x4; + } + + /* If we want to use lock enable based on counting + * PHY REG12 = FORCE_LOCK | PLL_LOCK_DETECT_EN | RETIMING_ENABLE + */ + HDMI_OUTP_ND(0x0330, 0x13); /*0b00010011*/ +} + +void hdmi_msm_powerdown_phy(void) +{ + /* Assert RESET PHY from controller */ + HDMI_OUTP_ND(0x02D4, 0x4); + udelay(10); + /* De-assert RESET PHY from controller */ + HDMI_OUTP_ND(0x02D4, 0x0); + /* Turn off Driver */ + HDMI_OUTP_ND(0x0308, 0x1F); + udelay(10); + /* Disable PLL */ + HDMI_OUTP_ND(0x030C, 0x00); + /* Power down PHY */ + HDMI_OUTP_ND(0x0308, 0x7F); /*0b01111111*/ +} + +void hdmi_frame_ctrl_cfg(const struct hdmi_disp_mode_timing_type *timing) +{ + /* 0x02C8 HDMI_FRAME_CTRL + * 31 INTERLACED_EN Interlaced or progressive enable bit + * 0: Frame in progressive + * 1: Frame is interlaced + * 29 HSYNC_HDMI_POL HSYNC polarity fed to HDMI core + * 0: Active Hi Hsync, detect the rising edge of hsync + * 1: Active lo Hsync, Detect the falling edge of Hsync + * 28 VSYNC_HDMI_POL VSYNC polarity fed to HDMI core + * 0: Active Hi Vsync, detect the rising edge of vsync + * 1: Active Lo Vsync, Detect the falling edge of Vsync + * 12 RGB_MUX_SEL ALPHA mdp4 input is RGB, mdp4 input is BGR + */ + HDMI_OUTP(0x02C8, + ((timing->interlaced << 31) & 0x80000000) + | ((timing->active_low_h << 29) & 0x20000000) + | ((timing->active_low_v << 28) & 0x10000000) + | (1 << 12)); +} + +void hdmi_msm_phy_status_poll(void) +{ + unsigned int phy_ready; + phy_ready = 0x1 & HDMI_INP_ND(0x33c); + if (phy_ready) { + pr_debug("HDMI Phy Status bit is set and ready\n"); + } else { + pr_debug("HDMI Phy Status bit is not set," + "waiting for ready status\n"); + do { + phy_ready = 0x1 & HDMI_INP_ND(0x33c); + } while (!phy_ready); + } +} +#endif diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c new file mode 100644 index 000000000000..c2ebb7d4f8ce --- /dev/null +++ b/drivers/video/msm/msm_fb.c @@ -0,0 +1,3771 @@ +/* drivers/video/msm/msm_fb.c + * + * Core MSM framebuffer driver. + * + * Copyright (C) 2007 Google Incorporated + * Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MSM_FB_C +#include "msm_fb.h" +#include "mddihosti.h" +#include "tvenc.h" +#include "mdp.h" +#include "mdp4.h" + +#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER +#define MSM_FB_NUM 3 +#endif + +static unsigned char *fbram; +static unsigned char *fbram_phys; +static int fbram_size; +static boolean bf_supported; + +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; + +int vsync_mode = 1; + +#define MAX_BLIT_REQ 256 + +#define MAX_FBI_LIST 32 +static struct fb_info *fbi_list[MAX_FBI_LIST]; +static int fbi_list_index; + +static struct msm_fb_data_type *mfd_list[MAX_FBI_LIST]; +static int mfd_list_index; + +static u32 msm_fb_pseudo_palette[16] = { + 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff +}; + +static struct ion_client *iclient; + +u32 msm_fb_debug_enabled; +/* Setting msm_fb_msg_level to 8 prints out ALL messages */ +u32 msm_fb_msg_level = 7; + +/* Setting mddi_msg_level to 8 prints out ALL messages */ +u32 mddi_msg_level = 5; + +extern int32 mdp_block_power_cnt[MDP_MAX_BLOCK]; +extern unsigned long mdp_timer_duration; + +static int msm_fb_register(struct msm_fb_data_type *mfd); +static int msm_fb_open(struct fb_info *info, int user); +static int msm_fb_release(struct fb_info *info, int user); +static int msm_fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info); +static int msm_fb_stop_sw_refresher(struct msm_fb_data_type *mfd); +int msm_fb_resume_sw_refresher(struct msm_fb_data_type *mfd); +static int msm_fb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info); +static int msm_fb_set_par(struct fb_info *info); +static int msm_fb_blank_sub(int blank_mode, struct fb_info *info, + boolean op_enable); +static int msm_fb_suspend_sub(struct msm_fb_data_type *mfd); +static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg); +static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma); + +#ifdef MSM_FB_ENABLE_DBGFS + +#define MSM_FB_MAX_DBGFS 1024 +#define MAX_BACKLIGHT_BRIGHTNESS 255 + +int msm_fb_debugfs_file_index; +struct dentry *msm_fb_debugfs_root; +struct dentry *msm_fb_debugfs_file[MSM_FB_MAX_DBGFS]; + +DEFINE_MUTEX(msm_fb_notify_update_sem); +void msmfb_no_update_notify_timer_cb(unsigned long data) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data; + if (!mfd) + pr_err("%s mfd NULL\n", __func__); + complete(&mfd->msmfb_no_update_notify); +} + +struct dentry *msm_fb_get_debugfs_root(void) +{ + if (msm_fb_debugfs_root == NULL) + msm_fb_debugfs_root = debugfs_create_dir("msm_fb", NULL); + + return msm_fb_debugfs_root; +} + +void msm_fb_debugfs_file_create(struct dentry *root, const char *name, + u32 *var) +{ + if (msm_fb_debugfs_file_index >= MSM_FB_MAX_DBGFS) + return; + + msm_fb_debugfs_file[msm_fb_debugfs_file_index++] = + debugfs_create_u32(name, S_IRUGO | S_IWUSR, root, var); +} +#endif + +int msm_fb_cursor(struct fb_info *info, struct fb_cursor *cursor) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (!mfd->cursor_update) + return -ENODEV; + + return mfd->cursor_update(info, cursor); +} + +static int msm_fb_resource_initialized; + +#ifndef CONFIG_FB_BACKLIGHT +static int lcd_backlight_registered; + +static void msm_fb_set_bl_brightness(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent); + int bl_lvl; + + if (value > MAX_BACKLIGHT_BRIGHTNESS) + value = MAX_BACKLIGHT_BRIGHTNESS; + + /* This maps android backlight level 0 to 255 into + driver backlight level 0 to bl_max with rounding */ + bl_lvl = (2 * value * mfd->panel_info.bl_max + MAX_BACKLIGHT_BRIGHTNESS) + /(2 * MAX_BACKLIGHT_BRIGHTNESS); + + if (!bl_lvl && value) + bl_lvl = 1; + + msm_fb_set_backlight(mfd, bl_lvl); +} + +static struct led_classdev backlight_led = { + .name = "lcd-backlight", + .brightness = MAX_BACKLIGHT_BRIGHTNESS, + .brightness_set = msm_fb_set_bl_brightness, +}; +#endif + +static struct msm_fb_platform_data *msm_fb_pdata; +unsigned char hdmi_prim_display; + +int msm_fb_detect_client(const char *name) +{ + int ret = 0; + u32 len; +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + u32 id; +#endif + if (!msm_fb_pdata) + return -EPERM; + + len = strnlen(name, PANEL_NAME_MAX_LEN); + if (strnlen(msm_fb_pdata->prim_panel_name, PANEL_NAME_MAX_LEN)) { + pr_err("\n name = %s, prim_display = %s", + name, msm_fb_pdata->prim_panel_name); + if (!strncmp((char *)msm_fb_pdata->prim_panel_name, + name, len)) { + if (!strncmp((char *)msm_fb_pdata->prim_panel_name, + "hdmi_msm", len)) + hdmi_prim_display = 1; + return 0; + } else { + ret = -EPERM; + } + } + + if (strnlen(msm_fb_pdata->ext_panel_name, PANEL_NAME_MAX_LEN)) { + pr_err("\n name = %s, ext_display = %s", + name, msm_fb_pdata->ext_panel_name); + if (!strncmp((char *)msm_fb_pdata->ext_panel_name, name, len)) + return 0; + else + ret = -EPERM; + } + + if (ret) + return ret; + + ret = -EPERM; + if (msm_fb_pdata && msm_fb_pdata->detect_client) { + ret = msm_fb_pdata->detect_client(name); + + /* if it's non mddi panel, we need to pre-scan + mddi client to see if we can disable mddi host */ + +#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT + if (!ret && msm_fb_pdata->mddi_prescan) + id = mddi_get_client_id(); +#endif + } + + return ret; +} + +static ssize_t msm_fb_msm_fb_type(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + struct fb_info *fbi = dev_get_drvdata(dev); + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; + struct msm_fb_panel_data *pdata = + (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + + switch (pdata->panel_info.type) { + case NO_PANEL: + ret = snprintf(buf, PAGE_SIZE, "no panel\n"); + break; + case MDDI_PANEL: + ret = snprintf(buf, PAGE_SIZE, "mddi panel\n"); + break; + case EBI2_PANEL: + ret = snprintf(buf, PAGE_SIZE, "ebi2 panel\n"); + break; + case LCDC_PANEL: + ret = snprintf(buf, PAGE_SIZE, "lcdc panel\n"); + break; + case EXT_MDDI_PANEL: + ret = snprintf(buf, PAGE_SIZE, "ext mddi panel\n"); + break; + case TV_PANEL: + ret = snprintf(buf, PAGE_SIZE, "tv panel\n"); + break; + case HDMI_PANEL: + ret = snprintf(buf, PAGE_SIZE, "hdmi panel\n"); + break; + case LVDS_PANEL: + ret = snprintf(buf, PAGE_SIZE, "lvds panel\n"); + break; + case DTV_PANEL: + ret = snprintf(buf, PAGE_SIZE, "dtv panel\n"); + break; + case MIPI_VIDEO_PANEL: + ret = snprintf(buf, PAGE_SIZE, "mipi dsi video panel\n"); + break; + case MIPI_CMD_PANEL: + ret = snprintf(buf, PAGE_SIZE, "mipi dsi cmd panel\n"); + break; + case WRITEBACK_PANEL: + ret = snprintf(buf, PAGE_SIZE, "writeback panel\n"); + break; + default: + ret = snprintf(buf, PAGE_SIZE, "unknown panel\n"); + break; + } + + return ret; +} + +static DEVICE_ATTR(msm_fb_type, S_IRUGO, msm_fb_msm_fb_type, NULL); +static struct attribute *msm_fb_attrs[] = { + &dev_attr_msm_fb_type.attr, + NULL, +}; +static struct attribute_group msm_fb_attr_group = { + .attrs = msm_fb_attrs, +}; + +static int msm_fb_create_sysfs(struct platform_device *pdev) +{ + int rc; + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); + + rc = sysfs_create_group(&mfd->fbi->dev->kobj, &msm_fb_attr_group); + if (rc) + MSM_FB_ERR("%s: sysfs group creation failed, rc=%d\n", __func__, + rc); + return rc; +} +static void msm_fb_remove_sysfs(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); + sysfs_remove_group(&mfd->fbi->dev->kobj, &msm_fb_attr_group); +} + +static int msm_fb_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + int rc; + int err = 0; + + MSM_FB_DEBUG("msm_fb_probe\n"); + + if ((pdev->id == 0) && (pdev->num_resources > 0)) { + msm_fb_pdata = pdev->dev.platform_data; + fbram_size = + pdev->resource[0].end - pdev->resource[0].start + 1; + fbram_phys = (char *)pdev->resource[0].start; + fbram = __va(fbram_phys); + + if (!fbram) { + printk(KERN_ERR "fbram ioremap failed!\n"); + return -ENOMEM; + } + MSM_FB_DEBUG("msm_fb_probe: phy_Addr = 0x%x virt = 0x%x\n", + (int)fbram_phys, (int)fbram); + + iclient = msm_ion_client_create(-1, pdev->name); + if (IS_ERR_OR_NULL(iclient)) { + pr_err("msm_ion_client_create() return" + " error, val %p\n", iclient); + iclient = NULL; + } + + msm_fb_resource_initialized = 1; + return 0; + } + + if (!msm_fb_resource_initialized) + return -EPERM; + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) + return -ENOMEM; + + mfd->panel_info.frame_count = 0; + mfd->bl_level = 0; +#ifdef CONFIG_FB_MSM_OVERLAY + mfd->overlay_play_enable = 1; +#endif + + bf_supported = mdp4_overlay_borderfill_supported(); + + rc = msm_fb_register(mfd); + if (rc) + return rc; + err = pm_runtime_set_active(mfd->fbi->dev); + if (err < 0) + printk(KERN_ERR "pm_runtime: fail to set active.\n"); + pm_runtime_enable(mfd->fbi->dev); +#ifdef CONFIG_FB_BACKLIGHT + msm_fb_config_backlight(mfd); +#else + /* android supports only one lcd-backlight/lcd for now */ + if (!lcd_backlight_registered) { + if (led_classdev_register(&pdev->dev, &backlight_led)) + printk(KERN_ERR "led_classdev_register failed\n"); + else + lcd_backlight_registered = 1; + } +#endif + + pdev_list[pdev_list_cnt++] = pdev; + msm_fb_create_sysfs(pdev); + return 0; +} + +static int msm_fb_remove(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + MSM_FB_DEBUG("msm_fb_remove\n"); + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + msm_fb_remove_sysfs(pdev); + + pm_runtime_disable(mfd->fbi->dev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (msm_fb_suspend_sub(mfd)) + printk(KERN_ERR "msm_fb_remove: can't stop the device %d\n", mfd->index); + + if (mfd->channel_irq != 0) + free_irq(mfd->channel_irq, (void *)mfd); + + if (mfd->vsync_width_boundary) + vfree(mfd->vsync_width_boundary); + + if (mfd->vsync_resync_timer.function) + del_timer(&mfd->vsync_resync_timer); + + if (mfd->refresh_timer.function) + del_timer(&mfd->refresh_timer); + + if (mfd->dma_hrtimer.function) + hrtimer_cancel(&mfd->dma_hrtimer); + + if (mfd->msmfb_no_update_notify_timer.function) + del_timer(&mfd->msmfb_no_update_notify_timer); + complete(&mfd->msmfb_no_update_notify); + complete(&mfd->msmfb_update_notify); + + /* remove /dev/fb* */ + unregister_framebuffer(mfd->fbi); + +#ifdef CONFIG_FB_BACKLIGHT + /* remove /sys/class/backlight */ + backlight_device_unregister(mfd->fbi->bl_dev); +#else + if (lcd_backlight_registered) { + lcd_backlight_registered = 0; + led_classdev_unregister(&backlight_led); + } +#endif + +#ifdef MSM_FB_ENABLE_DBGFS + if (mfd->sub_dir) + debugfs_remove(mfd->sub_dir); +#endif + + return 0; +} + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static int msm_fb_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct msm_fb_data_type *mfd; + int ret = 0; + + MSM_FB_DEBUG("msm_fb_suspend\n"); + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + + console_lock(); + fb_set_suspend(mfd->fbi, FBINFO_STATE_SUSPENDED); + + ret = msm_fb_suspend_sub(mfd); + if (ret != 0) { + printk(KERN_ERR "msm_fb: failed to suspend! %d\n", ret); + fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING); + } else { + pdev->dev.power.power_state = state; + } + + console_unlock(); + return ret; +} +#else +#define msm_fb_suspend NULL +#endif + +static int msm_fb_suspend_sub(struct msm_fb_data_type *mfd) +{ + int ret = 0; + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + + if (mfd->msmfb_no_update_notify_timer.function) + del_timer(&mfd->msmfb_no_update_notify_timer); + complete(&mfd->msmfb_no_update_notify); + + /* + * suspend this channel + */ + mfd->suspend.sw_refreshing_enable = mfd->sw_refreshing_enable; + mfd->suspend.op_enable = mfd->op_enable; + mfd->suspend.panel_power_on = mfd->panel_power_on; + + if (mfd->op_enable) { + ret = + msm_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi, + mfd->suspend.op_enable); + if (ret) { + MSM_FB_INFO + ("msm_fb_suspend: can't turn off display!\n"); + return ret; + } + mfd->op_enable = FALSE; + } + /* + * try to power down + */ + mdp_pipe_ctrl(MDP_MASTER_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + + /* + * detach display channel irq if there's any + * or wait until vsync-resync completes + */ + if ((mfd->dest == DISPLAY_LCD)) { + if (mfd->panel_info.lcd.vsync_enable) { + if (mfd->panel_info.lcd.hw_vsync_mode) { + if (mfd->channel_irq != 0) + disable_irq(mfd->channel_irq); + } else { + volatile boolean vh_pending; + do { + vh_pending = mfd->vsync_handler_pending; + } while (vh_pending); + } + } + } + + return 0; +} + +#ifdef CONFIG_PM +static int msm_fb_resume_sub(struct msm_fb_data_type *mfd) +{ + int ret = 0; + struct msm_fb_panel_data *pdata = NULL; + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + + pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + + /* attach display channel irq if there's any */ + if (mfd->channel_irq != 0) + enable_irq(mfd->channel_irq); + + /* resume state var recover */ + mfd->sw_refreshing_enable = mfd->suspend.sw_refreshing_enable; + mfd->op_enable = mfd->suspend.op_enable; + + if (mfd->suspend.panel_power_on) { + ret = + msm_fb_blank_sub(FB_BLANK_UNBLANK, mfd->fbi, + mfd->op_enable); + if (ret) + MSM_FB_INFO("msm_fb_resume: can't turn on display!\n"); + } else { + if (pdata->power_ctrl) + pdata->power_ctrl(TRUE); + } + + return ret; +} +#endif + +#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) +static int msm_fb_resume(struct platform_device *pdev) +{ + /* This resume function is called when interrupt is enabled. + */ + int ret = 0; + struct msm_fb_data_type *mfd; + + MSM_FB_DEBUG("msm_fb_resume\n"); + + mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev); + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + + console_lock(); + ret = msm_fb_resume_sub(mfd); + pdev->dev.power.power_state = PMSG_ON; + fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING); + console_unlock(); + + return ret; +} +#else +#define msm_fb_resume NULL +#endif + +static int msm_fb_runtime_suspend(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: suspending...\n"); + return 0; +} + +static int msm_fb_runtime_resume(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: resuming...\n"); + return 0; +} + +static int msm_fb_runtime_idle(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: idling...\n"); + return 0; +} + +#if (defined(CONFIG_SUSPEND) && defined(CONFIG_FB_MSM_HDMI_MSM_PANEL)) +static int msm_fb_ext_suspend(struct device *dev) +{ + struct msm_fb_data_type *mfd = dev_get_drvdata(dev); + int ret = 0; + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + + if (mfd->panel_info.type == HDMI_PANEL || + mfd->panel_info.type == DTV_PANEL) + ret = msm_fb_suspend_sub(mfd); + + return ret; +} + +static int msm_fb_ext_resume(struct device *dev) +{ + struct msm_fb_data_type *mfd = dev_get_drvdata(dev); + int ret = 0; + + if ((!mfd) || (mfd->key != MFD_KEY)) + return 0; + + if (mfd->panel_info.type == HDMI_PANEL || + mfd->panel_info.type == DTV_PANEL) + ret = msm_fb_resume_sub(mfd); + + return ret; +} +#endif + +static struct dev_pm_ops msm_fb_dev_pm_ops = { + .runtime_suspend = msm_fb_runtime_suspend, + .runtime_resume = msm_fb_runtime_resume, + .runtime_idle = msm_fb_runtime_idle, +#if (defined(CONFIG_SUSPEND) && defined(CONFIG_FB_MSM_HDMI_MSM_PANEL)) + .suspend = msm_fb_ext_suspend, + .resume = msm_fb_ext_resume, +#endif +}; + +static struct platform_driver msm_fb_driver = { + .probe = msm_fb_probe, + .remove = msm_fb_remove, +#ifndef CONFIG_HAS_EARLYSUSPEND + .suspend = msm_fb_suspend, + .resume = msm_fb_resume, +#endif + .shutdown = NULL, + .driver = { + /* Driver name must match the device name added in platform.c. */ + .name = "msm_fb", + .pm = &msm_fb_dev_pm_ops, + }, +}; + +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CONFIG_FB_MSM_MDP303) +static void memset32_io(u32 __iomem *_ptr, u32 val, size_t count) +{ + count >>= 2; + while (count--) + writel(val, _ptr++); +} +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void msmfb_early_suspend(struct early_suspend *h) +{ + struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type, + early_suspend); +#if defined(CONFIG_FB_MSM_MDP303) + /* + * For MDP with overlay, set framebuffer with black pixels + * to show black screen on HDMI. + */ + struct fb_info *fbi = mfd->fbi; + switch (mfd->fbi->var.bits_per_pixel) { + case 32: + memset32_io((void *)fbi->screen_base, 0xFF000000, + fbi->fix.smem_len); + break; + default: + memset32_io((void *)fbi->screen_base, 0x00, fbi->fix.smem_len); + break; + } +#endif + msm_fb_suspend_sub(mfd); +} + +static void msmfb_early_resume(struct early_suspend *h) +{ + struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type, + early_suspend); + msm_fb_resume_sub(mfd); +} +#endif + +static int unset_bl_level, bl_updated; +static int bl_level_old; + +void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl) +{ + struct msm_fb_panel_data *pdata; + + if (!mfd->panel_power_on || !bl_updated) { + unset_bl_level = bkl_lvl; + return; + } else { + unset_bl_level = 0; + } + + pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + + if ((pdata) && (pdata->set_backlight)) { + down(&mfd->sem); + if (bl_level_old == bkl_lvl) { + up(&mfd->sem); + return; + } + mfd->bl_level = bkl_lvl; + pdata->set_backlight(mfd); + bl_level_old = mfd->bl_level; + up(&mfd->sem); + } +} + +static int msm_fb_blank_sub(int blank_mode, struct fb_info *info, + boolean op_enable) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct msm_fb_panel_data *pdata = NULL; + int ret = 0; + + if (!op_enable) + return -EPERM; + + pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + if ((!pdata) || (!pdata->on) || (!pdata->off)) { + printk(KERN_ERR "msm_fb_blank_sub: no panel operation detected!\n"); + return -ENODEV; + } + + switch (blank_mode) { + case FB_BLANK_UNBLANK: + if (!mfd->panel_power_on) { + msleep(16); + ret = pdata->on(mfd->pdev); + if (ret == 0) { + mfd->panel_power_on = TRUE; + +/* ToDo: possible conflict with android which doesn't expect sw refresher */ +/* + if (!mfd->hw_refresh) + { + if ((ret = msm_fb_resume_sw_refresher(mfd)) != 0) + { + MSM_FB_INFO("msm_fb_blank_sub: msm_fb_resume_sw_refresher failed = %d!\n",ret); + } + } +*/ + } + } + break; + + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_NORMAL: + case FB_BLANK_POWERDOWN: + default: + if (mfd->panel_power_on) { + int curr_pwr_state; + + mfd->op_enable = FALSE; + curr_pwr_state = mfd->panel_power_on; + mfd->panel_power_on = FALSE; + bl_updated = 0; + + msleep(16); + ret = pdata->off(mfd->pdev); + if (ret) + mfd->panel_power_on = curr_pwr_state; + + mfd->op_enable = TRUE; + } else { + if (pdata->power_ctrl) + pdata->power_ctrl(FALSE); + } + break; + } + + return ret; +} + +int calc_fb_offset(struct msm_fb_data_type *mfd, struct fb_info *fbi, int bpp) +{ + struct msm_panel_info *panel_info = &mfd->panel_info; + int remainder, yres, offset; + + if (panel_info->mode2_yres != 0) { + yres = panel_info->mode2_yres; + remainder = (fbi->fix.line_length*yres) & (PAGE_SIZE - 1); + } else { + yres = panel_info->yres; + remainder = (fbi->fix.line_length*yres) & (PAGE_SIZE - 1); + } + + if (!remainder) + remainder = PAGE_SIZE; + + if (fbi->var.yoffset < yres) { + offset = (fbi->var.xoffset * bpp); + /* iBuf->buf += fbi->var.xoffset * bpp + 0 * + yres * fbi->fix.line_length; */ + } else if (fbi->var.yoffset >= yres && fbi->var.yoffset < 2 * yres) { + offset = (fbi->var.xoffset * bpp + yres * + fbi->fix.line_length + PAGE_SIZE - remainder); + } else { + offset = (fbi->var.xoffset * bpp + 2 * yres * + fbi->fix.line_length + 2 * (PAGE_SIZE - remainder)); + } + return offset; +} + +static void msm_fb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + cfb_fillrect(info, rect); + if (!mfd->hw_refresh && (info->var.yoffset == 0) && + !mfd->sw_currently_refreshing) { + struct fb_var_screeninfo var; + + var = info->var; + var.reserved[0] = 0x54445055; + var.reserved[1] = (rect->dy << 16) | (rect->dx); + var.reserved[2] = ((rect->dy + rect->height) << 16) | + (rect->dx + rect->width); + + msm_fb_pan_display(&var, info); + } +} + +static void msm_fb_copyarea(struct fb_info *info, + const struct fb_copyarea *area) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + cfb_copyarea(info, area); + if (!mfd->hw_refresh && (info->var.yoffset == 0) && + !mfd->sw_currently_refreshing) { + struct fb_var_screeninfo var; + + var = info->var; + var.reserved[0] = 0x54445055; + var.reserved[1] = (area->dy << 16) | (area->dx); + var.reserved[2] = ((area->dy + area->height) << 16) | + (area->dx + area->width); + + msm_fb_pan_display(&var, info); + } +} + +static void msm_fb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + cfb_imageblit(info, image); + if (!mfd->hw_refresh && (info->var.yoffset == 0) && + !mfd->sw_currently_refreshing) { + struct fb_var_screeninfo var; + + var = info->var; + var.reserved[0] = 0x54445055; + var.reserved[1] = (image->dy << 16) | (image->dx); + var.reserved[2] = ((image->dy + image->height) << 16) | + (image->dx + image->width); + + msm_fb_pan_display(&var, info); + } +} + +static int msm_fb_blank(int blank_mode, struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + return msm_fb_blank_sub(blank_mode, info, mfd->op_enable); +} + +static int msm_fb_set_lut(struct fb_cmap *cmap, struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (!mfd->lut_update) + return -ENODEV; + + mfd->lut_update(info, cmap); + return 0; +} + +/* + * Custom Framebuffer mmap() function for MSM driver. + * Differs from standard mmap() function by allowing for customized + * page-protection. + */ +static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma) +{ + /* Get frame buffer memory range. */ + unsigned long start = info->fix.smem_start; + u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len); + unsigned long off = vma->vm_pgoff << PAGE_SHIFT; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + if (off >= len) { + /* memory mapped io */ + off -= len; + if (info->var.accel_flags) { + mutex_unlock(&info->lock); + return -EINVAL; + } + start = info->fix.mmio_start; + len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len); + } + + /* Set VM flags. */ + start &= PAGE_MASK; + if ((vma->vm_end - vma->vm_start + off) > len) + return -EINVAL; + off += start; + vma->vm_pgoff = off >> PAGE_SHIFT; + /* This is an IO map - tell maydump to skip this VMA */ + vma->vm_flags |= VM_IO | VM_RESERVED; + + /* Set VM page protection */ + if (mfd->mdp_fb_page_protection == MDP_FB_PAGE_PROTECTION_WRITECOMBINE) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + else if (mfd->mdp_fb_page_protection == + MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE) + vma->vm_page_prot = pgprot_writethroughcache(vma->vm_page_prot); + else if (mfd->mdp_fb_page_protection == + MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE) + vma->vm_page_prot = pgprot_writebackcache(vma->vm_page_prot); + else if (mfd->mdp_fb_page_protection == + MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE) + vma->vm_page_prot = pgprot_writebackwacache(vma->vm_page_prot); + else + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + /* Remap the frame buffer I/O range */ + if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} + +static struct fb_ops msm_fb_ops = { + .owner = THIS_MODULE, + .fb_open = msm_fb_open, + .fb_release = msm_fb_release, + .fb_read = NULL, + .fb_write = NULL, + .fb_cursor = NULL, + .fb_check_var = msm_fb_check_var, /* vinfo check */ + .fb_set_par = msm_fb_set_par, /* set the video mode according to info->var */ + .fb_setcolreg = NULL, /* set color register */ + .fb_blank = msm_fb_blank, /* blank display */ + .fb_pan_display = msm_fb_pan_display, /* pan display */ + .fb_fillrect = msm_fb_fillrect, /* Draws a rectangle */ + .fb_copyarea = msm_fb_copyarea, /* Copy data from area to another */ + .fb_imageblit = msm_fb_imageblit, /* Draws a image to the display */ + .fb_rotate = NULL, + .fb_sync = NULL, /* wait for blit idle, optional */ + .fb_ioctl = msm_fb_ioctl, /* perform fb specific ioctl (optional) */ + .fb_mmap = msm_fb_mmap, +}; + +static __u32 msm_fb_line_length(__u32 fb_index, __u32 xres, int bpp) +{ + /* The adreno GPU hardware requires that the pitch be aligned to + 32 pixels for color buffers, so for the cases where the GPU + is writing directly to fb0, the framebuffer pitch + also needs to be 32 pixel aligned */ + + if (fb_index == 0) + return ALIGN(xres, 32) * bpp; + else + return xres * bpp; +} + +static int msm_fb_register(struct msm_fb_data_type *mfd) +{ + int ret = -ENODEV; + int bpp; + struct msm_panel_info *panel_info = &mfd->panel_info; + struct fb_info *fbi = mfd->fbi; + struct fb_fix_screeninfo *fix; + struct fb_var_screeninfo *var; + int *id; + int fbram_offset; + int remainder, remainder_mode2; + + /* + * fb info initialization + */ + fix = &fbi->fix; + var = &fbi->var; + + fix->type_aux = 0; /* if type == FB_TYPE_INTERLEAVED_PLANES */ + fix->visual = FB_VISUAL_TRUECOLOR; /* True Color */ + fix->ywrapstep = 0; /* No support */ + fix->mmio_start = 0; /* No MMIO Address */ + fix->mmio_len = 0; /* No MMIO Address */ + fix->accel = FB_ACCEL_NONE;/* FB_ACCEL_MSM needes to be added in fb.h */ + + var->xoffset = 0, /* Offset from virtual to visible */ + var->yoffset = 0, /* resolution */ + var->grayscale = 0, /* No graylevels */ + var->nonstd = 0, /* standard pixel format */ + var->activate = FB_ACTIVATE_VBL, /* activate it at vsync */ + var->height = -1, /* height of picture in mm */ + var->width = -1, /* width of picture in mm */ + var->accel_flags = 0, /* acceleration flags */ + var->sync = 0, /* see FB_SYNC_* */ + var->rotate = 0, /* angle we rotate counter clockwise */ + mfd->op_enable = FALSE; + + switch (mfd->fb_imgType) { + case MDP_RGB_565: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + var->blue.offset = 0; + var->green.offset = 5; + var->red.offset = 11; + var->blue.length = 5; + var->green.length = 6; + var->red.length = 5; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 0; + bpp = 2; + break; + + case MDP_RGB_888: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + var->blue.offset = 0; + var->green.offset = 8; + var->red.offset = 16; + var->blue.length = 8; + var->green.length = 8; + var->red.length = 8; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 0; + bpp = 3; + break; + + case MDP_ARGB_8888: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + var->blue.offset = 0; + var->green.offset = 8; + var->red.offset = 16; + var->blue.length = 8; + var->green.length = 8; + var->red.length = 8; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 24; + var->transp.length = 8; + bpp = 4; + break; + + case MDP_RGBA_8888: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->xpanstep = 1; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + var->blue.offset = 8; + var->green.offset = 16; + var->red.offset = 24; + var->blue.length = 8; + var->green.length = 8; + var->red.length = 8; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 8; + bpp = 4; + break; + + case MDP_YCRYCB_H2V1: + /* ToDo: need to check TV-Out YUV422i framebuffer format */ + /* we might need to create new type define */ + fix->type = FB_TYPE_INTERLEAVED_PLANES; + fix->xpanstep = 2; + fix->ypanstep = 1; + var->vmode = FB_VMODE_NONINTERLACED; + + /* how about R/G/B offset? */ + var->blue.offset = 0; + var->green.offset = 5; + var->red.offset = 11; + var->blue.length = 5; + var->green.length = 6; + var->red.length = 5; + var->blue.msb_right = 0; + var->green.msb_right = 0; + var->red.msb_right = 0; + var->transp.offset = 0; + var->transp.length = 0; + bpp = 2; + break; + + default: + MSM_FB_ERR("msm_fb_init: fb %d unkown image type!\n", + mfd->index); + return ret; + } + + fix->type = panel_info->is_3d_panel; + + fix->line_length = msm_fb_line_length(mfd->index, panel_info->xres, + bpp); + + /* Make sure all buffers can be addressed on a page boundary by an x + * and y offset */ + + remainder = (fix->line_length * panel_info->yres) & (PAGE_SIZE - 1); + /* PAGE_SIZE is a power of 2 */ + if (!remainder) + remainder = PAGE_SIZE; + remainder_mode2 = (fix->line_length * + panel_info->mode2_yres) & (PAGE_SIZE - 1); + if (!remainder_mode2) + remainder_mode2 = PAGE_SIZE; + + /* + * calculate smem_len based on max size of two supplied modes. + * Only fb0 has mem. fb1 and fb2 don't have mem. + */ + if (!bf_supported || mfd->index == 0) + fix->smem_len = MAX((msm_fb_line_length(mfd->index, + panel_info->xres, + bpp) * + panel_info->yres + PAGE_SIZE - + remainder) * mfd->fb_page, + (msm_fb_line_length(mfd->index, + panel_info->mode2_xres, + bpp) * + panel_info->mode2_yres + PAGE_SIZE - + remainder_mode2) * mfd->fb_page); + else if (mfd->index == 1 || mfd->index == 2) { + pr_debug("%s:%d no memory is allocated for fb%d!\n", + __func__, __LINE__, mfd->index); + fix->smem_len = 0; + } + + mfd->var_xres = panel_info->xres; + mfd->var_yres = panel_info->yres; + mfd->var_frame_rate = panel_info->frame_rate; + + var->pixclock = mfd->panel_info.clk_rate; + mfd->var_pixclock = var->pixclock; + + var->xres = panel_info->xres; + var->yres = panel_info->yres; + var->xres_virtual = panel_info->xres; + var->yres_virtual = panel_info->yres * mfd->fb_page + + ((PAGE_SIZE - remainder)/fix->line_length) * mfd->fb_page; + var->bits_per_pixel = bpp * 8; /* FrameBuffer color depth */ + if (mfd->dest == DISPLAY_LCD) { + if (panel_info->type == MDDI_PANEL && panel_info->mddi.is_type1) + var->reserved[3] = panel_info->lcd.refx100 / (100 * 2); + else + var->reserved[3] = panel_info->lcd.refx100 / 100; + } else { + if (panel_info->type == MIPI_VIDEO_PANEL) { + var->reserved[3] = panel_info->mipi.frame_rate; + } else { + var->reserved[3] = panel_info->clk_rate / + ((panel_info->lcdc.h_back_porch + + panel_info->lcdc.h_front_porch + + panel_info->lcdc.h_pulse_width + + panel_info->xres) * + (panel_info->lcdc.v_back_porch + + panel_info->lcdc.v_front_porch + + panel_info->lcdc.v_pulse_width + + panel_info->yres)); + } + } + pr_debug("reserved[3] %u\n", var->reserved[3]); + + /* + * id field for fb app + */ + id = (int *)&mfd->panel; + + switch (mdp_rev) { + case MDP_REV_20: + snprintf(fix->id, sizeof(fix->id), "msmfb20_%x", (__u32) *id); + break; + case MDP_REV_22: + snprintf(fix->id, sizeof(fix->id), "msmfb22_%x", (__u32) *id); + break; + case MDP_REV_30: + snprintf(fix->id, sizeof(fix->id), "msmfb30_%x", (__u32) *id); + break; + case MDP_REV_303: + snprintf(fix->id, sizeof(fix->id), "msmfb303_%x", (__u32) *id); + break; + case MDP_REV_31: + snprintf(fix->id, sizeof(fix->id), "msmfb31_%x", (__u32) *id); + break; + case MDP_REV_40: + snprintf(fix->id, sizeof(fix->id), "msmfb40_%x", (__u32) *id); + break; + case MDP_REV_41: + snprintf(fix->id, sizeof(fix->id), "msmfb41_%x", (__u32) *id); + break; + case MDP_REV_42: + snprintf(fix->id, sizeof(fix->id), "msmfb42_%x", (__u32) *id); + break; + case MDP_REV_43: + snprintf(fix->id, sizeof(fix->id), "msmfb43_%x", (__u32) *id); + break; + case MDP_REV_44: + snprintf(fix->id, sizeof(fix->id), "msmfb44_%x", (__u32) *id); + break; + default: + snprintf(fix->id, sizeof(fix->id), "msmfb0_%x", (__u32) *id); + break; + } + + fbi->fbops = &msm_fb_ops; + fbi->flags = FBINFO_FLAG_DEFAULT; + fbi->pseudo_palette = msm_fb_pseudo_palette; + + mfd->ref_cnt = 0; + mfd->sw_currently_refreshing = FALSE; + mfd->sw_refreshing_enable = TRUE; + mfd->panel_power_on = FALSE; + + mfd->pan_waiting = FALSE; + init_completion(&mfd->pan_comp); + init_completion(&mfd->refresher_comp); + sema_init(&mfd->sem, 1); + + init_timer(&mfd->msmfb_no_update_notify_timer); + mfd->msmfb_no_update_notify_timer.function = + msmfb_no_update_notify_timer_cb; + mfd->msmfb_no_update_notify_timer.data = (unsigned long)mfd; + init_completion(&mfd->msmfb_update_notify); + init_completion(&mfd->msmfb_no_update_notify); + + fbram_offset = PAGE_ALIGN((int)fbram)-(int)fbram; + fbram += fbram_offset; + fbram_phys += fbram_offset; + fbram_size -= fbram_offset; + + if (!bf_supported || mfd->index == 0) + if (fbram_size < fix->smem_len) { + pr_err("error: no more framebuffer memory!\n"); + return -ENOMEM; + } + + fbi->screen_base = fbram; + fbi->fix.smem_start = (unsigned long)fbram_phys; + + msm_iommu_map_contig_buffer(fbi->fix.smem_start, + DISPLAY_DOMAIN, + GEN_POOL, + fbi->fix.smem_len, + SZ_4K, + 1, + &(mfd->display_iova)); + + msm_iommu_map_contig_buffer(fbi->fix.smem_start, + ROTATOR_DOMAIN, + GEN_POOL, + fbi->fix.smem_len, + SZ_4K, + 1, + &(mfd->rotator_iova)); + + if (!bf_supported || mfd->index == 0) + memset(fbi->screen_base, 0x0, fix->smem_len); + + mfd->op_enable = TRUE; + mfd->panel_power_on = FALSE; + + /* cursor memory allocation */ + if (mfd->cursor_update) { + mfd->cursor_buf = dma_alloc_coherent(NULL, + MDP_CURSOR_SIZE, + (dma_addr_t *) &mfd->cursor_buf_phys, + GFP_KERNEL); + if (!mfd->cursor_buf) + mfd->cursor_update = 0; + } + + if (mfd->lut_update) { + ret = fb_alloc_cmap(&fbi->cmap, 256, 0); + if (ret) + printk(KERN_ERR "%s: fb_alloc_cmap() failed!\n", + __func__); + } + + if (register_framebuffer(fbi) < 0) { + if (mfd->lut_update) + fb_dealloc_cmap(&fbi->cmap); + + if (mfd->cursor_buf) + dma_free_coherent(NULL, + MDP_CURSOR_SIZE, + mfd->cursor_buf, + (dma_addr_t) mfd->cursor_buf_phys); + + mfd->op_enable = FALSE; + return -EPERM; + } + + fbram += fix->smem_len; + fbram_phys += fix->smem_len; + fbram_size -= fix->smem_len; + + MSM_FB_INFO + ("FrameBuffer[%d] %dx%d size=%d bytes is registered successfully!\n", + mfd->index, fbi->var.xres, fbi->var.yres, fbi->fix.smem_len); + +#ifdef CONFIG_FB_MSM_LOGO + /* Flip buffer */ + if (!load_565rle_image(INIT_IMAGE_FILE, bf_supported)) + ; +#endif + ret = 0; + +#ifdef CONFIG_HAS_EARLYSUSPEND + if (mfd->panel_info.type != DTV_PANEL) { + mfd->early_suspend.suspend = msmfb_early_suspend; + mfd->early_suspend.resume = msmfb_early_resume; + mfd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 2; + register_early_suspend(&mfd->early_suspend); + } +#endif + +#ifdef MSM_FB_ENABLE_DBGFS + { + struct dentry *root; + struct dentry *sub_dir; + char sub_name[2]; + + root = msm_fb_get_debugfs_root(); + if (root != NULL) { + sub_name[0] = (char)(mfd->index + 0x30); + sub_name[1] = '\0'; + sub_dir = debugfs_create_dir(sub_name, root); + } else { + sub_dir = NULL; + } + + mfd->sub_dir = sub_dir; + + if (sub_dir) { + msm_fb_debugfs_file_create(sub_dir, "op_enable", + (u32 *) &mfd->op_enable); + msm_fb_debugfs_file_create(sub_dir, "panel_power_on", + (u32 *) &mfd-> + panel_power_on); + msm_fb_debugfs_file_create(sub_dir, "ref_cnt", + (u32 *) &mfd->ref_cnt); + msm_fb_debugfs_file_create(sub_dir, "fb_imgType", + (u32 *) &mfd->fb_imgType); + msm_fb_debugfs_file_create(sub_dir, + "sw_currently_refreshing", + (u32 *) &mfd-> + sw_currently_refreshing); + msm_fb_debugfs_file_create(sub_dir, + "sw_refreshing_enable", + (u32 *) &mfd-> + sw_refreshing_enable); + + msm_fb_debugfs_file_create(sub_dir, "xres", + (u32 *) &mfd->panel_info. + xres); + msm_fb_debugfs_file_create(sub_dir, "yres", + (u32 *) &mfd->panel_info. + yres); + msm_fb_debugfs_file_create(sub_dir, "bpp", + (u32 *) &mfd->panel_info. + bpp); + msm_fb_debugfs_file_create(sub_dir, "type", + (u32 *) &mfd->panel_info. + type); + msm_fb_debugfs_file_create(sub_dir, "wait_cycle", + (u32 *) &mfd->panel_info. + wait_cycle); + msm_fb_debugfs_file_create(sub_dir, "pdest", + (u32 *) &mfd->panel_info. + pdest); + msm_fb_debugfs_file_create(sub_dir, "backbuff", + (u32 *) &mfd->panel_info. + fb_num); + msm_fb_debugfs_file_create(sub_dir, "clk_rate", + (u32 *) &mfd->panel_info. + clk_rate); + msm_fb_debugfs_file_create(sub_dir, "frame_count", + (u32 *) &mfd->panel_info. + frame_count); + + + switch (mfd->dest) { + case DISPLAY_LCD: + msm_fb_debugfs_file_create(sub_dir, + "vsync_enable", + (u32 *)&mfd->panel_info.lcd.vsync_enable); + msm_fb_debugfs_file_create(sub_dir, + "refx100", + (u32 *) &mfd->panel_info.lcd. refx100); + msm_fb_debugfs_file_create(sub_dir, + "v_back_porch", + (u32 *) &mfd->panel_info.lcd.v_back_porch); + msm_fb_debugfs_file_create(sub_dir, + "v_front_porch", + (u32 *) &mfd->panel_info.lcd.v_front_porch); + msm_fb_debugfs_file_create(sub_dir, + "v_pulse_width", + (u32 *) &mfd->panel_info.lcd.v_pulse_width); + msm_fb_debugfs_file_create(sub_dir, + "hw_vsync_mode", + (u32 *) &mfd->panel_info.lcd.hw_vsync_mode); + msm_fb_debugfs_file_create(sub_dir, + "vsync_notifier_period", (u32 *) + &mfd->panel_info.lcd.vsync_notifier_period); + break; + + case DISPLAY_LCDC: + msm_fb_debugfs_file_create(sub_dir, + "h_back_porch", + (u32 *) &mfd->panel_info.lcdc.h_back_porch); + msm_fb_debugfs_file_create(sub_dir, + "h_front_porch", + (u32 *) &mfd->panel_info.lcdc.h_front_porch); + msm_fb_debugfs_file_create(sub_dir, + "h_pulse_width", + (u32 *) &mfd->panel_info.lcdc.h_pulse_width); + msm_fb_debugfs_file_create(sub_dir, + "v_back_porch", + (u32 *) &mfd->panel_info.lcdc.v_back_porch); + msm_fb_debugfs_file_create(sub_dir, + "v_front_porch", + (u32 *) &mfd->panel_info.lcdc.v_front_porch); + msm_fb_debugfs_file_create(sub_dir, + "v_pulse_width", + (u32 *) &mfd->panel_info.lcdc.v_pulse_width); + msm_fb_debugfs_file_create(sub_dir, + "border_clr", + (u32 *) &mfd->panel_info.lcdc.border_clr); + msm_fb_debugfs_file_create(sub_dir, + "underflow_clr", + (u32 *) &mfd->panel_info.lcdc.underflow_clr); + msm_fb_debugfs_file_create(sub_dir, + "hsync_skew", + (u32 *) &mfd->panel_info.lcdc.hsync_skew); + break; + + default: + break; + } + } + } +#endif /* MSM_FB_ENABLE_DBGFS */ + + return ret; +} + +static int msm_fb_open(struct fb_info *info, int user) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + int result; + + result = pm_runtime_get_sync(info->dev); + + if (result < 0) { + printk(KERN_ERR "pm_runtime: fail to wake up\n"); + } + + if (info->node == 0 && !(mfd->cont_splash_done)) { /* primary */ + mfd->ref_cnt++; + return 0; + } + + if (!mfd->ref_cnt) { + if (!bf_supported || + (info->node != 1 && info->node != 2)) + mdp_set_dma_pan_info(info, NULL, TRUE); + else + pr_debug("%s:%d no mdp_set_dma_pan_info %d\n", + __func__, __LINE__, info->node); + + if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) { + printk(KERN_ERR "msm_fb_open: can't turn on display!\n"); + return -1; + } + } + + mfd->ref_cnt++; + return 0; +} + +static int msm_fb_release(struct fb_info *info, int user) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + int ret = 0; + + if (!mfd->ref_cnt) { + MSM_FB_INFO("msm_fb_release: try to close unopened fb %d!\n", + mfd->index); + return -EINVAL; + } + + mfd->ref_cnt--; + + if (!mfd->ref_cnt) { + if ((ret = + msm_fb_blank_sub(FB_BLANK_POWERDOWN, info, + mfd->op_enable)) != 0) { + printk(KERN_ERR "msm_fb_release: can't turn off display!\n"); + return ret; + } + } + + pm_runtime_put(info->dev); + return ret; +} + +DEFINE_SEMAPHORE(msm_fb_pan_sem); + +static int msm_fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct mdp_dirty_region dirty; + struct mdp_dirty_region *dirtyPtr = NULL; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct msm_fb_panel_data *pdata; + + /* + * If framebuffer is 1 or 2, io pen display is not allowed. + */ + if (bf_supported && + (info->node == 1 || info->node == 2)) { + pr_err("%s: no pan display for fb%d!", + __func__, info->node); + return -EPERM; + } + + if (info->node != 0 || mfd->cont_splash_done) /* primary */ + if ((!mfd->op_enable) || (!mfd->panel_power_on)) + return -EPERM; + + if (var->xoffset > (info->var.xres_virtual - info->var.xres)) + return -EINVAL; + + if (var->yoffset > (info->var.yres_virtual - info->var.yres)) + return -EINVAL; + + if (info->fix.xpanstep) + info->var.xoffset = + (var->xoffset / info->fix.xpanstep) * info->fix.xpanstep; + + if (info->fix.ypanstep) + info->var.yoffset = + (var->yoffset / info->fix.ypanstep) * info->fix.ypanstep; + + /* "UPDT" */ + if (var->reserved[0] == 0x54445055) { + + dirty.xoffset = var->reserved[1] & 0xffff; + dirty.yoffset = (var->reserved[1] >> 16) & 0xffff; + + if ((var->reserved[2] & 0xffff) <= dirty.xoffset) + return -EINVAL; + if (((var->reserved[2] >> 16) & 0xffff) <= dirty.yoffset) + return -EINVAL; + + dirty.width = (var->reserved[2] & 0xffff) - dirty.xoffset; + dirty.height = + ((var->reserved[2] >> 16) & 0xffff) - dirty.yoffset; + info->var.yoffset = var->yoffset; + + if (dirty.xoffset < 0) + return -EINVAL; + + if (dirty.yoffset < 0) + return -EINVAL; + + if ((dirty.xoffset + dirty.width) > info->var.xres) + return -EINVAL; + + if ((dirty.yoffset + dirty.height) > info->var.yres) + return -EINVAL; + + if ((dirty.width <= 0) || (dirty.height <= 0)) + return -EINVAL; + + dirtyPtr = &dirty; + } + complete(&mfd->msmfb_update_notify); + mutex_lock(&msm_fb_notify_update_sem); + if (mfd->msmfb_no_update_notify_timer.function) + del_timer(&mfd->msmfb_no_update_notify_timer); + + mfd->msmfb_no_update_notify_timer.expires = + jiffies + ((1000 * HZ) / 1000); + add_timer(&mfd->msmfb_no_update_notify_timer); + mutex_unlock(&msm_fb_notify_update_sem); + + down(&msm_fb_pan_sem); + + if (info->node == 0 && !(mfd->cont_splash_done)) { /* primary */ + mdp_set_dma_pan_info(info, NULL, TRUE); + if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) { + pr_err("%s: can't turn on display!\n", __func__); + return -EINVAL; + } + } + + mdp_set_dma_pan_info(info, dirtyPtr, + (var->activate == FB_ACTIVATE_VBL)); + mdp_dma_pan_update(info); + up(&msm_fb_pan_sem); + + if (unset_bl_level && !bl_updated) { + pdata = (struct msm_fb_panel_data *)mfd->pdev-> + dev.platform_data; + if ((pdata) && (pdata->set_backlight)) { + down(&mfd->sem); + mfd->bl_level = unset_bl_level; + pdata->set_backlight(mfd); + bl_level_old = unset_bl_level; + up(&mfd->sem); + bl_updated = 1; + } + } + + ++mfd->panel_info.frame_count; + return 0; +} + +static int msm_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (var->rotate != FB_ROTATE_UR) + return -EINVAL; + if (var->grayscale != info->var.grayscale) + return -EINVAL; + + switch (var->bits_per_pixel) { + case 16: + if ((var->green.offset != 5) || + !((var->blue.offset == 11) + || (var->blue.offset == 0)) || + !((var->red.offset == 11) + || (var->red.offset == 0)) || + (var->blue.length != 5) || + (var->green.length != 6) || + (var->red.length != 5) || + (var->blue.msb_right != 0) || + (var->green.msb_right != 0) || + (var->red.msb_right != 0) || + (var->transp.offset != 0) || + (var->transp.length != 0)) + return -EINVAL; + break; + + case 24: + if ((var->blue.offset != 0) || + (var->green.offset != 8) || + (var->red.offset != 16) || + (var->blue.length != 8) || + (var->green.length != 8) || + (var->red.length != 8) || + (var->blue.msb_right != 0) || + (var->green.msb_right != 0) || + (var->red.msb_right != 0) || + !(((var->transp.offset == 0) && + (var->transp.length == 0)) || + ((var->transp.offset == 24) && + (var->transp.length == 8)))) + return -EINVAL; + break; + + case 32: + /* Figure out if the user meant RGBA or ARGB + and verify the position of the RGB components */ + + if (var->transp.offset == 24) { + if ((var->blue.offset != 0) || + (var->green.offset != 8) || + (var->red.offset != 16)) + return -EINVAL; + } else if (var->transp.offset == 0) { + if ((var->blue.offset != 8) || + (var->green.offset != 16) || + (var->red.offset != 24)) + return -EINVAL; + } else + return -EINVAL; + + /* Check the common values for both RGBA and ARGB */ + + if ((var->blue.length != 8) || + (var->green.length != 8) || + (var->red.length != 8) || + (var->transp.length != 8) || + (var->blue.msb_right != 0) || + (var->green.msb_right != 0) || + (var->red.msb_right != 0)) + return -EINVAL; + + break; + + default: + return -EINVAL; + } + + if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0)) + return -EINVAL; + + if (!bf_supported || + (info->node != 1 && info->node != 2)) + if (info->fix.smem_len < + (var->xres_virtual* + var->yres_virtual* + (var->bits_per_pixel/8))) + return -EINVAL; + + if ((var->xres == 0) || (var->yres == 0)) + return -EINVAL; + + if ((var->xres > MAX(mfd->panel_info.xres, + mfd->panel_info.mode2_xres)) || + (var->yres > MAX(mfd->panel_info.yres, + mfd->panel_info.mode2_yres))) + return -EINVAL; + + if (var->xoffset > (var->xres_virtual - var->xres)) + return -EINVAL; + + if (var->yoffset > (var->yres_virtual - var->yres)) + return -EINVAL; + + return 0; +} + +int msm_fb_check_frame_rate(struct msm_fb_data_type *mfd + , struct fb_info *info) +{ + int panel_height, panel_width, var_frame_rate, fps_mod; + struct fb_var_screeninfo *var = &info->var; + fps_mod = 0; + if ((mfd->panel_info.type == DTV_PANEL) || + (mfd->panel_info.type == HDMI_PANEL)) { + panel_height = var->yres + var->upper_margin + + var->vsync_len + var->lower_margin; + panel_width = var->xres + var->right_margin + + var->hsync_len + var->left_margin; + var_frame_rate = ((var->pixclock)/(panel_height * panel_width)); + if (mfd->var_frame_rate != var_frame_rate) { + fps_mod = 1; + mfd->var_frame_rate = var_frame_rate; + } + } + return fps_mod; +} + +static int msm_fb_set_par(struct fb_info *info) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct fb_var_screeninfo *var = &info->var; + int old_imgType; + int blank = 0; + + old_imgType = mfd->fb_imgType; + switch (var->bits_per_pixel) { + case 16: + if (var->red.offset == 0) + mfd->fb_imgType = MDP_BGR_565; + else + mfd->fb_imgType = MDP_RGB_565; + break; + + case 24: + if ((var->transp.offset == 0) && (var->transp.length == 0)) + mfd->fb_imgType = MDP_RGB_888; + else if ((var->transp.offset == 24) && + (var->transp.length == 8)) { + mfd->fb_imgType = MDP_ARGB_8888; + info->var.bits_per_pixel = 32; + } + break; + + case 32: + if (var->transp.offset == 24) + mfd->fb_imgType = MDP_ARGB_8888; + else + mfd->fb_imgType = MDP_RGBA_8888; + break; + + default: + return -EINVAL; + } + + if ((mfd->var_pixclock != var->pixclock) || + (mfd->hw_refresh && ((mfd->fb_imgType != old_imgType) || + (mfd->var_pixclock != var->pixclock) || + (mfd->var_xres != var->xres) || + (mfd->var_yres != var->yres) || + (msm_fb_check_frame_rate(mfd, info))))) { + mfd->var_xres = var->xres; + mfd->var_yres = var->yres; + mfd->var_pixclock = var->pixclock; + blank = 1; + } + mfd->fbi->fix.line_length = msm_fb_line_length(mfd->index, var->xres, + var->bits_per_pixel/8); + + if (blank) { + msm_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable); + msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable); + } + + return 0; +} + +static int msm_fb_stop_sw_refresher(struct msm_fb_data_type *mfd) +{ + if (mfd->hw_refresh) + return -EPERM; + + if (mfd->sw_currently_refreshing) { + down(&mfd->sem); + mfd->sw_currently_refreshing = FALSE; + up(&mfd->sem); + + /* wait until the refresher finishes the last job */ + wait_for_completion_killable(&mfd->refresher_comp); + } + + return 0; +} + +int msm_fb_resume_sw_refresher(struct msm_fb_data_type *mfd) +{ + boolean do_refresh; + + if (mfd->hw_refresh) + return -EPERM; + + down(&mfd->sem); + if ((!mfd->sw_currently_refreshing) && (mfd->sw_refreshing_enable)) { + do_refresh = TRUE; + mfd->sw_currently_refreshing = TRUE; + } else { + do_refresh = FALSE; + } + up(&mfd->sem); + + if (do_refresh) + mdp_refresh_screen((unsigned long)mfd); + + return 0; +} + +#if defined CONFIG_FB_MSM_MDP31 +static int mdp_blit_split_height(struct fb_info *info, + struct mdp_blit_req *req) +{ + int ret; + struct mdp_blit_req splitreq; + int s_x_0, s_x_1, s_w_0, s_w_1, s_y_0, s_y_1, s_h_0, s_h_1; + int d_x_0, d_x_1, d_w_0, d_w_1, d_y_0, d_y_1, d_h_0, d_h_1; + + splitreq = *req; + /* break dest roi at height*/ + d_x_0 = d_x_1 = req->dst_rect.x; + d_w_0 = d_w_1 = req->dst_rect.w; + d_y_0 = req->dst_rect.y; + if (req->dst_rect.h % 32 == 3) + d_h_1 = (req->dst_rect.h - 3) / 2 - 1; + else if (req->dst_rect.h % 32 == 2) + d_h_1 = (req->dst_rect.h - 2) / 2 - 6; + else + d_h_1 = (req->dst_rect.h - 1) / 2 - 1; + d_h_0 = req->dst_rect.h - d_h_1; + d_y_1 = d_y_0 + d_h_0; + if (req->dst_rect.h == 3) { + d_h_1 = 2; + d_h_0 = 2; + d_y_1 = d_y_0 + 1; + } + + /* blit first region */ + if (((splitreq.flags & 0x07) == 0x04) || + ((splitreq.flags & 0x07) == 0x0)) { + + if (splitreq.flags & MDP_ROT_90) { + s_y_0 = s_y_1 = req->src_rect.y; + s_h_0 = s_h_1 = req->src_rect.h; + s_x_0 = req->src_rect.x; + s_w_1 = (req->src_rect.w * d_h_1) / req->dst_rect.h; + s_w_0 = req->src_rect.w - s_w_1; + s_x_1 = s_x_0 + s_w_0; + if (d_h_1 >= 8 * s_w_1) { + s_w_1++; + s_x_1--; + } + } else { + s_x_0 = s_x_1 = req->src_rect.x; + s_w_0 = s_w_1 = req->src_rect.w; + s_y_0 = req->src_rect.y; + s_h_1 = (req->src_rect.h * d_h_1) / req->dst_rect.h; + s_h_0 = req->src_rect.h - s_h_1; + s_y_1 = s_y_0 + s_h_0; + if (d_h_1 >= 8 * s_h_1) { + s_h_1++; + s_y_1--; + } + } + + splitreq.src_rect.h = s_h_0; + splitreq.src_rect.y = s_y_0; + splitreq.dst_rect.h = d_h_0; + splitreq.dst_rect.y = d_y_0; + splitreq.src_rect.x = s_x_0; + splitreq.src_rect.w = s_w_0; + splitreq.dst_rect.x = d_x_0; + splitreq.dst_rect.w = d_w_0; + } else { + + if (splitreq.flags & MDP_ROT_90) { + s_y_0 = s_y_1 = req->src_rect.y; + s_h_0 = s_h_1 = req->src_rect.h; + s_x_0 = req->src_rect.x; + s_w_1 = (req->src_rect.w * d_h_0) / req->dst_rect.h; + s_w_0 = req->src_rect.w - s_w_1; + s_x_1 = s_x_0 + s_w_0; + if (d_h_0 >= 8 * s_w_1) { + s_w_1++; + s_x_1--; + } + } else { + s_x_0 = s_x_1 = req->src_rect.x; + s_w_0 = s_w_1 = req->src_rect.w; + s_y_0 = req->src_rect.y; + s_h_1 = (req->src_rect.h * d_h_0) / req->dst_rect.h; + s_h_0 = req->src_rect.h - s_h_1; + s_y_1 = s_y_0 + s_h_0; + if (d_h_0 >= 8 * s_h_1) { + s_h_1++; + s_y_1--; + } + } + splitreq.src_rect.h = s_h_0; + splitreq.src_rect.y = s_y_0; + splitreq.dst_rect.h = d_h_1; + splitreq.dst_rect.y = d_y_1; + splitreq.src_rect.x = s_x_0; + splitreq.src_rect.w = s_w_0; + splitreq.dst_rect.x = d_x_1; + splitreq.dst_rect.w = d_w_1; + } + ret = mdp_ppp_blit(info, &splitreq); + if (ret) + return ret; + + /* blit second region */ + if (((splitreq.flags & 0x07) == 0x04) || + ((splitreq.flags & 0x07) == 0x0)) { + splitreq.src_rect.h = s_h_1; + splitreq.src_rect.y = s_y_1; + splitreq.dst_rect.h = d_h_1; + splitreq.dst_rect.y = d_y_1; + splitreq.src_rect.x = s_x_1; + splitreq.src_rect.w = s_w_1; + splitreq.dst_rect.x = d_x_1; + splitreq.dst_rect.w = d_w_1; + } else { + splitreq.src_rect.h = s_h_1; + splitreq.src_rect.y = s_y_1; + splitreq.dst_rect.h = d_h_0; + splitreq.dst_rect.y = d_y_0; + splitreq.src_rect.x = s_x_1; + splitreq.src_rect.w = s_w_1; + splitreq.dst_rect.x = d_x_0; + splitreq.dst_rect.w = d_w_0; + } + ret = mdp_ppp_blit(info, &splitreq); + return ret; +} +#endif + +int mdp_blit(struct fb_info *info, struct mdp_blit_req *req) +{ + int ret; +#if defined CONFIG_FB_MSM_MDP31 || defined CONFIG_FB_MSM_MDP30 + unsigned int remainder = 0, is_bpp_4 = 0; + struct mdp_blit_req splitreq; + int s_x_0, s_x_1, s_w_0, s_w_1, s_y_0, s_y_1, s_h_0, s_h_1; + int d_x_0, d_x_1, d_w_0, d_w_1, d_y_0, d_y_1, d_h_0, d_h_1; + + if (req->flags & MDP_ROT_90) { + if (((req->dst_rect.h == 1) && ((req->src_rect.w != 1) || + (req->dst_rect.w != req->src_rect.h))) || + ((req->dst_rect.w == 1) && ((req->src_rect.h != 1) || + (req->dst_rect.h != req->src_rect.w)))) { + printk(KERN_ERR "mpd_ppp: error scaling when size is 1!\n"); + return -EINVAL; + } + } else { + if (((req->dst_rect.w == 1) && ((req->src_rect.w != 1) || + (req->dst_rect.h != req->src_rect.h))) || + ((req->dst_rect.h == 1) && ((req->src_rect.h != 1) || + (req->dst_rect.w != req->src_rect.w)))) { + printk(KERN_ERR "mpd_ppp: error scaling when size is 1!\n"); + return -EINVAL; + } + } +#endif + if (unlikely(req->src_rect.h == 0 || req->src_rect.w == 0)) { + printk(KERN_ERR "mpd_ppp: src img of zero size!\n"); + return -EINVAL; + } + if (unlikely(req->dst_rect.h == 0 || req->dst_rect.w == 0)) + return 0; + +#if defined CONFIG_FB_MSM_MDP31 + /* MDP width split workaround */ + remainder = (req->dst_rect.w)%32; + ret = mdp_get_bytes_per_pixel(req->dst.format, + (struct msm_fb_data_type *)info->par); + if (ret <= 0) { + printk(KERN_ERR "mdp_ppp: incorrect bpp!\n"); + return -EINVAL; + } + is_bpp_4 = (ret == 4) ? 1 : 0; + + if ((is_bpp_4 && (remainder == 6 || remainder == 14 || + remainder == 22 || remainder == 30)) || remainder == 3 || + (remainder == 1 && req->dst_rect.w != 1) || + (remainder == 2 && req->dst_rect.w != 2)) { + /* make new request as provide by user */ + splitreq = *req; + + /* break dest roi at width*/ + d_y_0 = d_y_1 = req->dst_rect.y; + d_h_0 = d_h_1 = req->dst_rect.h; + d_x_0 = req->dst_rect.x; + + if (remainder == 14) + d_w_1 = (req->dst_rect.w - 14) / 2 + 4; + else if (remainder == 22) + d_w_1 = (req->dst_rect.w - 22) / 2 + 10; + else if (remainder == 30) + d_w_1 = (req->dst_rect.w - 30) / 2 + 10; + else if (remainder == 6) + d_w_1 = req->dst_rect.w / 2 - 1; + else if (remainder == 3) + d_w_1 = (req->dst_rect.w - 3) / 2 - 1; + else if (remainder == 2) + d_w_1 = (req->dst_rect.w - 2) / 2 - 6; + else + d_w_1 = (req->dst_rect.w - 1) / 2 - 1; + d_w_0 = req->dst_rect.w - d_w_1; + d_x_1 = d_x_0 + d_w_0; + if (req->dst_rect.w == 3) { + d_w_1 = 2; + d_w_0 = 2; + d_x_1 = d_x_0 + 1; + } + + /* blit first region */ + if (((splitreq.flags & 0x07) == 0x07) || + ((splitreq.flags & 0x07) == 0x0)) { + + if (splitreq.flags & MDP_ROT_90) { + s_x_0 = s_x_1 = req->src_rect.x; + s_w_0 = s_w_1 = req->src_rect.w; + s_y_0 = req->src_rect.y; + s_h_1 = (req->src_rect.h * d_w_1) / + req->dst_rect.w; + s_h_0 = req->src_rect.h - s_h_1; + s_y_1 = s_y_0 + s_h_0; + if (d_w_1 >= 8 * s_h_1) { + s_h_1++; + s_y_1--; + } + } else { + s_y_0 = s_y_1 = req->src_rect.y; + s_h_0 = s_h_1 = req->src_rect.h; + s_x_0 = req->src_rect.x; + s_w_1 = (req->src_rect.w * d_w_1) / + req->dst_rect.w; + s_w_0 = req->src_rect.w - s_w_1; + s_x_1 = s_x_0 + s_w_0; + if (d_w_1 >= 8 * s_w_1) { + s_w_1++; + s_x_1--; + } + } + + splitreq.src_rect.h = s_h_0; + splitreq.src_rect.y = s_y_0; + splitreq.dst_rect.h = d_h_0; + splitreq.dst_rect.y = d_y_0; + splitreq.src_rect.x = s_x_0; + splitreq.src_rect.w = s_w_0; + splitreq.dst_rect.x = d_x_0; + splitreq.dst_rect.w = d_w_0; + } else { + if (splitreq.flags & MDP_ROT_90) { + s_x_0 = s_x_1 = req->src_rect.x; + s_w_0 = s_w_1 = req->src_rect.w; + s_y_0 = req->src_rect.y; + s_h_1 = (req->src_rect.h * d_w_0) / + req->dst_rect.w; + s_h_0 = req->src_rect.h - s_h_1; + s_y_1 = s_y_0 + s_h_0; + if (d_w_0 >= 8 * s_h_1) { + s_h_1++; + s_y_1--; + } + } else { + s_y_0 = s_y_1 = req->src_rect.y; + s_h_0 = s_h_1 = req->src_rect.h; + s_x_0 = req->src_rect.x; + s_w_1 = (req->src_rect.w * d_w_0) / + req->dst_rect.w; + s_w_0 = req->src_rect.w - s_w_1; + s_x_1 = s_x_0 + s_w_0; + if (d_w_0 >= 8 * s_w_1) { + s_w_1++; + s_x_1--; + } + } + splitreq.src_rect.h = s_h_0; + splitreq.src_rect.y = s_y_0; + splitreq.dst_rect.h = d_h_1; + splitreq.dst_rect.y = d_y_1; + splitreq.src_rect.x = s_x_0; + splitreq.src_rect.w = s_w_0; + splitreq.dst_rect.x = d_x_1; + splitreq.dst_rect.w = d_w_1; + } + + if ((splitreq.dst_rect.h % 32 == 3) || + ((req->dst_rect.h % 32) == 1 && req->dst_rect.h != 1) || + ((req->dst_rect.h % 32) == 2 && req->dst_rect.h != 2)) + ret = mdp_blit_split_height(info, &splitreq); + else + ret = mdp_ppp_blit(info, &splitreq); + if (ret) + return ret; + /* blit second region */ + if (((splitreq.flags & 0x07) == 0x07) || + ((splitreq.flags & 0x07) == 0x0)) { + splitreq.src_rect.h = s_h_1; + splitreq.src_rect.y = s_y_1; + splitreq.dst_rect.h = d_h_1; + splitreq.dst_rect.y = d_y_1; + splitreq.src_rect.x = s_x_1; + splitreq.src_rect.w = s_w_1; + splitreq.dst_rect.x = d_x_1; + splitreq.dst_rect.w = d_w_1; + } else { + splitreq.src_rect.h = s_h_1; + splitreq.src_rect.y = s_y_1; + splitreq.dst_rect.h = d_h_0; + splitreq.dst_rect.y = d_y_0; + splitreq.src_rect.x = s_x_1; + splitreq.src_rect.w = s_w_1; + splitreq.dst_rect.x = d_x_0; + splitreq.dst_rect.w = d_w_0; + } + if (((splitreq.dst_rect.h % 32) == 3) || + ((req->dst_rect.h % 32) == 1 && req->dst_rect.h != 1) || + ((req->dst_rect.h % 32) == 2 && req->dst_rect.h != 2)) + ret = mdp_blit_split_height(info, &splitreq); + else + ret = mdp_ppp_blit(info, &splitreq); + if (ret) + return ret; + } else if ((req->dst_rect.h % 32) == 3 || + ((req->dst_rect.h % 32) == 1 && req->dst_rect.h != 1) || + ((req->dst_rect.h % 32) == 2 && req->dst_rect.h != 2)) + ret = mdp_blit_split_height(info, req); + else + ret = mdp_ppp_blit(info, req); + return ret; +#elif defined CONFIG_FB_MSM_MDP30 + /* MDP width split workaround */ + remainder = (req->dst_rect.w)%16; + ret = mdp_get_bytes_per_pixel(req->dst.format, + (struct msm_fb_data_type *)info->par); + if (ret <= 0) { + printk(KERN_ERR "mdp_ppp: incorrect bpp!\n"); + return -EINVAL; + } + is_bpp_4 = (ret == 4) ? 1 : 0; + + if ((is_bpp_4 && (remainder == 6 || remainder == 14))) { + + /* make new request as provide by user */ + splitreq = *req; + + /* break dest roi at width*/ + d_y_0 = d_y_1 = req->dst_rect.y; + d_h_0 = d_h_1 = req->dst_rect.h; + d_x_0 = req->dst_rect.x; + + if (remainder == 14 || remainder == 6) + d_w_1 = req->dst_rect.w / 2; + else + d_w_1 = (req->dst_rect.w - 1) / 2 - 1; + + d_w_0 = req->dst_rect.w - d_w_1; + d_x_1 = d_x_0 + d_w_0; + + /* blit first region */ + if (((splitreq.flags & 0x07) == 0x07) || + ((splitreq.flags & 0x07) == 0x05) || + ((splitreq.flags & 0x07) == 0x02) || + ((splitreq.flags & 0x07) == 0x0)) { + + if (splitreq.flags & MDP_ROT_90) { + s_x_0 = s_x_1 = req->src_rect.x; + s_w_0 = s_w_1 = req->src_rect.w; + s_y_0 = req->src_rect.y; + s_h_1 = (req->src_rect.h * d_w_1) / + req->dst_rect.w; + s_h_0 = req->src_rect.h - s_h_1; + s_y_1 = s_y_0 + s_h_0; + if (d_w_1 >= 8 * s_h_1) { + s_h_1++; + s_y_1--; + } + } else { + s_y_0 = s_y_1 = req->src_rect.y; + s_h_0 = s_h_1 = req->src_rect.h; + s_x_0 = req->src_rect.x; + s_w_1 = (req->src_rect.w * d_w_1) / + req->dst_rect.w; + s_w_0 = req->src_rect.w - s_w_1; + s_x_1 = s_x_0 + s_w_0; + if (d_w_1 >= 8 * s_w_1) { + s_w_1++; + s_x_1--; + } + } + + splitreq.src_rect.h = s_h_0; + splitreq.src_rect.y = s_y_0; + splitreq.dst_rect.h = d_h_0; + splitreq.dst_rect.y = d_y_0; + splitreq.src_rect.x = s_x_0; + splitreq.src_rect.w = s_w_0; + splitreq.dst_rect.x = d_x_0; + splitreq.dst_rect.w = d_w_0; + } else { + if (splitreq.flags & MDP_ROT_90) { + s_x_0 = s_x_1 = req->src_rect.x; + s_w_0 = s_w_1 = req->src_rect.w; + s_y_0 = req->src_rect.y; + s_h_1 = (req->src_rect.h * d_w_0) / + req->dst_rect.w; + s_h_0 = req->src_rect.h - s_h_1; + s_y_1 = s_y_0 + s_h_0; + if (d_w_0 >= 8 * s_h_1) { + s_h_1++; + s_y_1--; + } + } else { + s_y_0 = s_y_1 = req->src_rect.y; + s_h_0 = s_h_1 = req->src_rect.h; + s_x_0 = req->src_rect.x; + s_w_1 = (req->src_rect.w * d_w_0) / + req->dst_rect.w; + s_w_0 = req->src_rect.w - s_w_1; + s_x_1 = s_x_0 + s_w_0; + if (d_w_0 >= 8 * s_w_1) { + s_w_1++; + s_x_1--; + } + } + splitreq.src_rect.h = s_h_0; + splitreq.src_rect.y = s_y_0; + splitreq.dst_rect.h = d_h_1; + splitreq.dst_rect.y = d_y_1; + splitreq.src_rect.x = s_x_0; + splitreq.src_rect.w = s_w_0; + splitreq.dst_rect.x = d_x_1; + splitreq.dst_rect.w = d_w_1; + } + + /* No need to split in height */ + ret = mdp_ppp_blit(info, &splitreq); + + if (ret) + return ret; + + /* blit second region */ + if (((splitreq.flags & 0x07) == 0x07) || + ((splitreq.flags & 0x07) == 0x05) || + ((splitreq.flags & 0x07) == 0x02) || + ((splitreq.flags & 0x07) == 0x0)) { + splitreq.src_rect.h = s_h_1; + splitreq.src_rect.y = s_y_1; + splitreq.dst_rect.h = d_h_1; + splitreq.dst_rect.y = d_y_1; + splitreq.src_rect.x = s_x_1; + splitreq.src_rect.w = s_w_1; + splitreq.dst_rect.x = d_x_1; + splitreq.dst_rect.w = d_w_1; + } else { + splitreq.src_rect.h = s_h_1; + splitreq.src_rect.y = s_y_1; + splitreq.dst_rect.h = d_h_0; + splitreq.dst_rect.y = d_y_0; + splitreq.src_rect.x = s_x_1; + splitreq.src_rect.w = s_w_1; + splitreq.dst_rect.x = d_x_0; + splitreq.dst_rect.w = d_w_0; + } + + /* No need to split in height ... just width */ + ret = mdp_ppp_blit(info, &splitreq); + + if (ret) + return ret; + + } else + ret = mdp_ppp_blit(info, req); + return ret; +#else + ret = mdp_ppp_blit(info, req); + return ret; +#endif +} + +typedef void (*msm_dma_barrier_function_pointer) (void *, size_t); + +static inline void msm_fb_dma_barrier_for_rect(struct fb_info *info, + struct mdp_img *img, struct mdp_rect *rect, + msm_dma_barrier_function_pointer dma_barrier_fp + ) +{ + /* + * Compute the start and end addresses of the rectangles. + * NOTE: As currently implemented, the data between + * the end of one row and the start of the next is + * included in the address range rather than + * doing multiple calls for each row. + */ + unsigned long start; + size_t size; + char * const pmem_start = info->screen_base; + int bytes_per_pixel = mdp_get_bytes_per_pixel(img->format, + (struct msm_fb_data_type *)info->par); + if (bytes_per_pixel <= 0) { + printk(KERN_ERR "%s incorrect bpp!\n", __func__); + return; + } + start = (unsigned long)pmem_start + img->offset + + (img->width * rect->y + rect->x) * bytes_per_pixel; + size = (rect->h * img->width + rect->w) * bytes_per_pixel; + (*dma_barrier_fp) ((void *) start, size); + +} + +static inline void msm_dma_nc_pre(void) +{ + dmb(); +} +static inline void msm_dma_wt_pre(void) +{ + dmb(); +} +static inline void msm_dma_todevice_wb_pre(void *start, size_t size) +{ + dma_cache_pre_ops(start, size, DMA_TO_DEVICE); +} + +static inline void msm_dma_fromdevice_wb_pre(void *start, size_t size) +{ + dma_cache_pre_ops(start, size, DMA_FROM_DEVICE); +} + +static inline void msm_dma_nc_post(void) +{ + dmb(); +} + +static inline void msm_dma_fromdevice_wt_post(void *start, size_t size) +{ + dma_cache_post_ops(start, size, DMA_FROM_DEVICE); +} + +static inline void msm_dma_todevice_wb_post(void *start, size_t size) +{ + dma_cache_post_ops(start, size, DMA_TO_DEVICE); +} + +static inline void msm_dma_fromdevice_wb_post(void *start, size_t size) +{ + dma_cache_post_ops(start, size, DMA_FROM_DEVICE); +} + +/* + * Do the write barriers required to guarantee data is committed to RAM + * (from CPU cache or internal buffers) before a DMA operation starts. + * NOTE: As currently implemented, the data between + * the end of one row and the start of the next is + * included in the address range rather than + * doing multiple calls for each row. +*/ +static void msm_fb_ensure_memory_coherency_before_dma(struct fb_info *info, + struct mdp_blit_req *req_list, + int req_list_count) +{ +#ifdef CONFIG_ARCH_QSD8X50 + int i; + + /* + * Normally, do the requested barriers for each address + * range that corresponds to a rectangle. + * + * But if at least one write barrier is requested for data + * going to or from the device but no address range is + * needed for that barrier, then do the barrier, but do it + * only once, no matter how many requests there are. + */ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + switch (mfd->mdp_fb_page_protection) { + default: + case MDP_FB_PAGE_PROTECTION_NONCACHED: + case MDP_FB_PAGE_PROTECTION_WRITECOMBINE: + /* + * The following barrier is only done at most once, + * since further calls would be redundant. + */ + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags + & MDP_NO_DMA_BARRIER_START)) { + msm_dma_nc_pre(); + break; + } + } + break; + + case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE: + /* + * The following barrier is only done at most once, + * since further calls would be redundant. + */ + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags + & MDP_NO_DMA_BARRIER_START)) { + msm_dma_wt_pre(); + break; + } + } + break; + + case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE: + case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE: + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags & + MDP_NO_DMA_BARRIER_START)) { + + msm_fb_dma_barrier_for_rect(info, + &(req_list[i].src), + &(req_list[i].src_rect), + msm_dma_todevice_wb_pre + ); + + msm_fb_dma_barrier_for_rect(info, + &(req_list[i].dst), + &(req_list[i].dst_rect), + msm_dma_todevice_wb_pre + ); + } + } + break; + } +#else + dmb(); +#endif +} + + +/* + * Do the write barriers required to guarantee data will be re-read from RAM by + * the CPU after a DMA operation ends. + * NOTE: As currently implemented, the data between + * the end of one row and the start of the next is + * included in the address range rather than + * doing multiple calls for each row. +*/ +static void msm_fb_ensure_memory_coherency_after_dma(struct fb_info *info, + struct mdp_blit_req *req_list, + int req_list_count) +{ +#ifdef CONFIG_ARCH_QSD8X50 + int i; + + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + switch (mfd->mdp_fb_page_protection) { + default: + case MDP_FB_PAGE_PROTECTION_NONCACHED: + case MDP_FB_PAGE_PROTECTION_WRITECOMBINE: + /* + * The following barrier is only done at most once, + * since further calls would be redundant. + */ + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags + & MDP_NO_DMA_BARRIER_END)) { + msm_dma_nc_post(); + break; + } + } + break; + + case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE: + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags & + MDP_NO_DMA_BARRIER_END)) { + + msm_fb_dma_barrier_for_rect(info, + &(req_list[i].dst), + &(req_list[i].dst_rect), + msm_dma_fromdevice_wt_post + ); + } + } + break; + case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE: + case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE: + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags & + MDP_NO_DMA_BARRIER_END)) { + + msm_fb_dma_barrier_for_rect(info, + &(req_list[i].dst), + &(req_list[i].dst_rect), + msm_dma_fromdevice_wb_post + ); + } + } + break; + } +#else + dmb(); +#endif +} + +/* + * NOTE: The userspace issues blit operations in a sequence, the sequence + * start with a operation marked START and ends in an operation marked + * END. It is guranteed by the userspace that all the blit operations + * between START and END are only within the regions of areas designated + * by the START and END operations and that the userspace doesnt modify + * those areas. Hence it would be enough to perform barrier/cache operations + * only on the START and END operations. + */ +static int msmfb_blit(struct fb_info *info, void __user *p) +{ + /* + * CAUTION: The names of the struct types intentionally *DON'T* match + * the names of the variables declared -- they appear to be swapped. + * Read the code carefully and you should see that the variable names + * make sense. + */ + const int MAX_LIST_WINDOW = 16; + struct mdp_blit_req req_list[MAX_LIST_WINDOW]; + struct mdp_blit_req_list req_list_header; + + int count, i, req_list_count; + if (bf_supported && + (info->node == 1 || info->node == 2)) { + pr_err("%s: no pan display for fb%d.", + __func__, info->node); + return -EPERM; + } + /* Get the count size for the total BLIT request. */ + if (copy_from_user(&req_list_header, p, sizeof(req_list_header))) + return -EFAULT; + p += sizeof(req_list_header); + count = req_list_header.count; + if (count < 0 || count >= MAX_BLIT_REQ) + return -EINVAL; + while (count > 0) { + /* + * Access the requests through a narrow window to decrease copy + * overhead and make larger requests accessible to the + * coherency management code. + * NOTE: The window size is intended to be larger than the + * typical request size, but not require more than 2 + * kbytes of stack storage. + */ + req_list_count = count; + if (req_list_count > MAX_LIST_WINDOW) + req_list_count = MAX_LIST_WINDOW; + if (copy_from_user(&req_list, p, + sizeof(struct mdp_blit_req)*req_list_count)) + return -EFAULT; + + /* + * Ensure that any data CPU may have previously written to + * internal state (but not yet committed to memory) is + * guaranteed to be committed to memory now. + */ + msm_fb_ensure_memory_coherency_before_dma(info, + req_list, req_list_count); + + /* + * Do the blit DMA, if required -- returning early only if + * there is a failure. + */ + for (i = 0; i < req_list_count; i++) { + if (!(req_list[i].flags & MDP_NO_BLIT)) { + /* Do the actual blit. */ + int ret = mdp_blit(info, &(req_list[i])); + + /* + * Note that early returns don't guarantee + * memory coherency. + */ + if (ret) + return ret; + } + } + + /* + * Ensure that CPU cache and other internal CPU state is + * updated to reflect any change in memory modified by MDP blit + * DMA. + */ + msm_fb_ensure_memory_coherency_after_dma(info, + req_list, + req_list_count); + + /* Go to next window of requests. */ + count -= req_list_count; + p += sizeof(struct mdp_blit_req)*req_list_count; + } + return 0; +} + +#ifdef CONFIG_FB_MSM_OVERLAY +static int msmfb_overlay_get(struct fb_info *info, void __user *p) +{ + struct mdp_overlay req; + int ret; + + if (copy_from_user(&req, p, sizeof(req))) + return -EFAULT; + + ret = mdp4_overlay_get(info, &req); + if (ret) { + printk(KERN_ERR "%s: ioctl failed \n", + __func__); + return ret; + } + if (copy_to_user(p, &req, sizeof(req))) { + printk(KERN_ERR "%s: copy2user failed \n", + __func__); + return -EFAULT; + } + + return 0; +} + +static int msmfb_overlay_set(struct fb_info *info, void __user *p) +{ + struct mdp_overlay req; + int ret; + + if (copy_from_user(&req, p, sizeof(req))) + return -EFAULT; + + ret = mdp4_overlay_set(info, &req); + if (ret) { + printk(KERN_ERR "%s: ioctl failed, rc=%d\n", + __func__, ret); + return ret; + } + + if (copy_to_user(p, &req, sizeof(req))) { + printk(KERN_ERR "%s: copy2user failed \n", + __func__); + return -EFAULT; + } + + return 0; +} + +static int msmfb_overlay_unset(struct fb_info *info, unsigned long *argp) +{ + int ret, ndx; + + ret = copy_from_user(&ndx, argp, sizeof(ndx)); + if (ret) { + printk(KERN_ERR "%s:msmfb_overlay_unset ioctl failed \n", + __func__); + return ret; + } + + return mdp4_overlay_unset(info, ndx); +} + +static int msmfb_overlay_play_wait(struct fb_info *info, unsigned long *argp) +{ + int ret; + struct msmfb_overlay_data req; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + if (mfd->overlay_play_enable == 0) /* nothing to do */ + return 0; + + ret = copy_from_user(&req, argp, sizeof(req)); + if (ret) { + pr_err("%s:msmfb_overlay_wait ioctl failed", __func__); + return ret; + } + + ret = mdp4_overlay_play_wait(info, &req); + + return ret; +} + +static int msmfb_overlay_play(struct fb_info *info, unsigned long *argp) +{ + int ret; + struct msmfb_overlay_data req; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct msm_fb_panel_data *pdata; + + if (mfd->overlay_play_enable == 0) /* nothing to do */ + return 0; + + ret = copy_from_user(&req, argp, sizeof(req)); + if (ret) { + printk(KERN_ERR "%s:msmfb_overlay_play ioctl failed \n", + __func__); + return ret; + } + + complete(&mfd->msmfb_update_notify); + mutex_lock(&msm_fb_notify_update_sem); + if (mfd->msmfb_no_update_notify_timer.function) + del_timer(&mfd->msmfb_no_update_notify_timer); + + mfd->msmfb_no_update_notify_timer.expires = + jiffies + ((1000 * HZ) / 1000); + add_timer(&mfd->msmfb_no_update_notify_timer); + mutex_unlock(&msm_fb_notify_update_sem); + + if (info->node == 0 && !(mfd->cont_splash_done)) { /* primary */ + mdp_set_dma_pan_info(info, NULL, TRUE); + if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) { + pr_err("%s: can't turn on display!\n", __func__); + return -EINVAL; + } + } + + ret = mdp4_overlay_play(info, &req); + + if (unset_bl_level && !bl_updated) { + pdata = (struct msm_fb_panel_data *)mfd->pdev-> + dev.platform_data; + if ((pdata) && (pdata->set_backlight)) { + down(&mfd->sem); + mfd->bl_level = unset_bl_level; + pdata->set_backlight(mfd); + bl_level_old = unset_bl_level; + up(&mfd->sem); + bl_updated = 1; + } + } + + return ret; +} + +static int msmfb_overlay_play_enable(struct fb_info *info, unsigned long *argp) +{ + int ret, enable; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + ret = copy_from_user(&enable, argp, sizeof(enable)); + if (ret) { + printk(KERN_ERR "%s:msmfb_overlay_play_enable ioctl failed \n", + __func__); + return ret; + } + + mfd->overlay_play_enable = enable; + + return 0; +} + +static int msmfb_overlay_blt(struct fb_info *info, unsigned long *argp) +{ + int ret; + struct msmfb_overlay_blt req; + + ret = copy_from_user(&req, argp, sizeof(req)); + if (ret) { + pr_err("%s: failed\n", __func__); + return ret; + } + + ret = mdp4_overlay_blt(info, &req); + + return ret; +} + +static int msmfb_overlay_blt_off(struct fb_info *info, unsigned long *argp) +{ + int ret; + struct msmfb_overlay_blt req; + + ret = copy_from_user(&req, argp, sizeof(req)); + if (ret) { + pr_err("%s: failed\n", __func__); + return ret; + } + + ret = mdp4_overlay_blt_offset(info, &req); + + ret = copy_to_user(argp, &req, sizeof(req)); + if (ret) + printk(KERN_ERR "%s:msmfb_overlay_blt_off ioctl failed\n", + __func__); + + return ret; +} + +#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL +static int msmfb_overlay_ioctl_writeback_init(struct fb_info *info) +{ + return mdp4_writeback_init(info); +} +static int msmfb_overlay_ioctl_writeback_start( + struct fb_info *info) +{ + int ret = 0; + ret = mdp4_writeback_start(info); + if (ret) + goto error; +error: + if (ret) + pr_err("%s:msmfb_writeback_start " + " ioctl failed\n", __func__); + return ret; +} + +static int msmfb_overlay_ioctl_writeback_stop( + struct fb_info *info) +{ + int ret = 0; + ret = mdp4_writeback_stop(info); + if (ret) + goto error; + +error: + if (ret) + pr_err("%s:msmfb_writeback_stop ioctl failed\n", + __func__); + return ret; +} + +static int msmfb_overlay_ioctl_writeback_queue_buffer( + struct fb_info *info, unsigned long *argp) +{ + int ret = 0; + struct msmfb_data data; + + ret = copy_from_user(&data, argp, sizeof(data)); + if (ret) + goto error; + + ret = mdp4_writeback_queue_buffer(info, &data); + if (ret) + goto error; + +error: + if (ret) + pr_err("%s:msmfb_writeback_queue_buffer ioctl failed\n", + __func__); + return ret; +} + +static int msmfb_overlay_ioctl_writeback_dequeue_buffer( + struct fb_info *info, unsigned long *argp) +{ + int ret = 0; + struct msmfb_data data; + + ret = copy_from_user(&data, argp, sizeof(data)); + if (ret) + goto error; + + ret = mdp4_writeback_dequeue_buffer(info, &data); + if (ret) + goto error; + + ret = copy_to_user(argp, &data, sizeof(data)); + if (ret) + goto error; + +error: + if (ret) + pr_err("%s:msmfb_writeback_dequeue_buffer ioctl failed\n", + __func__); + return ret; +} +static int msmfb_overlay_ioctl_writeback_terminate(struct fb_info *info) +{ + return mdp4_writeback_terminate(info); +} + +#else +static int msmfb_overlay_ioctl_writeback_init(struct fb_info *info) +{ + return -ENOTSUPP; +} +static int msmfb_overlay_ioctl_writeback_start( + struct fb_info *info) +{ + return -ENOTSUPP; +} + +static int msmfb_overlay_ioctl_writeback_stop( + struct fb_info *info) +{ + return -ENOTSUPP; +} + +static int msmfb_overlay_ioctl_writeback_queue_buffer( + struct fb_info *info, unsigned long *argp) +{ + return -ENOTSUPP; +} + +static int msmfb_overlay_ioctl_writeback_dequeue_buffer( + struct fb_info *info, unsigned long *argp) +{ + return -ENOTSUPP; +} +static int msmfb_overlay_ioctl_writeback_terminate(struct fb_info *info) +{ + return -ENOTSUPP; +} +#endif + +static int msmfb_overlay_3d_sbys(struct fb_info *info, unsigned long *argp) +{ + int ret; + struct msmfb_overlay_3d req; + + ret = copy_from_user(&req, argp, sizeof(req)); + if (ret) { + pr_err("%s:msmfb_overlay_3d_ctrl ioctl failed\n", + __func__); + return ret; + } + + ret = mdp4_overlay_3d_sbys(info, &req); + + return ret; +} + +static int msmfb_mixer_info(struct fb_info *info, unsigned long *argp) +{ + int ret, cnt; + struct msmfb_mixer_info_req req; + + ret = copy_from_user(&req, argp, sizeof(req)); + if (ret) { + pr_err("%s: failed\n", __func__); + return ret; + } + + cnt = mdp4_mixer_info(req.mixer_num, req.info); + req.cnt = cnt; + ret = copy_to_user(argp, &req, sizeof(req)); + if (ret) + pr_err("%s:msmfb_overlay_blt_off ioctl failed\n", + __func__); + + return cnt; +} + +#endif + +DEFINE_SEMAPHORE(msm_fb_ioctl_ppp_sem); +DEFINE_MUTEX(msm_fb_ioctl_lut_sem); + +/* Set color conversion matrix from user space */ + +#ifndef CONFIG_FB_MSM_MDP40 +static void msmfb_set_color_conv(struct mdp_ccs *p) +{ + int i; + + if (p->direction == MDP_CCS_RGB2YUV) { + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* RGB->YUV primary forward matrix */ + for (i = 0; i < MDP_CCS_SIZE; i++) + writel(p->ccs[i], MDP_CSC_PFMVn(i)); + + #ifdef CONFIG_FB_MSM_MDP31 + for (i = 0; i < MDP_BV_SIZE; i++) + writel(p->bv[i], MDP_CSC_POST_BV2n(i)); + #endif + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + } else { + /* MDP cmd block enable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + + /* YUV->RGB primary reverse matrix */ + for (i = 0; i < MDP_CCS_SIZE; i++) + writel(p->ccs[i], MDP_CSC_PRMVn(i)); + for (i = 0; i < MDP_BV_SIZE; i++) + writel(p->bv[i], MDP_CSC_PRE_BV1n(i)); + + /* MDP cmd block disable */ + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); + } +} +#else +static void msmfb_set_color_conv(struct mdp_csc *p) +{ + mdp4_vg_csc_update(p); +} +#endif + +static int msmfb_notify_update(struct fb_info *info, unsigned long *argp) +{ + int ret, notify; + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + + ret = copy_from_user(¬ify, argp, sizeof(int)); + if (ret) { + pr_err("%s:ioctl failed\n", __func__); + return ret; + } + + if (notify > NOTIFY_UPDATE_STOP) + return -EINVAL; + + if (notify == NOTIFY_UPDATE_START) { + INIT_COMPLETION(mfd->msmfb_update_notify); + wait_for_completion_interruptible(&mfd->msmfb_update_notify); + } else { + INIT_COMPLETION(mfd->msmfb_no_update_notify); + wait_for_completion_interruptible(&mfd->msmfb_no_update_notify); + } + return 0; +} + +static int msmfb_handle_pp_ioctl(struct msmfb_mdp_pp *pp_ptr) +{ + int ret = -1; + + if (!pp_ptr) + return ret; + + switch (pp_ptr->op) { +#ifdef CONFIG_FB_MSM_MDP40 + case mdp_op_csc_cfg: + ret = mdp4_csc_config(&(pp_ptr->data.csc_cfg_data)); + break; + + case mdp_op_pcc_cfg: + ret = mdp4_pcc_cfg(&(pp_ptr->data.pcc_cfg_data)); + break; + + case mdp_op_lut_cfg: + switch (pp_ptr->data.lut_cfg_data.lut_type) { + case mdp_lut_igc: + ret = mdp4_igc_lut_config( + (struct mdp_igc_lut_data *) + &pp_ptr->data.lut_cfg_data.data); + break; + + case mdp_lut_pgc: + ret = mdp4_argc_cfg( + &pp_ptr->data.lut_cfg_data.data.pgc_lut_data); + break; + + case mdp_lut_hist: + ret = mdp_hist_lut_config( + (struct mdp_hist_lut_data *) + &pp_ptr->data.lut_cfg_data.data); + break; + + default: + break; + } + break; + case mdp_op_qseed_cfg: + ret = mdp4_qseed_cfg((struct mdp_qseed_cfg_data *) + &pp_ptr->data.qseed_cfg_data); + break; +#endif + default: + pr_warn("Unsupported request to MDP_PP IOCTL.\n"); + ret = -EINVAL; + break; + } + + return ret; +} + +static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + void __user *argp = (void __user *)arg; + struct fb_cursor cursor; + struct fb_cmap cmap; + struct mdp_histogram_data hist; + struct mdp_histogram_start_req hist_req; + uint32_t block; +#ifndef CONFIG_FB_MSM_MDP40 + struct mdp_ccs ccs_matrix; +#else + struct mdp_csc csc_matrix; +#endif + struct mdp_page_protection fb_page_protection; + struct msmfb_mdp_pp mdp_pp; + int ret = 0; + + switch (cmd) { +#ifdef CONFIG_FB_MSM_OVERLAY + case MSMFB_OVERLAY_GET: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_overlay_get(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; + case MSMFB_OVERLAY_SET: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_overlay_set(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; + case MSMFB_OVERLAY_UNSET: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_overlay_unset(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; + case MSMFB_OVERLAY_PLAY: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_overlay_play(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; + case MSMFB_OVERLAY_PLAY_ENABLE: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_overlay_play_enable(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; + case MSMFB_OVERLAY_PLAY_WAIT: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_overlay_play_wait(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; + case MSMFB_OVERLAY_BLT: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_overlay_blt(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; + case MSMFB_OVERLAY_BLT_OFFSET: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_overlay_blt_off(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; + case MSMFB_OVERLAY_3D: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_overlay_3d_sbys(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; + case MSMFB_MIXER_INFO: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_mixer_info(info, argp); + up(&msm_fb_ioctl_ppp_sem); + break; + case MSMFB_WRITEBACK_INIT: + ret = msmfb_overlay_ioctl_writeback_init(info); + break; + case MSMFB_WRITEBACK_START: + ret = msmfb_overlay_ioctl_writeback_start( + info); + break; + case MSMFB_WRITEBACK_STOP: + ret = msmfb_overlay_ioctl_writeback_stop( + info); + break; + case MSMFB_WRITEBACK_QUEUE_BUFFER: + ret = msmfb_overlay_ioctl_writeback_queue_buffer( + info, argp); + break; + case MSMFB_WRITEBACK_DEQUEUE_BUFFER: + ret = msmfb_overlay_ioctl_writeback_dequeue_buffer( + info, argp); + break; + case MSMFB_WRITEBACK_TERMINATE: + ret = msmfb_overlay_ioctl_writeback_terminate(info); + break; +#endif + case MSMFB_BLIT: + down(&msm_fb_ioctl_ppp_sem); + ret = msmfb_blit(info, argp); + up(&msm_fb_ioctl_ppp_sem); + + break; + + /* Ioctl for setting ccs matrix from user space */ + case MSMFB_SET_CCS_MATRIX: +#ifndef CONFIG_FB_MSM_MDP40 + ret = copy_from_user(&ccs_matrix, argp, sizeof(ccs_matrix)); + if (ret) { + printk(KERN_ERR + "%s:MSMFB_SET_CCS_MATRIX ioctl failed \n", + __func__); + return ret; + } + + down(&msm_fb_ioctl_ppp_sem); + if (ccs_matrix.direction == MDP_CCS_RGB2YUV) + mdp_ccs_rgb2yuv = ccs_matrix; + else + mdp_ccs_yuv2rgb = ccs_matrix; + + msmfb_set_color_conv(&ccs_matrix) ; + up(&msm_fb_ioctl_ppp_sem); +#else + ret = copy_from_user(&csc_matrix, argp, sizeof(csc_matrix)); + if (ret) { + pr_err("%s:MSMFB_SET_CSC_MATRIX ioctl failed\n", + __func__); + return ret; + } + down(&msm_fb_ioctl_ppp_sem); + msmfb_set_color_conv(&csc_matrix); + up(&msm_fb_ioctl_ppp_sem); + +#endif + + break; + + /* Ioctl for getting ccs matrix to user space */ + case MSMFB_GET_CCS_MATRIX: +#ifndef CONFIG_FB_MSM_MDP40 + ret = copy_from_user(&ccs_matrix, argp, sizeof(ccs_matrix)) ; + if (ret) { + printk(KERN_ERR + "%s:MSMFB_GET_CCS_MATRIX ioctl failed \n", + __func__); + return ret; + } + + down(&msm_fb_ioctl_ppp_sem); + if (ccs_matrix.direction == MDP_CCS_RGB2YUV) + ccs_matrix = mdp_ccs_rgb2yuv; + else + ccs_matrix = mdp_ccs_yuv2rgb; + + ret = copy_to_user(argp, &ccs_matrix, sizeof(ccs_matrix)); + + if (ret) { + printk(KERN_ERR + "%s:MSMFB_GET_CCS_MATRIX ioctl failed \n", + __func__); + return ret ; + } + up(&msm_fb_ioctl_ppp_sem); +#else + ret = -EINVAL; +#endif + + break; + + case MSMFB_GRP_DISP: +#ifdef CONFIG_FB_MSM_MDP22 + { + unsigned long grp_id; + + ret = copy_from_user(&grp_id, argp, sizeof(grp_id)); + if (ret) + return ret; + + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); + writel(grp_id, MDP_FULL_BYPASS_WORD43); + mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, + FALSE); + break; + } +#else + return -EFAULT; +#endif + case MSMFB_SUSPEND_SW_REFRESHER: + if (!mfd->panel_power_on) + return -EPERM; + + mfd->sw_refreshing_enable = FALSE; + ret = msm_fb_stop_sw_refresher(mfd); + break; + + case MSMFB_RESUME_SW_REFRESHER: + if (!mfd->panel_power_on) + return -EPERM; + + mfd->sw_refreshing_enable = TRUE; + ret = msm_fb_resume_sw_refresher(mfd); + break; + + case MSMFB_CURSOR: + ret = copy_from_user(&cursor, argp, sizeof(cursor)); + if (ret) + return ret; + + ret = msm_fb_cursor(info, &cursor); + break; + + case MSMFB_SET_LUT: + ret = copy_from_user(&cmap, argp, sizeof(cmap)); + if (ret) + return ret; + + mutex_lock(&msm_fb_ioctl_lut_sem); + ret = msm_fb_set_lut(&cmap, info); + mutex_unlock(&msm_fb_ioctl_lut_sem); + break; + + case MSMFB_HISTOGRAM: + if (!mfd->panel_power_on) + return -EPERM; + + if (!mfd->do_histogram) + return -ENODEV; + + ret = copy_from_user(&hist, argp, sizeof(hist)); + if (ret) + return ret; + + ret = mfd->do_histogram(info, &hist); + break; + + case MSMFB_HISTOGRAM_START: + if (!mfd->panel_power_on) + return -EPERM; + + if (!mfd->start_histogram) + return -ENODEV; + + ret = copy_from_user(&hist_req, argp, sizeof(hist_req)); + if (ret) + return ret; + + ret = mfd->start_histogram(&hist_req); + break; + + case MSMFB_HISTOGRAM_STOP: + if (!mfd->stop_histogram) + return -ENODEV; + + ret = copy_from_user(&block, argp, sizeof(int)); + if (ret) + return ret; + + ret = mfd->stop_histogram(info, block); + break; + + + case MSMFB_GET_PAGE_PROTECTION: + fb_page_protection.page_protection + = mfd->mdp_fb_page_protection; + ret = copy_to_user(argp, &fb_page_protection, + sizeof(fb_page_protection)); + if (ret) + return ret; + break; + + case MSMFB_NOTIFY_UPDATE: + ret = msmfb_notify_update(info, argp); + break; + + case MSMFB_SET_PAGE_PROTECTION: +#if defined CONFIG_ARCH_QSD8X50 || defined CONFIG_ARCH_MSM8X60 + ret = copy_from_user(&fb_page_protection, argp, + sizeof(fb_page_protection)); + if (ret) + return ret; + + /* Validate the proposed page protection settings. */ + switch (fb_page_protection.page_protection) { + case MDP_FB_PAGE_PROTECTION_NONCACHED: + case MDP_FB_PAGE_PROTECTION_WRITECOMBINE: + case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE: + /* Write-back cache (read allocate) */ + case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE: + /* Write-back cache (write allocate) */ + case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE: + mfd->mdp_fb_page_protection = + fb_page_protection.page_protection; + break; + default: + ret = -EINVAL; + break; + } +#else + /* + * Don't allow caching until 7k DMA cache operations are + * available. + */ + ret = -EINVAL; +#endif + break; + + case MSMFB_MDP_PP: + ret = copy_from_user(&mdp_pp, argp, sizeof(mdp_pp)); + if (ret) + return ret; + + ret = msmfb_handle_pp_ioctl(&mdp_pp); + break; + + default: + MSM_FB_INFO("MDP: unknown ioctl (cmd=%x) received!\n", cmd); + ret = -EINVAL; + break; + } + + return ret; +} + +static int msm_fb_register_driver(void) +{ + return platform_driver_register(&msm_fb_driver); +} + +#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL +struct fb_info *msm_fb_get_writeback_fb(void) +{ + int c = 0; + for (c = 0; c < fbi_list_index; ++c) { + struct msm_fb_data_type *mfd; + mfd = (struct msm_fb_data_type *)fbi_list[c]->par; + if (mfd->panel.type == WRITEBACK_PANEL) + return fbi_list[c]; + } + + return NULL; +} +EXPORT_SYMBOL(msm_fb_get_writeback_fb); + +int msm_fb_writeback_start(struct fb_info *info) +{ + return mdp4_writeback_start(info); +} +EXPORT_SYMBOL(msm_fb_writeback_start); + +int msm_fb_writeback_queue_buffer(struct fb_info *info, + struct msmfb_data *data) +{ + return mdp4_writeback_queue_buffer(info, data); +} +EXPORT_SYMBOL(msm_fb_writeback_queue_buffer); + +int msm_fb_writeback_dequeue_buffer(struct fb_info *info, + struct msmfb_data *data) +{ + return mdp4_writeback_dequeue_buffer(info, data); +} +EXPORT_SYMBOL(msm_fb_writeback_dequeue_buffer); + +int msm_fb_writeback_stop(struct fb_info *info) +{ + return mdp4_writeback_stop(info); +} +EXPORT_SYMBOL(msm_fb_writeback_stop); +int msm_fb_writeback_init(struct fb_info *info) +{ + return mdp4_writeback_init(info); +} +EXPORT_SYMBOL(msm_fb_writeback_init); +int msm_fb_writeback_terminate(struct fb_info *info) +{ + return mdp4_writeback_terminate(info); +} +EXPORT_SYMBOL(msm_fb_writeback_terminate); +#endif + +struct platform_device *msm_fb_add_device(struct platform_device *pdev) +{ + struct msm_fb_panel_data *pdata; + struct platform_device *this_dev = NULL; + struct fb_info *fbi; + struct msm_fb_data_type *mfd = NULL; + u32 type, id, fb_num; + + if (!pdev) + return NULL; + id = pdev->id; + + pdata = pdev->dev.platform_data; + if (!pdata) + return NULL; + type = pdata->panel_info.type; + +#if defined MSM_FB_NUM + /* + * over written fb_num which defined + * at panel_info + * + */ + if (type == HDMI_PANEL || type == DTV_PANEL || + type == TV_PANEL || type == WRITEBACK_PANEL) { + if (hdmi_prim_display) + pdata->panel_info.fb_num = 2; + else + pdata->panel_info.fb_num = 1; + } + else + pdata->panel_info.fb_num = MSM_FB_NUM; + + MSM_FB_INFO("setting pdata->panel_info.fb_num to %d. type: %d\n", + pdata->panel_info.fb_num, type); +#endif + fb_num = pdata->panel_info.fb_num; + + if (fb_num <= 0) + return NULL; + + if (fbi_list_index >= MAX_FBI_LIST) { + printk(KERN_ERR "msm_fb: no more framebuffer info list!\n"); + return NULL; + } + /* + * alloc panel device data + */ + this_dev = msm_fb_device_alloc(pdata, type, id); + + if (!this_dev) { + printk(KERN_ERR + "%s: msm_fb_device_alloc failed!\n", __func__); + return NULL; + } + + /* + * alloc framebuffer info + par data + */ + fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), NULL); + if (fbi == NULL) { + platform_device_put(this_dev); + printk(KERN_ERR "msm_fb: can't alloca framebuffer info data!\n"); + return NULL; + } + + mfd = (struct msm_fb_data_type *)fbi->par; + mfd->key = MFD_KEY; + mfd->fbi = fbi; + mfd->panel.type = type; + mfd->panel.id = id; + mfd->fb_page = fb_num; + mfd->index = fbi_list_index; + mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE; + mfd->iclient = iclient; + /* link to the latest pdev */ + mfd->pdev = this_dev; + + mfd_list[mfd_list_index++] = mfd; + fbi_list[fbi_list_index++] = fbi; + + /* + * set driver data + */ + platform_set_drvdata(this_dev, mfd); + + if (platform_device_add(this_dev)) { + printk(KERN_ERR "msm_fb: platform_device_add failed!\n"); + platform_device_put(this_dev); + framebuffer_release(fbi); + fbi_list_index--; + return NULL; + } + return this_dev; +} +EXPORT_SYMBOL(msm_fb_add_device); + +int get_fb_phys_info(unsigned long *start, unsigned long *len, int fb_num, + int subsys_id) +{ + struct fb_info *info; + struct msm_fb_data_type *mfd; + + if (fb_num > MAX_FBI_LIST || + (subsys_id != DISPLAY_SUBSYSTEM_ID && + subsys_id != ROTATOR_SUBSYSTEM_ID)) { + pr_err("%s(): Invalid parameters\n", __func__); + return -1; + } + + info = fbi_list[fb_num]; + if (!info) { + pr_err("%s(): info is NULL\n", __func__); + return -1; + } + + mfd = (struct msm_fb_data_type *)info->par; + + if (subsys_id == DISPLAY_SUBSYSTEM_ID) { + if (mfd->display_iova) + *start = mfd->display_iova; + else + *start = info->fix.smem_start; + } else { + if (mfd->rotator_iova) + *start = mfd->rotator_iova; + else + *start = info->fix.smem_start; + } + + *len = info->fix.smem_len; + + return 0; +} +EXPORT_SYMBOL(get_fb_phys_info); + +int __init msm_fb_init(void) +{ + int rc = -ENODEV; + + if (msm_fb_register_driver()) + return rc; + +#ifdef MSM_FB_ENABLE_DBGFS + { + struct dentry *root; + + if ((root = msm_fb_get_debugfs_root()) != NULL) { + msm_fb_debugfs_file_create(root, + "msm_fb_msg_printing_level", + (u32 *) &msm_fb_msg_level); + msm_fb_debugfs_file_create(root, + "mddi_msg_printing_level", + (u32 *) &mddi_msg_level); + msm_fb_debugfs_file_create(root, "msm_fb_debug_enabled", + (u32 *) &msm_fb_debug_enabled); + } + } +#endif + + return 0; +} + +/* Called by v4l2 driver to enable/disable overlay pipe */ +int msm_fb_v4l2_enable(struct mdp_overlay *req, bool enable, void **par) +{ + int err = 0; +#ifdef CONFIG_FB_MSM_MDP40 + struct mdp4_overlay_pipe *pipe; + if (enable) { + + err = mdp4_v4l2_overlay_set(fbi_list[0], req, &pipe); + + *(struct mdp4_overlay_pipe **)par = pipe; + + } else { + pipe = *(struct mdp4_overlay_pipe **)par; + mdp4_v4l2_overlay_clear(pipe); + } +#else +#ifdef CONFIG_FB_MSM_MDP30 + if (enable) + err = mdp_ppp_v4l2_overlay_set(fbi_list[0], req); + else + err = mdp_ppp_v4l2_overlay_clear(); +#else + err = -EINVAL; +#endif +#endif + + return err; +} +EXPORT_SYMBOL(msm_fb_v4l2_enable); + +/* Called by v4l2 driver to provide a frame for display */ +int msm_fb_v4l2_update(void *par, + unsigned long srcp0_addr, unsigned long srcp0_size, + unsigned long srcp1_addr, unsigned long srcp1_size, + unsigned long srcp2_addr, unsigned long srcp2_size) +{ +#ifdef CONFIG_FB_MSM_MDP40 + struct mdp4_overlay_pipe *pipe = (struct mdp4_overlay_pipe *)par; + return mdp4_v4l2_overlay_play(fbi_list[0], pipe, + srcp0_addr, srcp1_addr, + srcp2_addr); +#else +#ifdef CONFIG_FB_MSM_MDP30 + return mdp_ppp_v4l2_overlay_play(fbi_list[0], + srcp0_addr, srcp0_size, + srcp1_addr, srcp1_size); +#else + return -EINVAL; +#endif +#endif +} +EXPORT_SYMBOL(msm_fb_v4l2_update); + +module_init(msm_fb_init); diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h new file mode 100644 index 000000000000..e6d908aad6d3 --- /dev/null +++ b/drivers/video/msm/msm_fb.h @@ -0,0 +1,223 @@ +/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef MSM_FB_H +#define MSM_FB_H + +#include +#include +#include +#include +#include +#include +#include "linux/proc_fs.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + +#include "msm_fb_panel.h" +#include "mdp.h" + +#define MSM_FB_DEFAULT_PAGE_SIZE 2 +#define MFD_KEY 0x11161126 +#define MSM_FB_MAX_DEV_LIST 32 + +struct disp_info_type_suspend { + boolean op_enable; + boolean sw_refreshing_enable; + boolean panel_power_on; +}; + +struct msmfb_writeback_data_list { + struct list_head registered_entry; + struct list_head active_entry; + void *addr; + struct file *pmem_file; + struct msmfb_data buf_info; + struct msmfb_img img; + int state; +}; + + +struct msm_fb_data_type { + __u32 key; + __u32 index; + __u32 ref_cnt; + __u32 fb_page; + + panel_id_type panel; + struct msm_panel_info panel_info; + + DISP_TARGET dest; + struct fb_info *fbi; + + boolean op_enable; + uint32 fb_imgType; + boolean sw_currently_refreshing; + boolean sw_refreshing_enable; + boolean hw_refresh; +#ifdef CONFIG_FB_MSM_OVERLAY + int overlay_play_enable; +#endif + + MDPIBUF ibuf; + boolean ibuf_flushed; + struct timer_list refresh_timer; + struct completion refresher_comp; + + boolean pan_waiting; + struct completion pan_comp; + + /* vsync */ + boolean use_mdp_vsync; + __u32 vsync_gpio; + __u32 total_lcd_lines; + __u32 total_porch_lines; + __u32 lcd_ref_usec_time; + __u32 refresh_timer_duration; + + struct hrtimer dma_hrtimer; + + boolean panel_power_on; + struct work_struct dma_update_worker; + struct semaphore sem; + + struct timer_list vsync_resync_timer; + boolean vsync_handler_pending; + struct work_struct vsync_resync_worker; + + ktime_t last_vsync_timetick; + + __u32 *vsync_width_boundary; + + unsigned int pmem_id; + struct disp_info_type_suspend suspend; + + __u32 channel_irq; + + struct mdp_dma_data *dma; + void (*dma_fnc) (struct msm_fb_data_type *mfd); + int (*cursor_update) (struct fb_info *info, + struct fb_cursor *cursor); + int (*lut_update) (struct fb_info *info, + struct fb_cmap *cmap); + int (*do_histogram) (struct fb_info *info, + struct mdp_histogram_data *hist); + int (*start_histogram) (struct mdp_histogram_start_req *req); + int (*stop_histogram) (struct fb_info *info, uint32_t block); + void *cursor_buf; + void *cursor_buf_phys; + + void *cmd_port; + void *data_port; + void *data_port_phys; + + __u32 bl_level; + + struct platform_device *pdev; + + __u32 var_xres; + __u32 var_yres; + __u32 var_pixclock; + __u32 var_frame_rate; + +#ifdef MSM_FB_ENABLE_DBGFS + struct dentry *sub_dir; +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#ifdef CONFIG_FB_MSM_MDDI + struct early_suspend mddi_early_suspend; + struct early_suspend mddi_ext_early_suspend; +#endif +#endif + u32 mdp_fb_page_protection; + + struct clk *ebi1_clk; + boolean dma_update_flag; + struct timer_list msmfb_no_update_notify_timer; + struct completion msmfb_update_notify; + struct completion msmfb_no_update_notify; + struct mutex writeback_mutex; + struct mutex unregister_mutex; + struct list_head writeback_busy_queue; + struct list_head writeback_free_queue; + struct list_head writeback_register_queue; + wait_queue_head_t wait_q; + struct ion_client *iclient; + unsigned long display_iova; + unsigned long rotator_iova; + struct mdp_buf_type *ov0_wb_buf; + struct mdp_buf_type *ov1_wb_buf; + u32 ov_start; + u32 mem_hid; + u32 mdp_rev; + u32 use_ov0_blt, ov0_blt_state; + u32 use_ov1_blt, ov1_blt_state; + u32 writeback_state; + bool writeback_active_cnt; + int cont_splash_done; +}; + +struct dentry *msm_fb_get_debugfs_root(void); +void msm_fb_debugfs_file_create(struct dentry *root, const char *name, + u32 *var); +void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl); + +struct platform_device *msm_fb_add_device(struct platform_device *pdev); +struct fb_info *msm_fb_get_writeback_fb(void); +int msm_fb_writeback_init(struct fb_info *info); +int msm_fb_writeback_start(struct fb_info *info); +int msm_fb_writeback_queue_buffer(struct fb_info *info, + struct msmfb_data *data); +int msm_fb_writeback_dequeue_buffer(struct fb_info *info, + struct msmfb_data *data); +int msm_fb_writeback_stop(struct fb_info *info); +int msm_fb_writeback_terminate(struct fb_info *info); +int msm_fb_detect_client(const char *name); +int calc_fb_offset(struct msm_fb_data_type *mfd, struct fb_info *fbi, int bpp); + +#ifdef CONFIG_FB_BACKLIGHT +void msm_fb_config_backlight(struct msm_fb_data_type *mfd); +#endif + +void fill_black_screen(void); +void unfill_black_screen(void); +int msm_fb_check_frame_rate(struct msm_fb_data_type *mfd, + struct fb_info *info); + +#ifdef CONFIG_FB_MSM_LOGO +#define INIT_IMAGE_FILE "/initlogo.rle" +int load_565rle_image(char *filename, bool bf_supported); +#endif + +#endif /* MSM_FB_H */ diff --git a/drivers/video/msm/msm_fb_bl.c b/drivers/video/msm/msm_fb_bl.c new file mode 100644 index 000000000000..f4835ee1134b --- /dev/null +++ b/drivers/video/msm/msm_fb_bl.c @@ -0,0 +1,75 @@ +/* Copyright (c) 2008-2009, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_fb.h" + +static int msm_fb_bl_get_brightness(struct backlight_device *pbd) +{ + return pbd->props.brightness; +} + +static int msm_fb_bl_update_status(struct backlight_device *pbd) +{ + struct msm_fb_data_type *mfd = bl_get_data(pbd); + __u32 bl_lvl; + + bl_lvl = pbd->props.brightness; + bl_lvl = mfd->fbi->bl_curve[bl_lvl]; + msm_fb_set_backlight(mfd, bl_lvl); + return 0; +} + +static struct backlight_ops msm_fb_bl_ops = { + .get_brightness = msm_fb_bl_get_brightness, + .update_status = msm_fb_bl_update_status, +}; + +void msm_fb_config_backlight(struct msm_fb_data_type *mfd) +{ + struct msm_fb_panel_data *pdata; + struct backlight_device *pbd; + struct fb_info *fbi; + char name[16]; + struct backlight_properties props; + + fbi = mfd->fbi; + pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data; + + if ((pdata) && (pdata->set_backlight)) { + snprintf(name, sizeof(name), "msmfb_bl%d", mfd->index); + props.max_brightness = FB_BACKLIGHT_LEVELS - 1; + props.brightness = FB_BACKLIGHT_LEVELS - 1; + pbd = + backlight_device_register(name, fbi->dev, mfd, + &msm_fb_bl_ops, &props); + if (!IS_ERR(pbd)) { + fbi->bl_dev = pbd; + fb_bl_default_curve(fbi, + 0, + mfd->panel_info.bl_min, + mfd->panel_info.bl_max); + } else { + fbi->bl_dev = NULL; + printk(KERN_ERR "msm_fb: backlight_device_register failed!\n"); + } + } +} diff --git a/drivers/video/msm/msm_fb_def.h b/drivers/video/msm/msm_fb_def.h new file mode 100644 index 000000000000..dcd648bab809 --- /dev/null +++ b/drivers/video/msm/msm_fb_def.h @@ -0,0 +1,204 @@ +/* Copyright (c) 2008-2010, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef MSM_FB_DEF_H +#define MSM_FB_DEF_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "linux/proc_fs.h" +#include +#include +#include + +#include +#include + +#include + + +typedef s64 int64; +typedef s32 int32; +typedef s16 int16; +typedef s8 int8; + +typedef u64 uint64; +typedef u32 uint32; +typedef u16 uint16; +typedef u8 uint8; + +typedef s32 int4; +typedef s16 int2; +typedef s8 int1; + +typedef u32 uint4; +typedef u16 uint2; +typedef u8 uint1; + +typedef u32 dword; +typedef u16 word; +typedef u8 byte; + +typedef unsigned int boolean; + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define MSM_FB_ENABLE_DBGFS +#define FEATURE_MDDI + +#if defined(CONFIG_FB_MSM_DEFAULT_DEPTH_RGB565) +#define MSMFB_DEFAULT_TYPE MDP_RGB_565 +#elif defined(CONFIG_FB_MSM_DEFAULT_DEPTH_ARGB8888) +#define MSMFB_DEFAULT_TYPE MDP_ARGB_8888 +#elif defined(CONFIG_FB_MSM_DEFAULT_DEPTH_RGBA8888) +#define MSMFB_DEFAULT_TYPE MDP_RGBA_8888 +#else +#define MSMFB_DEFAULT_TYPE MDP_RGB_565 +#endif + +#define outp32(addr, val) writel(val, addr) +#define outp16(addr, val) writew(val, addr) +#define outp8(addr, val) writeb(val, addr) +#define outp(addr, val) outp32(addr, val) + +#ifndef MAX +#define MAX( x, y ) (((x) > (y)) ? (x) : (y)) +#endif + +#ifndef MIN +#define MIN( x, y ) (((x) < (y)) ? (x) : (y)) +#endif + +/*--------------------------------------------------------------------------*/ + +#define inp32(addr) readl(addr) +#define inp16(addr) readw(addr) +#define inp8(addr) readb(addr) +#define inp(addr) inp32(addr) + +#define inpw(port) readw(port) +#define outpw(port, val) writew(val, port) +#define inpdw(port) readl(port) +#define outpdw(port, val) writel(val, port) + + +#define clk_busy_wait(x) msleep_interruptible((x)/1000) + +#define memory_barrier() + +#define assert(expr) \ + if(!(expr)) { \ + printk(KERN_ERR "msm_fb: assertion failed! %s,%s,%s,line=%d\n",\ + #expr, __FILE__, __func__, __LINE__); \ + } + +#define ASSERT(x) assert(x) + +#define DISP_EBI2_LOCAL_DEFINE +#ifdef DISP_EBI2_LOCAL_DEFINE +#define LCD_PRIM_BASE_PHYS 0x98000000 +#define LCD_SECD_BASE_PHYS 0x9c000000 +#define EBI2_PRIM_LCD_RS_PIN 0x20000 +#define EBI2_SECD_LCD_RS_PIN 0x20000 + +#define EBI2_PRIM_LCD_CLR 0xC0 +#define EBI2_PRIM_LCD_SEL 0x40 + +#define EBI2_SECD_LCD_CLR 0x300 +#define EBI2_SECD_LCD_SEL 0x100 +#endif + +extern u32 msm_fb_msg_level; + +/* + * Message printing priorities: + * LEVEL 0 KERN_EMERG (highest priority) + * LEVEL 1 KERN_ALERT + * LEVEL 2 KERN_CRIT + * LEVEL 3 KERN_ERR + * LEVEL 4 KERN_WARNING + * LEVEL 5 KERN_NOTICE + * LEVEL 6 KERN_INFO + * LEVEL 7 KERN_DEBUG (Lowest priority) + */ +#define MSM_FB_EMERG(msg, ...) \ + if (msm_fb_msg_level > 0) \ + printk(KERN_EMERG msg, ## __VA_ARGS__); +#define MSM_FB_ALERT(msg, ...) \ + if (msm_fb_msg_level > 1) \ + printk(KERN_ALERT msg, ## __VA_ARGS__); +#define MSM_FB_CRIT(msg, ...) \ + if (msm_fb_msg_level > 2) \ + printk(KERN_CRIT msg, ## __VA_ARGS__); +#define MSM_FB_ERR(msg, ...) \ + if (msm_fb_msg_level > 3) \ + printk(KERN_ERR msg, ## __VA_ARGS__); +#define MSM_FB_WARNING(msg, ...) \ + if (msm_fb_msg_level > 4) \ + printk(KERN_WARNING msg, ## __VA_ARGS__); +#define MSM_FB_NOTICE(msg, ...) \ + if (msm_fb_msg_level > 5) \ + printk(KERN_NOTICE msg, ## __VA_ARGS__); +#define MSM_FB_INFO(msg, ...) \ + if (msm_fb_msg_level > 6) \ + printk(KERN_INFO msg, ## __VA_ARGS__); +#define MSM_FB_DEBUG(msg, ...) \ + if (msm_fb_msg_level > 7) \ + printk(KERN_DEBUG msg, ## __VA_ARGS__); + +#ifdef MSM_FB_C +unsigned char *msm_mdp_base; +unsigned char *msm_pmdh_base; +unsigned char *msm_emdh_base; +unsigned char *mipi_dsi_base; +#else +extern unsigned char *msm_mdp_base; +extern unsigned char *msm_pmdh_base; +extern unsigned char *msm_emdh_base; +extern unsigned char *mipi_dsi_base; +#endif + +#undef ENABLE_MDDI_MULTI_READ_WRITE +#undef ENABLE_FWD_LINK_SKEW_CALIBRATION + +#endif /* MSM_FB_DEF_H */ diff --git a/drivers/video/msm/msm_fb_panel.c b/drivers/video/msm/msm_fb_panel.c new file mode 100644 index 000000000000..8e6a8226f45f --- /dev/null +++ b/drivers/video/msm/msm_fb_panel.c @@ -0,0 +1,148 @@ +/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_fb_panel.h" + +int panel_next_on(struct platform_device *pdev) +{ + int ret = 0; + struct msm_fb_panel_data *pdata; + struct msm_fb_panel_data *next_pdata; + struct platform_device *next_pdev; + + pdata = (struct msm_fb_panel_data *)pdev->dev.platform_data; + + if (pdata) { + next_pdev = pdata->next; + if (next_pdev) { + next_pdata = + (struct msm_fb_panel_data *)next_pdev->dev. + platform_data; + if ((next_pdata) && (next_pdata->on)) + ret = next_pdata->on(next_pdev); + } + } + + return ret; +} + +int panel_next_off(struct platform_device *pdev) +{ + int ret = 0; + struct msm_fb_panel_data *pdata; + struct msm_fb_panel_data *next_pdata; + struct platform_device *next_pdev; + + pdata = (struct msm_fb_panel_data *)pdev->dev.platform_data; + + if (pdata) { + next_pdev = pdata->next; + if (next_pdev) { + next_pdata = + (struct msm_fb_panel_data *)next_pdev->dev. + platform_data; + if ((next_pdata) && (next_pdata->on)) + ret = next_pdata->off(next_pdev); + } + } + + return ret; +} + +struct platform_device *msm_fb_device_alloc(struct msm_fb_panel_data *pdata, + u32 type, u32 id) +{ + struct platform_device *this_dev = NULL; + char dev_name[16]; + + switch (type) { + case EBI2_PANEL: + snprintf(dev_name, sizeof(dev_name), "ebi2_lcd"); + break; + + case MDDI_PANEL: + snprintf(dev_name, sizeof(dev_name), "mddi"); + break; + + case EXT_MDDI_PANEL: + snprintf(dev_name, sizeof(dev_name), "mddi_ext"); + break; + + case TV_PANEL: + snprintf(dev_name, sizeof(dev_name), "tvenc"); + break; + + case HDMI_PANEL: + case LCDC_PANEL: + snprintf(dev_name, sizeof(dev_name), "lcdc"); + break; + + case LVDS_PANEL: + snprintf(dev_name, sizeof(dev_name), "lvds"); + break; + + case DTV_PANEL: + snprintf(dev_name, sizeof(dev_name), "dtv"); + break; + + case MIPI_VIDEO_PANEL: + case MIPI_CMD_PANEL: + snprintf(dev_name, sizeof(dev_name), "mipi_dsi"); + break; + case WRITEBACK_PANEL: + snprintf(dev_name, sizeof(dev_name), "writeback"); + break; + + default: + return NULL; + } + + if (pdata != NULL) + pdata->next = NULL; + else + return NULL; + + this_dev = + platform_device_alloc(dev_name, ((u32) type << 16) | (u32) id); + + if (this_dev) { + if (platform_device_add_data + (this_dev, pdata, sizeof(struct msm_fb_panel_data))) { + printk + ("msm_fb_device_alloc: platform_device_add_data failed!\n"); + platform_device_put(this_dev); + return NULL; + } + } + + return this_dev; +} diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h new file mode 100644 index 000000000000..61ddc1373ead --- /dev/null +++ b/drivers/video/msm/msm_fb_panel.h @@ -0,0 +1,213 @@ +/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef MSM_FB_PANEL_H +#define MSM_FB_PANEL_H + +#include "msm_fb_def.h" + +struct msm_fb_data_type; + +typedef void (*msm_fb_vsync_handler_type) (void *arg); + +/* panel id type */ +typedef struct panel_id_s { + uint16 id; + uint16 type; +} panel_id_type; + +/* panel type list */ +#define NO_PANEL 0xffff /* No Panel */ +#define MDDI_PANEL 1 /* MDDI */ +#define EBI2_PANEL 2 /* EBI2 */ +#define LCDC_PANEL 3 /* internal LCDC type */ +#define EXT_MDDI_PANEL 4 /* Ext.MDDI */ +#define TV_PANEL 5 /* TV */ +#define HDMI_PANEL 6 /* HDMI TV */ +#define DTV_PANEL 7 /* DTV */ +#define MIPI_VIDEO_PANEL 8 /* MIPI */ +#define MIPI_CMD_PANEL 9 /* MIPI */ +#define WRITEBACK_PANEL 10 /* Wifi display */ +#define LVDS_PANEL 11 /* LVDS */ + +/* panel class */ +typedef enum { + DISPLAY_LCD = 0, /* lcd = ebi2/mddi */ + DISPLAY_LCDC, /* lcdc */ + DISPLAY_TV, /* TV Out */ + DISPLAY_EXT_MDDI, /* External MDDI */ +} DISP_TARGET; + +/* panel device locaiton */ +typedef enum { + DISPLAY_1 = 0, /* attached as first device */ + DISPLAY_2, /* attached on second device */ + DISPLAY_3, /* attached on third writeback device */ + MAX_PHYS_TARGET_NUM, +} DISP_TARGET_PHYS; + +/* panel info type */ +struct lcd_panel_info { + __u32 vsync_enable; + __u32 refx100; + __u32 v_back_porch; + __u32 v_front_porch; + __u32 v_pulse_width; + __u32 hw_vsync_mode; + __u32 vsync_notifier_period; + __u32 rev; +}; + +struct lcdc_panel_info { + __u32 h_back_porch; + __u32 h_front_porch; + __u32 h_pulse_width; + __u32 v_back_porch; + __u32 v_front_porch; + __u32 v_pulse_width; + __u32 border_clr; + __u32 underflow_clr; + __u32 hsync_skew; + /* Pad width */ + uint32 xres_pad; + /* Pad height */ + uint32 yres_pad; +}; + +struct mddi_panel_info { + __u32 vdopkt; + boolean is_type1; +}; + +struct mipi_panel_info { + char mode; /* video/cmd */ + char interleave_mode; + char crc_check; + char ecc_check; + char dst_format; /* shared by video and command */ + char data_lane0; + char data_lane1; + char data_lane2; + char data_lane3; + char dlane_swap; /* data lane swap */ + char rgb_swap; + char b_sel; + char g_sel; + char r_sel; + char rx_eot_ignore; + char tx_eot_append; + char t_clk_post; /* 0xc0, DSI_CLKOUT_TIMING_CTRL */ + char t_clk_pre; /* 0xc0, DSI_CLKOUT_TIMING_CTRL */ + char vc; /* virtual channel */ + struct mipi_dsi_phy_ctrl *dsi_phy_db; + /* video mode */ + char pulse_mode_hsa_he; + char hfp_power_stop; + char hbp_power_stop; + char hsa_power_stop; + char eof_bllp_power_stop; + char bllp_power_stop; + char traffic_mode; + char frame_rate; + /* command mode */ + char interleave_max; + char insert_dcs_cmd; + char wr_mem_continue; + char wr_mem_start; + char te_sel; + char stream; /* 0 or 1 */ + char mdp_trigger; + char dma_trigger; + uint32 dsi_pclk_rate; + /* byte to esc clk ratio */ + uint32 esc_byte_ratio; + /* The packet-size should not bet changed */ + char no_max_pkt_size; + /* Clock required during LP commands */ + char force_clk_lane_hs; +}; + +enum lvds_mode { + LVDS_SINGLE_CHANNEL_MODE, + LVDS_DUAL_CHANNEL_MODE, +}; + +struct lvds_panel_info { + enum lvds_mode channel_mode; + /* Channel swap in dual mode */ + char channel_swap; +}; + +struct msm_panel_info { + __u32 xres; + __u32 yres; + __u32 bpp; + __u32 mode2_xres; + __u32 mode2_yres; + __u32 mode2_bpp; + __u32 type; + __u32 wait_cycle; + DISP_TARGET_PHYS pdest; + __u32 bl_max; + __u32 bl_min; + __u32 fb_num; + __u32 clk_rate; + __u32 clk_min; + __u32 clk_max; + __u32 frame_count; + __u32 is_3d_panel; + __u32 frame_rate; + + + struct mddi_panel_info mddi; + struct lcd_panel_info lcd; + struct lcdc_panel_info lcdc; + struct mipi_panel_info mipi; + struct lvds_panel_info lvds; +}; + +#define MSM_FB_SINGLE_MODE_PANEL(pinfo) \ + do { \ + (pinfo)->mode2_xres = 0; \ + (pinfo)->mode2_yres = 0; \ + (pinfo)->mode2_bpp = 0; \ + } while (0) + +struct msm_fb_panel_data { + struct msm_panel_info panel_info; + void (*set_rect) (int x, int y, int xres, int yres); + void (*set_vsync_notifier) (msm_fb_vsync_handler_type, void *arg); + void (*set_backlight) (struct msm_fb_data_type *); + + /* function entry chain */ + int (*on) (struct platform_device *pdev); + int (*off) (struct platform_device *pdev); + int (*power_ctrl) (boolean enable); + struct platform_device *next; + int (*clk_func) (int enable); +}; + +/*=========================================================================== + FUNCTIONS PROTOTYPES +============================================================================*/ +struct platform_device *msm_fb_device_alloc(struct msm_fb_panel_data *pdata, + u32 type, u32 id); +int panel_next_on(struct platform_device *pdev); +int panel_next_off(struct platform_device *pdev); + +int lcdc_device_register(struct msm_panel_info *pinfo); + +int mddi_toshiba_device_register(struct msm_panel_info *pinfo, + u32 channel, u32 panel); + +#endif /* MSM_FB_PANEL_H */ diff --git a/drivers/video/msm/tvenc.c b/drivers/video/msm/tvenc.c new file mode 100644 index 000000000000..2f3ee972730d --- /dev/null +++ b/drivers/video/msm/tvenc.c @@ -0,0 +1,522 @@ +/* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define TVENC_C +#include "tvenc.h" +#include "msm_fb.h" +#include "mdp4.h" +/* AXI rate in KHz */ +#define MSM_SYSTEM_BUS_RATE 128000000 + +static int tvenc_probe(struct platform_device *pdev); +static int tvenc_remove(struct platform_device *pdev); + +static int tvenc_off(struct platform_device *pdev); +static int tvenc_on(struct platform_device *pdev); + +static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST]; +static int pdev_list_cnt; + +static struct clk *tvenc_clk; +static struct clk *tvdac_clk; +static struct clk *tvenc_pclk; +static struct clk *mdp_tv_clk; +#ifdef CONFIG_FB_MSM_MDP40 +static struct clk *tv_src_clk; +#endif + +#ifdef CONFIG_MSM_BUS_SCALING +static uint32_t tvenc_bus_scale_handle; +#endif + +static int tvenc_runtime_suspend(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: suspending...\n"); + return 0; +} + +static int tvenc_runtime_resume(struct device *dev) +{ + dev_dbg(dev, "pm_runtime: resuming...\n"); + return 0; +} + +static struct dev_pm_ops tvenc_dev_pm_ops = { + .runtime_suspend = tvenc_runtime_suspend, + .runtime_resume = tvenc_runtime_resume, +}; + +static struct platform_driver tvenc_driver = { + .probe = tvenc_probe, + .remove = tvenc_remove, + .suspend = NULL, + .resume = NULL, + .shutdown = NULL, + .driver = { + .name = "tvenc", + .pm = &tvenc_dev_pm_ops + }, +}; + +int tvenc_set_encoder_clock(boolean clock_on) +{ + int ret = 0; + if (clock_on) { +#ifdef CONFIG_FB_MSM_MDP40 + /* Consolidated clock used by both HDMI & TV encoder. + Clock exists only in MDP4 and not in older versions */ + ret = clk_set_rate(tv_src_clk, 27000000); + if (ret) { + pr_err("%s: tvsrc_clk set rate failed! %d\n", + __func__, ret); + goto tvsrc_err; + } +#endif + ret = clk_prepare_enable(tvenc_clk); + if (ret) { + pr_err("%s: tvenc_clk enable failed! %d\n", + __func__, ret); + goto tvsrc_err; + } + + if (!IS_ERR(tvenc_pclk)) { + ret = clk_prepare_enable(tvenc_pclk); + if (ret) { + pr_err("%s: tvenc_pclk enable failed! %d\n", + __func__, ret); + goto tvencp_err; + } + } + return ret; + } else { + if (!IS_ERR(tvenc_pclk)) + clk_disable_unprepare(tvenc_pclk); + clk_disable_unprepare(tvenc_clk); + return ret; + } +tvencp_err: + clk_disable_unprepare(tvenc_clk); +tvsrc_err: + return ret; +} + +int tvenc_set_clock(boolean clock_on) +{ + int ret = 0; + if (clock_on) { + if (tvenc_pdata->poll) { + ret = tvenc_set_encoder_clock(CLOCK_ON); + if (ret) { + pr_err("%s: TVenc clock(s) enable failed! %d\n", + __func__, ret); + goto tvenc_err; + } + } + ret = clk_prepare_enable(tvdac_clk); + if (ret) { + pr_err("%s: tvdac_clk enable failed! %d\n", + __func__, ret); + goto tvdac_err; + } + if (!IS_ERR(mdp_tv_clk)) { + ret = clk_prepare_enable(mdp_tv_clk); + if (ret) { + pr_err("%s: mdp_tv_clk enable failed! %d\n", + __func__, ret); + goto mdptv_err; + } + } + return ret; + } else { + if (!IS_ERR(mdp_tv_clk)) + clk_disable_unprepare(mdp_tv_clk); + clk_disable_unprepare(tvdac_clk); + if (tvenc_pdata->poll) + tvenc_set_encoder_clock(CLOCK_OFF); + return ret; + } + +mdptv_err: + clk_disable_unprepare(tvdac_clk); +tvdac_err: + tvenc_set_encoder_clock(CLOCK_OFF); +tvenc_err: + return ret; +} + +static int tvenc_off(struct platform_device *pdev) +{ + int ret = 0; + + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + + ret = panel_next_off(pdev); + if (ret) + pr_err("%s: tvout_off failed! %d\n", + __func__, ret); + + tvenc_set_clock(CLOCK_OFF); + + if (tvenc_pdata && tvenc_pdata->pm_vid_en) + ret = tvenc_pdata->pm_vid_en(0); +#ifdef CONFIG_MSM_BUS_SCALING + if (tvenc_bus_scale_handle > 0) + msm_bus_scale_client_update_request(tvenc_bus_scale_handle, + 0); +#else + if (mfd->ebi1_clk) + clk_disable_unprepare(mfd->ebi1_clk); +#endif + + if (ret) + pr_err("%s: pm_vid_en(off) failed! %d\n", + __func__, ret); + mdp4_extn_disp = 0; + return ret; +} + +static int tvenc_on(struct platform_device *pdev) +{ + int ret = 0; + +#ifndef CONFIG_MSM_BUS_SCALING + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); +#endif + +#ifdef CONFIG_MSM_BUS_SCALING + if (tvenc_bus_scale_handle > 0) + msm_bus_scale_client_update_request(tvenc_bus_scale_handle, + 1); +#else + if (mfd->ebi1_clk) + clk_prepare_enable(mfd->ebi1_clk); +#endif + mdp4_extn_disp = 1; + if (tvenc_pdata && tvenc_pdata->pm_vid_en) + ret = tvenc_pdata->pm_vid_en(1); + if (ret) { + pr_err("%s: pm_vid_en(on) failed! %d\n", + __func__, ret); + return ret; + } + + ret = tvenc_set_clock(CLOCK_ON); + if (ret) { + pr_err("%s: tvenc_set_clock(CLOCK_ON) failed! %d\n", + __func__, ret); + tvenc_pdata->pm_vid_en(0); + goto error; + } + + ret = panel_next_on(pdev); + if (ret) { + pr_err("%s: tvout_on failed! %d\n", + __func__, ret); + tvenc_set_clock(CLOCK_OFF); + tvenc_pdata->pm_vid_en(0); + } + +error: + return ret; + +} + +void tvenc_gen_test_pattern(struct msm_fb_data_type *mfd) +{ + uint32 reg = 0, i; + + reg = readl(MSM_TV_ENC_CTL); + reg |= TVENC_CTL_TEST_PATT_EN; + + for (i = 0; i < 3; i++) { + TV_OUT(TV_ENC_CTL, 0); /* disable TV encoder */ + + switch (i) { + /* + * TV Encoder - Color Bar Test Pattern + */ + case 0: + reg |= TVENC_CTL_TPG_CLRBAR; + break; + /* + * TV Encoder - Red Frame Test Pattern + */ + case 1: + reg |= TVENC_CTL_TPG_REDCLR; + break; + /* + * TV Encoder - Modulated Ramp Test Pattern + */ + default: + reg |= TVENC_CTL_TPG_MODRAMP; + break; + } + + TV_OUT(TV_ENC_CTL, reg); + mdelay(5000); + + switch (i) { + /* + * TV Encoder - Color Bar Test Pattern + */ + case 0: + reg &= ~TVENC_CTL_TPG_CLRBAR; + break; + /* + * TV Encoder - Red Frame Test Pattern + */ + case 1: + reg &= ~TVENC_CTL_TPG_REDCLR; + break; + /* + * TV Encoder - Modulated Ramp Test Pattern + */ + default: + reg &= ~TVENC_CTL_TPG_MODRAMP; + break; + } + } +} + +static int tvenc_resource_initialized; + +static int tvenc_probe(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + struct platform_device *mdp_dev = NULL; + struct msm_fb_panel_data *pdata = NULL; + int rc, ret; + struct clk *ebi1_clk = NULL; + + if (pdev->id == 0) { + tvenc_base = ioremap(pdev->resource[0].start, + pdev->resource[0].end - + pdev->resource[0].start + 1); + if (!tvenc_base) { + pr_err("tvenc_base ioremap failed!\n"); + return -ENOMEM; + } + + tvenc_clk = clk_get(&pdev->dev, "enc_clk"); + tvdac_clk = clk_get(&pdev->dev, "dac_clk"); + tvenc_pclk = clk_get(&pdev->dev, "iface_clk"); + mdp_tv_clk = clk_get(&pdev->dev, "mdp_clk"); + +#ifndef CONFIG_MSM_BUS_SCALING + ebi1_clk = clk_get(&pdev->dev, "mem_clk"); + if (IS_ERR(ebi1_clk)) { + rc = PTR_ERR(ebi1_clk); + goto tvenc_probe_err; + } + clk_set_rate(ebi1_clk, MSM_SYSTEM_BUS_RATE); +#endif + +#ifdef CONFIG_FB_MSM_MDP40 + tv_src_clk = clk_get(&pdev->dev, "src_clk"); + if (IS_ERR(tv_src_clk)) + tv_src_clk = tvenc_clk; /* Fallback to slave */ +#endif + + if (IS_ERR(tvenc_clk)) { + pr_err("%s: error: can't get tvenc_clk!\n", __func__); + return PTR_ERR(tvenc_clk); + } + + if (IS_ERR(tvdac_clk)) { + pr_err("%s: error: can't get tvdac_clk!\n", __func__); + return PTR_ERR(tvdac_clk); + } + + if (IS_ERR(tvenc_pclk)) { + ret = PTR_ERR(tvenc_pclk); + if (-ENOENT == ret) + pr_info("%s: tvenc_pclk does not exist!\n", + __func__); + else { + pr_err("%s: error: can't get tvenc_pclk!\n", + __func__); + return ret; + } + } + + if (IS_ERR(mdp_tv_clk)) { + ret = PTR_ERR(mdp_tv_clk); + if (-ENOENT == ret) + pr_info("%s: mdp_tv_clk does not exist!\n", + __func__); + else { + pr_err("%s: error: can't get mdp_tv_clk!\n", + __func__); + return ret; + } + } + + tvenc_pdata = pdev->dev.platform_data; + tvenc_resource_initialized = 1; + return 0; + } + + if (!tvenc_resource_initialized) + return -EPERM; + + mfd = platform_get_drvdata(pdev); + mfd->ebi1_clk = ebi1_clk; + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + + if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST) + return -ENOMEM; + + if (tvenc_base == NULL) + return -ENOMEM; + + mdp_dev = platform_device_alloc("mdp", pdev->id); + if (!mdp_dev) + return -ENOMEM; + + /* + * link to the latest pdev + */ + mfd->pdev = mdp_dev; + mfd->dest = DISPLAY_TV; + + /* + * alloc panel device data + */ + if (platform_device_add_data + (mdp_dev, pdev->dev.platform_data, + sizeof(struct msm_fb_panel_data))) { + pr_err("tvenc_probe: platform_device_add_data failed!\n"); + platform_device_put(mdp_dev); + return -ENOMEM; + } + /* + * data chain + */ + pdata = mdp_dev->dev.platform_data; + pdata->on = tvenc_on; + pdata->off = tvenc_off; + pdata->next = pdev; + + /* + * get/set panel specific fb info + */ + mfd->panel_info = pdata->panel_info; +#ifdef CONFIG_FB_MSM_MDP40 + mfd->fb_imgType = MDP_RGB_565; /* base layer */ +#else + mfd->fb_imgType = MDP_YCRYCB_H2V1; +#endif + +#ifdef CONFIG_MSM_BUS_SCALING + if (!tvenc_bus_scale_handle && tvenc_pdata && + tvenc_pdata->bus_scale_table) { + tvenc_bus_scale_handle = + msm_bus_scale_register_client( + tvenc_pdata->bus_scale_table); + if (!tvenc_bus_scale_handle) { + printk(KERN_ERR "%s not able to get bus scale\n", + __func__); + } + } +#endif + + /* + * set driver data + */ + platform_set_drvdata(mdp_dev, mfd); + + /* + * register in mdp driver + */ + rc = platform_device_add(mdp_dev); + if (rc) + goto tvenc_probe_err; + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + + + pdev_list[pdev_list_cnt++] = pdev; + + return 0; + +tvenc_probe_err: +#ifdef CONFIG_MSM_BUS_SCALING + if (tvenc_pdata && tvenc_pdata->bus_scale_table && + tvenc_bus_scale_handle > 0) { + msm_bus_scale_unregister_client(tvenc_bus_scale_handle); + tvenc_bus_scale_handle = 0; + } +#endif + platform_device_put(mdp_dev); + return rc; +} + +static int tvenc_remove(struct platform_device *pdev) +{ + struct msm_fb_data_type *mfd; + + mfd = platform_get_drvdata(pdev); + +#ifdef CONFIG_MSM_BUS_SCALING + if (tvenc_pdata && tvenc_pdata->bus_scale_table && + tvenc_bus_scale_handle > 0) { + msm_bus_scale_unregister_client(tvenc_bus_scale_handle); + tvenc_bus_scale_handle = 0; + } +#else + clk_put(mfd->ebi1_clk); +#endif + + pm_runtime_disable(&pdev->dev); + return 0; +} + +static int tvenc_register_driver(void) +{ + return platform_driver_register(&tvenc_driver); +} + +static int __init tvenc_driver_init(void) +{ + return tvenc_register_driver(); +} + +module_init(tvenc_driver_init); diff --git a/drivers/video/msm/tvenc.h b/drivers/video/msm/tvenc.h new file mode 100644 index 000000000000..0368cb860b8e --- /dev/null +++ b/drivers/video/msm/tvenc.h @@ -0,0 +1,129 @@ +/* Copyright (c) 2008-2010, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef TVENC_H +#define TVENC_H + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "msm_fb_panel.h" + +#define NTSC_M 0 /* North America, Korea */ +#define NTSC_J 1 /* Japan */ +#define PAL_BDGHIN 2 /* Non-argentina PAL-N */ +#define PAL_M 3 /* PAL-M */ +#define PAL_N 4 /* Argentina PAL-N */ + +#define CLOCK_OFF 0 +#define CLOCK_ON 1 + +/* 3.57954545 Mhz */ +#define TVENC_CTL_TV_MODE_NTSC_M_PAL60 0 +/* 3.57961149 Mhz */ +#define TVENC_CTL_TV_MODE_PAL_M BIT(0) +/*non-Argintina = 4.3361875 Mhz */ +#define TVENC_CTL_TV_MODE_PAL_BDGHIN BIT(1) +/*Argentina = 3.582055625 Mhz */ +#define TVENC_CTL_TV_MODE_PAL_N (BIT(1)|BIT(0)) + +#define TVENC_CTL_ENC_EN BIT(2) +#define TVENC_CTL_CC_EN BIT(3) +#define TVENC_CTL_CGMS_EN BIT(4) +#define TVENC_CTL_MACRO_EN BIT(5) +#define TVENC_CTL_Y_FILTER_W_NOTCH BIT(6) +#define TVENC_CTL_Y_FILTER_WO_NOTCH 0 +#define TVENC_CTL_Y_FILTER_EN BIT(7) +#define TVENC_CTL_CR_FILTER_EN BIT(8) +#define TVENC_CTL_CB_FILTER_EN BIT(9) +#define TVENC_CTL_SINX_FILTER_EN BIT(10) +#define TVENC_CTL_TEST_PATT_EN BIT(11) +#define TVENC_CTL_OUTPUT_INV BIT(12) +#define TVENC_CTL_PAL60_MODE BIT(13) +#define TVENC_CTL_NTSCJ_MODE BIT(14) +#define TVENC_CTL_S_VIDEO_EN BIT(19) + + +#define TVENC_CTL_TPG_CLRBAR 0 +#define TVENC_CTL_TPG_MODRAMP BIT(15) +#define TVENC_CTL_TPG_REDCLR BIT(16) +#define TVENC_CTL_TPG_NTSC_CBAR (BIT(16)|BIT(15)) +#define TVENC_CTL_TPG_BLACK BIT(17) +#define TVENC_CTL_TPG_WHITE100 (BIT(17)|BIT(15)) +#define TVENC_CTL_TPG_YELLOW75 (BIT(17)|BIT(16)) +#define TVENC_CTL_TPG_CYAN75 (BIT(17)|BIT(16)|BIT(15)) +#define TVENC_CTL_TPG_GREEN75 BIT(18) +#define TVENC_CTL_TPG_MAGENTA75 (BIT(18)|BIT(15)) +#define TVENC_CTL_TPG_RED75 (BIT(18)|BIT(16)) +#define TVENC_CTL_TPG_BLUE75 (BIT(18)|BIT(16)|BIT(15)) +#define TVENC_CTL_TPG_WHITE75 (BIT(18)|BIT(17)) +#define TVENC_CTL_TPG_WHITE_TRSTN (BIT(18)|BIT(17)|BIT(15)) + +#define TVENC_LOAD_DETECT_EN BIT(8) + +#ifdef TVENC_C +void *tvenc_base; +struct tvenc_platform_data *tvenc_pdata; +#else +extern void *tvenc_base; +extern struct tvenc_platform_data *tvenc_pdata; +#endif + +#define TV_OUT(reg, v) writel(v, tvenc_base + MSM_##reg) +#define TV_IN(reg) readl(tvenc_base + MSM_##reg) + +#define MSM_TV_ENC_CTL 0x00 +#define MSM_TV_LEVEL 0x04 +#define MSM_TV_GAIN 0x08 +#define MSM_TV_OFFSET 0x0c +#define MSM_TV_CGMS 0x10 +#define MSM_TV_SYNC_1 0x14 +#define MSM_TV_SYNC_2 0x18 +#define MSM_TV_SYNC_3 0x1c +#define MSM_TV_SYNC_4 0x20 +#define MSM_TV_SYNC_5 0x24 +#define MSM_TV_SYNC_6 0x28 +#define MSM_TV_SYNC_7 0x2c +#define MSM_TV_BURST_V1 0x30 +#define MSM_TV_BURST_V2 0x34 +#define MSM_TV_BURST_V3 0x38 +#define MSM_TV_BURST_V4 0x3c +#define MSM_TV_BURST_H 0x40 +#define MSM_TV_SOL_REQ_ODD 0x44 +#define MSM_TV_SOL_REQ_EVEN 0x48 +#define MSM_TV_DAC_CTL 0x4c +#define MSM_TV_TEST_MUX 0x50 +#define MSM_TV_TEST_MODE 0x54 +#define MSM_TV_TEST_MISR_RESET 0x58 +#define MSM_TV_TEST_EXPORT_MISR 0x5c +#define MSM_TV_TEST_MISR_CURR_VAL 0x60 +#define MSM_TV_TEST_SOF_CFG 0x64 +#define MSM_TV_DAC_INTF 0x100 + +#define MSM_TV_INTR_ENABLE 0x200 +#define MSM_TV_INTR_STATUS 0x204 +#define MSM_TV_INTR_CLEAR 0x208 + +int tvenc_set_encoder_clock(boolean clock_on); +int tvenc_set_clock(boolean clock_on); +#endif /* TVENC_H */ diff --git a/drivers/video/msm/tvout_msm.c b/drivers/video/msm/tvout_msm.c new file mode 100644 index 000000000000..983c585e0981 --- /dev/null +++ b/drivers/video/msm/tvout_msm.c @@ -0,0 +1,652 @@ +/* Copyright (c) 2008-2011, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include + +#include "msm_fb.h" +#include "tvenc.h" +#include "external_common.h" + +#define TVOUT_HPD_DUTY_CYCLE 3000 + +#define TV_DIMENSION_MAX_WIDTH 720 +#define TV_DIMENSION_MAX_HEIGHT 576 + +struct tvout_msm_state_type { + struct external_common_state_type common; + struct platform_device *pdev; + struct timer_list hpd_state_timer; + struct timer_list hpd_work_timer; + struct work_struct hpd_work; + uint32 hpd_int_status; + uint32 prev_hpd_int_status; + uint32 five_retry; + int irq; + uint16 y_res; + boolean hpd_initialized; + boolean disp_powered_up; +#ifdef CONFIG_SUSPEND + boolean pm_suspended; +#endif + +}; + +static struct tvout_msm_state_type *tvout_msm_state; +static DEFINE_MUTEX(tvout_msm_state_mutex); + +static int tvout_off(struct platform_device *pdev); +static int tvout_on(struct platform_device *pdev); +static void tvout_check_status(void); + +static void tvout_msm_turn_on(boolean power_on) +{ + uint32 reg_val = 0; + reg_val = TV_IN(TV_ENC_CTL); + if (power_on) { + DEV_DBG("%s: TV Encoder turned on\n", __func__); + reg_val |= TVENC_CTL_ENC_EN; + } else { + DEV_DBG("%s: TV Encoder turned off\n", __func__); + reg_val = 0; + } + /* Enable TV Encoder*/ + TV_OUT(TV_ENC_CTL, reg_val); +} + +static void tvout_check_status() +{ + tvout_msm_state->hpd_int_status &= 0x05; + /* hpd_int_status could either be 0x05 or 0x04 for a cable + plug-out event when cable detect is driven by polling. */ + if ((((tvout_msm_state->hpd_int_status == 0x05) || + (tvout_msm_state->hpd_int_status == 0x04)) && + (tvout_msm_state->prev_hpd_int_status == BIT(2))) || + ((tvout_msm_state->hpd_int_status == 0x01) && + (tvout_msm_state->prev_hpd_int_status == BIT(0)))) { + DEV_DBG("%s: cable event sent already!", __func__); + return; + } + + if (tvout_msm_state->hpd_int_status & BIT(2)) { + DEV_DBG("%s: cable plug-out\n", __func__); + mutex_lock(&external_common_state_hpd_mutex); + external_common_state->hpd_state = FALSE; + mutex_unlock(&external_common_state_hpd_mutex); + kobject_uevent(external_common_state->uevent_kobj, + KOBJ_OFFLINE); + tvout_msm_state->prev_hpd_int_status = BIT(2); + } else if (tvout_msm_state->hpd_int_status & BIT(0)) { + DEV_DBG("%s: cable plug-in\n", __func__); + mutex_lock(&external_common_state_hpd_mutex); + external_common_state->hpd_state = TRUE; + mutex_unlock(&external_common_state_hpd_mutex); + kobject_uevent(external_common_state->uevent_kobj, + KOBJ_ONLINE); + tvout_msm_state->prev_hpd_int_status = BIT(0); + } +} + +/* ISR for TV out cable detect */ +static irqreturn_t tvout_msm_isr(int irq, void *dev_id) +{ + tvout_msm_state->hpd_int_status = TV_IN(TV_INTR_STATUS); + TV_OUT(TV_INTR_CLEAR, tvout_msm_state->hpd_int_status); + DEV_DBG("%s: ISR: 0x%02x\n", __func__, + tvout_msm_state->hpd_int_status & 0x05); + + if (tvenc_pdata->poll) + if (!tvout_msm_state || !tvout_msm_state->disp_powered_up) { + DEV_DBG("%s: ISR ignored, display not yet powered on\n", + __func__); + return IRQ_HANDLED; + } + if (tvout_msm_state->hpd_int_status & BIT(0) || + tvout_msm_state->hpd_int_status & BIT(2)) { + /* Use .75sec to debounce the interrupt */ + mod_timer(&tvout_msm_state->hpd_state_timer, jiffies + + msecs_to_jiffies(750)); + } + + return IRQ_HANDLED; +} + +/* Interrupt debounce timer */ +static void tvout_msm_hpd_state_timer(unsigned long data) +{ +#ifdef CONFIG_SUSPEND + mutex_lock(&tvout_msm_state_mutex); + if (tvout_msm_state->pm_suspended) { + mutex_unlock(&tvout_msm_state_mutex); + DEV_WARN("%s: ignored, pm_suspended\n", __func__); + return; + } + mutex_unlock(&tvout_msm_state_mutex); +#endif + + if (tvenc_pdata->poll) + if (!tvout_msm_state || !tvout_msm_state->disp_powered_up) { + DEV_DBG("%s: ignored, display powered off\n", __func__); + return; + } + + /* TV_INTR_STATUS[0x204] + When a TV_ENC interrupt occurs, then reading this register will + indicate what caused the interrupt since that each bit indicates + the source of the interrupt that had happened. If multiple + interrupt sources had happened, then multiple bits of this + register will be set + Bit 0 : Load present on Video1 + Bit 1 : Load present on Video2 + Bit 2 : Load removed on Video1 + Bit 3 : Load removed on Video2 + */ + + /* Locking interrupt status is not required because + last status read after debouncing is used */ + if ((tvout_msm_state->hpd_int_status & 0x05) == 0x05) { + /* SW-workaround :If the status read after debouncing is + 0x05(indicating both load present & load removed- which can't + happen in reality), force an update. If status remains 0x05 + after retry, it's a cable unplug event */ + if (++tvout_msm_state->five_retry < 2) { + uint32 reg; + DEV_DBG("tvout: Timer: 0x05\n"); + TV_OUT(TV_INTR_CLEAR, 0xf); + reg = TV_IN(TV_DAC_INTF); + TV_OUT(TV_DAC_INTF, reg & ~TVENC_LOAD_DETECT_EN); + TV_OUT(TV_INTR_CLEAR, 0xf); + reg = TV_IN(TV_DAC_INTF); + TV_OUT(TV_DAC_INTF, reg | TVENC_LOAD_DETECT_EN); + return; + } + } + tvout_msm_state->five_retry = 0; + tvout_check_status(); +} + +static void tvout_msm_hpd_work(struct work_struct *work) +{ + uint32 reg; + +#ifdef CONFIG_SUSPEND + mutex_lock(&tvout_msm_state_mutex); + if (tvout_msm_state->pm_suspended) { + mutex_unlock(&tvout_msm_state_mutex); + DEV_WARN("%s: ignored, pm_suspended\n", __func__); + return; + } + mutex_unlock(&tvout_msm_state_mutex); +#endif + + /* Enable power lines & clocks */ + tvenc_pdata->pm_vid_en(1); + tvenc_set_clock(CLOCK_ON); + + /* Enable encoder to get a stable interrupt */ + reg = TV_IN(TV_ENC_CTL); + TV_OUT(TV_ENC_CTL, reg | TVENC_CTL_ENC_EN); + + /* SW- workaround to update status register */ + reg = TV_IN(TV_DAC_INTF); + TV_OUT(TV_DAC_INTF, reg & ~TVENC_LOAD_DETECT_EN); + TV_OUT(TV_INTR_CLEAR, 0xf); + reg = TV_IN(TV_DAC_INTF); + TV_OUT(TV_DAC_INTF, reg | TVENC_LOAD_DETECT_EN); + + tvout_msm_state->hpd_int_status = TV_IN(TV_INTR_STATUS); + + /* Disable TV encoder */ + reg = TV_IN(TV_ENC_CTL); + TV_OUT(TV_ENC_CTL, reg & ~TVENC_CTL_ENC_EN); + + /*Disable power lines & clocks */ + tvenc_set_clock(CLOCK_OFF); + tvenc_pdata->pm_vid_en(0); + + DEV_DBG("%s: ISR: 0x%02x\n", __func__, + tvout_msm_state->hpd_int_status & 0x05); + + mod_timer(&tvout_msm_state->hpd_work_timer, jiffies + + msecs_to_jiffies(TVOUT_HPD_DUTY_CYCLE)); + + tvout_check_status(); +} + +static void tvout_msm_hpd_work_timer(unsigned long data) +{ + schedule_work(&tvout_msm_state->hpd_work); +} + +static int tvout_on(struct platform_device *pdev) +{ + uint32 reg = 0; + struct fb_var_screeninfo *var; + struct msm_fb_data_type *mfd = platform_get_drvdata(pdev); + + if (!mfd) + return -ENODEV; + + if (mfd->key != MFD_KEY) + return -EINVAL; + +#ifdef CONFIG_SUSPEND + mutex_lock(&tvout_msm_state_mutex); + if (tvout_msm_state->pm_suspended) { + mutex_unlock(&tvout_msm_state_mutex); + DEV_WARN("%s: ignored, pm_suspended\n", __func__); + return -ENODEV; + } + mutex_unlock(&tvout_msm_state_mutex); +#endif + + var = &mfd->fbi->var; + if (var->reserved[3] >= NTSC_M && var->reserved[3] <= PAL_N) + external_common_state->video_resolution = var->reserved[3]; + + tvout_msm_state->pdev = pdev; + if (del_timer(&tvout_msm_state->hpd_work_timer)) + DEV_DBG("%s: work timer stopped\n", __func__); + + TV_OUT(TV_ENC_CTL, 0); /* disable TV encoder */ + + switch (external_common_state->video_resolution) { + case NTSC_M: + case NTSC_J: + TV_OUT(TV_CGMS, 0x0); + /* NTSC Timing */ + TV_OUT(TV_SYNC_1, 0x0020009e); + TV_OUT(TV_SYNC_2, 0x011306B4); + TV_OUT(TV_SYNC_3, 0x0006000C); + TV_OUT(TV_SYNC_4, 0x0028020D); + TV_OUT(TV_SYNC_5, 0x005E02FB); + TV_OUT(TV_SYNC_6, 0x0006000C); + TV_OUT(TV_SYNC_7, 0x00000012); + TV_OUT(TV_BURST_V1, 0x0013020D); + TV_OUT(TV_BURST_V2, 0x0014020C); + TV_OUT(TV_BURST_V3, 0x0013020D); + TV_OUT(TV_BURST_V4, 0x0014020C); + TV_OUT(TV_BURST_H, 0x00AE00F2); + TV_OUT(TV_SOL_REQ_ODD, 0x00280208); + TV_OUT(TV_SOL_REQ_EVEN, 0x00290209); + + reg |= TVENC_CTL_TV_MODE_NTSC_M_PAL60; + + if (external_common_state->video_resolution == NTSC_M) { + /* Cr gain 11, Cb gain C6, y_gain 97 */ + TV_OUT(TV_GAIN, 0x0081B697); + } else { + /* Cr gain 11, Cb gain C6, y_gain 97 */ + TV_OUT(TV_GAIN, 0x008bc4a3); + reg |= TVENC_CTL_NTSCJ_MODE; + } + + var->yres = 480; + break; + case PAL_BDGHIN: + case PAL_N: + /* PAL Timing */ + TV_OUT(TV_SYNC_1, 0x00180097); + TV_OUT(TV_SYNC_3, 0x0005000a); + TV_OUT(TV_SYNC_4, 0x00320271); + TV_OUT(TV_SYNC_5, 0x005602f9); + TV_OUT(TV_SYNC_6, 0x0005000a); + TV_OUT(TV_SYNC_7, 0x0000000f); + TV_OUT(TV_BURST_V1, 0x0012026e); + TV_OUT(TV_BURST_V2, 0x0011026d); + TV_OUT(TV_BURST_V3, 0x00100270); + TV_OUT(TV_BURST_V4, 0x0013026f); + TV_OUT(TV_SOL_REQ_ODD, 0x0030026e); + TV_OUT(TV_SOL_REQ_EVEN, 0x0031026f); + + if (external_common_state->video_resolution == PAL_BDGHIN) { + /* Cr gain 11, Cb gain C6, y_gain 97 */ + TV_OUT(TV_GAIN, 0x0088c1a0); + TV_OUT(TV_CGMS, 0x00012345); + TV_OUT(TV_SYNC_2, 0x011f06c0); + TV_OUT(TV_BURST_H, 0x00af00ea); + reg |= TVENC_CTL_TV_MODE_PAL_BDGHIN; + } else { + /* Cr gain 11, Cb gain C6, y_gain 97 */ + TV_OUT(TV_GAIN, 0x0081b697); + TV_OUT(TV_CGMS, 0x000af317); + TV_OUT(TV_SYNC_2, 0x12006c0); + TV_OUT(TV_BURST_H, 0x00af00fa); + reg |= TVENC_CTL_TV_MODE_PAL_N; + } + var->yres = 576; + break; + case PAL_M: + /* Cr gain 11, Cb gain C6, y_gain 97 */ + TV_OUT(TV_GAIN, 0x0081b697); + TV_OUT(TV_CGMS, 0x000af317); + TV_OUT(TV_TEST_MUX, 0x000001c3); + TV_OUT(TV_TEST_MODE, 0x00000002); + /* PAL Timing */ + TV_OUT(TV_SYNC_1, 0x0020009e); + TV_OUT(TV_SYNC_2, 0x011306b4); + TV_OUT(TV_SYNC_3, 0x0006000c); + TV_OUT(TV_SYNC_4, 0x0028020D); + TV_OUT(TV_SYNC_5, 0x005e02fb); + TV_OUT(TV_SYNC_6, 0x0006000c); + TV_OUT(TV_SYNC_7, 0x00000012); + TV_OUT(TV_BURST_V1, 0x0012020b); + TV_OUT(TV_BURST_V2, 0x0016020c); + TV_OUT(TV_BURST_V3, 0x00150209); + TV_OUT(TV_BURST_V4, 0x0013020c); + TV_OUT(TV_BURST_H, 0x00bf010b); + TV_OUT(TV_SOL_REQ_ODD, 0x00280208); + TV_OUT(TV_SOL_REQ_EVEN, 0x00290209); + + reg |= TVENC_CTL_TV_MODE_PAL_M; + var->yres = 480; + break; + default: + return -ENODEV; + } + + reg |= TVENC_CTL_Y_FILTER_EN | TVENC_CTL_CR_FILTER_EN | + TVENC_CTL_CB_FILTER_EN | TVENC_CTL_SINX_FILTER_EN; + + /* DC offset to 0. */ + TV_OUT(TV_LEVEL, 0x00000000); + TV_OUT(TV_OFFSET, 0x008080f0); + +#ifdef CONFIG_FB_MSM_TVOUT_SVIDEO + reg |= TVENC_CTL_S_VIDEO_EN; +#endif +#if defined(CONFIG_FB_MSM_MDP31) + TV_OUT(TV_DAC_INTF, 0x29); +#endif + TV_OUT(TV_ENC_CTL, reg); + + if (!tvout_msm_state->hpd_initialized) { + tvout_msm_state->hpd_initialized = TRUE; + /* Load detect enable */ + reg = TV_IN(TV_DAC_INTF); + reg |= TVENC_LOAD_DETECT_EN; + TV_OUT(TV_DAC_INTF, reg); + } + + tvout_msm_state->disp_powered_up = TRUE; + tvout_msm_turn_on(TRUE); + + if (tvenc_pdata->poll) { + /* Enable Load present & removal interrupts for Video1 */ + TV_OUT(TV_INTR_ENABLE, 0x5); + + /* Enable interrupts when display is on */ + enable_irq(tvout_msm_state->irq); + } + return 0; +} + +static int tvout_off(struct platform_device *pdev) +{ + /* Disable TV encoder irqs when display is off */ + if (tvenc_pdata->poll) + disable_irq(tvout_msm_state->irq); + tvout_msm_turn_on(FALSE); + tvout_msm_state->hpd_initialized = FALSE; + tvout_msm_state->disp_powered_up = FALSE; + if (tvenc_pdata->poll) { + mod_timer(&tvout_msm_state->hpd_work_timer, jiffies + + msecs_to_jiffies(TVOUT_HPD_DUTY_CYCLE)); + } + return 0; +} + +static int tvout_probe(struct platform_device *pdev) +{ + int rc = 0; + uint32 reg; + struct platform_device *fb_dev; + +#ifdef CONFIG_FB_MSM_TVOUT_NTSC_M + external_common_state->video_resolution = NTSC_M; +#elif defined CONFIG_FB_MSM_TVOUT_NTSC_J + external_common_state->video_resolution = NTSC_J; +#elif defined CONFIG_FB_MSM_TVOUT_PAL_M + external_common_state->video_resolution = PAL_M; +#elif defined CONFIG_FB_MSM_TVOUT_PAL_N + external_common_state->video_resolution = PAL_N; +#elif defined CONFIG_FB_MSM_TVOUT_PAL_BDGHIN + external_common_state->video_resolution = PAL_BDGHIN; +#endif + external_common_state->dev = &pdev->dev; + if (pdev->id == 0) { + struct resource *res; + + #define GET_RES(name, mode) do { \ + res = platform_get_resource_byname(pdev, mode, name); \ + if (!res) { \ + DEV_DBG("'" name "' resource not found\n"); \ + rc = -ENODEV; \ + goto error; \ + } \ + } while (0) + + #define GET_IRQ(var, name) do { \ + GET_RES(name, IORESOURCE_IRQ); \ + var = res->start; \ + } while (0) + + GET_IRQ(tvout_msm_state->irq, "tvout_device_irq"); + #undef GET_IRQ + #undef GET_RES + return 0; + } + + DEV_DBG("%s: tvout_msm_state->irq : %d", + __func__, tvout_msm_state->irq); + + rc = request_irq(tvout_msm_state->irq, &tvout_msm_isr, + IRQF_TRIGGER_HIGH, "tvout_msm_isr", NULL); + + if (rc) { + DEV_DBG("Init FAILED: IRQ request, rc=%d\n", rc); + goto error; + } + disable_irq(tvout_msm_state->irq); + + init_timer(&tvout_msm_state->hpd_state_timer); + tvout_msm_state->hpd_state_timer.function = + tvout_msm_hpd_state_timer; + tvout_msm_state->hpd_state_timer.data = (uint32)NULL; + tvout_msm_state->hpd_state_timer.expires = jiffies + + msecs_to_jiffies(1000); + + if (tvenc_pdata->poll) { + init_timer(&tvout_msm_state->hpd_work_timer); + tvout_msm_state->hpd_work_timer.function = + tvout_msm_hpd_work_timer; + tvout_msm_state->hpd_work_timer.data = (uint32)NULL; + tvout_msm_state->hpd_work_timer.expires = jiffies + + msecs_to_jiffies(1000); + } + fb_dev = msm_fb_add_device(pdev); + if (fb_dev) { + rc = external_common_state_create(fb_dev); + if (rc) { + DEV_ERR("Init FAILED: tvout_msm_state_create, rc=%d\n", + rc); + goto error; + } + if (tvenc_pdata->poll) { + /* Start polling timer to detect load */ + mod_timer(&tvout_msm_state->hpd_work_timer, jiffies + + msecs_to_jiffies(TVOUT_HPD_DUTY_CYCLE)); + } else { + /* Enable interrupt to detect load */ + tvenc_set_encoder_clock(CLOCK_ON); + reg = TV_IN(TV_DAC_INTF); + reg |= TVENC_LOAD_DETECT_EN; + TV_OUT(TV_DAC_INTF, reg); + TV_OUT(TV_INTR_ENABLE, 0x5); + enable_irq(tvout_msm_state->irq); + } + } else + DEV_ERR("Init FAILED: failed to add fb device\n"); +error: + return 0; +} + +static int tvout_remove(struct platform_device *pdev) +{ + external_common_state_remove(); + kfree(tvout_msm_state); + tvout_msm_state = NULL; + return 0; +} + +#ifdef CONFIG_SUSPEND +static int tvout_device_pm_suspend(struct device *dev) +{ + mutex_lock(&tvout_msm_state_mutex); + if (tvout_msm_state->pm_suspended) { + mutex_unlock(&tvout_msm_state_mutex); + return 0; + } + if (tvenc_pdata->poll) { + if (del_timer(&tvout_msm_state->hpd_work_timer)) + DEV_DBG("%s: suspending cable detect timer\n", + __func__); + } else { + disable_irq(tvout_msm_state->irq); + tvenc_set_encoder_clock(CLOCK_OFF); + } + tvout_msm_state->pm_suspended = TRUE; + mutex_unlock(&tvout_msm_state_mutex); + return 0; +} + +static int tvout_device_pm_resume(struct device *dev) +{ + mutex_lock(&tvout_msm_state_mutex); + if (!tvout_msm_state->pm_suspended) { + mutex_unlock(&tvout_msm_state_mutex); + return 0; + } + + if (tvenc_pdata->poll) { + tvout_msm_state->pm_suspended = FALSE; + mod_timer(&tvout_msm_state->hpd_work_timer, jiffies + + msecs_to_jiffies(TVOUT_HPD_DUTY_CYCLE)); + mutex_unlock(&tvout_msm_state_mutex); + DEV_DBG("%s: resuming cable detect timer\n", __func__); + } else { + tvenc_set_encoder_clock(CLOCK_ON); + tvout_msm_state->pm_suspended = FALSE; + mutex_unlock(&tvout_msm_state_mutex); + enable_irq(tvout_msm_state->irq); + DEV_DBG("%s: enable cable detect interrupt\n", __func__); + } + return 0; +} +#else +#define tvout_device_pm_suspend NULL +#define tvout_device_pm_resume NULL +#endif + + +static const struct dev_pm_ops tvout_device_pm_ops = { + .suspend = tvout_device_pm_suspend, + .resume = tvout_device_pm_resume, +}; + +static struct platform_driver this_driver = { + .probe = tvout_probe, + .remove = tvout_remove, + .driver = { + .name = "tvout_device", + .pm = &tvout_device_pm_ops, + }, +}; + +static struct msm_fb_panel_data tvout_panel_data = { + .panel_info.xres = TV_DIMENSION_MAX_WIDTH, + .panel_info.yres = TV_DIMENSION_MAX_HEIGHT, + .panel_info.type = TV_PANEL, + .panel_info.pdest = DISPLAY_2, + .panel_info.wait_cycle = 0, +#ifdef CONFIG_FB_MSM_MDP40 + .panel_info.bpp = 24, +#else + .panel_info.bpp = 16, +#endif + .panel_info.fb_num = 2, + .on = tvout_on, + .off = tvout_off, +}; + +static struct platform_device this_device = { + .name = "tvout_device", + .id = 1, + .dev = { + .platform_data = &tvout_panel_data, + } +}; + +static int __init tvout_init(void) +{ + int ret; + + if (msm_fb_detect_client("tvout_msm")) + return 0; + + tvout_msm_state = kzalloc(sizeof(*tvout_msm_state), GFP_KERNEL); + if (!tvout_msm_state) { + DEV_ERR("tvout_msm_init FAILED: out of memory\n"); + ret = -ENOMEM; + goto init_exit; + } + + external_common_state = &tvout_msm_state->common; + ret = platform_driver_register(&this_driver); + if (ret) { + DEV_ERR("tvout_device_init FAILED: platform_driver_register\ + rc=%d\n", ret); + goto init_exit; + } + + ret = platform_device_register(&this_device); + if (ret) { + DEV_ERR("tvout_device_init FAILED: platform_driver_register\ + rc=%d\n", ret); + platform_driver_unregister(&this_driver); + goto init_exit; + } + + INIT_WORK(&tvout_msm_state->hpd_work, tvout_msm_hpd_work); + return 0; + +init_exit: + kfree(tvout_msm_state); + tvout_msm_state = NULL; + return ret; +} + +static void __exit tvout_exit(void) +{ + platform_device_unregister(&this_device); + platform_driver_unregister(&this_driver); +} + +module_init(tvout_init); +module_exit(tvout_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("1.0"); +MODULE_AUTHOR("Qualcomm Innovation Center, Inc."); +MODULE_DESCRIPTION("TV out driver"); -- GitLab