diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-08 13:02:59 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-08 13:02:59 -0400 |
| commit | 537d84787659b355b3331813dc134c7497ddafa5 (patch) | |
| tree | e43d376ed8522b09163ed1f7902e1fed25d2fe3b | |
| parent | d71048e22f47725a5808ea2e4e1e72fa36c1a788 (diff) | |
| parent | ece350d3949e9a60b39e4f9853be118e98d48fbc (diff) | |
Merge branch 'for-linus' of git://gitorious.org/linux-omap-dss2/linux
* 'for-linus' of git://gitorious.org/linux-omap-dss2/linux: (64 commits)
OMAP: DSS2: OMAPFB: add support for FBIO_WAITFORVSYNC
OMAP: DSS2: Replace strncmp() with sysfs_streq() in overlay_manager_store()
OMAP: DSS2: Fix error path in omap_dsi_update()
OMAP: DSS2: TDO35S: fix video signaling
OMAP: DSS2: OMAPFB: Fix invalid bpp for PAL and NTSC modes
OMAP: DSS2: OMAPFB: Fix probe error path
OMAP3EVM: Replace vdvi regulator supply with vdds_dsi
OMAP: DSS2: Remove extra return statement
OMAP: DSS2: adjust YUV overlay width to be even
OMAP: DSS2: OMAPFB: Fix sysfs mirror input check
OMAP: DSS2: OMAPFB: Remove redundant color register range check
OMAP: DSS2: OMAPFB: Remove redundant rotate range check
OMAP: DSS2: OMAPFB: Check fb2display() return value
OMAP: DSS2: Taal: Optimize enable_te, rotate, mirror when value unchanged
OMAP: DSS2: DSI: detect unsupported update requests
OMAP: DSS2: DSI: increase FIFO low threshold
OMAP: DSS2: DSI: Add error IRQ mask for DSI complexIO
OMAP: DSS2: DSI: Remove BTA after set_max_rx_packet_size
OMAP: DSS2: change manual update scaling setup
OMAP: DSS2: DSI: use BTA to end the frame transfer
...
| -rw-r--r-- | arch/arm/mach-omap2/board-omap3evm.c | 7 | ||||
| -rw-r--r-- | arch/arm/plat-omap/include/plat/display.h | 9 | ||||
| -rw-r--r-- | arch/arm/plat-omap/include/plat/nokia-dsi-panel.h | 31 | ||||
| -rw-r--r-- | drivers/video/omap2/displays/panel-taal.c | 567 | ||||
| -rw-r--r-- | drivers/video/omap2/displays/panel-toppoly-tdo35s.c | 8 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/dispc.c | 16 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/display.c | 4 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/dsi.c | 463 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/dss.c | 6 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/dss.h | 11 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/manager.c | 204 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/overlay.c | 2 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/rfbi.c | 2 | ||||
| -rw-r--r-- | drivers/video/omap2/omapfb/omapfb-ioctl.c | 188 | ||||
| -rw-r--r-- | drivers/video/omap2/omapfb/omapfb-main.c | 229 | ||||
| -rw-r--r-- | drivers/video/omap2/omapfb/omapfb-sysfs.c | 70 | ||||
| -rw-r--r-- | drivers/video/omap2/omapfb/omapfb.h | 29 | ||||
| -rw-r--r-- | include/linux/omapfb.h | 5 |
18 files changed, 1265 insertions, 586 deletions
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c index 6494dbdfc39..f76d9c0a47a 100644 --- a/arch/arm/mach-omap2/board-omap3evm.c +++ b/arch/arm/mach-omap2/board-omap3evm.c | |||
| @@ -514,14 +514,11 @@ static struct regulator_init_data omap3_evm_vdac = { | |||
| 514 | }; | 514 | }; |
| 515 | 515 | ||
| 516 | /* VPLL2 for digital video outputs */ | 516 | /* VPLL2 for digital video outputs */ |
| 517 | static struct regulator_consumer_supply omap3_evm_vpll2_supply = { | 517 | static struct regulator_consumer_supply omap3_evm_vpll2_supply = |
| 518 | .supply = "vdvi", | 518 | REGULATOR_SUPPLY("vdds_dsi", "omapdss"); |
| 519 | .dev = &omap3_evm_lcd_device.dev, | ||
| 520 | }; | ||
| 521 | 519 | ||
| 522 | static struct regulator_init_data omap3_evm_vpll2 = { | 520 | static struct regulator_init_data omap3_evm_vpll2 = { |
| 523 | .constraints = { | 521 | .constraints = { |
| 524 | .name = "VDVI", | ||
| 525 | .min_uV = 1800000, | 522 | .min_uV = 1800000, |
| 526 | .max_uV = 1800000, | 523 | .max_uV = 1800000, |
| 527 | .apply_uV = true, | 524 | .apply_uV = true, |
diff --git a/arch/arm/plat-omap/include/plat/display.h b/arch/arm/plat-omap/include/plat/display.h index 1c529ce9dc1..8bd15bdb413 100644 --- a/arch/arm/plat-omap/include/plat/display.h +++ b/arch/arm/plat-omap/include/plat/display.h | |||
| @@ -238,7 +238,7 @@ int dsi_vc_dcs_write_1(int channel, u8 dcs_cmd, u8 param); | |||
| 238 | int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len); | 238 | int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len); |
| 239 | int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen); | 239 | int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen); |
| 240 | int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data); | 240 | int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data); |
| 241 | int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data); | 241 | int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u8 *data1, u8 *data2); |
| 242 | int dsi_vc_set_max_rx_packet_size(int channel, u16 len); | 242 | int dsi_vc_set_max_rx_packet_size(int channel, u16 len); |
| 243 | int dsi_vc_send_null(int channel); | 243 | int dsi_vc_send_null(int channel); |
| 244 | int dsi_vc_send_bta_sync(int channel); | 244 | int dsi_vc_send_bta_sync(int channel); |
| @@ -277,8 +277,8 @@ struct omap_video_timings { | |||
| 277 | * identify the mode, and does not actually use the configs | 277 | * identify the mode, and does not actually use the configs |
| 278 | * itself. However, the configs should be something that | 278 | * itself. However, the configs should be something that |
| 279 | * a normal monitor can also show */ | 279 | * a normal monitor can also show */ |
| 280 | const extern struct omap_video_timings omap_dss_pal_timings; | 280 | extern const struct omap_video_timings omap_dss_pal_timings; |
| 281 | const extern struct omap_video_timings omap_dss_ntsc_timings; | 281 | extern const struct omap_video_timings omap_dss_ntsc_timings; |
| 282 | #endif | 282 | #endif |
| 283 | 283 | ||
| 284 | struct omap_overlay_info { | 284 | struct omap_overlay_info { |
| @@ -560,7 +560,8 @@ void omapdss_dsi_vc_enable_hs(int channel, bool enable); | |||
| 560 | int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable); | 560 | int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable); |
| 561 | 561 | ||
| 562 | int omap_dsi_prepare_update(struct omap_dss_device *dssdev, | 562 | int omap_dsi_prepare_update(struct omap_dss_device *dssdev, |
| 563 | u16 *x, u16 *y, u16 *w, u16 *h); | 563 | u16 *x, u16 *y, u16 *w, u16 *h, |
| 564 | bool enlarge_update_area); | ||
| 564 | int omap_dsi_update(struct omap_dss_device *dssdev, | 565 | int omap_dsi_update(struct omap_dss_device *dssdev, |
| 565 | int channel, | 566 | int channel, |
| 566 | u16 x, u16 y, u16 w, u16 h, | 567 | u16 x, u16 y, u16 w, u16 h, |
diff --git a/arch/arm/plat-omap/include/plat/nokia-dsi-panel.h b/arch/arm/plat-omap/include/plat/nokia-dsi-panel.h new file mode 100644 index 00000000000..01ab6572ccb --- /dev/null +++ b/arch/arm/plat-omap/include/plat/nokia-dsi-panel.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | #ifndef __ARCH_ARM_PLAT_OMAP_NOKIA_DSI_PANEL_H | ||
| 2 | #define __ARCH_ARM_PLAT_OMAP_NOKIA_DSI_PANEL_H | ||
| 3 | |||
| 4 | #include "display.h" | ||
| 5 | |||
| 6 | /** | ||
| 7 | * struct nokia_dsi_panel_data - Nokia DSI panel driver configuration | ||
| 8 | * @name: panel name | ||
| 9 | * @use_ext_te: use external TE | ||
| 10 | * @ext_te_gpio: external TE GPIO | ||
| 11 | * @use_esd_check: perform ESD checks | ||
| 12 | * @max_backlight_level: maximum backlight level | ||
| 13 | * @set_backlight: pointer to backlight set function | ||
| 14 | * @get_backlight: pointer to backlight get function | ||
| 15 | */ | ||
| 16 | struct nokia_dsi_panel_data { | ||
| 17 | const char *name; | ||
| 18 | |||
| 19 | int reset_gpio; | ||
| 20 | |||
| 21 | bool use_ext_te; | ||
| 22 | int ext_te_gpio; | ||
| 23 | |||
| 24 | bool use_esd_check; | ||
| 25 | |||
| 26 | int max_backlight_level; | ||
| 27 | int (*set_backlight)(struct omap_dss_device *dssdev, int level); | ||
| 28 | int (*get_backlight)(struct omap_dss_device *dssdev); | ||
| 29 | }; | ||
| 30 | |||
| 31 | #endif /* __ARCH_ARM_PLAT_OMAP_NOKIA_DSI_PANEL_H */ | ||
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index aaf5d308a04..e1c765d1141 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c | |||
| @@ -28,12 +28,13 @@ | |||
| 28 | #include <linux/fb.h> | 28 | #include <linux/fb.h> |
| 29 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
| 30 | #include <linux/gpio.h> | 30 | #include <linux/gpio.h> |
| 31 | #include <linux/completion.h> | ||
| 32 | #include <linux/workqueue.h> | 31 | #include <linux/workqueue.h> |
| 33 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
| 33 | #include <linux/regulator/consumer.h> | ||
| 34 | #include <linux/mutex.h> | 34 | #include <linux/mutex.h> |
| 35 | 35 | ||
| 36 | #include <plat/display.h> | 36 | #include <plat/display.h> |
| 37 | #include <plat/nokia-dsi-panel.h> | ||
| 37 | 38 | ||
| 38 | /* DSI Virtual channel. Hardcoded for now. */ | 39 | /* DSI Virtual channel. Hardcoded for now. */ |
| 39 | #define TCH 0 | 40 | #define TCH 0 |
| @@ -62,11 +63,136 @@ | |||
| 62 | #define DCS_GET_ID2 0xdb | 63 | #define DCS_GET_ID2 0xdb |
| 63 | #define DCS_GET_ID3 0xdc | 64 | #define DCS_GET_ID3 0xdc |
| 64 | 65 | ||
| 65 | /* #define TAAL_USE_ESD_CHECK */ | ||
| 66 | #define TAAL_ESD_CHECK_PERIOD msecs_to_jiffies(5000) | 66 | #define TAAL_ESD_CHECK_PERIOD msecs_to_jiffies(5000) |
| 67 | 67 | ||
| 68 | static irqreturn_t taal_te_isr(int irq, void *data); | ||
| 69 | static void taal_te_timeout_work_callback(struct work_struct *work); | ||
| 68 | static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable); | 70 | static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable); |
| 69 | 71 | ||
| 72 | struct panel_regulator { | ||
| 73 | struct regulator *regulator; | ||
| 74 | const char *name; | ||
| 75 | int min_uV; | ||
| 76 | int max_uV; | ||
| 77 | }; | ||
| 78 | |||
| 79 | static void free_regulators(struct panel_regulator *regulators, int n) | ||
| 80 | { | ||
| 81 | int i; | ||
| 82 | |||
| 83 | for (i = 0; i < n; i++) { | ||
| 84 | /* disable/put in reverse order */ | ||
| 85 | regulator_disable(regulators[n - i - 1].regulator); | ||
| 86 | regulator_put(regulators[n - i - 1].regulator); | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | static int init_regulators(struct omap_dss_device *dssdev, | ||
| 91 | struct panel_regulator *regulators, int n) | ||
| 92 | { | ||
| 93 | int r, i, v; | ||
| 94 | |||
| 95 | for (i = 0; i < n; i++) { | ||
| 96 | struct regulator *reg; | ||
| 97 | |||
| 98 | reg = regulator_get(&dssdev->dev, regulators[i].name); | ||
| 99 | if (IS_ERR(reg)) { | ||
| 100 | dev_err(&dssdev->dev, "failed to get regulator %s\n", | ||
| 101 | regulators[i].name); | ||
| 102 | r = PTR_ERR(reg); | ||
| 103 | goto err; | ||
| 104 | } | ||
| 105 | |||
| 106 | /* FIXME: better handling of fixed vs. variable regulators */ | ||
| 107 | v = regulator_get_voltage(reg); | ||
| 108 | if (v < regulators[i].min_uV || v > regulators[i].max_uV) { | ||
| 109 | r = regulator_set_voltage(reg, regulators[i].min_uV, | ||
| 110 | regulators[i].max_uV); | ||
| 111 | if (r) { | ||
| 112 | dev_err(&dssdev->dev, | ||
| 113 | "failed to set regulator %s voltage\n", | ||
| 114 | regulators[i].name); | ||
| 115 | regulator_put(reg); | ||
| 116 | goto err; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | r = regulator_enable(reg); | ||
| 121 | if (r) { | ||
| 122 | dev_err(&dssdev->dev, "failed to enable regulator %s\n", | ||
| 123 | regulators[i].name); | ||
| 124 | regulator_put(reg); | ||
| 125 | goto err; | ||
| 126 | } | ||
| 127 | |||
| 128 | regulators[i].regulator = reg; | ||
| 129 | } | ||
| 130 | |||
| 131 | return 0; | ||
| 132 | |||
| 133 | err: | ||
| 134 | free_regulators(regulators, i); | ||
| 135 | |||
| 136 | return r; | ||
| 137 | } | ||
| 138 | |||
| 139 | /** | ||
| 140 | * struct panel_config - panel configuration | ||
| 141 | * @name: panel name | ||
| 142 | * @type: panel type | ||
| 143 | * @timings: panel resolution | ||
| 144 | * @sleep: various panel specific delays, passed to msleep() if non-zero | ||
| 145 | * @reset_sequence: reset sequence timings, passed to udelay() if non-zero | ||
| 146 | * @regulators: array of panel regulators | ||
| 147 | * @num_regulators: number of regulators in the array | ||
| 148 | */ | ||
| 149 | struct panel_config { | ||
| 150 | const char *name; | ||
| 151 | int type; | ||
| 152 | |||
| 153 | struct omap_video_timings timings; | ||
| 154 | |||
| 155 | struct { | ||
| 156 | unsigned int sleep_in; | ||
| 157 | unsigned int sleep_out; | ||
| 158 | unsigned int hw_reset; | ||
| 159 | unsigned int enable_te; | ||
| 160 | } sleep; | ||
| 161 | |||
| 162 | struct { | ||
| 163 | unsigned int high; | ||
| 164 | unsigned int low; | ||
| 165 | } reset_sequence; | ||
| 166 | |||
| 167 | struct panel_regulator *regulators; | ||
| 168 | int num_regulators; | ||
| 169 | }; | ||
| 170 | |||
| 171 | enum { | ||
| 172 | PANEL_TAAL, | ||
| 173 | }; | ||
| 174 | |||
| 175 | static struct panel_config panel_configs[] = { | ||
| 176 | { | ||
| 177 | .name = "taal", | ||
| 178 | .type = PANEL_TAAL, | ||
| 179 | .timings = { | ||
| 180 | .x_res = 864, | ||
| 181 | .y_res = 480, | ||
| 182 | }, | ||
| 183 | .sleep = { | ||
| 184 | .sleep_in = 5, | ||
| 185 | .sleep_out = 5, | ||
| 186 | .hw_reset = 5, | ||
| 187 | .enable_te = 100, /* possible panel bug */ | ||
| 188 | }, | ||
| 189 | .reset_sequence = { | ||
| 190 | .high = 10, | ||
| 191 | .low = 10, | ||
| 192 | }, | ||
| 193 | }, | ||
| 194 | }; | ||
| 195 | |||
| 70 | struct taal_data { | 196 | struct taal_data { |
| 71 | struct mutex lock; | 197 | struct mutex lock; |
| 72 | 198 | ||
| @@ -84,8 +210,15 @@ struct taal_data { | |||
| 84 | bool mirror; | 210 | bool mirror; |
| 85 | 211 | ||
| 86 | bool te_enabled; | 212 | bool te_enabled; |
| 87 | bool use_ext_te; | 213 | |
| 88 | struct completion te_completion; | 214 | atomic_t do_update; |
| 215 | struct { | ||
| 216 | u16 x; | ||
| 217 | u16 y; | ||
| 218 | u16 w; | ||
| 219 | u16 h; | ||
| 220 | } update_region; | ||
| 221 | struct delayed_work te_timeout_work; | ||
| 89 | 222 | ||
| 90 | bool use_dsi_bl; | 223 | bool use_dsi_bl; |
| 91 | 224 | ||
| @@ -96,8 +229,16 @@ struct taal_data { | |||
| 96 | 229 | ||
| 97 | struct workqueue_struct *esd_wq; | 230 | struct workqueue_struct *esd_wq; |
| 98 | struct delayed_work esd_work; | 231 | struct delayed_work esd_work; |
| 232 | |||
| 233 | struct panel_config *panel_config; | ||
| 99 | }; | 234 | }; |
| 100 | 235 | ||
| 236 | static inline struct nokia_dsi_panel_data | ||
| 237 | *get_panel_data(const struct omap_dss_device *dssdev) | ||
| 238 | { | ||
| 239 | return (struct nokia_dsi_panel_data *) dssdev->data; | ||
| 240 | } | ||
| 241 | |||
| 101 | static void taal_esd_work(struct work_struct *work); | 242 | static void taal_esd_work(struct work_struct *work); |
| 102 | 243 | ||
| 103 | static void hw_guard_start(struct taal_data *td, int guard_msec) | 244 | static void hw_guard_start(struct taal_data *td, int guard_msec) |
| @@ -159,7 +300,8 @@ static int taal_sleep_in(struct taal_data *td) | |||
| 159 | 300 | ||
| 160 | hw_guard_start(td, 120); | 301 | hw_guard_start(td, 120); |
| 161 | 302 | ||
| 162 | msleep(5); | 303 | if (td->panel_config->sleep.sleep_in) |
| 304 | msleep(td->panel_config->sleep.sleep_in); | ||
| 163 | 305 | ||
| 164 | return 0; | 306 | return 0; |
| 165 | } | 307 | } |
| @@ -176,7 +318,8 @@ static int taal_sleep_out(struct taal_data *td) | |||
| 176 | 318 | ||
| 177 | hw_guard_start(td, 120); | 319 | hw_guard_start(td, 120); |
| 178 | 320 | ||
| 179 | msleep(5); | 321 | if (td->panel_config->sleep.sleep_out) |
| 322 | msleep(td->panel_config->sleep.sleep_out); | ||
| 180 | 323 | ||
| 181 | return 0; | 324 | return 0; |
| 182 | } | 325 | } |
| @@ -279,6 +422,7 @@ static int taal_bl_update_status(struct backlight_device *dev) | |||
| 279 | { | 422 | { |
| 280 | struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev); | 423 | struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev); |
| 281 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 424 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
| 425 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
| 282 | int r; | 426 | int r; |
| 283 | int level; | 427 | int level; |
| 284 | 428 | ||
| @@ -290,24 +434,26 @@ static int taal_bl_update_status(struct backlight_device *dev) | |||
| 290 | 434 | ||
| 291 | dev_dbg(&dssdev->dev, "update brightness to %d\n", level); | 435 | dev_dbg(&dssdev->dev, "update brightness to %d\n", level); |
| 292 | 436 | ||
| 437 | mutex_lock(&td->lock); | ||
| 438 | |||
| 293 | if (td->use_dsi_bl) { | 439 | if (td->use_dsi_bl) { |
| 294 | if (td->enabled) { | 440 | if (td->enabled) { |
| 295 | dsi_bus_lock(); | 441 | dsi_bus_lock(); |
| 296 | r = taal_dcs_write_1(DCS_BRIGHTNESS, level); | 442 | r = taal_dcs_write_1(DCS_BRIGHTNESS, level); |
| 297 | dsi_bus_unlock(); | 443 | dsi_bus_unlock(); |
| 298 | if (r) | 444 | } else { |
| 299 | return r; | 445 | r = 0; |
| 300 | } | 446 | } |
| 301 | } else { | 447 | } else { |
| 302 | if (!dssdev->set_backlight) | 448 | if (!panel_data->set_backlight) |
| 303 | return -EINVAL; | 449 | r = -EINVAL; |
| 304 | 450 | else | |
| 305 | r = dssdev->set_backlight(dssdev, level); | 451 | r = panel_data->set_backlight(dssdev, level); |
| 306 | if (r) | ||
| 307 | return r; | ||
| 308 | } | 452 | } |
| 309 | 453 | ||
| 310 | return 0; | 454 | mutex_unlock(&td->lock); |
| 455 | |||
| 456 | return r; | ||
| 311 | } | 457 | } |
| 312 | 458 | ||
| 313 | static int taal_bl_get_intensity(struct backlight_device *dev) | 459 | static int taal_bl_get_intensity(struct backlight_device *dev) |
| @@ -344,16 +490,6 @@ static void taal_get_resolution(struct omap_dss_device *dssdev, | |||
| 344 | } | 490 | } |
| 345 | } | 491 | } |
| 346 | 492 | ||
| 347 | static irqreturn_t taal_te_isr(int irq, void *data) | ||
| 348 | { | ||
| 349 | struct omap_dss_device *dssdev = data; | ||
| 350 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | ||
| 351 | |||
| 352 | complete_all(&td->te_completion); | ||
| 353 | |||
| 354 | return IRQ_HANDLED; | ||
| 355 | } | ||
| 356 | |||
| 357 | static ssize_t taal_num_errors_show(struct device *dev, | 493 | static ssize_t taal_num_errors_show(struct device *dev, |
| 358 | struct device_attribute *attr, char *buf) | 494 | struct device_attribute *attr, char *buf) |
| 359 | { | 495 | { |
| @@ -362,6 +498,8 @@ static ssize_t taal_num_errors_show(struct device *dev, | |||
| 362 | u8 errors; | 498 | u8 errors; |
| 363 | int r; | 499 | int r; |
| 364 | 500 | ||
| 501 | mutex_lock(&td->lock); | ||
| 502 | |||
| 365 | if (td->enabled) { | 503 | if (td->enabled) { |
| 366 | dsi_bus_lock(); | 504 | dsi_bus_lock(); |
| 367 | r = taal_dcs_read_1(DCS_READ_NUM_ERRORS, &errors); | 505 | r = taal_dcs_read_1(DCS_READ_NUM_ERRORS, &errors); |
| @@ -370,6 +508,8 @@ static ssize_t taal_num_errors_show(struct device *dev, | |||
| 370 | r = -ENODEV; | 508 | r = -ENODEV; |
| 371 | } | 509 | } |
| 372 | 510 | ||
| 511 | mutex_unlock(&td->lock); | ||
| 512 | |||
| 373 | if (r) | 513 | if (r) |
| 374 | return r; | 514 | return r; |
| 375 | 515 | ||
| @@ -384,6 +524,8 @@ static ssize_t taal_hw_revision_show(struct device *dev, | |||
| 384 | u8 id1, id2, id3; | 524 | u8 id1, id2, id3; |
| 385 | int r; | 525 | int r; |
| 386 | 526 | ||
| 527 | mutex_lock(&td->lock); | ||
| 528 | |||
| 387 | if (td->enabled) { | 529 | if (td->enabled) { |
| 388 | dsi_bus_lock(); | 530 | dsi_bus_lock(); |
| 389 | r = taal_get_id(&id1, &id2, &id3); | 531 | r = taal_get_id(&id1, &id2, &id3); |
| @@ -392,6 +534,8 @@ static ssize_t taal_hw_revision_show(struct device *dev, | |||
| 392 | r = -ENODEV; | 534 | r = -ENODEV; |
| 393 | } | 535 | } |
| 394 | 536 | ||
| 537 | mutex_unlock(&td->lock); | ||
| 538 | |||
| 395 | if (r) | 539 | if (r) |
| 396 | return r; | 540 | return r; |
| 397 | 541 | ||
| @@ -441,6 +585,8 @@ static ssize_t store_cabc_mode(struct device *dev, | |||
| 441 | if (i == ARRAY_SIZE(cabc_modes)) | 585 | if (i == ARRAY_SIZE(cabc_modes)) |
| 442 | return -EINVAL; | 586 | return -EINVAL; |
| 443 | 587 | ||
| 588 | mutex_lock(&td->lock); | ||
| 589 | |||
| 444 | if (td->enabled) { | 590 | if (td->enabled) { |
| 445 | dsi_bus_lock(); | 591 | dsi_bus_lock(); |
| 446 | if (!td->cabc_broken) | 592 | if (!td->cabc_broken) |
| @@ -450,6 +596,8 @@ static ssize_t store_cabc_mode(struct device *dev, | |||
| 450 | 596 | ||
| 451 | td->cabc_mode = i; | 597 | td->cabc_mode = i; |
| 452 | 598 | ||
| 599 | mutex_unlock(&td->lock); | ||
| 600 | |||
| 453 | return count; | 601 | return count; |
| 454 | } | 602 | } |
| 455 | 603 | ||
| @@ -488,47 +636,93 @@ static struct attribute_group taal_attr_group = { | |||
| 488 | .attrs = taal_attrs, | 636 | .attrs = taal_attrs, |
| 489 | }; | 637 | }; |
| 490 | 638 | ||
| 639 | static void taal_hw_reset(struct omap_dss_device *dssdev) | ||
| 640 | { | ||
| 641 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | ||
| 642 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
| 643 | |||
| 644 | if (panel_data->reset_gpio == -1) | ||
| 645 | return; | ||
| 646 | |||
| 647 | gpio_set_value(panel_data->reset_gpio, 1); | ||
| 648 | if (td->panel_config->reset_sequence.high) | ||
| 649 | udelay(td->panel_config->reset_sequence.high); | ||
| 650 | /* reset the panel */ | ||
| 651 | gpio_set_value(panel_data->reset_gpio, 0); | ||
| 652 | /* assert reset */ | ||
| 653 | if (td->panel_config->reset_sequence.low) | ||
| 654 | udelay(td->panel_config->reset_sequence.low); | ||
| 655 | gpio_set_value(panel_data->reset_gpio, 1); | ||
| 656 | /* wait after releasing reset */ | ||
| 657 | if (td->panel_config->sleep.hw_reset) | ||
| 658 | msleep(td->panel_config->sleep.hw_reset); | ||
| 659 | } | ||
| 660 | |||
| 491 | static int taal_probe(struct omap_dss_device *dssdev) | 661 | static int taal_probe(struct omap_dss_device *dssdev) |
| 492 | { | 662 | { |
| 493 | struct backlight_properties props; | 663 | struct backlight_properties props; |
| 494 | struct taal_data *td; | 664 | struct taal_data *td; |
| 495 | struct backlight_device *bldev; | 665 | struct backlight_device *bldev; |
| 496 | int r; | 666 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); |
| 497 | 667 | struct panel_config *panel_config = NULL; | |
| 498 | const struct omap_video_timings taal_panel_timings = { | 668 | int r, i; |
| 499 | .x_res = 864, | ||
| 500 | .y_res = 480, | ||
| 501 | }; | ||
| 502 | 669 | ||
| 503 | dev_dbg(&dssdev->dev, "probe\n"); | 670 | dev_dbg(&dssdev->dev, "probe\n"); |
| 504 | 671 | ||
| 672 | if (!panel_data || !panel_data->name) { | ||
| 673 | r = -EINVAL; | ||
| 674 | goto err; | ||
| 675 | } | ||
| 676 | |||
| 677 | for (i = 0; i < ARRAY_SIZE(panel_configs); i++) { | ||
| 678 | if (strcmp(panel_data->name, panel_configs[i].name) == 0) { | ||
| 679 | panel_config = &panel_configs[i]; | ||
| 680 | break; | ||
| 681 | } | ||
| 682 | } | ||
| 683 | |||
| 684 | if (!panel_config) { | ||
| 685 | r = -EINVAL; | ||
| 686 | goto err; | ||
| 687 | } | ||
| 688 | |||
| 505 | dssdev->panel.config = OMAP_DSS_LCD_TFT; | 689 | dssdev->panel.config = OMAP_DSS_LCD_TFT; |
| 506 | dssdev->panel.timings = taal_panel_timings; | 690 | dssdev->panel.timings = panel_config->timings; |
| 507 | dssdev->ctrl.pixel_size = 24; | 691 | dssdev->ctrl.pixel_size = 24; |
| 508 | 692 | ||
| 509 | td = kzalloc(sizeof(*td), GFP_KERNEL); | 693 | td = kzalloc(sizeof(*td), GFP_KERNEL); |
| 510 | if (!td) { | 694 | if (!td) { |
| 511 | r = -ENOMEM; | 695 | r = -ENOMEM; |
| 512 | goto err0; | 696 | goto err; |
| 513 | } | 697 | } |
| 514 | td->dssdev = dssdev; | 698 | td->dssdev = dssdev; |
| 699 | td->panel_config = panel_config; | ||
| 515 | 700 | ||
| 516 | mutex_init(&td->lock); | 701 | mutex_init(&td->lock); |
| 517 | 702 | ||
| 703 | atomic_set(&td->do_update, 0); | ||
| 704 | |||
| 705 | r = init_regulators(dssdev, panel_config->regulators, | ||
| 706 | panel_config->num_regulators); | ||
| 707 | if (r) | ||
| 708 | goto err_reg; | ||
| 709 | |||
| 518 | td->esd_wq = create_singlethread_workqueue("taal_esd"); | 710 | td->esd_wq = create_singlethread_workqueue("taal_esd"); |
| 519 | if (td->esd_wq == NULL) { | 711 | if (td->esd_wq == NULL) { |
| 520 | dev_err(&dssdev->dev, "can't create ESD workqueue\n"); | 712 | dev_err(&dssdev->dev, "can't create ESD workqueue\n"); |
| 521 | r = -ENOMEM; | 713 | r = -ENOMEM; |
| 522 | goto err1; | 714 | goto err_wq; |
| 523 | } | 715 | } |
| 524 | INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work); | 716 | INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work); |
| 525 | 717 | ||
| 526 | dev_set_drvdata(&dssdev->dev, td); | 718 | dev_set_drvdata(&dssdev->dev, td); |
| 527 | 719 | ||
| 720 | taal_hw_reset(dssdev); | ||
| 721 | |||
| 528 | /* if no platform set_backlight() defined, presume DSI backlight | 722 | /* if no platform set_backlight() defined, presume DSI backlight |
| 529 | * control */ | 723 | * control */ |
| 530 | memset(&props, 0, sizeof(struct backlight_properties)); | 724 | memset(&props, 0, sizeof(struct backlight_properties)); |
| 531 | if (!dssdev->set_backlight) | 725 | if (!panel_data->set_backlight) |
| 532 | td->use_dsi_bl = true; | 726 | td->use_dsi_bl = true; |
| 533 | 727 | ||
| 534 | if (td->use_dsi_bl) | 728 | if (td->use_dsi_bl) |
| @@ -539,7 +733,7 @@ static int taal_probe(struct omap_dss_device *dssdev) | |||
| 539 | &taal_bl_ops, &props); | 733 | &taal_bl_ops, &props); |
| 540 | if (IS_ERR(bldev)) { | 734 | if (IS_ERR(bldev)) { |
| 541 | r = PTR_ERR(bldev); | 735 | r = PTR_ERR(bldev); |
| 542 | goto err2; | 736 | goto err_bl; |
| 543 | } | 737 | } |
| 544 | 738 | ||
| 545 | td->bldev = bldev; | 739 | td->bldev = bldev; |
| @@ -553,13 +747,13 @@ static int taal_probe(struct omap_dss_device *dssdev) | |||
| 553 | 747 | ||
| 554 | taal_bl_update_status(bldev); | 748 | taal_bl_update_status(bldev); |
| 555 | 749 | ||
| 556 | if (dssdev->phy.dsi.ext_te) { | 750 | if (panel_data->use_ext_te) { |
| 557 | int gpio = dssdev->phy.dsi.ext_te_gpio; | 751 | int gpio = panel_data->ext_te_gpio; |
| 558 | 752 | ||
| 559 | r = gpio_request(gpio, "taal irq"); | 753 | r = gpio_request(gpio, "taal irq"); |
| 560 | if (r) { | 754 | if (r) { |
| 561 | dev_err(&dssdev->dev, "GPIO request failed\n"); | 755 | dev_err(&dssdev->dev, "GPIO request failed\n"); |
| 562 | goto err3; | 756 | goto err_gpio; |
| 563 | } | 757 | } |
| 564 | 758 | ||
| 565 | gpio_direction_input(gpio); | 759 | gpio_direction_input(gpio); |
| @@ -571,49 +765,52 @@ static int taal_probe(struct omap_dss_device *dssdev) | |||
| 571 | if (r) { | 765 | if (r) { |
| 572 | dev_err(&dssdev->dev, "IRQ request failed\n"); | 766 | dev_err(&dssdev->dev, "IRQ request failed\n"); |
| 573 | gpio_free(gpio); | 767 | gpio_free(gpio); |
| 574 | goto err3; | 768 | goto err_irq; |
| 575 | } | 769 | } |
| 576 | 770 | ||
| 577 | init_completion(&td->te_completion); | 771 | INIT_DELAYED_WORK_DEFERRABLE(&td->te_timeout_work, |
| 772 | taal_te_timeout_work_callback); | ||
| 578 | 773 | ||
| 579 | td->use_ext_te = true; | 774 | dev_dbg(&dssdev->dev, "Using GPIO TE\n"); |
| 580 | } | 775 | } |
| 581 | 776 | ||
| 582 | r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group); | 777 | r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group); |
| 583 | if (r) { | 778 | if (r) { |
| 584 | dev_err(&dssdev->dev, "failed to create sysfs files\n"); | 779 | dev_err(&dssdev->dev, "failed to create sysfs files\n"); |
| 585 | goto err4; | 780 | goto err_sysfs; |
| 586 | } | 781 | } |
| 587 | 782 | ||
| 588 | return 0; | 783 | return 0; |
| 589 | err4: | 784 | err_sysfs: |
| 590 | if (td->use_ext_te) { | 785 | if (panel_data->use_ext_te) |
| 591 | int gpio = dssdev->phy.dsi.ext_te_gpio; | 786 | free_irq(gpio_to_irq(panel_data->ext_te_gpio), dssdev); |
| 592 | free_irq(gpio_to_irq(gpio), dssdev); | 787 | err_irq: |
| 593 | gpio_free(gpio); | 788 | if (panel_data->use_ext_te) |
| 594 | } | 789 | gpio_free(panel_data->ext_te_gpio); |
| 595 | err3: | 790 | err_gpio: |
| 596 | backlight_device_unregister(bldev); | 791 | backlight_device_unregister(bldev); |
| 597 | err2: | 792 | err_bl: |
| 598 | cancel_delayed_work_sync(&td->esd_work); | ||
| 599 | destroy_workqueue(td->esd_wq); | 793 | destroy_workqueue(td->esd_wq); |
| 600 | err1: | 794 | err_wq: |
| 795 | free_regulators(panel_config->regulators, panel_config->num_regulators); | ||
| 796 | err_reg: | ||
| 601 | kfree(td); | 797 | kfree(td); |
| 602 | err0: | 798 | err: |
| 603 | return r; | 799 | return r; |
| 604 | } | 800 | } |
| 605 | 801 | ||
| 606 | static void taal_remove(struct omap_dss_device *dssdev) | 802 | static void taal_remove(struct omap_dss_device *dssdev) |
| 607 | { | 803 | { |
| 608 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 804 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
| 805 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
| 609 | struct backlight_device *bldev; | 806 | struct backlight_device *bldev; |
| 610 | 807 | ||
| 611 | dev_dbg(&dssdev->dev, "remove\n"); | 808 | dev_dbg(&dssdev->dev, "remove\n"); |
| 612 | 809 | ||
| 613 | sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group); | 810 | sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group); |
| 614 | 811 | ||
| 615 | if (td->use_ext_te) { | 812 | if (panel_data->use_ext_te) { |
| 616 | int gpio = dssdev->phy.dsi.ext_te_gpio; | 813 | int gpio = panel_data->ext_te_gpio; |
| 617 | free_irq(gpio_to_irq(gpio), dssdev); | 814 | free_irq(gpio_to_irq(gpio), dssdev); |
| 618 | gpio_free(gpio); | 815 | gpio_free(gpio); |
| 619 | } | 816 | } |
| @@ -623,9 +820,15 @@ static void taal_remove(struct omap_dss_device *dssdev) | |||
| 623 | taal_bl_update_status(bldev); | 820 | taal_bl_update_status(bldev); |
| 624 | backlight_device_unregister(bldev); | 821 | backlight_device_unregister(bldev); |
| 625 | 822 | ||
| 626 | cancel_delayed_work_sync(&td->esd_work); | 823 | cancel_delayed_work(&td->esd_work); |
| 627 | destroy_workqueue(td->esd_wq); | 824 | destroy_workqueue(td->esd_wq); |
| 628 | 825 | ||
| 826 | /* reset, to be sure that the panel is in a valid state */ | ||
| 827 | taal_hw_reset(dssdev); | ||
| 828 | |||
| 829 | free_regulators(td->panel_config->regulators, | ||
| 830 | td->panel_config->num_regulators); | ||
| 831 | |||
| 629 | kfree(td); | 832 | kfree(td); |
| 630 | } | 833 | } |
| 631 | 834 | ||
| @@ -635,23 +838,14 @@ static int taal_power_on(struct omap_dss_device *dssdev) | |||
| 635 | u8 id1, id2, id3; | 838 | u8 id1, id2, id3; |
| 636 | int r; | 839 | int r; |
| 637 | 840 | ||
| 638 | if (dssdev->platform_enable) { | ||
| 639 | r = dssdev->platform_enable(dssdev); | ||
| 640 | if (r) | ||
| 641 | return r; | ||
| 642 | } | ||
| 643 | |||
| 644 | /* it seems we have to wait a bit until taal is ready */ | ||
| 645 | msleep(5); | ||
| 646 | |||
| 647 | dsi_bus_lock(); | ||
| 648 | |||
| 649 | r = omapdss_dsi_display_enable(dssdev); | 841 | r = omapdss_dsi_display_enable(dssdev); |
| 650 | if (r) { | 842 | if (r) { |
| 651 | dev_err(&dssdev->dev, "failed to enable DSI\n"); | 843 | dev_err(&dssdev->dev, "failed to enable DSI\n"); |
| 652 | goto err0; | 844 | goto err0; |
| 653 | } | 845 | } |
| 654 | 846 | ||
| 847 | taal_hw_reset(dssdev); | ||
| 848 | |||
| 655 | omapdss_dsi_vc_enable_hs(TCH, false); | 849 | omapdss_dsi_vc_enable_hs(TCH, false); |
| 656 | 850 | ||
| 657 | r = taal_sleep_out(td); | 851 | r = taal_sleep_out(td); |
| @@ -662,34 +856,47 @@ static int taal_power_on(struct omap_dss_device *dssdev) | |||
| 662 | if (r) | 856 | if (r) |
| 663 | goto err; | 857 | goto err; |
| 664 | 858 | ||
| 665 | /* on early revisions CABC is broken */ | 859 | /* on early Taal revisions CABC is broken */ |
| 666 | if (id2 == 0x00 || id2 == 0xff || id2 == 0x81) | 860 | if (td->panel_config->type == PANEL_TAAL && |
| 861 | (id2 == 0x00 || id2 == 0xff || id2 == 0x81)) | ||
| 667 | td->cabc_broken = true; | 862 | td->cabc_broken = true; |
| 668 | 863 | ||
| 669 | taal_dcs_write_1(DCS_BRIGHTNESS, 0xff); | 864 | r = taal_dcs_write_1(DCS_BRIGHTNESS, 0xff); |
| 670 | taal_dcs_write_1(DCS_CTRL_DISPLAY, (1<<2) | (1<<5)); /* BL | BCTRL */ | 865 | if (r) |
| 866 | goto err; | ||
| 867 | |||
| 868 | r = taal_dcs_write_1(DCS_CTRL_DISPLAY, | ||
| 869 | (1<<2) | (1<<5)); /* BL | BCTRL */ | ||
| 870 | if (r) | ||
| 871 | goto err; | ||
| 872 | |||
| 873 | r = taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */ | ||
| 874 | if (r) | ||
| 875 | goto err; | ||
| 671 | 876 | ||
| 672 | taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */ | 877 | r = taal_set_addr_mode(td->rotate, td->mirror); |
| 878 | if (r) | ||
| 879 | goto err; | ||
| 673 | 880 | ||
| 674 | taal_set_addr_mode(td->rotate, td->mirror); | 881 | if (!td->cabc_broken) { |
| 675 | if (!td->cabc_broken) | 882 | r = taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode); |
| 676 | taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode); | 883 | if (r) |
| 884 | goto err; | ||
| 885 | } | ||
| 677 | 886 | ||
| 678 | taal_dcs_write_0(DCS_DISPLAY_ON); | 887 | r = taal_dcs_write_0(DCS_DISPLAY_ON); |
| 888 | if (r) | ||
| 889 | goto err; | ||
| 679 | 890 | ||
| 680 | r = _taal_enable_te(dssdev, td->te_enabled); | 891 | r = _taal_enable_te(dssdev, td->te_enabled); |
| 681 | if (r) | 892 | if (r) |
| 682 | goto err; | 893 | goto err; |
| 683 | 894 | ||
| 684 | #ifdef TAAL_USE_ESD_CHECK | ||
| 685 | queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD); | ||
| 686 | #endif | ||
| 687 | |||
| 688 | td->enabled = 1; | 895 | td->enabled = 1; |
| 689 | 896 | ||
| 690 | if (!td->intro_printed) { | 897 | if (!td->intro_printed) { |
| 691 | dev_info(&dssdev->dev, "revision %02x.%02x.%02x\n", | 898 | dev_info(&dssdev->dev, "%s panel revision %02x.%02x.%02x\n", |
| 692 | id1, id2, id3); | 899 | td->panel_config->name, id1, id2, id3); |
| 693 | if (td->cabc_broken) | 900 | if (td->cabc_broken) |
| 694 | dev_info(&dssdev->dev, | 901 | dev_info(&dssdev->dev, |
| 695 | "old Taal version, CABC disabled\n"); | 902 | "old Taal version, CABC disabled\n"); |
| @@ -698,46 +905,44 @@ static int taal_power_on(struct omap_dss_device *dssdev) | |||
| 698 | 905 | ||
| 699 | omapdss_dsi_vc_enable_hs(TCH, true); | 906 | omapdss_dsi_vc_enable_hs(TCH, true); |
| 700 | 907 | ||
| 701 | dsi_bus_unlock(); | ||
| 702 | |||
| 703 | return 0; | 908 | return 0; |
| 704 | err: | 909 | err: |
| 910 | dev_err(&dssdev->dev, "error while enabling panel, issuing HW reset\n"); | ||
| 911 | |||
| 912 | taal_hw_reset(dssdev); | ||
| 913 | |||
| 705 | omapdss_dsi_display_disable(dssdev); | 914 | omapdss_dsi_display_disable(dssdev); |
| 706 | err0: | 915 | err0: |
| 707 | dsi_bus_unlock(); | ||
| 708 | if (dssdev->platform_disable) | ||
| 709 | dssdev->platform_disable(dssdev); | ||
| 710 | |||
| 711 | return r; | 916 | return r; |
| 712 | } | 917 | } |
| 713 | 918 | ||
| 714 | static void taal_power_off(struct omap_dss_device *dssdev) | 919 | static void taal_power_off(struct omap_dss_device *dssdev) |
| 715 | { | 920 | { |
| 716 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 921 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
| 922 | int r; | ||
| 717 | 923 | ||
| 718 | dsi_bus_lock(); | 924 | r = taal_dcs_write_0(DCS_DISPLAY_OFF); |
| 719 | 925 | if (!r) { | |
| 720 | cancel_delayed_work(&td->esd_work); | 926 | r = taal_sleep_in(td); |
| 721 | 927 | /* HACK: wait a bit so that the message goes through */ | |
| 722 | taal_dcs_write_0(DCS_DISPLAY_OFF); | 928 | msleep(10); |
| 723 | taal_sleep_in(td); | 929 | } |
| 724 | 930 | ||
| 725 | /* wait a bit so that the message goes through */ | 931 | if (r) { |
| 726 | msleep(10); | 932 | dev_err(&dssdev->dev, |
| 933 | "error disabling panel, issuing HW reset\n"); | ||
| 934 | taal_hw_reset(dssdev); | ||
| 935 | } | ||
| 727 | 936 | ||
| 728 | omapdss_dsi_display_disable(dssdev); | 937 | omapdss_dsi_display_disable(dssdev); |
| 729 | 938 | ||
| 730 | if (dssdev->platform_disable) | ||
| 731 | dssdev->platform_disable(dssdev); | ||
| 732 | |||
| 733 | td->enabled = 0; | 939 | td->enabled = 0; |
| 734 | |||
| 735 | dsi_bus_unlock(); | ||
| 736 | } | 940 | } |
| 737 | 941 | ||
| 738 | static int taal_enable(struct omap_dss_device *dssdev) | 942 | static int taal_enable(struct omap_dss_device *dssdev) |
| 739 | { | 943 | { |
| 740 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 944 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
| 945 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
| 741 | int r; | 946 | int r; |
| 742 | 947 | ||
| 743 | dev_dbg(&dssdev->dev, "enable\n"); | 948 | dev_dbg(&dssdev->dev, "enable\n"); |
| @@ -749,10 +954,19 @@ static int taal_enable(struct omap_dss_device *dssdev) | |||
| 749 | goto err; | 954 | goto err; |
| 750 | } | 955 | } |
| 751 | 956 | ||
| 957 | dsi_bus_lock(); | ||
| 958 | |||
| 752 | r = taal_power_on(dssdev); | 959 | r = taal_power_on(dssdev); |
| 960 | |||
| 961 | dsi_bus_unlock(); | ||
| 962 | |||
| 753 | if (r) | 963 | if (r) |
| 754 | goto err; | 964 | goto err; |
| 755 | 965 | ||
| 966 | if (panel_data->use_esd_check) | ||
| 967 | queue_delayed_work(td->esd_wq, &td->esd_work, | ||
| 968 | TAAL_ESD_CHECK_PERIOD); | ||
| 969 | |||
| 756 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | 970 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; |
| 757 | 971 | ||
| 758 | mutex_unlock(&td->lock); | 972 | mutex_unlock(&td->lock); |
| @@ -772,9 +986,15 @@ static void taal_disable(struct omap_dss_device *dssdev) | |||
| 772 | 986 | ||
| 773 | mutex_lock(&td->lock); | 987 | mutex_lock(&td->lock); |
| 774 | 988 | ||
| 989 | cancel_delayed_work(&td->esd_work); | ||
| 990 | |||
| 991 | dsi_bus_lock(); | ||
| 992 | |||
| 775 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | 993 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) |
| 776 | taal_power_off(dssdev); | 994 | taal_power_off(dssdev); |
| 777 | 995 | ||
| 996 | dsi_bus_unlock(); | ||
| 997 | |||
| 778 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | 998 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
| 779 | 999 | ||
| 780 | mutex_unlock(&td->lock); | 1000 | mutex_unlock(&td->lock); |
| @@ -794,7 +1014,14 @@ static int taal_suspend(struct omap_dss_device *dssdev) | |||
| 794 | goto err; | 1014 | goto err; |
| 795 | } | 1015 | } |
| 796 | 1016 | ||
| 1017 | cancel_delayed_work(&td->esd_work); | ||
| 1018 | |||
| 1019 | dsi_bus_lock(); | ||
| 1020 | |||
| 797 | taal_power_off(dssdev); | 1021 | taal_power_off(dssdev); |
| 1022 | |||
| 1023 | dsi_bus_unlock(); | ||
| 1024 | |||
| 798 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | 1025 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; |
| 799 | 1026 | ||
| 800 | mutex_unlock(&td->lock); | 1027 | mutex_unlock(&td->lock); |
| @@ -808,6 +1035,7 @@ err: | |||
| 808 | static int taal_resume(struct omap_dss_device *dssdev) | 1035 | static int taal_resume(struct omap_dss_device *dssdev) |
| 809 | { | 1036 | { |
| 810 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1037 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
| 1038 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
| 811 | int r; | 1039 | int r; |
| 812 | 1040 | ||
| 813 | dev_dbg(&dssdev->dev, "resume\n"); | 1041 | dev_dbg(&dssdev->dev, "resume\n"); |
| @@ -819,8 +1047,20 @@ static int taal_resume(struct omap_dss_device *dssdev) | |||
| 819 | goto err; | 1047 | goto err; |
| 820 | } | 1048 | } |
| 821 | 1049 | ||
| 1050 | dsi_bus_lock(); | ||
| 1051 | |||
| 822 | r = taal_power_on(dssdev); | 1052 | r = taal_power_on(dssdev); |
| 823 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | 1053 | |
| 1054 | dsi_bus_unlock(); | ||
| 1055 | |||
| 1056 | if (r) { | ||
| 1057 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
| 1058 | } else { | ||
| 1059 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
| 1060 | if (panel_data->use_esd_check) | ||
| 1061 | queue_delayed_work(td->esd_wq, &td->esd_work, | ||
| 1062 | TAAL_ESD_CHECK_PERIOD); | ||
| 1063 | } | ||
| 824 | 1064 | ||
| 825 | mutex_unlock(&td->lock); | 1065 | mutex_unlock(&td->lock); |
| 826 | 1066 | ||
| @@ -837,10 +1077,52 @@ static void taal_framedone_cb(int err, void *data) | |||
| 837 | dsi_bus_unlock(); | 1077 | dsi_bus_unlock(); |
| 838 | } | 1078 | } |
| 839 | 1079 | ||
| 1080 | static irqreturn_t taal_te_isr(int irq, void *data) | ||
| 1081 | { | ||
| 1082 | struct omap_dss_device *dssdev = data; | ||
| 1083 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | ||
| 1084 | int old; | ||
| 1085 | int r; | ||
| 1086 | |||
| 1087 | old = atomic_cmpxchg(&td->do_update, 1, 0); | ||
| 1088 | |||
| 1089 | if (old) { | ||
| 1090 | cancel_delayed_work(&td->te_timeout_work); | ||
| 1091 | |||
| 1092 | r = omap_dsi_update(dssdev, TCH, | ||
| 1093 | td->update_region.x, | ||
| 1094 | td->update_region.y, | ||
| 1095 | td->update_region.w, | ||
| 1096 | td->update_region.h, | ||
| 1097 | taal_framedone_cb, dssdev); | ||
| 1098 | if (r) | ||
| 1099 | goto err; | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | return IRQ_HANDLED; | ||
| 1103 | err: | ||
| 1104 | dev_err(&dssdev->dev, "start update failed\n"); | ||
| 1105 | dsi_bus_unlock(); | ||
| 1106 | return IRQ_HANDLED; | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | static void taal_te_timeout_work_callback(struct work_struct *work) | ||
| 1110 | { | ||
| 1111 | struct taal_data *td = container_of(work, struct taal_data, | ||
| 1112 | te_timeout_work.work); | ||
| 1113 | struct omap_dss_device *dssdev = td->dssdev; | ||
| 1114 | |||
| 1115 | dev_err(&dssdev->dev, "TE not received for 250ms!\n"); | ||
| 1116 | |||
| 1117 | atomic_set(&td->do_update, 0); | ||
| 1118 | dsi_bus_unlock(); | ||
| 1119 | } | ||
| 1120 | |||
| 840 | static int taal_update(struct omap_dss_device *dssdev, | 1121 | static int taal_update(struct omap_dss_device *dssdev, |
| 841 | u16 x, u16 y, u16 w, u16 h) | 1122 | u16 x, u16 y, u16 w, u16 h) |
| 842 | { | 1123 | { |
| 843 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1124 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
| 1125 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
| 844 | int r; | 1126 | int r; |
| 845 | 1127 | ||
| 846 | dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h); | 1128 | dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h); |
| @@ -853,7 +1135,7 @@ static int taal_update(struct omap_dss_device *dssdev, | |||
| 853 | goto err; | 1135 | goto err; |
| 854 | } | 1136 | } |
| 855 | 1137 | ||
| 856 | r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h); | 1138 | r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h, true); |
| 857 | if (r) | 1139 | if (r) |
| 858 | goto err; | 1140 | goto err; |
| 859 | 1141 | ||
| @@ -861,10 +1143,21 @@ static int taal_update(struct omap_dss_device *dssdev, | |||
| 861 | if (r) | 1143 | if (r) |
| 862 | goto err; | 1144 | goto err; |
| 863 | 1145 | ||
| 864 | r = omap_dsi_update(dssdev, TCH, x, y, w, h, | 1146 | if (td->te_enabled && panel_data->use_ext_te) { |
| 865 | taal_framedone_cb, dssdev); | 1147 | td->update_region.x = x; |
| 866 | if (r) | 1148 | td->update_region.y = y; |
| 867 | goto err; | 1149 | td->update_region.w = w; |
| 1150 | td->update_region.h = h; | ||
| 1151 | barrier(); | ||
| 1152 | schedule_delayed_work(&td->te_timeout_work, | ||
| 1153 | msecs_to_jiffies(250)); | ||
| 1154 | atomic_set(&td->do_update, 1); | ||
| 1155 | } else { | ||
| 1156 | r = omap_dsi_update(dssdev, TCH, x, y, w, h, | ||
| 1157 | taal_framedone_cb, dssdev); | ||
| 1158 | if (r) | ||
| 1159 | goto err; | ||
| 1160 | } | ||
| 868 | 1161 | ||
| 869 | /* note: no bus_unlock here. unlock is in framedone_cb */ | 1162 | /* note: no bus_unlock here. unlock is in framedone_cb */ |
| 870 | mutex_unlock(&td->lock); | 1163 | mutex_unlock(&td->lock); |
| @@ -894,20 +1187,19 @@ static int taal_sync(struct omap_dss_device *dssdev) | |||
| 894 | static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) | 1187 | static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) |
| 895 | { | 1188 | { |
| 896 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1189 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
| 1190 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
| 897 | int r; | 1191 | int r; |
| 898 | 1192 | ||
| 899 | td->te_enabled = enable; | ||
| 900 | |||
| 901 | if (enable) | 1193 | if (enable) |
| 902 | r = taal_dcs_write_1(DCS_TEAR_ON, 0); | 1194 | r = taal_dcs_write_1(DCS_TEAR_ON, 0); |
| 903 | else | 1195 | else |
| 904 | r = taal_dcs_write_0(DCS_TEAR_OFF); | 1196 | r = taal_dcs_write_0(DCS_TEAR_OFF); |
| 905 | 1197 | ||
| 906 | omapdss_dsi_enable_te(dssdev, enable); | 1198 | if (!panel_data->use_ext_te) |
| 1199 | omapdss_dsi_enable_te(dssdev, enable); | ||
| 907 | 1200 | ||
| 908 | /* XXX for some reason, DSI TE breaks if we don't wait here. | 1201 | if (td->panel_config->sleep.enable_te) |
| 909 | * Panel bug? Needs more studying */ | 1202 | msleep(td->panel_config->sleep.enable_te); |
| 910 | msleep(100); | ||
| 911 | 1203 | ||
| 912 | return r; | 1204 | return r; |
| 913 | } | 1205 | } |
| @@ -918,10 +1210,26 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable) | |||
| 918 | int r; | 1210 | int r; |
| 919 | 1211 | ||
| 920 | mutex_lock(&td->lock); | 1212 | mutex_lock(&td->lock); |
| 1213 | |||
| 1214 | if (td->te_enabled == enable) | ||
| 1215 | goto end; | ||
| 1216 | |||
| 921 | dsi_bus_lock(); | 1217 | dsi_bus_lock(); |
| 922 | 1218 | ||
| 923 | r = _taal_enable_te(dssdev, enable); | 1219 | if (td->enabled) { |
| 1220 | r = _taal_enable_te(dssdev, enable); | ||
| 1221 | if (r) | ||
| 1222 | goto err; | ||
| 1223 | } | ||
| 1224 | |||
| 1225 | td->te_enabled = enable; | ||
| 1226 | |||
| 1227 | dsi_bus_unlock(); | ||
| 1228 | end: | ||
| 1229 | mutex_unlock(&td->lock); | ||
| 924 | 1230 | ||
| 1231 | return 0; | ||
| 1232 | err: | ||
| 925 | dsi_bus_unlock(); | 1233 | dsi_bus_unlock(); |
| 926 | mutex_unlock(&td->lock); | 1234 | mutex_unlock(&td->lock); |
| 927 | 1235 | ||
| @@ -948,6 +1256,10 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) | |||
| 948 | dev_dbg(&dssdev->dev, "rotate %d\n", rotate); | 1256 | dev_dbg(&dssdev->dev, "rotate %d\n", rotate); |
| 949 | 1257 | ||
| 950 | mutex_lock(&td->lock); | 1258 | mutex_lock(&td->lock); |
| 1259 | |||
| 1260 | if (td->rotate == rotate) | ||
| 1261 | goto end; | ||
| 1262 | |||
| 951 | dsi_bus_lock(); | 1263 | dsi_bus_lock(); |
| 952 | 1264 | ||
| 953 | if (td->enabled) { | 1265 | if (td->enabled) { |
| @@ -959,6 +1271,7 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) | |||
| 959 | td->rotate = rotate; | 1271 | td->rotate = rotate; |
| 960 | 1272 | ||
| 961 | dsi_bus_unlock(); | 1273 | dsi_bus_unlock(); |
| 1274 | end: | ||
| 962 | mutex_unlock(&td->lock); | 1275 | mutex_unlock(&td->lock); |
| 963 | return 0; | 1276 | return 0; |
| 964 | err: | 1277 | err: |
| @@ -987,6 +1300,10 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable) | |||
| 987 | dev_dbg(&dssdev->dev, "mirror %d\n", enable); | 1300 | dev_dbg(&dssdev->dev, "mirror %d\n", enable); |
| 988 | 1301 | ||
| 989 | mutex_lock(&td->lock); | 1302 | mutex_lock(&td->lock); |
| 1303 | |||
| 1304 | if (td->mirror == enable) | ||
| 1305 | goto end; | ||
| 1306 | |||
| 990 | dsi_bus_lock(); | 1307 | dsi_bus_lock(); |
| 991 | if (td->enabled) { | 1308 | if (td->enabled) { |
| 992 | r = taal_set_addr_mode(td->rotate, enable); | 1309 | r = taal_set_addr_mode(td->rotate, enable); |
| @@ -997,6 +1314,7 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable) | |||
| 997 | td->mirror = enable; | 1314 | td->mirror = enable; |
| 998 | 1315 | ||
| 999 | dsi_bus_unlock(); | 1316 | dsi_bus_unlock(); |
| 1317 | end: | ||
| 1000 | mutex_unlock(&td->lock); | 1318 | mutex_unlock(&td->lock); |
| 1001 | return 0; | 1319 | return 0; |
| 1002 | err: | 1320 | err: |
| @@ -1024,23 +1342,30 @@ static int taal_run_test(struct omap_dss_device *dssdev, int test_num) | |||
| 1024 | int r; | 1342 | int r; |
| 1025 | 1343 | ||
| 1026 | mutex_lock(&td->lock); | 1344 | mutex_lock(&td->lock); |
| 1345 | |||
| 1346 | if (!td->enabled) { | ||
| 1347 | r = -ENODEV; | ||
| 1348 | goto err1; | ||
| 1349 | } | ||
| 1350 | |||
| 1027 | dsi_bus_lock(); | 1351 | dsi_bus_lock(); |
| 1028 | 1352 | ||
| 1029 | r = taal_dcs_read_1(DCS_GET_ID1, &id1); | 1353 | r = taal_dcs_read_1(DCS_GET_ID1, &id1); |
| 1030 | if (r) | 1354 | if (r) |
| 1031 | goto err; | 1355 | goto err2; |
| 1032 | r = taal_dcs_read_1(DCS_GET_ID2, &id2); | 1356 | r = taal_dcs_read_1(DCS_GET_ID2, &id2); |
| 1033 | if (r) | 1357 | if (r) |
| 1034 | goto err; | 1358 | goto err2; |
| 1035 | r = taal_dcs_read_1(DCS_GET_ID3, &id3); | 1359 | r = taal_dcs_read_1(DCS_GET_ID3, &id3); |
| 1036 | if (r) | 1360 | if (r) |
| 1037 | goto err; | 1361 | goto err2; |
| 1038 | 1362 | ||
| 1039 | dsi_bus_unlock(); | 1363 | dsi_bus_unlock(); |
| 1040 | mutex_unlock(&td->lock); | 1364 | mutex_unlock(&td->lock); |
| 1041 | return 0; | 1365 | return 0; |
| 1042 | err: | 1366 | err2: |
| 1043 | dsi_bus_unlock(); | 1367 | dsi_bus_unlock(); |
| 1368 | err1: | ||
| 1044 | mutex_unlock(&td->lock); | 1369 | mutex_unlock(&td->lock); |
| 1045 | return r; | 1370 | return r; |
| 1046 | } | 1371 | } |
| @@ -1128,6 +1453,7 @@ static void taal_esd_work(struct work_struct *work) | |||
| 1128 | struct taal_data *td = container_of(work, struct taal_data, | 1453 | struct taal_data *td = container_of(work, struct taal_data, |
| 1129 | esd_work.work); | 1454 | esd_work.work); |
| 1130 | struct omap_dss_device *dssdev = td->dssdev; | 1455 | struct omap_dss_device *dssdev = td->dssdev; |
| 1456 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
| 1131 | u8 state1, state2; | 1457 | u8 state1, state2; |
| 1132 | int r; | 1458 | int r; |
| 1133 | 1459 | ||
| @@ -1168,7 +1494,7 @@ static void taal_esd_work(struct work_struct *work) | |||
| 1168 | } | 1494 | } |
| 1169 | /* Self-diagnostics result is also shown on TE GPIO line. We need | 1495 | /* Self-diagnostics result is also shown on TE GPIO line. We need |
| 1170 | * to re-enable TE after self diagnostics */ | 1496 | * to re-enable TE after self diagnostics */ |
| 1171 | if (td->use_ext_te && td->te_enabled) { | 1497 | if (td->te_enabled && panel_data->use_ext_te) { |
| 1172 | r = taal_dcs_write_1(DCS_TEAR_ON, 0); | 1498 | r = taal_dcs_write_1(DCS_TEAR_ON, 0); |
| 1173 | if (r) | 1499 | if (r) |
| 1174 | goto err; | 1500 | goto err; |
| @@ -1184,6 +1510,7 @@ err: | |||
| 1184 | dev_err(&dssdev->dev, "performing LCD reset\n"); | 1510 | dev_err(&dssdev->dev, "performing LCD reset\n"); |
| 1185 | 1511 | ||
| 1186 | taal_power_off(dssdev); | 1512 | taal_power_off(dssdev); |
| 1513 | taal_hw_reset(dssdev); | ||
| 1187 | taal_power_on(dssdev); | 1514 | taal_power_on(dssdev); |
| 1188 | 1515 | ||
| 1189 | dsi_bus_unlock(); | 1516 | dsi_bus_unlock(); |
diff --git a/drivers/video/omap2/displays/panel-toppoly-tdo35s.c b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c index fa434ca6e4b..e320e67d06f 100644 --- a/drivers/video/omap2/displays/panel-toppoly-tdo35s.c +++ b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c | |||
| @@ -73,8 +73,12 @@ static void toppoly_tdo_panel_power_off(struct omap_dss_device *dssdev) | |||
| 73 | 73 | ||
| 74 | static int toppoly_tdo_panel_probe(struct omap_dss_device *dssdev) | 74 | static int toppoly_tdo_panel_probe(struct omap_dss_device *dssdev) |
| 75 | { | 75 | { |
| 76 | dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | 76 | dssdev->panel.config = OMAP_DSS_LCD_TFT | |
| 77 | OMAP_DSS_LCD_IHS; | 77 | OMAP_DSS_LCD_IVS | |
| 78 | OMAP_DSS_LCD_IHS | | ||
| 79 | OMAP_DSS_LCD_IPC | | ||
| 80 | OMAP_DSS_LCD_ONOFF; | ||
| 81 | |||
| 78 | dssdev->panel.timings = toppoly_tdo_panel_timings; | 82 | dssdev->panel.timings = toppoly_tdo_panel_timings; |
| 79 | 83 | ||
| 80 | return 0; | 84 | return 0; |
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index e777e352dbc..5ecdc000409 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <linux/seq_file.h> | 31 | #include <linux/seq_file.h> |
| 32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
| 33 | #include <linux/workqueue.h> | 33 | #include <linux/workqueue.h> |
| 34 | #include <linux/hardirq.h> | ||
| 34 | 35 | ||
| 35 | #include <plat/sram.h> | 36 | #include <plat/sram.h> |
| 36 | #include <plat/clock.h> | 37 | #include <plat/clock.h> |
| @@ -335,7 +336,7 @@ void dispc_save_context(void) | |||
| 335 | void dispc_restore_context(void) | 336 | void dispc_restore_context(void) |
| 336 | { | 337 | { |
| 337 | RR(SYSCONFIG); | 338 | RR(SYSCONFIG); |
| 338 | RR(IRQENABLE); | 339 | /*RR(IRQENABLE);*/ |
| 339 | /*RR(CONTROL);*/ | 340 | /*RR(CONTROL);*/ |
| 340 | RR(CONFIG); | 341 | RR(CONFIG); |
| 341 | RR(DEFAULT_COLOR0); | 342 | RR(DEFAULT_COLOR0); |
| @@ -472,6 +473,15 @@ void dispc_restore_context(void) | |||
| 472 | 473 | ||
| 473 | /* enable last, because LCD & DIGIT enable are here */ | 474 | /* enable last, because LCD & DIGIT enable are here */ |
| 474 | RR(CONTROL); | 475 | RR(CONTROL); |
| 476 | |||
| 477 | /* clear spurious SYNC_LOST_DIGIT interrupts */ | ||
| 478 | dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); | ||
| 479 | |||
| 480 | /* | ||
| 481 | * enable last so IRQs won't trigger before | ||
| 482 | * the context is fully restored | ||
| 483 | */ | ||
| 484 | RR(IRQENABLE); | ||
| 475 | } | 485 | } |
| 476 | 486 | ||
| 477 | #undef SR | 487 | #undef SR |
| @@ -3019,7 +3029,7 @@ void dispc_fake_vsync_irq(void) | |||
| 3019 | u32 irqstatus = DISPC_IRQ_VSYNC; | 3029 | u32 irqstatus = DISPC_IRQ_VSYNC; |
| 3020 | int i; | 3030 | int i; |
| 3021 | 3031 | ||
| 3022 | local_irq_disable(); | 3032 | WARN_ON(!in_interrupt()); |
| 3023 | 3033 | ||
| 3024 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | 3034 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { |
| 3025 | struct omap_dispc_isr_data *isr_data; | 3035 | struct omap_dispc_isr_data *isr_data; |
| @@ -3031,8 +3041,6 @@ void dispc_fake_vsync_irq(void) | |||
| 3031 | if (isr_data->mask & irqstatus) | 3041 | if (isr_data->mask & irqstatus) |
| 3032 | isr_data->isr(isr_data->arg, irqstatus); | 3042 | isr_data->isr(isr_data->arg, irqstatus); |
| 3033 | } | 3043 | } |
| 3034 | |||
| 3035 | local_irq_enable(); | ||
| 3036 | } | 3044 | } |
| 3037 | #endif | 3045 | #endif |
| 3038 | 3046 | ||
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index ef8c8529dda..22dd7a474f7 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c | |||
| @@ -82,6 +82,9 @@ static ssize_t display_upd_mode_store(struct device *dev, | |||
| 82 | int val, r; | 82 | int val, r; |
| 83 | enum omap_dss_update_mode mode; | 83 | enum omap_dss_update_mode mode; |
| 84 | 84 | ||
| 85 | if (!dssdev->driver->set_update_mode) | ||
| 86 | return -EINVAL; | ||
| 87 | |||
| 85 | val = simple_strtoul(buf, NULL, 10); | 88 | val = simple_strtoul(buf, NULL, 10); |
| 86 | 89 | ||
| 87 | switch (val) { | 90 | switch (val) { |
| @@ -343,7 +346,6 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) | |||
| 343 | case OMAP_DISPLAY_TYPE_VENC: | 346 | case OMAP_DISPLAY_TYPE_VENC: |
| 344 | case OMAP_DISPLAY_TYPE_SDI: | 347 | case OMAP_DISPLAY_TYPE_SDI: |
| 345 | return 24; | 348 | return 24; |
| 346 | return 24; | ||
| 347 | default: | 349 | default: |
| 348 | BUG(); | 350 | BUG(); |
| 349 | } | 351 | } |
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 3af207b2bde..b3fa3a7db91 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c | |||
| @@ -165,6 +165,14 @@ struct dsi_reg { u16 idx; }; | |||
| 165 | #define DSI_CIO_IRQ_ERRCONTENTIONLP1_3 (1 << 25) | 165 | #define DSI_CIO_IRQ_ERRCONTENTIONLP1_3 (1 << 25) |
| 166 | #define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0 (1 << 30) | 166 | #define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0 (1 << 30) |
| 167 | #define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1 (1 << 31) | 167 | #define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1 (1 << 31) |
| 168 | #define DSI_CIO_IRQ_ERROR_MASK \ | ||
| 169 | (DSI_CIO_IRQ_ERRSYNCESC1 | DSI_CIO_IRQ_ERRSYNCESC2 | \ | ||
| 170 | DSI_CIO_IRQ_ERRSYNCESC3 | DSI_CIO_IRQ_ERRESC1 | DSI_CIO_IRQ_ERRESC2 | \ | ||
| 171 | DSI_CIO_IRQ_ERRESC3 | DSI_CIO_IRQ_ERRCONTROL1 | \ | ||
| 172 | DSI_CIO_IRQ_ERRCONTROL2 | DSI_CIO_IRQ_ERRCONTROL3 | \ | ||
| 173 | DSI_CIO_IRQ_ERRCONTENTIONLP0_1 | DSI_CIO_IRQ_ERRCONTENTIONLP1_1 | \ | ||
| 174 | DSI_CIO_IRQ_ERRCONTENTIONLP0_2 | DSI_CIO_IRQ_ERRCONTENTIONLP1_2 | \ | ||
| 175 | DSI_CIO_IRQ_ERRCONTENTIONLP0_3 | DSI_CIO_IRQ_ERRCONTENTIONLP1_3) | ||
| 168 | 176 | ||
| 169 | #define DSI_DT_DCS_SHORT_WRITE_0 0x05 | 177 | #define DSI_DT_DCS_SHORT_WRITE_0 0x05 |
| 170 | #define DSI_DT_DCS_SHORT_WRITE_1 0x15 | 178 | #define DSI_DT_DCS_SHORT_WRITE_1 0x15 |
| @@ -232,13 +240,15 @@ static struct | |||
| 232 | unsigned pll_locked; | 240 | unsigned pll_locked; |
| 233 | 241 | ||
| 234 | struct completion bta_completion; | 242 | struct completion bta_completion; |
| 243 | void (*bta_callback)(void); | ||
| 235 | 244 | ||
| 236 | int update_channel; | 245 | int update_channel; |
| 237 | struct dsi_update_region update_region; | 246 | struct dsi_update_region update_region; |
| 238 | 247 | ||
| 239 | bool te_enabled; | 248 | bool te_enabled; |
| 240 | 249 | ||
| 241 | struct work_struct framedone_work; | 250 | struct workqueue_struct *workqueue; |
| 251 | |||
| 242 | void (*framedone_callback)(int, void *); | 252 | void (*framedone_callback)(int, void *); |
| 243 | void *framedone_data; | 253 | void *framedone_data; |
| 244 | 254 | ||
| @@ -509,9 +519,13 @@ void dsi_irq_handler(void) | |||
| 509 | dss_collect_irq_stats(vcstatus, dsi.irq_stats.vc_irqs[i]); | 519 | dss_collect_irq_stats(vcstatus, dsi.irq_stats.vc_irqs[i]); |
| 510 | #endif | 520 | #endif |
| 511 | 521 | ||
| 512 | if (vcstatus & DSI_VC_IRQ_BTA) | 522 | if (vcstatus & DSI_VC_IRQ_BTA) { |
| 513 | complete(&dsi.bta_completion); | 523 | complete(&dsi.bta_completion); |
| 514 | 524 | ||
| 525 | if (dsi.bta_callback) | ||
| 526 | dsi.bta_callback(); | ||
| 527 | } | ||
| 528 | |||
| 515 | if (vcstatus & DSI_VC_IRQ_ERROR_MASK) { | 529 | if (vcstatus & DSI_VC_IRQ_ERROR_MASK) { |
| 516 | DSSERR("DSI VC(%d) error, vc irqstatus %x\n", | 530 | DSSERR("DSI VC(%d) error, vc irqstatus %x\n", |
| 517 | i, vcstatus); | 531 | i, vcstatus); |
| @@ -536,8 +550,12 @@ void dsi_irq_handler(void) | |||
| 536 | /* flush posted write */ | 550 | /* flush posted write */ |
| 537 | dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS); | 551 | dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS); |
| 538 | 552 | ||
| 539 | DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus); | 553 | if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) { |
| 540 | print_irq_status_cio(ciostatus); | 554 | DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus); |
| 555 | print_irq_status_cio(ciostatus); | ||
| 556 | } else if (debug_irq) { | ||
| 557 | print_irq_status_cio(ciostatus); | ||
| 558 | } | ||
| 541 | } | 559 | } |
| 542 | 560 | ||
| 543 | dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK); | 561 | dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK); |
| @@ -584,11 +602,8 @@ static void _dsi_initialize_irq(void) | |||
| 584 | for (i = 0; i < 4; ++i) | 602 | for (i = 0; i < 4; ++i) |
| 585 | dsi_write_reg(DSI_VC_IRQENABLE(i), l); | 603 | dsi_write_reg(DSI_VC_IRQENABLE(i), l); |
| 586 | 604 | ||
| 587 | /* XXX zonda responds incorrectly, causing control error: | 605 | l = DSI_CIO_IRQ_ERROR_MASK; |
| 588 | Exit from LP-ESC mode to LP11 uses wrong transition states on the | 606 | dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, l); |
| 589 | data lines LP0 and LN0. */ | ||
| 590 | dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, | ||
| 591 | -1 & (~DSI_CIO_IRQ_ERRCONTROL2)); | ||
| 592 | } | 607 | } |
| 593 | 608 | ||
| 594 | static u32 dsi_get_errors(void) | 609 | static u32 dsi_get_errors(void) |
| @@ -1098,6 +1113,7 @@ int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk, | |||
| 1098 | if (wait_for_bit_change(DSI_PLL_STATUS, 0, 1) != 1) { | 1113 | if (wait_for_bit_change(DSI_PLL_STATUS, 0, 1) != 1) { |
| 1099 | DSSERR("PLL not coming out of reset.\n"); | 1114 | DSSERR("PLL not coming out of reset.\n"); |
| 1100 | r = -ENODEV; | 1115 | r = -ENODEV; |
| 1116 | dispc_pck_free_enable(0); | ||
| 1101 | goto err1; | 1117 | goto err1; |
| 1102 | } | 1118 | } |
| 1103 | 1119 | ||
| @@ -1740,42 +1756,52 @@ static void dsi_vc_initial_config(int channel) | |||
| 1740 | dsi.vc[channel].mode = DSI_VC_MODE_L4; | 1756 | dsi.vc[channel].mode = DSI_VC_MODE_L4; |
| 1741 | } | 1757 | } |
| 1742 | 1758 | ||
| 1743 | static void dsi_vc_config_l4(int channel) | 1759 | static int dsi_vc_config_l4(int channel) |
| 1744 | { | 1760 | { |
| 1745 | if (dsi.vc[channel].mode == DSI_VC_MODE_L4) | 1761 | if (dsi.vc[channel].mode == DSI_VC_MODE_L4) |
| 1746 | return; | 1762 | return 0; |
| 1747 | 1763 | ||
| 1748 | DSSDBGF("%d", channel); | 1764 | DSSDBGF("%d", channel); |
| 1749 | 1765 | ||
| 1750 | dsi_vc_enable(channel, 0); | 1766 | dsi_vc_enable(channel, 0); |
| 1751 | 1767 | ||
| 1752 | if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */ | 1768 | /* VC_BUSY */ |
| 1769 | if (wait_for_bit_change(DSI_VC_CTRL(channel), 15, 0) != 0) { | ||
| 1753 | DSSERR("vc(%d) busy when trying to config for L4\n", channel); | 1770 | DSSERR("vc(%d) busy when trying to config for L4\n", channel); |
| 1771 | return -EIO; | ||
| 1772 | } | ||
| 1754 | 1773 | ||
| 1755 | REG_FLD_MOD(DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */ | 1774 | REG_FLD_MOD(DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */ |
| 1756 | 1775 | ||
| 1757 | dsi_vc_enable(channel, 1); | 1776 | dsi_vc_enable(channel, 1); |
| 1758 | 1777 | ||
| 1759 | dsi.vc[channel].mode = DSI_VC_MODE_L4; | 1778 | dsi.vc[channel].mode = DSI_VC_MODE_L4; |
| 1779 | |||
| 1780 | return 0; | ||
| 1760 | } | 1781 | } |
| 1761 | 1782 | ||
| 1762 | static void dsi_vc_config_vp(int channel) | 1783 | static int dsi_vc_config_vp(int channel) |
| 1763 | { | 1784 | { |
| 1764 | if (dsi.vc[channel].mode == DSI_VC_MODE_VP) | 1785 | if (dsi.vc[channel].mode == DSI_VC_MODE_VP) |
| 1765 | return; | 1786 | return 0; |
| 1766 | 1787 | ||
| 1767 | DSSDBGF("%d", channel); | 1788 | DSSDBGF("%d", channel); |
| 1768 | 1789 | ||
| 1769 | dsi_vc_enable(channel, 0); | 1790 | dsi_vc_enable(channel, 0); |
| 1770 | 1791 | ||
| 1771 | if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */ | 1792 | /* VC_BUSY */ |
| 1793 | if (wait_for_bit_change(DSI_VC_CTRL(channel), 15, 0) != 0) { | ||
| 1772 | DSSERR("vc(%d) busy when trying to config for VP\n", channel); | 1794 | DSSERR("vc(%d) busy when trying to config for VP\n", channel); |
| 1795 | return -EIO; | ||
| 1796 | } | ||
| 1773 | 1797 | ||
| 1774 | REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 1, 1); /* SOURCE, 1 = video port */ | 1798 | REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 1, 1); /* SOURCE, 1 = video port */ |
| 1775 | 1799 | ||
| 1776 | dsi_vc_enable(channel, 1); | 1800 | dsi_vc_enable(channel, 1); |
| 1777 | 1801 | ||
| 1778 | dsi.vc[channel].mode = DSI_VC_MODE_VP; | 1802 | dsi.vc[channel].mode = DSI_VC_MODE_VP; |
| 1803 | |||
| 1804 | return 0; | ||
| 1779 | } | 1805 | } |
| 1780 | 1806 | ||
| 1781 | 1807 | ||
| @@ -1854,19 +1880,19 @@ static u16 dsi_vc_flush_receive_data(int channel) | |||
| 1854 | u32 val; | 1880 | u32 val; |
| 1855 | u8 dt; | 1881 | u8 dt; |
| 1856 | val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel)); | 1882 | val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel)); |
| 1857 | DSSDBG("\trawval %#08x\n", val); | 1883 | DSSERR("\trawval %#08x\n", val); |
| 1858 | dt = FLD_GET(val, 5, 0); | 1884 | dt = FLD_GET(val, 5, 0); |
| 1859 | if (dt == DSI_DT_RX_ACK_WITH_ERR) { | 1885 | if (dt == DSI_DT_RX_ACK_WITH_ERR) { |
| 1860 | u16 err = FLD_GET(val, 23, 8); | 1886 | u16 err = FLD_GET(val, 23, 8); |
| 1861 | dsi_show_rx_ack_with_err(err); | 1887 | dsi_show_rx_ack_with_err(err); |
| 1862 | } else if (dt == DSI_DT_RX_SHORT_READ_1) { | 1888 | } else if (dt == DSI_DT_RX_SHORT_READ_1) { |
| 1863 | DSSDBG("\tDCS short response, 1 byte: %#x\n", | 1889 | DSSERR("\tDCS short response, 1 byte: %#x\n", |
| 1864 | FLD_GET(val, 23, 8)); | 1890 | FLD_GET(val, 23, 8)); |
| 1865 | } else if (dt == DSI_DT_RX_SHORT_READ_2) { | 1891 | } else if (dt == DSI_DT_RX_SHORT_READ_2) { |
| 1866 | DSSDBG("\tDCS short response, 2 byte: %#x\n", | 1892 | DSSERR("\tDCS short response, 2 byte: %#x\n", |
| 1867 | FLD_GET(val, 23, 8)); | 1893 | FLD_GET(val, 23, 8)); |
| 1868 | } else if (dt == DSI_DT_RX_DCS_LONG_READ) { | 1894 | } else if (dt == DSI_DT_RX_DCS_LONG_READ) { |
| 1869 | DSSDBG("\tDCS long response, len %d\n", | 1895 | DSSERR("\tDCS long response, len %d\n", |
| 1870 | FLD_GET(val, 23, 8)); | 1896 | FLD_GET(val, 23, 8)); |
| 1871 | dsi_vc_flush_long_data(channel); | 1897 | dsi_vc_flush_long_data(channel); |
| 1872 | } else { | 1898 | } else { |
| @@ -2087,6 +2113,13 @@ int dsi_vc_dcs_write(int channel, u8 *data, int len) | |||
| 2087 | if (r) | 2113 | if (r) |
| 2088 | goto err; | 2114 | goto err; |
| 2089 | 2115 | ||
| 2116 | if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { /* RX_FIFO_NOT_EMPTY */ | ||
| 2117 | DSSERR("rx fifo not empty after write, dumping data:\n"); | ||
| 2118 | dsi_vc_flush_receive_data(channel); | ||
| 2119 | r = -EIO; | ||
| 2120 | goto err; | ||
| 2121 | } | ||
| 2122 | |||
| 2090 | return 0; | 2123 | return 0; |
| 2091 | err: | 2124 | err: |
| 2092 | DSSERR("dsi_vc_dcs_write(ch %d, cmd 0x%02x, len %d) failed\n", | 2125 | DSSERR("dsi_vc_dcs_write(ch %d, cmd 0x%02x, len %d) failed\n", |
| @@ -2233,11 +2266,12 @@ int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data) | |||
| 2233 | } | 2266 | } |
| 2234 | EXPORT_SYMBOL(dsi_vc_dcs_read_1); | 2267 | EXPORT_SYMBOL(dsi_vc_dcs_read_1); |
| 2235 | 2268 | ||
| 2236 | int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data) | 2269 | int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u8 *data1, u8 *data2) |
| 2237 | { | 2270 | { |
| 2271 | u8 buf[2]; | ||
| 2238 | int r; | 2272 | int r; |
| 2239 | 2273 | ||
| 2240 | r = dsi_vc_dcs_read(channel, dcs_cmd, (u8 *)data, 2); | 2274 | r = dsi_vc_dcs_read(channel, dcs_cmd, buf, 2); |
| 2241 | 2275 | ||
| 2242 | if (r < 0) | 2276 | if (r < 0) |
| 2243 | return r; | 2277 | return r; |
| @@ -2245,231 +2279,122 @@ int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data) | |||
| 2245 | if (r != 2) | 2279 | if (r != 2) |
| 2246 | return -EIO; | 2280 | return -EIO; |
| 2247 | 2281 | ||
| 2282 | *data1 = buf[0]; | ||
| 2283 | *data2 = buf[1]; | ||
| 2284 | |||
| 2248 | return 0; | 2285 | return 0; |
| 2249 | } | 2286 | } |
| 2250 | EXPORT_SYMBOL(dsi_vc_dcs_read_2); | 2287 | EXPORT_SYMBOL(dsi_vc_dcs_read_2); |
| 2251 | 2288 | ||
| 2252 | int dsi_vc_set_max_rx_packet_size(int channel, u16 len) | 2289 | int dsi_vc_set_max_rx_packet_size(int channel, u16 len) |
| 2253 | { | 2290 | { |
| 2254 | int r; | 2291 | return dsi_vc_send_short(channel, DSI_DT_SET_MAX_RET_PKG_SIZE, |
| 2255 | r = dsi_vc_send_short(channel, DSI_DT_SET_MAX_RET_PKG_SIZE, | ||
| 2256 | len, 0); | 2292 | len, 0); |
| 2257 | |||
| 2258 | if (r) | ||
| 2259 | return r; | ||
| 2260 | |||
| 2261 | r = dsi_vc_send_bta_sync(channel); | ||
| 2262 | |||
| 2263 | return r; | ||
| 2264 | } | 2293 | } |
| 2265 | EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size); | 2294 | EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size); |
| 2266 | 2295 | ||
| 2267 | static void dsi_set_lp_rx_timeout(unsigned long ns) | 2296 | static void dsi_set_lp_rx_timeout(unsigned ticks, bool x4, bool x16) |
| 2268 | { | 2297 | { |
| 2269 | u32 r; | ||
| 2270 | unsigned x4, x16; | ||
| 2271 | unsigned long fck; | 2298 | unsigned long fck; |
| 2272 | unsigned long ticks; | 2299 | unsigned long total_ticks; |
| 2300 | u32 r; | ||
| 2273 | 2301 | ||
| 2274 | /* ticks in DSI_FCK */ | 2302 | BUG_ON(ticks > 0x1fff); |
| 2275 | 2303 | ||
| 2304 | /* ticks in DSI_FCK */ | ||
| 2276 | fck = dsi_fclk_rate(); | 2305 | fck = dsi_fclk_rate(); |
| 2277 | ticks = (fck / 1000 / 1000) * ns / 1000; | ||
| 2278 | x4 = 0; | ||
| 2279 | x16 = 0; | ||
| 2280 | |||
| 2281 | if (ticks > 0x1fff) { | ||
| 2282 | ticks = (fck / 1000 / 1000) * ns / 1000 / 4; | ||
| 2283 | x4 = 1; | ||
| 2284 | x16 = 0; | ||
| 2285 | } | ||
| 2286 | |||
| 2287 | if (ticks > 0x1fff) { | ||
| 2288 | ticks = (fck / 1000 / 1000) * ns / 1000 / 16; | ||
| 2289 | x4 = 0; | ||
| 2290 | x16 = 1; | ||
| 2291 | } | ||
| 2292 | |||
| 2293 | if (ticks > 0x1fff) { | ||
| 2294 | ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16); | ||
| 2295 | x4 = 1; | ||
| 2296 | x16 = 1; | ||
| 2297 | } | ||
| 2298 | |||
| 2299 | if (ticks > 0x1fff) { | ||
| 2300 | DSSWARN("LP_TX_TO over limit, setting it to max\n"); | ||
| 2301 | ticks = 0x1fff; | ||
| 2302 | x4 = 1; | ||
| 2303 | x16 = 1; | ||
| 2304 | } | ||
| 2305 | 2306 | ||
| 2306 | r = dsi_read_reg(DSI_TIMING2); | 2307 | r = dsi_read_reg(DSI_TIMING2); |
| 2307 | r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */ | 2308 | r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */ |
| 2308 | r = FLD_MOD(r, x16, 14, 14); /* LP_RX_TO_X16 */ | 2309 | r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* LP_RX_TO_X16 */ |
| 2309 | r = FLD_MOD(r, x4, 13, 13); /* LP_RX_TO_X4 */ | 2310 | r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* LP_RX_TO_X4 */ |
| 2310 | r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */ | 2311 | r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */ |
| 2311 | dsi_write_reg(DSI_TIMING2, r); | 2312 | dsi_write_reg(DSI_TIMING2, r); |
| 2312 | 2313 | ||
| 2313 | DSSDBG("LP_RX_TO %lu ns (%#lx ticks%s%s)\n", | 2314 | total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1); |
| 2314 | (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) / | 2315 | |
| 2315 | (fck / 1000 / 1000), | 2316 | DSSDBG("LP_RX_TO %lu ticks (%#x%s%s) = %lu ns\n", |
| 2316 | ticks, x4 ? " x4" : "", x16 ? " x16" : ""); | 2317 | total_ticks, |
| 2318 | ticks, x4 ? " x4" : "", x16 ? " x16" : "", | ||
| 2319 | (total_ticks * 1000) / (fck / 1000 / 1000)); | ||
| 2317 | } | 2320 | } |
| 2318 | 2321 | ||
| 2319 | static void dsi_set_ta_timeout(unsigned long ns) | 2322 | static void dsi_set_ta_timeout(unsigned ticks, bool x8, bool x16) |
| 2320 | { | 2323 | { |
| 2321 | u32 r; | ||
| 2322 | unsigned x8, x16; | ||
| 2323 | unsigned long fck; | 2324 | unsigned long fck; |
| 2324 | unsigned long ticks; | 2325 | unsigned long total_ticks; |
| 2326 | u32 r; | ||
| 2327 | |||
| 2328 | BUG_ON(ticks > 0x1fff); | ||
| 2325 | 2329 | ||
| 2326 | /* ticks in DSI_FCK */ | 2330 | /* ticks in DSI_FCK */ |
| 2327 | fck = dsi_fclk_rate(); | 2331 | fck = dsi_fclk_rate(); |
| 2328 | ticks = (fck / 1000 / 1000) * ns / 1000; | ||
| 2329 | x8 = 0; | ||
| 2330 | x16 = 0; | ||
| 2331 | |||
| 2332 | if (ticks > 0x1fff) { | ||
| 2333 | ticks = (fck / 1000 / 1000) * ns / 1000 / 8; | ||
| 2334 | x8 = 1; | ||
| 2335 | x16 = 0; | ||
| 2336 | } | ||
| 2337 | |||
| 2338 | if (ticks > 0x1fff) { | ||
| 2339 | ticks = (fck / 1000 / 1000) * ns / 1000 / 16; | ||
| 2340 | x8 = 0; | ||
| 2341 | x16 = 1; | ||
| 2342 | } | ||
| 2343 | |||
| 2344 | if (ticks > 0x1fff) { | ||
| 2345 | ticks = (fck / 1000 / 1000) * ns / 1000 / (8 * 16); | ||
| 2346 | x8 = 1; | ||
| 2347 | x16 = 1; | ||
| 2348 | } | ||
| 2349 | |||
| 2350 | if (ticks > 0x1fff) { | ||
| 2351 | DSSWARN("TA_TO over limit, setting it to max\n"); | ||
| 2352 | ticks = 0x1fff; | ||
| 2353 | x8 = 1; | ||
| 2354 | x16 = 1; | ||
| 2355 | } | ||
| 2356 | 2332 | ||
| 2357 | r = dsi_read_reg(DSI_TIMING1); | 2333 | r = dsi_read_reg(DSI_TIMING1); |
| 2358 | r = FLD_MOD(r, 1, 31, 31); /* TA_TO */ | 2334 | r = FLD_MOD(r, 1, 31, 31); /* TA_TO */ |
| 2359 | r = FLD_MOD(r, x16, 30, 30); /* TA_TO_X16 */ | 2335 | r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* TA_TO_X16 */ |
| 2360 | r = FLD_MOD(r, x8, 29, 29); /* TA_TO_X8 */ | 2336 | r = FLD_MOD(r, x8 ? 1 : 0, 29, 29); /* TA_TO_X8 */ |
| 2361 | r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */ | 2337 | r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */ |
| 2362 | dsi_write_reg(DSI_TIMING1, r); | 2338 | dsi_write_reg(DSI_TIMING1, r); |
| 2363 | 2339 | ||
| 2364 | DSSDBG("TA_TO %lu ns (%#lx ticks%s%s)\n", | 2340 | total_ticks = ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1); |
| 2365 | (ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1) * 1000) / | 2341 | |
| 2366 | (fck / 1000 / 1000), | 2342 | DSSDBG("TA_TO %lu ticks (%#x%s%s) = %lu ns\n", |
| 2367 | ticks, x8 ? " x8" : "", x16 ? " x16" : ""); | 2343 | total_ticks, |
| 2344 | ticks, x8 ? " x8" : "", x16 ? " x16" : "", | ||
| 2345 | (total_ticks * 1000) / (fck / 1000 / 1000)); | ||
| 2368 | } | 2346 | } |
| 2369 | 2347 | ||
| 2370 | static void dsi_set_stop_state_counter(unsigned long ns) | 2348 | static void dsi_set_stop_state_counter(unsigned ticks, bool x4, bool x16) |
| 2371 | { | 2349 | { |
| 2372 | u32 r; | ||
| 2373 | unsigned x4, x16; | ||
| 2374 | unsigned long fck; | 2350 | unsigned long fck; |
| 2375 | unsigned long ticks; | 2351 | unsigned long total_ticks; |
| 2352 | u32 r; | ||
| 2376 | 2353 | ||
| 2377 | /* ticks in DSI_FCK */ | 2354 | BUG_ON(ticks > 0x1fff); |
| 2378 | 2355 | ||
| 2356 | /* ticks in DSI_FCK */ | ||
| 2379 | fck = dsi_fclk_rate(); | 2357 | fck = dsi_fclk_rate(); |
| 2380 | ticks = (fck / 1000 / 1000) * ns / 1000; | ||
| 2381 | x4 = 0; | ||
| 2382 | x16 = 0; | ||
| 2383 | |||
| 2384 | if (ticks > 0x1fff) { | ||
| 2385 | ticks = (fck / 1000 / 1000) * ns / 1000 / 4; | ||
| 2386 | x4 = 1; | ||
| 2387 | x16 = 0; | ||
| 2388 | } | ||
| 2389 | |||
| 2390 | if (ticks > 0x1fff) { | ||
| 2391 | ticks = (fck / 1000 / 1000) * ns / 1000 / 16; | ||
| 2392 | x4 = 0; | ||
| 2393 | x16 = 1; | ||
| 2394 | } | ||
| 2395 | |||
| 2396 | if (ticks > 0x1fff) { | ||
| 2397 | ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16); | ||
| 2398 | x4 = 1; | ||
| 2399 | x16 = 1; | ||
| 2400 | } | ||
| 2401 | |||
| 2402 | if (ticks > 0x1fff) { | ||
| 2403 | DSSWARN("STOP_STATE_COUNTER_IO over limit, " | ||
| 2404 | "setting it to max\n"); | ||
| 2405 | ticks = 0x1fff; | ||
| 2406 | x4 = 1; | ||
| 2407 | x16 = 1; | ||
| 2408 | } | ||
| 2409 | 2358 | ||
| 2410 | r = dsi_read_reg(DSI_TIMING1); | 2359 | r = dsi_read_reg(DSI_TIMING1); |
| 2411 | r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */ | 2360 | r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */ |
| 2412 | r = FLD_MOD(r, x16, 14, 14); /* STOP_STATE_X16_IO */ | 2361 | r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* STOP_STATE_X16_IO */ |
| 2413 | r = FLD_MOD(r, x4, 13, 13); /* STOP_STATE_X4_IO */ | 2362 | r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* STOP_STATE_X4_IO */ |
| 2414 | r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */ | 2363 | r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */ |
| 2415 | dsi_write_reg(DSI_TIMING1, r); | 2364 | dsi_write_reg(DSI_TIMING1, r); |
| 2416 | 2365 | ||
| 2417 | DSSDBG("STOP_STATE_COUNTER %lu ns (%#lx ticks%s%s)\n", | 2366 | total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1); |
| 2418 | (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) / | 2367 | |
| 2419 | (fck / 1000 / 1000), | 2368 | DSSDBG("STOP_STATE_COUNTER %lu ticks (%#x%s%s) = %lu ns\n", |
| 2420 | ticks, x4 ? " x4" : "", x16 ? " x16" : ""); | 2369 | total_ticks, |
| 2370 | ticks, x4 ? " x4" : "", x16 ? " x16" : "", | ||
| 2371 | (total_ticks * 1000) / (fck / 1000 / 1000)); | ||
| 2421 | } | 2372 | } |
| 2422 | 2373 | ||
| 2423 | static void dsi_set_hs_tx_timeout(unsigned long ns) | 2374 | static void dsi_set_hs_tx_timeout(unsigned ticks, bool x4, bool x16) |
| 2424 | { | 2375 | { |
| 2425 | u32 r; | ||
| 2426 | unsigned x4, x16; | ||
| 2427 | unsigned long fck; | 2376 | unsigned long fck; |
| 2428 | unsigned long ticks; | 2377 | unsigned long total_ticks; |
| 2378 | u32 r; | ||
| 2429 | 2379 | ||
| 2430 | /* ticks in TxByteClkHS */ | 2380 | BUG_ON(ticks > 0x1fff); |
| 2431 | 2381 | ||
| 2382 | /* ticks in TxByteClkHS */ | ||
| 2432 | fck = dsi_get_txbyteclkhs(); | 2383 | fck = dsi_get_txbyteclkhs(); |
| 2433 | ticks = (fck / 1000 / 1000) * ns / 1000; | ||
| 2434 | x4 = 0; | ||
| 2435 | x16 = 0; | ||
| 2436 | |||
| 2437 | if (ticks > 0x1fff) { | ||
| 2438 | ticks = (fck / 1000 / 1000) * ns / 1000 / 4; | ||
| 2439 | x4 = 1; | ||
| 2440 | x16 = 0; | ||
| 2441 | } | ||
| 2442 | |||
| 2443 | if (ticks > 0x1fff) { | ||
| 2444 | ticks = (fck / 1000 / 1000) * ns / 1000 / 16; | ||
| 2445 | x4 = 0; | ||
| 2446 | x16 = 1; | ||
| 2447 | } | ||
| 2448 | |||
| 2449 | if (ticks > 0x1fff) { | ||
| 2450 | ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16); | ||
| 2451 | x4 = 1; | ||
| 2452 | x16 = 1; | ||
| 2453 | } | ||
| 2454 | |||
| 2455 | if (ticks > 0x1fff) { | ||
| 2456 | DSSWARN("HS_TX_TO over limit, setting it to max\n"); | ||
| 2457 | ticks = 0x1fff; | ||
| 2458 | x4 = 1; | ||
| 2459 | x16 = 1; | ||
| 2460 | } | ||
| 2461 | 2384 | ||
| 2462 | r = dsi_read_reg(DSI_TIMING2); | 2385 | r = dsi_read_reg(DSI_TIMING2); |
| 2463 | r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */ | 2386 | r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */ |
| 2464 | r = FLD_MOD(r, x16, 30, 30); /* HS_TX_TO_X16 */ | 2387 | r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* HS_TX_TO_X16 */ |
| 2465 | r = FLD_MOD(r, x4, 29, 29); /* HS_TX_TO_X8 (4 really) */ | 2388 | r = FLD_MOD(r, x4 ? 1 : 0, 29, 29); /* HS_TX_TO_X8 (4 really) */ |
| 2466 | r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */ | 2389 | r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */ |
| 2467 | dsi_write_reg(DSI_TIMING2, r); | 2390 | dsi_write_reg(DSI_TIMING2, r); |
| 2468 | 2391 | ||
| 2469 | DSSDBG("HS_TX_TO %lu ns (%#lx ticks%s%s)\n", | 2392 | total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1); |
| 2470 | (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) / | 2393 | |
| 2471 | (fck / 1000 / 1000), | 2394 | DSSDBG("HS_TX_TO %lu ticks (%#x%s%s) = %lu ns\n", |
| 2472 | ticks, x4 ? " x4" : "", x16 ? " x16" : ""); | 2395 | total_ticks, |
| 2396 | ticks, x4 ? " x4" : "", x16 ? " x16" : "", | ||
| 2397 | (total_ticks * 1000) / (fck / 1000 / 1000)); | ||
| 2473 | } | 2398 | } |
| 2474 | static int dsi_proto_config(struct omap_dss_device *dssdev) | 2399 | static int dsi_proto_config(struct omap_dss_device *dssdev) |
| 2475 | { | 2400 | { |
| @@ -2487,10 +2412,10 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) | |||
| 2487 | DSI_FIFO_SIZE_32); | 2412 | DSI_FIFO_SIZE_32); |
| 2488 | 2413 | ||
| 2489 | /* XXX what values for the timeouts? */ | 2414 | /* XXX what values for the timeouts? */ |
| 2490 | dsi_set_stop_state_counter(1000); | 2415 | dsi_set_stop_state_counter(0x1000, false, false); |
| 2491 | dsi_set_ta_timeout(6400000); | 2416 | dsi_set_ta_timeout(0x1fff, true, true); |
| 2492 | dsi_set_lp_rx_timeout(48000); | 2417 | dsi_set_lp_rx_timeout(0x1fff, true, true); |
| 2493 | dsi_set_hs_tx_timeout(1000000); | 2418 | dsi_set_hs_tx_timeout(0x1fff, true, true); |
| 2494 | 2419 | ||
| 2495 | switch (dssdev->ctrl.pixel_size) { | 2420 | switch (dssdev->ctrl.pixel_size) { |
| 2496 | case 16: | 2421 | case 16: |
| @@ -2759,6 +2684,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, | |||
| 2759 | unsigned packet_payload; | 2684 | unsigned packet_payload; |
| 2760 | unsigned packet_len; | 2685 | unsigned packet_len; |
| 2761 | u32 l; | 2686 | u32 l; |
| 2687 | int r; | ||
| 2762 | const unsigned channel = dsi.update_channel; | 2688 | const unsigned channel = dsi.update_channel; |
| 2763 | /* line buffer is 1024 x 24bits */ | 2689 | /* line buffer is 1024 x 24bits */ |
| 2764 | /* XXX: for some reason using full buffer size causes considerable TX | 2690 | /* XXX: for some reason using full buffer size causes considerable TX |
| @@ -2809,8 +2735,9 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, | |||
| 2809 | 2735 | ||
| 2810 | dsi_perf_mark_start(); | 2736 | dsi_perf_mark_start(); |
| 2811 | 2737 | ||
| 2812 | schedule_delayed_work(&dsi.framedone_timeout_work, | 2738 | r = queue_delayed_work(dsi.workqueue, &dsi.framedone_timeout_work, |
| 2813 | msecs_to_jiffies(250)); | 2739 | msecs_to_jiffies(250)); |
| 2740 | BUG_ON(r == 0); | ||
| 2814 | 2741 | ||
| 2815 | dss_start_update(dssdev); | 2742 | dss_start_update(dssdev); |
| 2816 | 2743 | ||
| @@ -2834,62 +2761,70 @@ static void dsi_te_timeout(unsigned long arg) | |||
| 2834 | } | 2761 | } |
| 2835 | #endif | 2762 | #endif |
| 2836 | 2763 | ||
| 2837 | static void dsi_framedone_timeout_work_callback(struct work_struct *work) | 2764 | static void dsi_handle_framedone(int error) |
| 2838 | { | 2765 | { |
| 2839 | int r; | ||
| 2840 | const int channel = dsi.update_channel; | 2766 | const int channel = dsi.update_channel; |
| 2841 | 2767 | ||
| 2842 | DSSERR("Framedone not received for 250ms!\n"); | 2768 | cancel_delayed_work(&dsi.framedone_timeout_work); |
| 2769 | |||
| 2770 | dsi_vc_disable_bta_irq(channel); | ||
| 2843 | 2771 | ||
| 2844 | /* SIDLEMODE back to smart-idle */ | 2772 | /* SIDLEMODE back to smart-idle */ |
| 2845 | dispc_enable_sidle(); | 2773 | dispc_enable_sidle(); |
| 2846 | 2774 | ||
| 2775 | dsi.bta_callback = NULL; | ||
| 2776 | |||
| 2847 | if (dsi.te_enabled) { | 2777 | if (dsi.te_enabled) { |
| 2848 | /* enable LP_RX_TO again after the TE */ | 2778 | /* enable LP_RX_TO again after the TE */ |
| 2849 | REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */ | 2779 | REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */ |
| 2850 | } | 2780 | } |
| 2851 | 2781 | ||
| 2852 | /* Send BTA after the frame. We need this for the TE to work, as TE | ||
| 2853 | * trigger is only sent for BTAs without preceding packet. Thus we need | ||
| 2854 | * to BTA after the pixel packets so that next BTA will cause TE | ||
| 2855 | * trigger. | ||
| 2856 | * | ||
| 2857 | * This is not needed when TE is not in use, but we do it anyway to | ||
| 2858 | * make sure that the transfer has been completed. It would be more | ||
| 2859 | * optimal, but more complex, to wait only just before starting next | ||
| 2860 | * transfer. */ | ||
| 2861 | r = dsi_vc_send_bta_sync(channel); | ||
| 2862 | if (r) | ||
| 2863 | DSSERR("BTA after framedone failed\n"); | ||
| 2864 | |||
| 2865 | /* RX_FIFO_NOT_EMPTY */ | 2782 | /* RX_FIFO_NOT_EMPTY */ |
| 2866 | if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { | 2783 | if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { |
| 2867 | DSSERR("Received error during frame transfer:\n"); | 2784 | DSSERR("Received error during frame transfer:\n"); |
| 2868 | dsi_vc_flush_receive_data(channel); | 2785 | dsi_vc_flush_receive_data(channel); |
| 2786 | if (!error) | ||
| 2787 | error = -EIO; | ||
| 2869 | } | 2788 | } |
| 2870 | 2789 | ||
| 2871 | dsi.framedone_callback(-ETIMEDOUT, dsi.framedone_data); | 2790 | dsi.framedone_callback(error, dsi.framedone_data); |
| 2791 | |||
| 2792 | if (!error) | ||
| 2793 | dsi_perf_show("DISPC"); | ||
| 2872 | } | 2794 | } |
| 2873 | 2795 | ||
| 2874 | static void dsi_framedone_irq_callback(void *data, u32 mask) | 2796 | static void dsi_framedone_timeout_work_callback(struct work_struct *work) |
| 2875 | { | 2797 | { |
| 2876 | /* Note: We get FRAMEDONE when DISPC has finished sending pixels and | 2798 | /* XXX While extremely unlikely, we could get FRAMEDONE interrupt after |
| 2877 | * turns itself off. However, DSI still has the pixels in its buffers, | 2799 | * 250ms which would conflict with this timeout work. What should be |
| 2878 | * and is sending the data. | 2800 | * done is first cancel the transfer on the HW, and then cancel the |
| 2879 | */ | 2801 | * possibly scheduled framedone work. However, cancelling the transfer |
| 2802 | * on the HW is buggy, and would probably require resetting the whole | ||
| 2803 | * DSI */ | ||
| 2880 | 2804 | ||
| 2881 | /* SIDLEMODE back to smart-idle */ | 2805 | DSSERR("Framedone not received for 250ms!\n"); |
| 2882 | dispc_enable_sidle(); | ||
| 2883 | 2806 | ||
| 2884 | schedule_work(&dsi.framedone_work); | 2807 | dsi_handle_framedone(-ETIMEDOUT); |
| 2885 | } | 2808 | } |
| 2886 | 2809 | ||
| 2887 | static void dsi_handle_framedone(void) | 2810 | static void dsi_framedone_bta_callback(void) |
| 2811 | { | ||
| 2812 | dsi_handle_framedone(0); | ||
| 2813 | |||
| 2814 | #ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC | ||
| 2815 | dispc_fake_vsync_irq(); | ||
| 2816 | #endif | ||
| 2817 | } | ||
| 2818 | |||
| 2819 | static void dsi_framedone_irq_callback(void *data, u32 mask) | ||
| 2888 | { | 2820 | { |
| 2889 | int r; | ||
| 2890 | const int channel = dsi.update_channel; | 2821 | const int channel = dsi.update_channel; |
| 2822 | int r; | ||
| 2891 | 2823 | ||
| 2892 | DSSDBG("FRAMEDONE\n"); | 2824 | /* Note: We get FRAMEDONE when DISPC has finished sending pixels and |
| 2825 | * turns itself off. However, DSI still has the pixels in its buffers, | ||
| 2826 | * and is sending the data. | ||
| 2827 | */ | ||
| 2893 | 2828 | ||
| 2894 | if (dsi.te_enabled) { | 2829 | if (dsi.te_enabled) { |
| 2895 | /* enable LP_RX_TO again after the TE */ | 2830 | /* enable LP_RX_TO again after the TE */ |
| @@ -2904,37 +2839,30 @@ static void dsi_handle_framedone(void) | |||
| 2904 | * This is not needed when TE is not in use, but we do it anyway to | 2839 | * This is not needed when TE is not in use, but we do it anyway to |
| 2905 | * make sure that the transfer has been completed. It would be more | 2840 | * make sure that the transfer has been completed. It would be more |
| 2906 | * optimal, but more complex, to wait only just before starting next | 2841 | * optimal, but more complex, to wait only just before starting next |
| 2907 | * transfer. */ | 2842 | * transfer. |
| 2908 | r = dsi_vc_send_bta_sync(channel); | 2843 | * |
| 2909 | if (r) | 2844 | * Also, as there's no interrupt telling when the transfer has been |
| 2910 | DSSERR("BTA after framedone failed\n"); | 2845 | * done and the channel could be reconfigured, the only way is to |
| 2911 | 2846 | * busyloop until TE_SIZE is zero. With BTA we can do this | |
| 2912 | /* RX_FIFO_NOT_EMPTY */ | 2847 | * asynchronously. |
| 2913 | if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { | 2848 | * */ |
| 2914 | DSSERR("Received error during frame transfer:\n"); | ||
| 2915 | dsi_vc_flush_receive_data(channel); | ||
| 2916 | } | ||
| 2917 | |||
| 2918 | #ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC | ||
| 2919 | dispc_fake_vsync_irq(); | ||
| 2920 | #endif | ||
| 2921 | } | ||
| 2922 | |||
| 2923 | static void dsi_framedone_work_callback(struct work_struct *work) | ||
| 2924 | { | ||
| 2925 | DSSDBGF(); | ||
| 2926 | 2849 | ||
| 2927 | cancel_delayed_work_sync(&dsi.framedone_timeout_work); | 2850 | dsi.bta_callback = dsi_framedone_bta_callback; |
| 2928 | 2851 | ||
| 2929 | dsi_handle_framedone(); | 2852 | barrier(); |
| 2930 | 2853 | ||
| 2931 | dsi_perf_show("DISPC"); | 2854 | dsi_vc_enable_bta_irq(channel); |
| 2932 | 2855 | ||
| 2933 | dsi.framedone_callback(0, dsi.framedone_data); | 2856 | r = dsi_vc_send_bta(channel); |
| 2857 | if (r) { | ||
| 2858 | DSSERR("BTA after framedone failed\n"); | ||
| 2859 | dsi_handle_framedone(-EIO); | ||
| 2860 | } | ||
| 2934 | } | 2861 | } |
| 2935 | 2862 | ||
| 2936 | int omap_dsi_prepare_update(struct omap_dss_device *dssdev, | 2863 | int omap_dsi_prepare_update(struct omap_dss_device *dssdev, |
| 2937 | u16 *x, u16 *y, u16 *w, u16 *h) | 2864 | u16 *x, u16 *y, u16 *w, u16 *h, |
| 2865 | bool enlarge_update_area) | ||
| 2938 | { | 2866 | { |
| 2939 | u16 dw, dh; | 2867 | u16 dw, dh; |
| 2940 | 2868 | ||
| @@ -2958,7 +2886,8 @@ int omap_dsi_prepare_update(struct omap_dss_device *dssdev, | |||
| 2958 | dsi_perf_mark_setup(); | 2886 | dsi_perf_mark_setup(); |
| 2959 | 2887 | ||
| 2960 | if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { | 2888 | if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { |
| 2961 | dss_setup_partial_planes(dssdev, x, y, w, h); | 2889 | dss_setup_partial_planes(dssdev, x, y, w, h, |
| 2890 | enlarge_update_area); | ||
| 2962 | dispc_set_lcd_size(*w, *h); | 2891 | dispc_set_lcd_size(*w, *h); |
| 2963 | } | 2892 | } |
| 2964 | 2893 | ||
| @@ -2973,6 +2902,12 @@ int omap_dsi_update(struct omap_dss_device *dssdev, | |||
| 2973 | { | 2902 | { |
| 2974 | dsi.update_channel = channel; | 2903 | dsi.update_channel = channel; |
| 2975 | 2904 | ||
| 2905 | /* OMAP DSS cannot send updates of odd widths. | ||
| 2906 | * omap_dsi_prepare_update() makes the widths even, but add a BUG_ON | ||
| 2907 | * here to make sure we catch erroneous updates. Otherwise we'll only | ||
| 2908 | * see rather obscure HW error happening, as DSS halts. */ | ||
| 2909 | BUG_ON(x % 2 == 1); | ||
| 2910 | |||
| 2976 | if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { | 2911 | if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { |
| 2977 | dsi.framedone_callback = callback; | 2912 | dsi.framedone_callback = callback; |
| 2978 | dsi.framedone_data = data; | 2913 | dsi.framedone_data = data; |
| @@ -2985,7 +2920,12 @@ int omap_dsi_update(struct omap_dss_device *dssdev, | |||
| 2985 | 2920 | ||
| 2986 | dsi_update_screen_dispc(dssdev, x, y, w, h); | 2921 | dsi_update_screen_dispc(dssdev, x, y, w, h); |
| 2987 | } else { | 2922 | } else { |
| 2988 | dsi_update_screen_l4(dssdev, x, y, w, h); | 2923 | int r; |
| 2924 | |||
| 2925 | r = dsi_update_screen_l4(dssdev, x, y, w, h); | ||
| 2926 | if (r) | ||
| 2927 | return r; | ||
| 2928 | |||
| 2989 | dsi_perf_show("L4"); | 2929 | dsi_perf_show("L4"); |
| 2990 | callback(0, data); | 2930 | callback(0, data); |
| 2991 | } | 2931 | } |
| @@ -3048,8 +2988,10 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) | |||
| 3048 | cinfo.regm3 = dssdev->phy.dsi.div.regm3; | 2988 | cinfo.regm3 = dssdev->phy.dsi.div.regm3; |
| 3049 | cinfo.regm4 = dssdev->phy.dsi.div.regm4; | 2989 | cinfo.regm4 = dssdev->phy.dsi.div.regm4; |
| 3050 | r = dsi_calc_clock_rates(&cinfo); | 2990 | r = dsi_calc_clock_rates(&cinfo); |
| 3051 | if (r) | 2991 | if (r) { |
| 2992 | DSSERR("Failed to calc dsi clocks\n"); | ||
| 3052 | return r; | 2993 | return r; |
| 2994 | } | ||
| 3053 | 2995 | ||
| 3054 | r = dsi_pll_set_clock_div(&cinfo); | 2996 | r = dsi_pll_set_clock_div(&cinfo); |
| 3055 | if (r) { | 2997 | if (r) { |
| @@ -3147,6 +3089,13 @@ err0: | |||
| 3147 | 3089 | ||
| 3148 | static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev) | 3090 | static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev) |
| 3149 | { | 3091 | { |
| 3092 | /* disable interface */ | ||
| 3093 | dsi_if_enable(0); | ||
| 3094 | dsi_vc_enable(0, 0); | ||
| 3095 | dsi_vc_enable(1, 0); | ||
| 3096 | dsi_vc_enable(2, 0); | ||
| 3097 | dsi_vc_enable(3, 0); | ||
| 3098 | |||
| 3150 | dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK); | 3099 | dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK); |
| 3151 | dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK); | 3100 | dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK); |
| 3152 | dsi_complexio_uninit(); | 3101 | dsi_complexio_uninit(); |
| @@ -3257,7 +3206,7 @@ void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, | |||
| 3257 | burst_size_bytes = 16 * 32 / 8; | 3206 | burst_size_bytes = 16 * 32 / 8; |
| 3258 | 3207 | ||
| 3259 | *fifo_high = fifo_size - burst_size_bytes; | 3208 | *fifo_high = fifo_size - burst_size_bytes; |
| 3260 | *fifo_low = fifo_size - burst_size_bytes * 8; | 3209 | *fifo_low = fifo_size - burst_size_bytes * 2; |
| 3261 | } | 3210 | } |
| 3262 | 3211 | ||
| 3263 | int dsi_init_display(struct omap_dss_device *dssdev) | 3212 | int dsi_init_display(struct omap_dss_device *dssdev) |
| @@ -3274,6 +3223,18 @@ int dsi_init_display(struct omap_dss_device *dssdev) | |||
| 3274 | return 0; | 3223 | return 0; |
| 3275 | } | 3224 | } |
| 3276 | 3225 | ||
| 3226 | void dsi_wait_dsi1_pll_active(void) | ||
| 3227 | { | ||
| 3228 | if (wait_for_bit_change(DSI_PLL_STATUS, 7, 1) != 1) | ||
| 3229 | DSSERR("DSI1 PLL clock not active\n"); | ||
| 3230 | } | ||
| 3231 | |||
| 3232 | void dsi_wait_dsi2_pll_active(void) | ||
| 3233 | { | ||
| 3234 | if (wait_for_bit_change(DSI_PLL_STATUS, 8, 1) != 1) | ||
| 3235 | DSSERR("DSI2 PLL clock not active\n"); | ||
| 3236 | } | ||
| 3237 | |||
| 3277 | int dsi_init(struct platform_device *pdev) | 3238 | int dsi_init(struct platform_device *pdev) |
| 3278 | { | 3239 | { |
| 3279 | u32 rev; | 3240 | u32 rev; |
| @@ -3292,7 +3253,10 @@ int dsi_init(struct platform_device *pdev) | |||
| 3292 | mutex_init(&dsi.lock); | 3253 | mutex_init(&dsi.lock); |
| 3293 | sema_init(&dsi.bus_lock, 1); | 3254 | sema_init(&dsi.bus_lock, 1); |
| 3294 | 3255 | ||
| 3295 | INIT_WORK(&dsi.framedone_work, dsi_framedone_work_callback); | 3256 | dsi.workqueue = create_singlethread_workqueue("dsi"); |
| 3257 | if (dsi.workqueue == NULL) | ||
| 3258 | return -ENOMEM; | ||
| 3259 | |||
| 3296 | INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work, | 3260 | INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work, |
| 3297 | dsi_framedone_timeout_work_callback); | 3261 | dsi_framedone_timeout_work_callback); |
| 3298 | 3262 | ||
| @@ -3328,6 +3292,7 @@ int dsi_init(struct platform_device *pdev) | |||
| 3328 | err2: | 3292 | err2: |
| 3329 | iounmap(dsi.base); | 3293 | iounmap(dsi.base); |
| 3330 | err1: | 3294 | err1: |
| 3295 | destroy_workqueue(dsi.workqueue); | ||
| 3331 | return r; | 3296 | return r; |
| 3332 | } | 3297 | } |
| 3333 | 3298 | ||
| @@ -3335,6 +3300,8 @@ void dsi_exit(void) | |||
| 3335 | { | 3300 | { |
| 3336 | iounmap(dsi.base); | 3301 | iounmap(dsi.base); |
| 3337 | 3302 | ||
| 3303 | destroy_workqueue(dsi.workqueue); | ||
| 3304 | |||
| 3338 | DSSDBG("omap_dsi_exit\n"); | 3305 | DSSDBG("omap_dsi_exit\n"); |
| 3339 | } | 3306 | } |
| 3340 | 3307 | ||
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 24b18258654..77c3621c917 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c | |||
| @@ -265,6 +265,9 @@ void dss_select_dispc_clk_source(enum dss_clk_source clk_src) | |||
| 265 | 265 | ||
| 266 | b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; | 266 | b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; |
| 267 | 267 | ||
| 268 | if (clk_src == DSS_SRC_DSI1_PLL_FCLK) | ||
| 269 | dsi_wait_dsi1_pll_active(); | ||
| 270 | |||
| 268 | REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */ | 271 | REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */ |
| 269 | 272 | ||
| 270 | dss.dispc_clk_source = clk_src; | 273 | dss.dispc_clk_source = clk_src; |
| @@ -279,6 +282,9 @@ void dss_select_dsi_clk_source(enum dss_clk_source clk_src) | |||
| 279 | 282 | ||
| 280 | b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; | 283 | b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; |
| 281 | 284 | ||
| 285 | if (clk_src == DSS_SRC_DSI2_PLL_FCLK) | ||
| 286 | dsi_wait_dsi2_pll_active(); | ||
| 287 | |||
| 282 | REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */ | 288 | REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */ |
| 283 | 289 | ||
| 284 | dss.dsi_clk_source = clk_src; | 290 | dss.dsi_clk_source = clk_src; |
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 786f433fd57..5c7940d5f28 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h | |||
| @@ -199,7 +199,8 @@ int dss_init_overlay_managers(struct platform_device *pdev); | |||
| 199 | void dss_uninit_overlay_managers(struct platform_device *pdev); | 199 | void dss_uninit_overlay_managers(struct platform_device *pdev); |
| 200 | int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl); | 200 | int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl); |
| 201 | void dss_setup_partial_planes(struct omap_dss_device *dssdev, | 201 | void dss_setup_partial_planes(struct omap_dss_device *dssdev, |
| 202 | u16 *x, u16 *y, u16 *w, u16 *h); | 202 | u16 *x, u16 *y, u16 *w, u16 *h, |
| 203 | bool enlarge_update_area); | ||
| 203 | void dss_start_update(struct omap_dss_device *dssdev); | 204 | void dss_start_update(struct omap_dss_device *dssdev); |
| 204 | 205 | ||
| 205 | /* overlay */ | 206 | /* overlay */ |
| @@ -281,6 +282,8 @@ void dsi_pll_uninit(void); | |||
| 281 | void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, | 282 | void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, |
| 282 | u32 fifo_size, enum omap_burst_size *burst_size, | 283 | u32 fifo_size, enum omap_burst_size *burst_size, |
| 283 | u32 *fifo_low, u32 *fifo_high); | 284 | u32 *fifo_low, u32 *fifo_high); |
| 285 | void dsi_wait_dsi1_pll_active(void); | ||
| 286 | void dsi_wait_dsi2_pll_active(void); | ||
| 284 | #else | 287 | #else |
| 285 | static inline int dsi_init(struct platform_device *pdev) | 288 | static inline int dsi_init(struct platform_device *pdev) |
| 286 | { | 289 | { |
| @@ -289,6 +292,12 @@ static inline int dsi_init(struct platform_device *pdev) | |||
| 289 | static inline void dsi_exit(void) | 292 | static inline void dsi_exit(void) |
| 290 | { | 293 | { |
| 291 | } | 294 | } |
| 295 | static inline void dsi_wait_dsi1_pll_active(void) | ||
| 296 | { | ||
| 297 | } | ||
| 298 | static inline void dsi_wait_dsi2_pll_active(void) | ||
| 299 | { | ||
| 300 | } | ||
| 292 | #endif | 301 | #endif |
| 293 | 302 | ||
| 294 | /* DPI */ | 303 | /* DPI */ |
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 9e1fbe531bf..6a649ab5539 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c | |||
| @@ -440,6 +440,10 @@ struct manager_cache_data { | |||
| 440 | 440 | ||
| 441 | /* manual update region */ | 441 | /* manual update region */ |
| 442 | u16 x, y, w, h; | 442 | u16 x, y, w, h; |
| 443 | |||
| 444 | /* enlarge the update area if the update area contains scaled | ||
| 445 | * overlays */ | ||
| 446 | bool enlarge_update_area; | ||
| 443 | }; | 447 | }; |
| 444 | 448 | ||
| 445 | static struct { | 449 | static struct { |
| @@ -525,7 +529,7 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) | |||
| 525 | int i; | 529 | int i; |
| 526 | struct omap_dss_device *dssdev = mgr->device; | 530 | struct omap_dss_device *dssdev = mgr->device; |
| 527 | 531 | ||
| 528 | if (!dssdev) | 532 | if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) |
| 529 | return 0; | 533 | return 0; |
| 530 | 534 | ||
| 531 | if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { | 535 | if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { |
| @@ -596,11 +600,14 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) | |||
| 596 | int r; | 600 | int r; |
| 597 | int i; | 601 | int i; |
| 598 | 602 | ||
| 599 | if (!ovl->manager || !ovl->manager->device) | 603 | if (!ovl->manager) |
| 600 | return 0; | 604 | return 0; |
| 601 | 605 | ||
| 602 | dssdev = ovl->manager->device; | 606 | dssdev = ovl->manager->device; |
| 603 | 607 | ||
| 608 | if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
| 609 | return 0; | ||
| 610 | |||
| 604 | if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { | 611 | if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { |
| 605 | irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; | 612 | irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; |
| 606 | channel = OMAP_DSS_CHANNEL_DIGIT; | 613 | channel = OMAP_DSS_CHANNEL_DIGIT; |
| @@ -718,6 +725,7 @@ static int configure_overlay(enum omap_plane plane) | |||
| 718 | u16 x, y, w, h; | 725 | u16 x, y, w, h; |
| 719 | u32 paddr; | 726 | u32 paddr; |
| 720 | int r; | 727 | int r; |
| 728 | u16 orig_w, orig_h, orig_outw, orig_outh; | ||
| 721 | 729 | ||
| 722 | DSSDBGF("%d", plane); | 730 | DSSDBGF("%d", plane); |
| 723 | 731 | ||
| @@ -738,8 +746,16 @@ static int configure_overlay(enum omap_plane plane) | |||
| 738 | outh = c->out_height == 0 ? c->height : c->out_height; | 746 | outh = c->out_height == 0 ? c->height : c->out_height; |
| 739 | paddr = c->paddr; | 747 | paddr = c->paddr; |
| 740 | 748 | ||
| 749 | orig_w = w; | ||
| 750 | orig_h = h; | ||
| 751 | orig_outw = outw; | ||
| 752 | orig_outh = outh; | ||
| 753 | |||
| 741 | if (c->manual_update && mc->do_manual_update) { | 754 | if (c->manual_update && mc->do_manual_update) { |
| 742 | unsigned bpp; | 755 | unsigned bpp; |
| 756 | unsigned scale_x_m = w, scale_x_d = outw; | ||
| 757 | unsigned scale_y_m = h, scale_y_d = outh; | ||
| 758 | |||
| 743 | /* If the overlay is outside the update region, disable it */ | 759 | /* If the overlay is outside the update region, disable it */ |
| 744 | if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h, | 760 | if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h, |
| 745 | x, y, outw, outh)) { | 761 | x, y, outw, outh)) { |
| @@ -770,38 +786,47 @@ static int configure_overlay(enum omap_plane plane) | |||
| 770 | BUG(); | 786 | BUG(); |
| 771 | } | 787 | } |
| 772 | 788 | ||
| 773 | if (dispc_is_overlay_scaled(c)) { | 789 | if (mc->x > c->pos_x) { |
| 774 | /* If the overlay is scaled, the update area has | 790 | x = 0; |
| 775 | * already been enlarged to cover the whole overlay. We | 791 | outw -= (mc->x - c->pos_x); |
| 776 | * only need to adjust x/y here */ | 792 | paddr += (mc->x - c->pos_x) * |
| 777 | x = c->pos_x - mc->x; | 793 | scale_x_m / scale_x_d * bpp / 8; |
| 778 | y = c->pos_y - mc->y; | ||
| 779 | } else { | 794 | } else { |
| 780 | if (mc->x > c->pos_x) { | 795 | x = c->pos_x - mc->x; |
| 781 | x = 0; | 796 | } |
| 782 | w -= (mc->x - c->pos_x); | ||
| 783 | paddr += (mc->x - c->pos_x) * bpp / 8; | ||
| 784 | } else { | ||
| 785 | x = c->pos_x - mc->x; | ||
| 786 | } | ||
| 787 | |||
| 788 | if (mc->y > c->pos_y) { | ||
| 789 | y = 0; | ||
| 790 | h -= (mc->y - c->pos_y); | ||
| 791 | paddr += (mc->y - c->pos_y) * c->screen_width * | ||
| 792 | bpp / 8; | ||
| 793 | } else { | ||
| 794 | y = c->pos_y - mc->y; | ||
| 795 | } | ||
| 796 | |||
| 797 | if (mc->w < (x+w)) | ||
| 798 | w -= (x+w) - (mc->w); | ||
| 799 | 797 | ||
| 800 | if (mc->h < (y+h)) | 798 | if (mc->y > c->pos_y) { |
| 801 | h -= (y+h) - (mc->h); | 799 | y = 0; |
| 800 | outh -= (mc->y - c->pos_y); | ||
| 801 | paddr += (mc->y - c->pos_y) * | ||
| 802 | scale_y_m / scale_y_d * | ||
| 803 | c->screen_width * bpp / 8; | ||
| 804 | } else { | ||
| 805 | y = c->pos_y - mc->y; | ||
| 806 | } | ||
| 802 | 807 | ||
| 803 | outw = w; | 808 | if (mc->w < (x + outw)) |
| 804 | outh = h; | 809 | outw -= (x + outw) - (mc->w); |
| 810 | |||
| 811 | if (mc->h < (y + outh)) | ||
| 812 | outh -= (y + outh) - (mc->h); | ||
| 813 | |||
| 814 | w = w * outw / orig_outw; | ||
| 815 | h = h * outh / orig_outh; | ||
| 816 | |||
| 817 | /* YUV mode overlay's input width has to be even and the | ||
| 818 | * algorithm above may adjust the width to be odd. | ||
| 819 | * | ||
| 820 | * Here we adjust the width if needed, preferring to increase | ||
| 821 | * the width if the original width was bigger. | ||
| 822 | */ | ||
| 823 | if ((w & 1) && | ||
| 824 | (c->color_mode == OMAP_DSS_COLOR_YUV2 || | ||
| 825 | c->color_mode == OMAP_DSS_COLOR_UYVY)) { | ||
| 826 | if (orig_w > w) | ||
| 827 | w += 1; | ||
| 828 | else | ||
| 829 | w -= 1; | ||
| 805 | } | 830 | } |
| 806 | } | 831 | } |
| 807 | 832 | ||
| @@ -960,7 +985,7 @@ static void make_even(u16 *x, u16 *w) | |||
| 960 | /* Configure dispc for partial update. Return possibly modified update | 985 | /* Configure dispc for partial update. Return possibly modified update |
| 961 | * area */ | 986 | * area */ |
| 962 | void dss_setup_partial_planes(struct omap_dss_device *dssdev, | 987 | void dss_setup_partial_planes(struct omap_dss_device *dssdev, |
| 963 | u16 *xi, u16 *yi, u16 *wi, u16 *hi) | 988 | u16 *xi, u16 *yi, u16 *wi, u16 *hi, bool enlarge_update_area) |
| 964 | { | 989 | { |
| 965 | struct overlay_cache_data *oc; | 990 | struct overlay_cache_data *oc; |
| 966 | struct manager_cache_data *mc; | 991 | struct manager_cache_data *mc; |
| @@ -969,6 +994,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev, | |||
| 969 | int i; | 994 | int i; |
| 970 | u16 x, y, w, h; | 995 | u16 x, y, w, h; |
| 971 | unsigned long flags; | 996 | unsigned long flags; |
| 997 | bool area_changed; | ||
| 972 | 998 | ||
| 973 | x = *xi; | 999 | x = *xi; |
| 974 | y = *yi; | 1000 | y = *yi; |
| @@ -989,73 +1015,91 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev, | |||
| 989 | 1015 | ||
| 990 | spin_lock_irqsave(&dss_cache.lock, flags); | 1016 | spin_lock_irqsave(&dss_cache.lock, flags); |
| 991 | 1017 | ||
| 992 | /* We need to show the whole overlay if it is scaled. So look for | 1018 | /* |
| 993 | * those, and make the update area larger if found. | 1019 | * Execute the outer loop until the inner loop has completed |
| 994 | * Also mark the overlay cache dirty */ | 1020 | * once without increasing the update area. This will ensure that |
| 995 | for (i = 0; i < num_ovls; ++i) { | 1021 | * all scaled overlays end up completely within the update area. |
| 996 | unsigned x1, y1, x2, y2; | 1022 | */ |
| 997 | unsigned outw, outh; | 1023 | do { |
| 1024 | area_changed = false; | ||
| 998 | 1025 | ||
| 999 | oc = &dss_cache.overlay_cache[i]; | 1026 | /* We need to show the whole overlay if it is scaled. So look |
| 1027 | * for those, and make the update area larger if found. | ||
| 1028 | * Also mark the overlay cache dirty */ | ||
| 1029 | for (i = 0; i < num_ovls; ++i) { | ||
| 1030 | unsigned x1, y1, x2, y2; | ||
| 1031 | unsigned outw, outh; | ||
| 1000 | 1032 | ||
| 1001 | if (oc->channel != mgr->id) | 1033 | oc = &dss_cache.overlay_cache[i]; |
| 1002 | continue; | ||
| 1003 | 1034 | ||
| 1004 | oc->dirty = true; | 1035 | if (oc->channel != mgr->id) |
| 1036 | continue; | ||
| 1005 | 1037 | ||
| 1006 | if (!oc->enabled) | 1038 | oc->dirty = true; |
| 1007 | continue; | ||
| 1008 | 1039 | ||
| 1009 | if (!dispc_is_overlay_scaled(oc)) | 1040 | if (!enlarge_update_area) |
| 1010 | continue; | 1041 | continue; |
| 1011 | 1042 | ||
| 1012 | outw = oc->out_width == 0 ? oc->width : oc->out_width; | 1043 | if (!oc->enabled) |
| 1013 | outh = oc->out_height == 0 ? oc->height : oc->out_height; | 1044 | continue; |
| 1014 | 1045 | ||
| 1015 | /* is the overlay outside the update region? */ | 1046 | if (!dispc_is_overlay_scaled(oc)) |
| 1016 | if (!rectangle_intersects(x, y, w, h, | 1047 | continue; |
| 1017 | oc->pos_x, oc->pos_y, | ||
| 1018 | outw, outh)) | ||
| 1019 | continue; | ||
| 1020 | 1048 | ||
| 1021 | /* if the overlay totally inside the update region? */ | 1049 | outw = oc->out_width == 0 ? |
| 1022 | if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh, | 1050 | oc->width : oc->out_width; |
| 1023 | x, y, w, h)) | 1051 | outh = oc->out_height == 0 ? |
| 1024 | continue; | 1052 | oc->height : oc->out_height; |
| 1053 | |||
| 1054 | /* is the overlay outside the update region? */ | ||
| 1055 | if (!rectangle_intersects(x, y, w, h, | ||
| 1056 | oc->pos_x, oc->pos_y, | ||
| 1057 | outw, outh)) | ||
| 1058 | continue; | ||
| 1025 | 1059 | ||
| 1026 | if (x > oc->pos_x) | 1060 | /* if the overlay totally inside the update region? */ |
| 1027 | x1 = oc->pos_x; | 1061 | if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh, |
| 1028 | else | 1062 | x, y, w, h)) |
| 1029 | x1 = x; | 1063 | continue; |
| 1030 | 1064 | ||
| 1031 | if (y > oc->pos_y) | 1065 | if (x > oc->pos_x) |
| 1032 | y1 = oc->pos_y; | 1066 | x1 = oc->pos_x; |
| 1033 | else | 1067 | else |
| 1034 | y1 = y; | 1068 | x1 = x; |
| 1035 | 1069 | ||
| 1036 | if ((x + w) < (oc->pos_x + outw)) | 1070 | if (y > oc->pos_y) |
| 1037 | x2 = oc->pos_x + outw; | 1071 | y1 = oc->pos_y; |
| 1038 | else | 1072 | else |
| 1039 | x2 = x + w; | 1073 | y1 = y; |
| 1040 | 1074 | ||
| 1041 | if ((y + h) < (oc->pos_y + outh)) | 1075 | if ((x + w) < (oc->pos_x + outw)) |
| 1042 | y2 = oc->pos_y + outh; | 1076 | x2 = oc->pos_x + outw; |
| 1043 | else | 1077 | else |
| 1044 | y2 = y + h; | 1078 | x2 = x + w; |
| 1045 | 1079 | ||
| 1046 | x = x1; | 1080 | if ((y + h) < (oc->pos_y + outh)) |
| 1047 | y = y1; | 1081 | y2 = oc->pos_y + outh; |
| 1048 | w = x2 - x1; | 1082 | else |
| 1049 | h = y2 - y1; | 1083 | y2 = y + h; |
| 1050 | 1084 | ||
| 1051 | make_even(&x, &w); | 1085 | x = x1; |
| 1086 | y = y1; | ||
| 1087 | w = x2 - x1; | ||
| 1088 | h = y2 - y1; | ||
| 1052 | 1089 | ||
| 1053 | DSSDBG("changing upd area due to ovl(%d) scaling %d,%d %dx%d\n", | 1090 | make_even(&x, &w); |
| 1091 | |||
| 1092 | DSSDBG("changing upd area due to ovl(%d) " | ||
| 1093 | "scaling %d,%d %dx%d\n", | ||
| 1054 | i, x, y, w, h); | 1094 | i, x, y, w, h); |
| 1055 | } | 1095 | |
| 1096 | area_changed = true; | ||
| 1097 | } | ||
| 1098 | } while (area_changed); | ||
| 1056 | 1099 | ||
| 1057 | mc = &dss_cache.manager_cache[mgr->id]; | 1100 | mc = &dss_cache.manager_cache[mgr->id]; |
| 1058 | mc->do_manual_update = true; | 1101 | mc->do_manual_update = true; |
| 1102 | mc->enlarge_update_area = enlarge_update_area; | ||
| 1059 | mc->x = x; | 1103 | mc->x = x; |
| 1060 | mc->y = y; | 1104 | mc->y = y; |
| 1061 | mc->w = w; | 1105 | mc->w = w; |
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 82336583ade..244dca81a39 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c | |||
| @@ -65,7 +65,7 @@ static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, | |||
| 65 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { | 65 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { |
| 66 | mgr = omap_dss_get_overlay_manager(i); | 66 | mgr = omap_dss_get_overlay_manager(i); |
| 67 | 67 | ||
| 68 | if (strncmp(buf, mgr->name, len) == 0) | 68 | if (sysfs_streq(buf, mgr->name)) |
| 69 | break; | 69 | break; |
| 70 | 70 | ||
| 71 | mgr = NULL; | 71 | mgr = NULL; |
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index cc23f53cc62..bbe62464e92 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c | |||
| @@ -886,7 +886,7 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, | |||
| 886 | return -EINVAL; | 886 | return -EINVAL; |
| 887 | 887 | ||
| 888 | if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { | 888 | if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { |
| 889 | dss_setup_partial_planes(dssdev, x, y, w, h); | 889 | dss_setup_partial_planes(dssdev, x, y, w, h, true); |
| 890 | dispc_set_lcd_size(*w, *h); | 890 | dispc_set_lcd_size(*w, *h); |
| 891 | } | 891 | } |
| 892 | 892 | ||
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 9c7361871d7..6f435450987 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c | |||
| @@ -34,12 +34,37 @@ | |||
| 34 | 34 | ||
| 35 | #include "omapfb.h" | 35 | #include "omapfb.h" |
| 36 | 36 | ||
| 37 | static u8 get_mem_idx(struct omapfb_info *ofbi) | ||
| 38 | { | ||
| 39 | if (ofbi->id == ofbi->region->id) | ||
| 40 | return 0; | ||
| 41 | |||
| 42 | return OMAPFB_MEM_IDX_ENABLED | ofbi->region->id; | ||
| 43 | } | ||
| 44 | |||
| 45 | static struct omapfb2_mem_region *get_mem_region(struct omapfb_info *ofbi, | ||
| 46 | u8 mem_idx) | ||
| 47 | { | ||
| 48 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
| 49 | |||
| 50 | if (mem_idx & OMAPFB_MEM_IDX_ENABLED) | ||
| 51 | mem_idx &= OMAPFB_MEM_IDX_MASK; | ||
| 52 | else | ||
| 53 | mem_idx = ofbi->id; | ||
| 54 | |||
| 55 | if (mem_idx >= fbdev->num_fbs) | ||
| 56 | return NULL; | ||
| 57 | |||
| 58 | return &fbdev->regions[mem_idx]; | ||
| 59 | } | ||
| 60 | |||
| 37 | static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | 61 | static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) |
| 38 | { | 62 | { |
| 39 | struct omapfb_info *ofbi = FB2OFB(fbi); | 63 | struct omapfb_info *ofbi = FB2OFB(fbi); |
| 40 | struct omapfb2_device *fbdev = ofbi->fbdev; | 64 | struct omapfb2_device *fbdev = ofbi->fbdev; |
| 41 | struct omap_overlay *ovl; | 65 | struct omap_overlay *ovl; |
| 42 | struct omap_overlay_info info; | 66 | struct omap_overlay_info old_info; |
| 67 | struct omapfb2_mem_region *old_rg, *new_rg; | ||
| 43 | int r = 0; | 68 | int r = 0; |
| 44 | 69 | ||
| 45 | DBG("omapfb_setup_plane\n"); | 70 | DBG("omapfb_setup_plane\n"); |
| @@ -52,36 +77,106 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | |||
| 52 | /* XXX uses only the first overlay */ | 77 | /* XXX uses only the first overlay */ |
| 53 | ovl = ofbi->overlays[0]; | 78 | ovl = ofbi->overlays[0]; |
| 54 | 79 | ||
| 55 | if (pi->enabled && !ofbi->region.size) { | 80 | old_rg = ofbi->region; |
| 81 | new_rg = get_mem_region(ofbi, pi->mem_idx); | ||
| 82 | if (!new_rg) { | ||
| 83 | r = -EINVAL; | ||
| 84 | goto out; | ||
| 85 | } | ||
| 86 | |||
| 87 | /* Take the locks in a specific order to keep lockdep happy */ | ||
| 88 | if (old_rg->id < new_rg->id) { | ||
| 89 | omapfb_get_mem_region(old_rg); | ||
| 90 | omapfb_get_mem_region(new_rg); | ||
| 91 | } else if (new_rg->id < old_rg->id) { | ||
| 92 | omapfb_get_mem_region(new_rg); | ||
| 93 | omapfb_get_mem_region(old_rg); | ||
| 94 | } else | ||
| 95 | omapfb_get_mem_region(old_rg); | ||
| 96 | |||
| 97 | if (pi->enabled && !new_rg->size) { | ||
| 56 | /* | 98 | /* |
| 57 | * This plane's memory was freed, can't enable it | 99 | * This plane's memory was freed, can't enable it |
| 58 | * until it's reallocated. | 100 | * until it's reallocated. |
| 59 | */ | 101 | */ |
| 60 | r = -EINVAL; | 102 | r = -EINVAL; |
| 61 | goto out; | 103 | goto put_mem; |
| 62 | } | 104 | } |
| 63 | 105 | ||
| 64 | ovl->get_overlay_info(ovl, &info); | 106 | ovl->get_overlay_info(ovl, &old_info); |
| 65 | 107 | ||
| 66 | info.pos_x = pi->pos_x; | 108 | if (old_rg != new_rg) { |
| 67 | info.pos_y = pi->pos_y; | 109 | ofbi->region = new_rg; |
| 68 | info.out_width = pi->out_width; | 110 | set_fb_fix(fbi); |
| 69 | info.out_height = pi->out_height; | 111 | } |
| 70 | info.enabled = pi->enabled; | ||
| 71 | 112 | ||
| 72 | r = ovl->set_overlay_info(ovl, &info); | 113 | if (pi->enabled) { |
| 73 | if (r) | 114 | struct omap_overlay_info info; |
| 74 | goto out; | ||
| 75 | 115 | ||
| 76 | if (ovl->manager) { | 116 | r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y, |
| 77 | r = ovl->manager->apply(ovl->manager); | 117 | pi->out_width, pi->out_height); |
| 78 | if (r) | 118 | if (r) |
| 79 | goto out; | 119 | goto undo; |
| 120 | |||
| 121 | ovl->get_overlay_info(ovl, &info); | ||
| 122 | |||
| 123 | if (!info.enabled) { | ||
| 124 | info.enabled = pi->enabled; | ||
| 125 | r = ovl->set_overlay_info(ovl, &info); | ||
| 126 | if (r) | ||
| 127 | goto undo; | ||
| 128 | } | ||
| 129 | } else { | ||
| 130 | struct omap_overlay_info info; | ||
| 131 | |||
| 132 | ovl->get_overlay_info(ovl, &info); | ||
| 133 | |||
| 134 | info.enabled = pi->enabled; | ||
| 135 | info.pos_x = pi->pos_x; | ||
| 136 | info.pos_y = pi->pos_y; | ||
| 137 | info.out_width = pi->out_width; | ||
| 138 | info.out_height = pi->out_height; | ||
| 139 | |||
| 140 | r = ovl->set_overlay_info(ovl, &info); | ||
| 141 | if (r) | ||
| 142 | goto undo; | ||
| 80 | } | 143 | } |
| 81 | 144 | ||
| 82 | out: | 145 | if (ovl->manager) |
| 83 | if (r) | 146 | ovl->manager->apply(ovl->manager); |
| 84 | dev_err(fbdev->dev, "setup_plane failed\n"); | 147 | |
| 148 | /* Release the locks in a specific order to keep lockdep happy */ | ||
| 149 | if (old_rg->id > new_rg->id) { | ||
| 150 | omapfb_put_mem_region(old_rg); | ||
| 151 | omapfb_put_mem_region(new_rg); | ||
| 152 | } else if (new_rg->id > old_rg->id) { | ||
| 153 | omapfb_put_mem_region(new_rg); | ||
| 154 | omapfb_put_mem_region(old_rg); | ||
| 155 | } else | ||
| 156 | omapfb_put_mem_region(old_rg); | ||
| 157 | |||
| 158 | return 0; | ||
| 159 | |||
| 160 | undo: | ||
| 161 | if (old_rg != new_rg) { | ||
| 162 | ofbi->region = old_rg; | ||
| 163 | set_fb_fix(fbi); | ||
| 164 | } | ||
| 165 | |||
| 166 | ovl->set_overlay_info(ovl, &old_info); | ||
| 167 | put_mem: | ||
| 168 | /* Release the locks in a specific order to keep lockdep happy */ | ||
| 169 | if (old_rg->id > new_rg->id) { | ||
| 170 | omapfb_put_mem_region(old_rg); | ||
| 171 | omapfb_put_mem_region(new_rg); | ||
| 172 | } else if (new_rg->id > old_rg->id) { | ||
| 173 | omapfb_put_mem_region(new_rg); | ||
| 174 | omapfb_put_mem_region(old_rg); | ||
| 175 | } else | ||
| 176 | omapfb_put_mem_region(old_rg); | ||
| 177 | out: | ||
| 178 | dev_err(fbdev->dev, "setup_plane failed\n"); | ||
| 179 | |||
| 85 | return r; | 180 | return r; |
| 86 | } | 181 | } |
| 87 | 182 | ||
| @@ -92,8 +187,8 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | |||
| 92 | if (ofbi->num_overlays != 1) { | 187 | if (ofbi->num_overlays != 1) { |
| 93 | memset(pi, 0, sizeof(*pi)); | 188 | memset(pi, 0, sizeof(*pi)); |
| 94 | } else { | 189 | } else { |
| 95 | struct omap_overlay_info *ovli; | ||
| 96 | struct omap_overlay *ovl; | 190 | struct omap_overlay *ovl; |
| 191 | struct omap_overlay_info *ovli; | ||
| 97 | 192 | ||
| 98 | ovl = ofbi->overlays[0]; | 193 | ovl = ofbi->overlays[0]; |
| 99 | ovli = &ovl->info; | 194 | ovli = &ovl->info; |
| @@ -103,6 +198,7 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | |||
| 103 | pi->enabled = ovli->enabled; | 198 | pi->enabled = ovli->enabled; |
| 104 | pi->channel_out = 0; /* xxx */ | 199 | pi->channel_out = 0; /* xxx */ |
| 105 | pi->mirror = 0; | 200 | pi->mirror = 0; |
| 201 | pi->mem_idx = get_mem_idx(ofbi); | ||
| 106 | pi->out_width = ovli->out_width; | 202 | pi->out_width = ovli->out_width; |
| 107 | pi->out_height = ovli->out_height; | 203 | pi->out_height = ovli->out_height; |
| 108 | } | 204 | } |
| @@ -115,7 +211,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | |||
| 115 | struct omapfb_info *ofbi = FB2OFB(fbi); | 211 | struct omapfb_info *ofbi = FB2OFB(fbi); |
| 116 | struct omapfb2_device *fbdev = ofbi->fbdev; | 212 | struct omapfb2_device *fbdev = ofbi->fbdev; |
| 117 | struct omapfb2_mem_region *rg; | 213 | struct omapfb2_mem_region *rg; |
| 118 | int r, i; | 214 | int r = 0, i; |
| 119 | size_t size; | 215 | size_t size; |
| 120 | 216 | ||
| 121 | if (mi->type > OMAPFB_MEMTYPE_MAX) | 217 | if (mi->type > OMAPFB_MEMTYPE_MAX) |
| @@ -123,22 +219,44 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | |||
| 123 | 219 | ||
| 124 | size = PAGE_ALIGN(mi->size); | 220 | size = PAGE_ALIGN(mi->size); |
| 125 | 221 | ||
| 126 | rg = &ofbi->region; | 222 | rg = ofbi->region; |
| 127 | 223 | ||
| 128 | for (i = 0; i < ofbi->num_overlays; i++) { | 224 | down_write_nested(&rg->lock, rg->id); |
| 129 | if (ofbi->overlays[i]->info.enabled) | 225 | atomic_inc(&rg->lock_count); |
| 130 | return -EBUSY; | 226 | |
| 227 | if (atomic_read(&rg->map_count)) { | ||
| 228 | r = -EBUSY; | ||
| 229 | goto out; | ||
| 230 | } | ||
| 231 | |||
| 232 | for (i = 0; i < fbdev->num_fbs; i++) { | ||
| 233 | struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]); | ||
| 234 | int j; | ||
| 235 | |||
| 236 | if (ofbi2->region != rg) | ||
| 237 | continue; | ||
| 238 | |||
| 239 | for (j = 0; j < ofbi2->num_overlays; j++) { | ||
| 240 | if (ofbi2->overlays[j]->info.enabled) { | ||
| 241 | r = -EBUSY; | ||
| 242 | goto out; | ||
| 243 | } | ||
| 244 | } | ||
| 131 | } | 245 | } |
| 132 | 246 | ||
| 133 | if (rg->size != size || rg->type != mi->type) { | 247 | if (rg->size != size || rg->type != mi->type) { |
| 134 | r = omapfb_realloc_fbmem(fbi, size, mi->type); | 248 | r = omapfb_realloc_fbmem(fbi, size, mi->type); |
| 135 | if (r) { | 249 | if (r) { |
| 136 | dev_err(fbdev->dev, "realloc fbmem failed\n"); | 250 | dev_err(fbdev->dev, "realloc fbmem failed\n"); |
| 137 | return r; | 251 | goto out; |
| 138 | } | 252 | } |
| 139 | } | 253 | } |
| 140 | 254 | ||
| 141 | return 0; | 255 | out: |
| 256 | atomic_dec(&rg->lock_count); | ||
| 257 | up_write(&rg->lock); | ||
| 258 | |||
| 259 | return r; | ||
| 142 | } | 260 | } |
| 143 | 261 | ||
| 144 | static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | 262 | static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) |
| @@ -146,12 +264,14 @@ static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | |||
| 146 | struct omapfb_info *ofbi = FB2OFB(fbi); | 264 | struct omapfb_info *ofbi = FB2OFB(fbi); |
| 147 | struct omapfb2_mem_region *rg; | 265 | struct omapfb2_mem_region *rg; |
| 148 | 266 | ||
| 149 | rg = &ofbi->region; | 267 | rg = omapfb_get_mem_region(ofbi->region); |
| 150 | memset(mi, 0, sizeof(*mi)); | 268 | memset(mi, 0, sizeof(*mi)); |
| 151 | 269 | ||
| 152 | mi->size = rg->size; | 270 | mi->size = rg->size; |
| 153 | mi->type = rg->type; | 271 | mi->type = rg->type; |
| 154 | 272 | ||
| 273 | omapfb_put_mem_region(rg); | ||
| 274 | |||
| 155 | return 0; | 275 | return 0; |
| 156 | } | 276 | } |
| 157 | 277 | ||
| @@ -490,6 +610,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) | |||
| 490 | struct omapfb_vram_info vram_info; | 610 | struct omapfb_vram_info vram_info; |
| 491 | struct omapfb_tearsync_info tearsync_info; | 611 | struct omapfb_tearsync_info tearsync_info; |
| 492 | struct omapfb_display_info display_info; | 612 | struct omapfb_display_info display_info; |
| 613 | u32 crt; | ||
| 493 | } p; | 614 | } p; |
| 494 | 615 | ||
| 495 | int r = 0; | 616 | int r = 0; |
| @@ -648,6 +769,17 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) | |||
| 648 | r = -EFAULT; | 769 | r = -EFAULT; |
| 649 | break; | 770 | break; |
| 650 | 771 | ||
| 772 | case FBIO_WAITFORVSYNC: | ||
| 773 | if (get_user(p.crt, (__u32 __user *)arg)) { | ||
| 774 | r = -EFAULT; | ||
| 775 | break; | ||
| 776 | } | ||
| 777 | if (p.crt != 0) { | ||
| 778 | r = -ENODEV; | ||
| 779 | break; | ||
| 780 | } | ||
| 781 | /* FALLTHROUGH */ | ||
| 782 | |||
| 651 | case OMAPFB_WAITFORVSYNC: | 783 | case OMAPFB_WAITFORVSYNC: |
| 652 | DBG("ioctl WAITFORVSYNC\n"); | 784 | DBG("ioctl WAITFORVSYNC\n"); |
| 653 | if (!display) { | 785 | if (!display) { |
| @@ -738,7 +870,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) | |||
| 738 | break; | 870 | break; |
| 739 | } | 871 | } |
| 740 | 872 | ||
| 741 | if (!display->driver->enable_te) { | 873 | if (!display || !display->driver->enable_te) { |
| 742 | r = -ENODEV; | 874 | r = -ENODEV; |
| 743 | break; | 875 | break; |
| 744 | } | 876 | } |
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 4b4506da96d..04034d410d6 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c | |||
| @@ -157,7 +157,7 @@ static void fill_fb(struct fb_info *fbi) | |||
| 157 | 157 | ||
| 158 | static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot) | 158 | static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot) |
| 159 | { | 159 | { |
| 160 | const struct vrfb *vrfb = &ofbi->region.vrfb; | 160 | const struct vrfb *vrfb = &ofbi->region->vrfb; |
| 161 | unsigned offset; | 161 | unsigned offset; |
| 162 | 162 | ||
| 163 | switch (rot) { | 163 | switch (rot) { |
| @@ -185,27 +185,27 @@ static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot) | |||
| 185 | static u32 omapfb_get_region_rot_paddr(const struct omapfb_info *ofbi, int rot) | 185 | static u32 omapfb_get_region_rot_paddr(const struct omapfb_info *ofbi, int rot) |
| 186 | { | 186 | { |
| 187 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { | 187 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { |
| 188 | return ofbi->region.vrfb.paddr[rot] | 188 | return ofbi->region->vrfb.paddr[rot] |
| 189 | + omapfb_get_vrfb_offset(ofbi, rot); | 189 | + omapfb_get_vrfb_offset(ofbi, rot); |
| 190 | } else { | 190 | } else { |
| 191 | return ofbi->region.paddr; | 191 | return ofbi->region->paddr; |
| 192 | } | 192 | } |
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | static u32 omapfb_get_region_paddr(const struct omapfb_info *ofbi) | 195 | static u32 omapfb_get_region_paddr(const struct omapfb_info *ofbi) |
| 196 | { | 196 | { |
| 197 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) | 197 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) |
| 198 | return ofbi->region.vrfb.paddr[0]; | 198 | return ofbi->region->vrfb.paddr[0]; |
| 199 | else | 199 | else |
| 200 | return ofbi->region.paddr; | 200 | return ofbi->region->paddr; |
| 201 | } | 201 | } |
| 202 | 202 | ||
| 203 | static void __iomem *omapfb_get_region_vaddr(const struct omapfb_info *ofbi) | 203 | static void __iomem *omapfb_get_region_vaddr(const struct omapfb_info *ofbi) |
| 204 | { | 204 | { |
| 205 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) | 205 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) |
| 206 | return ofbi->region.vrfb.vaddr[0]; | 206 | return ofbi->region->vrfb.vaddr[0]; |
| 207 | else | 207 | else |
| 208 | return ofbi->region.vaddr; | 208 | return ofbi->region->vaddr; |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | static struct omapfb_colormode omapfb_colormodes[] = { | 211 | static struct omapfb_colormode omapfb_colormodes[] = { |
| @@ -450,7 +450,7 @@ static int check_vrfb_fb_size(unsigned long region_size, | |||
| 450 | static int check_fb_size(const struct omapfb_info *ofbi, | 450 | static int check_fb_size(const struct omapfb_info *ofbi, |
| 451 | struct fb_var_screeninfo *var) | 451 | struct fb_var_screeninfo *var) |
| 452 | { | 452 | { |
| 453 | unsigned long max_frame_size = ofbi->region.size; | 453 | unsigned long max_frame_size = ofbi->region->size; |
| 454 | int bytespp = var->bits_per_pixel >> 3; | 454 | int bytespp = var->bits_per_pixel >> 3; |
| 455 | unsigned long line_size = var->xres_virtual * bytespp; | 455 | unsigned long line_size = var->xres_virtual * bytespp; |
| 456 | 456 | ||
| @@ -497,7 +497,7 @@ static int check_fb_size(const struct omapfb_info *ofbi, | |||
| 497 | static int setup_vrfb_rotation(struct fb_info *fbi) | 497 | static int setup_vrfb_rotation(struct fb_info *fbi) |
| 498 | { | 498 | { |
| 499 | struct omapfb_info *ofbi = FB2OFB(fbi); | 499 | struct omapfb_info *ofbi = FB2OFB(fbi); |
| 500 | struct omapfb2_mem_region *rg = &ofbi->region; | 500 | struct omapfb2_mem_region *rg = ofbi->region; |
| 501 | struct vrfb *vrfb = &rg->vrfb; | 501 | struct vrfb *vrfb = &rg->vrfb; |
| 502 | struct fb_var_screeninfo *var = &fbi->var; | 502 | struct fb_var_screeninfo *var = &fbi->var; |
| 503 | struct fb_fix_screeninfo *fix = &fbi->fix; | 503 | struct fb_fix_screeninfo *fix = &fbi->fix; |
| @@ -558,9 +558,9 @@ static int setup_vrfb_rotation(struct fb_info *fbi) | |||
| 558 | return r; | 558 | return r; |
| 559 | 559 | ||
| 560 | /* used by open/write in fbmem.c */ | 560 | /* used by open/write in fbmem.c */ |
| 561 | fbi->screen_base = ofbi->region.vrfb.vaddr[0]; | 561 | fbi->screen_base = ofbi->region->vrfb.vaddr[0]; |
| 562 | 562 | ||
| 563 | fix->smem_start = ofbi->region.vrfb.paddr[0]; | 563 | fix->smem_start = ofbi->region->vrfb.paddr[0]; |
| 564 | 564 | ||
| 565 | switch (var->nonstd) { | 565 | switch (var->nonstd) { |
| 566 | case OMAPFB_COLOR_YUV422: | 566 | case OMAPFB_COLOR_YUV422: |
| @@ -599,7 +599,7 @@ void set_fb_fix(struct fb_info *fbi) | |||
| 599 | struct fb_fix_screeninfo *fix = &fbi->fix; | 599 | struct fb_fix_screeninfo *fix = &fbi->fix; |
| 600 | struct fb_var_screeninfo *var = &fbi->var; | 600 | struct fb_var_screeninfo *var = &fbi->var; |
| 601 | struct omapfb_info *ofbi = FB2OFB(fbi); | 601 | struct omapfb_info *ofbi = FB2OFB(fbi); |
| 602 | struct omapfb2_mem_region *rg = &ofbi->region; | 602 | struct omapfb2_mem_region *rg = ofbi->region; |
| 603 | 603 | ||
| 604 | DBG("set_fb_fix\n"); | 604 | DBG("set_fb_fix\n"); |
| 605 | 605 | ||
| @@ -668,8 +668,7 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var) | |||
| 668 | 668 | ||
| 669 | DBG("check_fb_var %d\n", ofbi->id); | 669 | DBG("check_fb_var %d\n", ofbi->id); |
| 670 | 670 | ||
| 671 | if (ofbi->region.size == 0) | 671 | WARN_ON(!atomic_read(&ofbi->region->lock_count)); |
| 672 | return 0; | ||
| 673 | 672 | ||
| 674 | r = fb_mode_to_dss_mode(var, &mode); | 673 | r = fb_mode_to_dss_mode(var, &mode); |
| 675 | if (r) { | 674 | if (r) { |
| @@ -684,13 +683,14 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var) | |||
| 684 | } | 683 | } |
| 685 | } | 684 | } |
| 686 | 685 | ||
| 687 | if (var->rotate < 0 || var->rotate > 3) | 686 | if (var->rotate > 3) |
| 688 | return -EINVAL; | 687 | return -EINVAL; |
| 689 | 688 | ||
| 690 | if (check_fb_res_bounds(var)) | 689 | if (check_fb_res_bounds(var)) |
| 691 | return -EINVAL; | 690 | return -EINVAL; |
| 692 | 691 | ||
| 693 | if (check_fb_size(ofbi, var)) | 692 | /* When no memory is allocated ignore the size check */ |
| 693 | if (ofbi->region->size != 0 && check_fb_size(ofbi, var)) | ||
| 694 | return -EINVAL; | 694 | return -EINVAL; |
| 695 | 695 | ||
| 696 | if (var->xres + var->xoffset > var->xres_virtual) | 696 | if (var->xres + var->xoffset > var->xres_virtual) |
| @@ -822,9 +822,43 @@ static unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var, | |||
| 822 | return offset; | 822 | return offset; |
| 823 | } | 823 | } |
| 824 | 824 | ||
| 825 | static void omapfb_calc_addr(const struct omapfb_info *ofbi, | ||
| 826 | const struct fb_var_screeninfo *var, | ||
| 827 | const struct fb_fix_screeninfo *fix, | ||
| 828 | int rotation, u32 *paddr, void __iomem **vaddr) | ||
| 829 | { | ||
| 830 | u32 data_start_p; | ||
| 831 | void __iomem *data_start_v; | ||
| 832 | int offset; | ||
| 833 | |||
| 834 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { | ||
| 835 | data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation); | ||
| 836 | data_start_v = NULL; | ||
| 837 | } else { | ||
| 838 | data_start_p = omapfb_get_region_paddr(ofbi); | ||
| 839 | data_start_v = omapfb_get_region_vaddr(ofbi); | ||
| 840 | } | ||
| 841 | |||
| 842 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) | ||
| 843 | offset = calc_rotation_offset_vrfb(var, fix, rotation); | ||
| 844 | else | ||
| 845 | offset = calc_rotation_offset_dma(var, fix, rotation); | ||
| 846 | |||
| 847 | data_start_p += offset; | ||
| 848 | data_start_v += offset; | ||
| 849 | |||
| 850 | if (offset) | ||
| 851 | DBG("offset %d, %d = %d\n", | ||
| 852 | var->xoffset, var->yoffset, offset); | ||
| 853 | |||
| 854 | DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v); | ||
| 855 | |||
| 856 | *paddr = data_start_p; | ||
| 857 | *vaddr = data_start_v; | ||
| 858 | } | ||
| 825 | 859 | ||
| 826 | /* setup overlay according to the fb */ | 860 | /* setup overlay according to the fb */ |
| 827 | static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, | 861 | int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, |
| 828 | u16 posx, u16 posy, u16 outw, u16 outh) | 862 | u16 posx, u16 posy, u16 outw, u16 outh) |
| 829 | { | 863 | { |
| 830 | int r = 0; | 864 | int r = 0; |
| @@ -832,9 +866,8 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, | |||
| 832 | struct fb_var_screeninfo *var = &fbi->var; | 866 | struct fb_var_screeninfo *var = &fbi->var; |
| 833 | struct fb_fix_screeninfo *fix = &fbi->fix; | 867 | struct fb_fix_screeninfo *fix = &fbi->fix; |
| 834 | enum omap_color_mode mode = 0; | 868 | enum omap_color_mode mode = 0; |
| 835 | int offset; | 869 | u32 data_start_p = 0; |
| 836 | u32 data_start_p; | 870 | void __iomem *data_start_v = NULL; |
| 837 | void __iomem *data_start_v; | ||
| 838 | struct omap_overlay_info info; | 871 | struct omap_overlay_info info; |
| 839 | int xres, yres; | 872 | int xres, yres; |
| 840 | int screen_width; | 873 | int screen_width; |
| @@ -842,6 +875,8 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, | |||
| 842 | int rotation = var->rotate; | 875 | int rotation = var->rotate; |
| 843 | int i; | 876 | int i; |
| 844 | 877 | ||
| 878 | WARN_ON(!atomic_read(&ofbi->region->lock_count)); | ||
| 879 | |||
| 845 | for (i = 0; i < ofbi->num_overlays; i++) { | 880 | for (i = 0; i < ofbi->num_overlays; i++) { |
| 846 | if (ovl != ofbi->overlays[i]) | 881 | if (ovl != ofbi->overlays[i]) |
| 847 | continue; | 882 | continue; |
| @@ -861,28 +896,9 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, | |||
| 861 | yres = var->yres; | 896 | yres = var->yres; |
| 862 | } | 897 | } |
| 863 | 898 | ||
| 864 | 899 | if (ofbi->region->size) | |
| 865 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { | 900 | omapfb_calc_addr(ofbi, var, fix, rotation, |
| 866 | data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation); | 901 | &data_start_p, &data_start_v); |
| 867 | data_start_v = NULL; | ||
| 868 | } else { | ||
| 869 | data_start_p = omapfb_get_region_paddr(ofbi); | ||
| 870 | data_start_v = omapfb_get_region_vaddr(ofbi); | ||
| 871 | } | ||
| 872 | |||
| 873 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) | ||
| 874 | offset = calc_rotation_offset_vrfb(var, fix, rotation); | ||
| 875 | else | ||
| 876 | offset = calc_rotation_offset_dma(var, fix, rotation); | ||
| 877 | |||
| 878 | data_start_p += offset; | ||
| 879 | data_start_v += offset; | ||
| 880 | |||
| 881 | if (offset) | ||
| 882 | DBG("offset %d, %d = %d\n", | ||
| 883 | var->xoffset, var->yoffset, offset); | ||
| 884 | |||
| 885 | DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v); | ||
| 886 | 902 | ||
| 887 | r = fb_mode_to_dss_mode(var, &mode); | 903 | r = fb_mode_to_dss_mode(var, &mode); |
| 888 | if (r) { | 904 | if (r) { |
| @@ -954,12 +970,14 @@ int omapfb_apply_changes(struct fb_info *fbi, int init) | |||
| 954 | fill_fb(fbi); | 970 | fill_fb(fbi); |
| 955 | #endif | 971 | #endif |
| 956 | 972 | ||
| 973 | WARN_ON(!atomic_read(&ofbi->region->lock_count)); | ||
| 974 | |||
| 957 | for (i = 0; i < ofbi->num_overlays; i++) { | 975 | for (i = 0; i < ofbi->num_overlays; i++) { |
| 958 | ovl = ofbi->overlays[i]; | 976 | ovl = ofbi->overlays[i]; |
| 959 | 977 | ||
| 960 | DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id); | 978 | DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id); |
| 961 | 979 | ||
| 962 | if (ofbi->region.size == 0) { | 980 | if (ofbi->region->size == 0) { |
| 963 | /* the fb is not available. disable the overlay */ | 981 | /* the fb is not available. disable the overlay */ |
| 964 | omapfb_overlay_enable(ovl, 0); | 982 | omapfb_overlay_enable(ovl, 0); |
| 965 | if (!init && ovl->manager) | 983 | if (!init && ovl->manager) |
| @@ -1007,36 +1025,48 @@ err: | |||
| 1007 | * DO NOT MODIFY PAR */ | 1025 | * DO NOT MODIFY PAR */ |
| 1008 | static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi) | 1026 | static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi) |
| 1009 | { | 1027 | { |
| 1028 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
| 1010 | int r; | 1029 | int r; |
| 1011 | 1030 | ||
| 1012 | DBG("check_var(%d)\n", FB2OFB(fbi)->id); | 1031 | DBG("check_var(%d)\n", FB2OFB(fbi)->id); |
| 1013 | 1032 | ||
| 1033 | omapfb_get_mem_region(ofbi->region); | ||
| 1034 | |||
| 1014 | r = check_fb_var(fbi, var); | 1035 | r = check_fb_var(fbi, var); |
| 1015 | 1036 | ||
| 1037 | omapfb_put_mem_region(ofbi->region); | ||
| 1038 | |||
| 1016 | return r; | 1039 | return r; |
| 1017 | } | 1040 | } |
| 1018 | 1041 | ||
| 1019 | /* set the video mode according to info->var */ | 1042 | /* set the video mode according to info->var */ |
| 1020 | static int omapfb_set_par(struct fb_info *fbi) | 1043 | static int omapfb_set_par(struct fb_info *fbi) |
| 1021 | { | 1044 | { |
| 1045 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
| 1022 | int r; | 1046 | int r; |
| 1023 | 1047 | ||
| 1024 | DBG("set_par(%d)\n", FB2OFB(fbi)->id); | 1048 | DBG("set_par(%d)\n", FB2OFB(fbi)->id); |
| 1025 | 1049 | ||
| 1050 | omapfb_get_mem_region(ofbi->region); | ||
| 1051 | |||
| 1026 | set_fb_fix(fbi); | 1052 | set_fb_fix(fbi); |
| 1027 | 1053 | ||
| 1028 | r = setup_vrfb_rotation(fbi); | 1054 | r = setup_vrfb_rotation(fbi); |
| 1029 | if (r) | 1055 | if (r) |
| 1030 | return r; | 1056 | goto out; |
| 1031 | 1057 | ||
| 1032 | r = omapfb_apply_changes(fbi, 0); | 1058 | r = omapfb_apply_changes(fbi, 0); |
| 1033 | 1059 | ||
| 1060 | out: | ||
| 1061 | omapfb_put_mem_region(ofbi->region); | ||
| 1062 | |||
| 1034 | return r; | 1063 | return r; |
| 1035 | } | 1064 | } |
| 1036 | 1065 | ||
| 1037 | static int omapfb_pan_display(struct fb_var_screeninfo *var, | 1066 | static int omapfb_pan_display(struct fb_var_screeninfo *var, |
| 1038 | struct fb_info *fbi) | 1067 | struct fb_info *fbi) |
| 1039 | { | 1068 | { |
| 1069 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
| 1040 | struct fb_var_screeninfo new_var; | 1070 | struct fb_var_screeninfo new_var; |
| 1041 | int r; | 1071 | int r; |
| 1042 | 1072 | ||
| @@ -1052,23 +1082,31 @@ static int omapfb_pan_display(struct fb_var_screeninfo *var, | |||
| 1052 | 1082 | ||
| 1053 | fbi->var = new_var; | 1083 | fbi->var = new_var; |
| 1054 | 1084 | ||
| 1085 | omapfb_get_mem_region(ofbi->region); | ||
| 1086 | |||
| 1055 | r = omapfb_apply_changes(fbi, 0); | 1087 | r = omapfb_apply_changes(fbi, 0); |
| 1056 | 1088 | ||
| 1089 | omapfb_put_mem_region(ofbi->region); | ||
| 1090 | |||
| 1057 | return r; | 1091 | return r; |
| 1058 | } | 1092 | } |
| 1059 | 1093 | ||
| 1060 | static void mmap_user_open(struct vm_area_struct *vma) | 1094 | static void mmap_user_open(struct vm_area_struct *vma) |
| 1061 | { | 1095 | { |
| 1062 | struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data; | 1096 | struct omapfb2_mem_region *rg = vma->vm_private_data; |
| 1063 | 1097 | ||
| 1064 | atomic_inc(&ofbi->map_count); | 1098 | omapfb_get_mem_region(rg); |
| 1099 | atomic_inc(&rg->map_count); | ||
| 1100 | omapfb_put_mem_region(rg); | ||
| 1065 | } | 1101 | } |
| 1066 | 1102 | ||
| 1067 | static void mmap_user_close(struct vm_area_struct *vma) | 1103 | static void mmap_user_close(struct vm_area_struct *vma) |
| 1068 | { | 1104 | { |
| 1069 | struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data; | 1105 | struct omapfb2_mem_region *rg = vma->vm_private_data; |
| 1070 | 1106 | ||
| 1071 | atomic_dec(&ofbi->map_count); | 1107 | omapfb_get_mem_region(rg); |
| 1108 | atomic_dec(&rg->map_count); | ||
| 1109 | omapfb_put_mem_region(rg); | ||
| 1072 | } | 1110 | } |
| 1073 | 1111 | ||
| 1074 | static struct vm_operations_struct mmap_user_ops = { | 1112 | static struct vm_operations_struct mmap_user_ops = { |
| @@ -1080,9 +1118,11 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) | |||
| 1080 | { | 1118 | { |
| 1081 | struct omapfb_info *ofbi = FB2OFB(fbi); | 1119 | struct omapfb_info *ofbi = FB2OFB(fbi); |
| 1082 | struct fb_fix_screeninfo *fix = &fbi->fix; | 1120 | struct fb_fix_screeninfo *fix = &fbi->fix; |
| 1121 | struct omapfb2_mem_region *rg; | ||
| 1083 | unsigned long off; | 1122 | unsigned long off; |
| 1084 | unsigned long start; | 1123 | unsigned long start; |
| 1085 | u32 len; | 1124 | u32 len; |
| 1125 | int r = -EINVAL; | ||
| 1086 | 1126 | ||
| 1087 | if (vma->vm_end - vma->vm_start == 0) | 1127 | if (vma->vm_end - vma->vm_start == 0) |
| 1088 | return 0; | 1128 | return 0; |
| @@ -1090,12 +1130,14 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) | |||
| 1090 | return -EINVAL; | 1130 | return -EINVAL; |
| 1091 | off = vma->vm_pgoff << PAGE_SHIFT; | 1131 | off = vma->vm_pgoff << PAGE_SHIFT; |
| 1092 | 1132 | ||
| 1133 | rg = omapfb_get_mem_region(ofbi->region); | ||
| 1134 | |||
| 1093 | start = omapfb_get_region_paddr(ofbi); | 1135 | start = omapfb_get_region_paddr(ofbi); |
| 1094 | len = fix->smem_len; | 1136 | len = fix->smem_len; |
| 1095 | if (off >= len) | 1137 | if (off >= len) |
| 1096 | return -EINVAL; | 1138 | goto error; |
| 1097 | if ((vma->vm_end - vma->vm_start + off) > len) | 1139 | if ((vma->vm_end - vma->vm_start + off) > len) |
| 1098 | return -EINVAL; | 1140 | goto error; |
| 1099 | 1141 | ||
| 1100 | off += start; | 1142 | off += start; |
| 1101 | 1143 | ||
| @@ -1105,13 +1147,25 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) | |||
| 1105 | vma->vm_flags |= VM_IO | VM_RESERVED; | 1147 | vma->vm_flags |= VM_IO | VM_RESERVED; |
| 1106 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); | 1148 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); |
| 1107 | vma->vm_ops = &mmap_user_ops; | 1149 | vma->vm_ops = &mmap_user_ops; |
| 1108 | vma->vm_private_data = ofbi; | 1150 | vma->vm_private_data = rg; |
| 1109 | if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, | 1151 | if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, |
| 1110 | vma->vm_end - vma->vm_start, vma->vm_page_prot)) | 1152 | vma->vm_end - vma->vm_start, |
| 1111 | return -EAGAIN; | 1153 | vma->vm_page_prot)) { |
| 1154 | r = -EAGAIN; | ||
| 1155 | goto error; | ||
| 1156 | } | ||
| 1157 | |||
| 1112 | /* vm_ops.open won't be called for mmap itself. */ | 1158 | /* vm_ops.open won't be called for mmap itself. */ |
| 1113 | atomic_inc(&ofbi->map_count); | 1159 | atomic_inc(&rg->map_count); |
| 1160 | |||
| 1161 | omapfb_put_mem_region(rg); | ||
| 1162 | |||
| 1114 | return 0; | 1163 | return 0; |
| 1164 | |||
| 1165 | error: | ||
| 1166 | omapfb_put_mem_region(ofbi->region); | ||
| 1167 | |||
| 1168 | return r; | ||
| 1115 | } | 1169 | } |
| 1116 | 1170 | ||
| 1117 | /* Store a single color palette entry into a pseudo palette or the hardware | 1171 | /* Store a single color palette entry into a pseudo palette or the hardware |
| @@ -1154,11 +1208,6 @@ static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green, | |||
| 1154 | if (r != 0) | 1208 | if (r != 0) |
| 1155 | break; | 1209 | break; |
| 1156 | 1210 | ||
| 1157 | if (regno < 0) { | ||
| 1158 | r = -EINVAL; | ||
| 1159 | break; | ||
| 1160 | } | ||
| 1161 | |||
| 1162 | if (regno < 16) { | 1211 | if (regno < 16) { |
| 1163 | u16 pal; | 1212 | u16 pal; |
| 1164 | pal = ((red >> (16 - var->red.length)) << | 1213 | pal = ((red >> (16 - var->red.length)) << |
| @@ -1217,6 +1266,9 @@ static int omapfb_blank(int blank, struct fb_info *fbi) | |||
| 1217 | int do_update = 0; | 1266 | int do_update = 0; |
| 1218 | int r = 0; | 1267 | int r = 0; |
| 1219 | 1268 | ||
| 1269 | if (!display) | ||
| 1270 | return -EINVAL; | ||
| 1271 | |||
| 1220 | omapfb_lock(fbdev); | 1272 | omapfb_lock(fbdev); |
| 1221 | 1273 | ||
| 1222 | switch (blank) { | 1274 | switch (blank) { |
| @@ -1300,7 +1352,9 @@ static void omapfb_free_fbmem(struct fb_info *fbi) | |||
| 1300 | struct omapfb2_device *fbdev = ofbi->fbdev; | 1352 | struct omapfb2_device *fbdev = ofbi->fbdev; |
| 1301 | struct omapfb2_mem_region *rg; | 1353 | struct omapfb2_mem_region *rg; |
| 1302 | 1354 | ||
| 1303 | rg = &ofbi->region; | 1355 | rg = ofbi->region; |
| 1356 | |||
| 1357 | WARN_ON(atomic_read(&rg->map_count)); | ||
| 1304 | 1358 | ||
| 1305 | if (rg->paddr) | 1359 | if (rg->paddr) |
| 1306 | if (omap_vram_free(rg->paddr, rg->size)) | 1360 | if (omap_vram_free(rg->paddr, rg->size)) |
| @@ -1355,8 +1409,15 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size, | |||
| 1355 | void __iomem *vaddr; | 1409 | void __iomem *vaddr; |
| 1356 | int r; | 1410 | int r; |
| 1357 | 1411 | ||
| 1358 | rg = &ofbi->region; | 1412 | rg = ofbi->region; |
| 1359 | memset(rg, 0, sizeof(*rg)); | 1413 | |
| 1414 | rg->paddr = 0; | ||
| 1415 | rg->vaddr = NULL; | ||
| 1416 | memset(&rg->vrfb, 0, sizeof rg->vrfb); | ||
| 1417 | rg->size = 0; | ||
| 1418 | rg->type = 0; | ||
| 1419 | rg->alloc = false; | ||
| 1420 | rg->map = false; | ||
| 1360 | 1421 | ||
| 1361 | size = PAGE_ALIGN(size); | 1422 | size = PAGE_ALIGN(size); |
| 1362 | 1423 | ||
| @@ -1609,7 +1670,7 @@ static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev) | |||
| 1609 | for (i = 0; i < fbdev->num_fbs; i++) { | 1670 | for (i = 0; i < fbdev->num_fbs; i++) { |
| 1610 | struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]); | 1671 | struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]); |
| 1611 | struct omapfb2_mem_region *rg; | 1672 | struct omapfb2_mem_region *rg; |
| 1612 | rg = &ofbi->region; | 1673 | rg = ofbi->region; |
| 1613 | 1674 | ||
| 1614 | DBG("region%d phys %08x virt %p size=%lu\n", | 1675 | DBG("region%d phys %08x virt %p size=%lu\n", |
| 1615 | i, | 1676 | i, |
| @@ -1626,7 +1687,7 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) | |||
| 1626 | struct omapfb_info *ofbi = FB2OFB(fbi); | 1687 | struct omapfb_info *ofbi = FB2OFB(fbi); |
| 1627 | struct omapfb2_device *fbdev = ofbi->fbdev; | 1688 | struct omapfb2_device *fbdev = ofbi->fbdev; |
| 1628 | struct omap_dss_device *display = fb2display(fbi); | 1689 | struct omap_dss_device *display = fb2display(fbi); |
| 1629 | struct omapfb2_mem_region *rg = &ofbi->region; | 1690 | struct omapfb2_mem_region *rg = ofbi->region; |
| 1630 | unsigned long old_size = rg->size; | 1691 | unsigned long old_size = rg->size; |
| 1631 | unsigned long old_paddr = rg->paddr; | 1692 | unsigned long old_paddr = rg->paddr; |
| 1632 | int old_type = rg->type; | 1693 | int old_type = rg->type; |
| @@ -1709,7 +1770,7 @@ static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi) | |||
| 1709 | fbi->flags = FBINFO_FLAG_DEFAULT; | 1770 | fbi->flags = FBINFO_FLAG_DEFAULT; |
| 1710 | fbi->pseudo_palette = fbdev->pseudo_palette; | 1771 | fbi->pseudo_palette = fbdev->pseudo_palette; |
| 1711 | 1772 | ||
| 1712 | if (ofbi->region.size == 0) { | 1773 | if (ofbi->region->size == 0) { |
| 1713 | clear_fb_info(fbi); | 1774 | clear_fb_info(fbi); |
| 1714 | return 0; | 1775 | return 0; |
| 1715 | } | 1776 | } |
| @@ -1871,6 +1932,10 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) | |||
| 1871 | ofbi->fbdev = fbdev; | 1932 | ofbi->fbdev = fbdev; |
| 1872 | ofbi->id = i; | 1933 | ofbi->id = i; |
| 1873 | 1934 | ||
| 1935 | ofbi->region = &fbdev->regions[i]; | ||
| 1936 | ofbi->region->id = i; | ||
| 1937 | init_rwsem(&ofbi->region->lock); | ||
| 1938 | |||
| 1874 | /* assign these early, so that fb alloc can use them */ | 1939 | /* assign these early, so that fb alloc can use them */ |
| 1875 | ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB : | 1940 | ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB : |
| 1876 | OMAP_DSS_ROT_DMA; | 1941 | OMAP_DSS_ROT_DMA; |
| @@ -1900,7 +1965,13 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) | |||
| 1900 | 1965 | ||
| 1901 | /* setup fb_infos */ | 1966 | /* setup fb_infos */ |
| 1902 | for (i = 0; i < fbdev->num_fbs; i++) { | 1967 | for (i = 0; i < fbdev->num_fbs; i++) { |
| 1903 | r = omapfb_fb_init(fbdev, fbdev->fbs[i]); | 1968 | struct fb_info *fbi = fbdev->fbs[i]; |
| 1969 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
| 1970 | |||
| 1971 | omapfb_get_mem_region(ofbi->region); | ||
| 1972 | r = omapfb_fb_init(fbdev, fbi); | ||
| 1973 | omapfb_put_mem_region(ofbi->region); | ||
| 1974 | |||
| 1904 | if (r) { | 1975 | if (r) { |
| 1905 | dev_err(fbdev->dev, "failed to setup fb_info\n"); | 1976 | dev_err(fbdev->dev, "failed to setup fb_info\n"); |
| 1906 | return r; | 1977 | return r; |
| @@ -1921,20 +1992,19 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) | |||
| 1921 | DBG("framebuffers registered\n"); | 1992 | DBG("framebuffers registered\n"); |
| 1922 | 1993 | ||
| 1923 | for (i = 0; i < fbdev->num_fbs; i++) { | 1994 | for (i = 0; i < fbdev->num_fbs; i++) { |
| 1924 | r = omapfb_apply_changes(fbdev->fbs[i], 1); | 1995 | struct fb_info *fbi = fbdev->fbs[i]; |
| 1996 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
| 1997 | |||
| 1998 | omapfb_get_mem_region(ofbi->region); | ||
| 1999 | r = omapfb_apply_changes(fbi, 1); | ||
| 2000 | omapfb_put_mem_region(ofbi->region); | ||
| 2001 | |||
| 1925 | if (r) { | 2002 | if (r) { |
| 1926 | dev_err(fbdev->dev, "failed to change mode\n"); | 2003 | dev_err(fbdev->dev, "failed to change mode\n"); |
| 1927 | return r; | 2004 | return r; |
| 1928 | } | 2005 | } |
| 1929 | } | 2006 | } |
| 1930 | 2007 | ||
| 1931 | DBG("create sysfs for fbs\n"); | ||
| 1932 | r = omapfb_create_sysfs(fbdev); | ||
| 1933 | if (r) { | ||
| 1934 | dev_err(fbdev->dev, "failed to create sysfs entries\n"); | ||
| 1935 | return r; | ||
| 1936 | } | ||
| 1937 | |||
| 1938 | /* Enable fb0 */ | 2008 | /* Enable fb0 */ |
| 1939 | if (fbdev->num_fbs > 0) { | 2009 | if (fbdev->num_fbs > 0) { |
| 1940 | struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]); | 2010 | struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]); |
| @@ -1968,11 +2038,11 @@ static int omapfb_mode_to_timings(const char *mode_str, | |||
| 1968 | #ifdef CONFIG_OMAP2_DSS_VENC | 2038 | #ifdef CONFIG_OMAP2_DSS_VENC |
| 1969 | if (strcmp(mode_str, "pal") == 0) { | 2039 | if (strcmp(mode_str, "pal") == 0) { |
| 1970 | *timings = omap_dss_pal_timings; | 2040 | *timings = omap_dss_pal_timings; |
| 1971 | *bpp = 0; | 2041 | *bpp = 24; |
| 1972 | return 0; | 2042 | return 0; |
| 1973 | } else if (strcmp(mode_str, "ntsc") == 0) { | 2043 | } else if (strcmp(mode_str, "ntsc") == 0) { |
| 1974 | *timings = omap_dss_ntsc_timings; | 2044 | *timings = omap_dss_ntsc_timings; |
| 1975 | *bpp = 0; | 2045 | *bpp = 24; |
| 1976 | return 0; | 2046 | return 0; |
| 1977 | } | 2047 | } |
| 1978 | #endif | 2048 | #endif |
| @@ -2220,6 +2290,13 @@ static int omapfb_probe(struct platform_device *pdev) | |||
| 2220 | } | 2290 | } |
| 2221 | } | 2291 | } |
| 2222 | 2292 | ||
| 2293 | DBG("create sysfs for fbs\n"); | ||
| 2294 | r = omapfb_create_sysfs(fbdev); | ||
| 2295 | if (r) { | ||
| 2296 | dev_err(fbdev->dev, "failed to create sysfs entries\n"); | ||
| 2297 | goto cleanup; | ||
| 2298 | } | ||
| 2299 | |||
| 2223 | return 0; | 2300 | return 0; |
| 2224 | 2301 | ||
| 2225 | cleanup: | 2302 | cleanup: |
diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index 5179219128b..6f9c72cd6bb 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c | |||
| @@ -49,6 +49,7 @@ static ssize_t store_rotate_type(struct device *dev, | |||
| 49 | { | 49 | { |
| 50 | struct fb_info *fbi = dev_get_drvdata(dev); | 50 | struct fb_info *fbi = dev_get_drvdata(dev); |
| 51 | struct omapfb_info *ofbi = FB2OFB(fbi); | 51 | struct omapfb_info *ofbi = FB2OFB(fbi); |
| 52 | struct omapfb2_mem_region *rg; | ||
| 52 | enum omap_dss_rotation_type rot_type; | 53 | enum omap_dss_rotation_type rot_type; |
| 53 | int r; | 54 | int r; |
| 54 | 55 | ||
| @@ -64,9 +65,11 @@ static ssize_t store_rotate_type(struct device *dev, | |||
| 64 | if (rot_type == ofbi->rotation_type) | 65 | if (rot_type == ofbi->rotation_type) |
| 65 | goto out; | 66 | goto out; |
| 66 | 67 | ||
| 67 | if (ofbi->region.size) { | 68 | rg = omapfb_get_mem_region(ofbi->region); |
| 69 | |||
| 70 | if (rg->size) { | ||
| 68 | r = -EBUSY; | 71 | r = -EBUSY; |
| 69 | goto out; | 72 | goto put_region; |
| 70 | } | 73 | } |
| 71 | 74 | ||
| 72 | ofbi->rotation_type = rot_type; | 75 | ofbi->rotation_type = rot_type; |
| @@ -75,6 +78,8 @@ static ssize_t store_rotate_type(struct device *dev, | |||
| 75 | * Since the VRAM for this FB is not allocated at the moment we don't | 78 | * Since the VRAM for this FB is not allocated at the moment we don't |
| 76 | * need to do any further parameter checking at this point. | 79 | * need to do any further parameter checking at this point. |
| 77 | */ | 80 | */ |
| 81 | put_region: | ||
| 82 | omapfb_put_mem_region(rg); | ||
| 78 | out: | 83 | out: |
| 79 | unlock_fb_info(fbi); | 84 | unlock_fb_info(fbi); |
| 80 | 85 | ||
| @@ -97,7 +102,7 @@ static ssize_t store_mirror(struct device *dev, | |||
| 97 | { | 102 | { |
| 98 | struct fb_info *fbi = dev_get_drvdata(dev); | 103 | struct fb_info *fbi = dev_get_drvdata(dev); |
| 99 | struct omapfb_info *ofbi = FB2OFB(fbi); | 104 | struct omapfb_info *ofbi = FB2OFB(fbi); |
| 100 | bool mirror; | 105 | unsigned long mirror; |
| 101 | int r; | 106 | int r; |
| 102 | struct fb_var_screeninfo new_var; | 107 | struct fb_var_screeninfo new_var; |
| 103 | 108 | ||
| @@ -111,6 +116,8 @@ static ssize_t store_mirror(struct device *dev, | |||
| 111 | 116 | ||
| 112 | ofbi->mirror = mirror; | 117 | ofbi->mirror = mirror; |
| 113 | 118 | ||
| 119 | omapfb_get_mem_region(ofbi->region); | ||
| 120 | |||
| 114 | memcpy(&new_var, &fbi->var, sizeof(new_var)); | 121 | memcpy(&new_var, &fbi->var, sizeof(new_var)); |
| 115 | r = check_fb_var(fbi, &new_var); | 122 | r = check_fb_var(fbi, &new_var); |
| 116 | if (r) | 123 | if (r) |
| @@ -125,6 +132,8 @@ static ssize_t store_mirror(struct device *dev, | |||
| 125 | 132 | ||
| 126 | r = count; | 133 | r = count; |
| 127 | out: | 134 | out: |
| 135 | omapfb_put_mem_region(ofbi->region); | ||
| 136 | |||
| 128 | unlock_fb_info(fbi); | 137 | unlock_fb_info(fbi); |
| 129 | 138 | ||
| 130 | return r; | 139 | return r; |
| @@ -263,11 +272,15 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr, | |||
| 263 | 272 | ||
| 264 | DBG("detaching %d\n", ofbi->overlays[i]->id); | 273 | DBG("detaching %d\n", ofbi->overlays[i]->id); |
| 265 | 274 | ||
| 275 | omapfb_get_mem_region(ofbi->region); | ||
| 276 | |||
| 266 | omapfb_overlay_enable(ovl, 0); | 277 | omapfb_overlay_enable(ovl, 0); |
| 267 | 278 | ||
| 268 | if (ovl->manager) | 279 | if (ovl->manager) |
| 269 | ovl->manager->apply(ovl->manager); | 280 | ovl->manager->apply(ovl->manager); |
| 270 | 281 | ||
| 282 | omapfb_put_mem_region(ofbi->region); | ||
| 283 | |||
| 271 | for (t = i + 1; t < ofbi->num_overlays; t++) { | 284 | for (t = i + 1; t < ofbi->num_overlays; t++) { |
| 272 | ofbi->rotation[t-1] = ofbi->rotation[t]; | 285 | ofbi->rotation[t-1] = ofbi->rotation[t]; |
| 273 | ofbi->overlays[t-1] = ofbi->overlays[t]; | 286 | ofbi->overlays[t-1] = ofbi->overlays[t]; |
| @@ -300,7 +313,12 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr, | |||
| 300 | } | 313 | } |
| 301 | 314 | ||
| 302 | if (added) { | 315 | if (added) { |
| 316 | omapfb_get_mem_region(ofbi->region); | ||
| 317 | |||
| 303 | r = omapfb_apply_changes(fbi, 0); | 318 | r = omapfb_apply_changes(fbi, 0); |
| 319 | |||
| 320 | omapfb_put_mem_region(ofbi->region); | ||
| 321 | |||
| 304 | if (r) | 322 | if (r) |
| 305 | goto out; | 323 | goto out; |
| 306 | } | 324 | } |
| @@ -388,7 +406,12 @@ static ssize_t store_overlays_rotate(struct device *dev, | |||
| 388 | for (i = 0; i < num_ovls; ++i) | 406 | for (i = 0; i < num_ovls; ++i) |
| 389 | ofbi->rotation[i] = rotation[i]; | 407 | ofbi->rotation[i] = rotation[i]; |
| 390 | 408 | ||
| 409 | omapfb_get_mem_region(ofbi->region); | ||
| 410 | |||
| 391 | r = omapfb_apply_changes(fbi, 0); | 411 | r = omapfb_apply_changes(fbi, 0); |
| 412 | |||
| 413 | omapfb_put_mem_region(ofbi->region); | ||
| 414 | |||
| 392 | if (r) | 415 | if (r) |
| 393 | goto out; | 416 | goto out; |
| 394 | 417 | ||
| @@ -408,7 +431,7 @@ static ssize_t show_size(struct device *dev, | |||
| 408 | struct fb_info *fbi = dev_get_drvdata(dev); | 431 | struct fb_info *fbi = dev_get_drvdata(dev); |
| 409 | struct omapfb_info *ofbi = FB2OFB(fbi); | 432 | struct omapfb_info *ofbi = FB2OFB(fbi); |
| 410 | 433 | ||
| 411 | return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region.size); | 434 | return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region->size); |
| 412 | } | 435 | } |
| 413 | 436 | ||
| 414 | static ssize_t store_size(struct device *dev, struct device_attribute *attr, | 437 | static ssize_t store_size(struct device *dev, struct device_attribute *attr, |
| @@ -416,6 +439,8 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, | |||
| 416 | { | 439 | { |
| 417 | struct fb_info *fbi = dev_get_drvdata(dev); | 440 | struct fb_info *fbi = dev_get_drvdata(dev); |
| 418 | struct omapfb_info *ofbi = FB2OFB(fbi); | 441 | struct omapfb_info *ofbi = FB2OFB(fbi); |
| 442 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
| 443 | struct omapfb2_mem_region *rg; | ||
| 419 | unsigned long size; | 444 | unsigned long size; |
| 420 | int r; | 445 | int r; |
| 421 | int i; | 446 | int i; |
| @@ -425,15 +450,33 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, | |||
| 425 | if (!lock_fb_info(fbi)) | 450 | if (!lock_fb_info(fbi)) |
| 426 | return -ENODEV; | 451 | return -ENODEV; |
| 427 | 452 | ||
| 428 | for (i = 0; i < ofbi->num_overlays; i++) { | 453 | rg = ofbi->region; |
| 429 | if (ofbi->overlays[i]->info.enabled) { | 454 | |
| 430 | r = -EBUSY; | 455 | down_write_nested(&rg->lock, rg->id); |
| 431 | goto out; | 456 | atomic_inc(&rg->lock_count); |
| 457 | |||
| 458 | if (atomic_read(&rg->map_count)) { | ||
| 459 | r = -EBUSY; | ||
| 460 | goto out; | ||
| 461 | } | ||
| 462 | |||
| 463 | for (i = 0; i < fbdev->num_fbs; i++) { | ||
| 464 | struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]); | ||
| 465 | int j; | ||
| 466 | |||
| 467 | if (ofbi2->region != rg) | ||
| 468 | continue; | ||
| 469 | |||
| 470 | for (j = 0; j < ofbi2->num_overlays; j++) { | ||
| 471 | if (ofbi2->overlays[j]->info.enabled) { | ||
| 472 | r = -EBUSY; | ||
| 473 | goto out; | ||
| 474 | } | ||
| 432 | } | 475 | } |
| 433 | } | 476 | } |
| 434 | 477 | ||
| 435 | if (size != ofbi->region.size) { | 478 | if (size != ofbi->region->size) { |
| 436 | r = omapfb_realloc_fbmem(fbi, size, ofbi->region.type); | 479 | r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type); |
| 437 | if (r) { | 480 | if (r) { |
| 438 | dev_err(dev, "realloc fbmem failed\n"); | 481 | dev_err(dev, "realloc fbmem failed\n"); |
| 439 | goto out; | 482 | goto out; |
| @@ -442,6 +485,9 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, | |||
| 442 | 485 | ||
| 443 | r = count; | 486 | r = count; |
| 444 | out: | 487 | out: |
| 488 | atomic_dec(&rg->lock_count); | ||
| 489 | up_write(&rg->lock); | ||
| 490 | |||
| 445 | unlock_fb_info(fbi); | 491 | unlock_fb_info(fbi); |
| 446 | 492 | ||
| 447 | return r; | 493 | return r; |
| @@ -453,7 +499,7 @@ static ssize_t show_phys(struct device *dev, | |||
| 453 | struct fb_info *fbi = dev_get_drvdata(dev); | 499 | struct fb_info *fbi = dev_get_drvdata(dev); |
| 454 | struct omapfb_info *ofbi = FB2OFB(fbi); | 500 | struct omapfb_info *ofbi = FB2OFB(fbi); |
| 455 | 501 | ||
| 456 | return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region.paddr); | 502 | return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region->paddr); |
| 457 | } | 503 | } |
| 458 | 504 | ||
| 459 | static ssize_t show_virt(struct device *dev, | 505 | static ssize_t show_virt(struct device *dev, |
| @@ -462,7 +508,7 @@ static ssize_t show_virt(struct device *dev, | |||
| 462 | struct fb_info *fbi = dev_get_drvdata(dev); | 508 | struct fb_info *fbi = dev_get_drvdata(dev); |
| 463 | struct omapfb_info *ofbi = FB2OFB(fbi); | 509 | struct omapfb_info *ofbi = FB2OFB(fbi); |
| 464 | 510 | ||
| 465 | return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region.vaddr); | 511 | return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr); |
| 466 | } | 512 | } |
| 467 | 513 | ||
| 468 | static struct device_attribute omapfb_attrs[] = { | 514 | static struct device_attribute omapfb_attrs[] = { |
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index cd54fdbfd8b..1305fc9880b 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h | |||
| @@ -27,6 +27,8 @@ | |||
| 27 | #define DEBUG | 27 | #define DEBUG |
| 28 | #endif | 28 | #endif |
| 29 | 29 | ||
| 30 | #include <linux/rwsem.h> | ||
| 31 | |||
| 30 | #include <plat/display.h> | 32 | #include <plat/display.h> |
| 31 | 33 | ||
| 32 | #ifdef DEBUG | 34 | #ifdef DEBUG |
| @@ -44,6 +46,7 @@ extern unsigned int omapfb_debug; | |||
| 44 | #define OMAPFB_MAX_OVL_PER_FB 3 | 46 | #define OMAPFB_MAX_OVL_PER_FB 3 |
| 45 | 47 | ||
| 46 | struct omapfb2_mem_region { | 48 | struct omapfb2_mem_region { |
| 49 | int id; | ||
| 47 | u32 paddr; | 50 | u32 paddr; |
| 48 | void __iomem *vaddr; | 51 | void __iomem *vaddr; |
| 49 | struct vrfb vrfb; | 52 | struct vrfb vrfb; |
| @@ -51,13 +54,15 @@ struct omapfb2_mem_region { | |||
| 51 | u8 type; /* OMAPFB_PLANE_MEM_* */ | 54 | u8 type; /* OMAPFB_PLANE_MEM_* */ |
| 52 | bool alloc; /* allocated by the driver */ | 55 | bool alloc; /* allocated by the driver */ |
| 53 | bool map; /* kernel mapped by the driver */ | 56 | bool map; /* kernel mapped by the driver */ |
| 57 | atomic_t map_count; | ||
| 58 | struct rw_semaphore lock; | ||
| 59 | atomic_t lock_count; | ||
| 54 | }; | 60 | }; |
| 55 | 61 | ||
| 56 | /* appended to fb_info */ | 62 | /* appended to fb_info */ |
| 57 | struct omapfb_info { | 63 | struct omapfb_info { |
| 58 | int id; | 64 | int id; |
| 59 | struct omapfb2_mem_region region; | 65 | struct omapfb2_mem_region *region; |
| 60 | atomic_t map_count; | ||
| 61 | int num_overlays; | 66 | int num_overlays; |
| 62 | struct omap_overlay *overlays[OMAPFB_MAX_OVL_PER_FB]; | 67 | struct omap_overlay *overlays[OMAPFB_MAX_OVL_PER_FB]; |
| 63 | struct omapfb2_device *fbdev; | 68 | struct omapfb2_device *fbdev; |
| @@ -76,6 +81,7 @@ struct omapfb2_device { | |||
| 76 | 81 | ||
| 77 | unsigned num_fbs; | 82 | unsigned num_fbs; |
| 78 | struct fb_info *fbs[10]; | 83 | struct fb_info *fbs[10]; |
| 84 | struct omapfb2_mem_region regions[10]; | ||
| 79 | 85 | ||
| 80 | unsigned num_displays; | 86 | unsigned num_displays; |
| 81 | struct omap_dss_device *displays[10]; | 87 | struct omap_dss_device *displays[10]; |
| @@ -117,6 +123,9 @@ int omapfb_update_window(struct fb_info *fbi, | |||
| 117 | int dss_mode_to_fb_mode(enum omap_color_mode dssmode, | 123 | int dss_mode_to_fb_mode(enum omap_color_mode dssmode, |
| 118 | struct fb_var_screeninfo *var); | 124 | struct fb_var_screeninfo *var); |
| 119 | 125 | ||
| 126 | int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, | ||
| 127 | u16 posx, u16 posy, u16 outw, u16 outh); | ||
| 128 | |||
| 120 | /* find the display connected to this fb, if any */ | 129 | /* find the display connected to this fb, if any */ |
| 121 | static inline struct omap_dss_device *fb2display(struct fb_info *fbi) | 130 | static inline struct omap_dss_device *fb2display(struct fb_info *fbi) |
| 122 | { | 131 | { |
| @@ -148,8 +157,24 @@ static inline int omapfb_overlay_enable(struct omap_overlay *ovl, | |||
| 148 | struct omap_overlay_info info; | 157 | struct omap_overlay_info info; |
| 149 | 158 | ||
| 150 | ovl->get_overlay_info(ovl, &info); | 159 | ovl->get_overlay_info(ovl, &info); |
| 160 | if (info.enabled == enable) | ||
| 161 | return 0; | ||
| 151 | info.enabled = enable; | 162 | info.enabled = enable; |
| 152 | return ovl->set_overlay_info(ovl, &info); | 163 | return ovl->set_overlay_info(ovl, &info); |
| 153 | } | 164 | } |
| 154 | 165 | ||
| 166 | static inline struct omapfb2_mem_region * | ||
| 167 | omapfb_get_mem_region(struct omapfb2_mem_region *rg) | ||
| 168 | { | ||
| 169 | down_read_nested(&rg->lock, rg->id); | ||
| 170 | atomic_inc(&rg->lock_count); | ||
| 171 | return rg; | ||
| 172 | } | ||
| 173 | |||
| 174 | static inline void omapfb_put_mem_region(struct omapfb2_mem_region *rg) | ||
| 175 | { | ||
| 176 | atomic_dec(&rg->lock_count); | ||
| 177 | up_read(&rg->lock); | ||
| 178 | } | ||
| 179 | |||
| 155 | #endif | 180 | #endif |
diff --git a/include/linux/omapfb.h b/include/linux/omapfb.h index 7e4cd616bcb..c0b018790f0 100644 --- a/include/linux/omapfb.h +++ b/include/linux/omapfb.h | |||
| @@ -85,6 +85,9 @@ | |||
| 85 | #define OMAPFB_MEMTYPE_SRAM 1 | 85 | #define OMAPFB_MEMTYPE_SRAM 1 |
| 86 | #define OMAPFB_MEMTYPE_MAX 1 | 86 | #define OMAPFB_MEMTYPE_MAX 1 |
| 87 | 87 | ||
| 88 | #define OMAPFB_MEM_IDX_ENABLED 0x80 | ||
| 89 | #define OMAPFB_MEM_IDX_MASK 0x7f | ||
| 90 | |||
| 88 | enum omapfb_color_format { | 91 | enum omapfb_color_format { |
| 89 | OMAPFB_COLOR_RGB565 = 0, | 92 | OMAPFB_COLOR_RGB565 = 0, |
| 90 | OMAPFB_COLOR_YUV422, | 93 | OMAPFB_COLOR_YUV422, |
| @@ -136,7 +139,7 @@ struct omapfb_plane_info { | |||
| 136 | __u8 enabled; | 139 | __u8 enabled; |
| 137 | __u8 channel_out; | 140 | __u8 channel_out; |
| 138 | __u8 mirror; | 141 | __u8 mirror; |
| 139 | __u8 reserved1; | 142 | __u8 mem_idx; |
| 140 | __u32 out_width; | 143 | __u32 out_width; |
| 141 | __u32 out_height; | 144 | __u32 out_height; |
| 142 | __u32 reserved2[12]; | 145 | __u32 reserved2[12]; |
