diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-01-07 18:17:52 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-01-07 18:17:52 -0500 |
commit | 17cb3be61b45d716f6b21a9380925493413ce0ed (patch) | |
tree | d29ca8bc010a22f358032346d7e7b6887c455e08 | |
parent | d7f9729f6e06c9613a88a18c4e1fbbdf2f6146fd (diff) | |
parent | e16a922a27ec352537a8027cadc32dc156534ca5 (diff) |
Merge branch 'staging-linus' into staging-next
This is to get the comedi fixes, and resolve the issue in comdi_test.c
and comedi_fops.c that were caused by changes in both branches.
It also allows the fwserial driver changes to be applied, as they
required the fixes that are in staging-linus.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
49 files changed, 1366 insertions, 967 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index fe4bcd7c5b12..05e996fafc9d 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig | |||
@@ -8,6 +8,7 @@ config HID_SENSOR_ACCEL_3D | |||
8 | select IIO_BUFFER | 8 | select IIO_BUFFER |
9 | select IIO_TRIGGERED_BUFFER | 9 | select IIO_TRIGGERED_BUFFER |
10 | select HID_SENSOR_IIO_COMMON | 10 | select HID_SENSOR_IIO_COMMON |
11 | select HID_SENSOR_IIO_TRIGGER | ||
11 | tristate "HID Accelerometers 3D" | 12 | tristate "HID Accelerometers 3D" |
12 | help | 13 | help |
13 | Say yes here to build support for the HID SENSOR | 14 | Say yes here to build support for the HID SENSOR |
diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index a6f4fc5f8201..e36107dc30b9 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c | |||
@@ -411,7 +411,11 @@ static int __devinit ad7266_probe(struct spi_device *spi) | |||
411 | if (ret) | 411 | if (ret) |
412 | goto error_put_reg; | 412 | goto error_put_reg; |
413 | 413 | ||
414 | st->vref_uv = regulator_get_voltage(st->reg); | 414 | ret = regulator_get_voltage(st->reg); |
415 | if (ret < 0) | ||
416 | goto error_disable_reg; | ||
417 | |||
418 | st->vref_uv = ret; | ||
415 | } else { | 419 | } else { |
416 | /* Use internal reference */ | 420 | /* Use internal reference */ |
417 | st->vref_uv = 2500000; | 421 | st->vref_uv = 2500000; |
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 03b85940f4ba..315bed1f401f 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c | |||
@@ -80,7 +80,7 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p) | |||
80 | *timestamp = pf->timestamp; | 80 | *timestamp = pf->timestamp; |
81 | } | 81 | } |
82 | 82 | ||
83 | iio_push_to_buffers(indio_dev, (u8 *)st->buffer); | 83 | iio_push_to_buffers(idev, (u8 *)st->buffer); |
84 | 84 | ||
85 | iio_trigger_notify_done(idev->trig); | 85 | iio_trigger_notify_done(idev->trig); |
86 | 86 | ||
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 0ba4fea960ac..aac572290cbf 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c | |||
@@ -1558,17 +1558,18 @@ static int __devinit max1363_probe(struct i2c_client *client, | |||
1558 | 1558 | ||
1559 | return 0; | 1559 | return 0; |
1560 | error_free_irq: | 1560 | error_free_irq: |
1561 | free_irq(st->client->irq, indio_dev); | 1561 | if (client->irq) |
1562 | free_irq(st->client->irq, indio_dev); | ||
1562 | error_uninit_buffer: | 1563 | error_uninit_buffer: |
1563 | iio_triggered_buffer_cleanup(indio_dev); | 1564 | iio_triggered_buffer_cleanup(indio_dev); |
1564 | error_free_available_scan_masks: | 1565 | error_free_available_scan_masks: |
1565 | kfree(indio_dev->available_scan_masks); | 1566 | kfree(indio_dev->available_scan_masks); |
1566 | error_unregister_map: | ||
1567 | iio_map_array_unregister(indio_dev, client->dev.platform_data); | ||
1568 | error_disable_reg: | 1567 | error_disable_reg: |
1569 | regulator_disable(st->reg); | 1568 | regulator_disable(st->reg); |
1570 | error_put_reg: | 1569 | error_put_reg: |
1571 | regulator_put(st->reg); | 1570 | regulator_put(st->reg); |
1571 | error_unregister_map: | ||
1572 | iio_map_array_unregister(indio_dev, client->dev.platform_data); | ||
1572 | error_free_device: | 1573 | error_free_device: |
1573 | iio_device_free(indio_dev); | 1574 | iio_device_free(indio_dev); |
1574 | error_out: | 1575 | error_out: |
@@ -1585,10 +1586,8 @@ static int __devexit max1363_remove(struct i2c_client *client) | |||
1585 | free_irq(st->client->irq, indio_dev); | 1586 | free_irq(st->client->irq, indio_dev); |
1586 | iio_triggered_buffer_cleanup(indio_dev); | 1587 | iio_triggered_buffer_cleanup(indio_dev); |
1587 | kfree(indio_dev->available_scan_masks); | 1588 | kfree(indio_dev->available_scan_masks); |
1588 | if (!IS_ERR(st->reg)) { | 1589 | regulator_disable(st->reg); |
1589 | regulator_disable(st->reg); | 1590 | regulator_put(st->reg); |
1590 | regulator_put(st->reg); | ||
1591 | } | ||
1592 | iio_map_array_unregister(indio_dev, client->dev.platform_data); | 1591 | iio_map_array_unregister(indio_dev, client->dev.platform_data); |
1593 | iio_device_free(indio_dev); | 1592 | iio_device_free(indio_dev); |
1594 | 1593 | ||
diff --git a/drivers/iio/common/hid-sensors/Kconfig b/drivers/iio/common/hid-sensors/Kconfig index ae10778da7aa..1178121b55b0 100644 --- a/drivers/iio/common/hid-sensors/Kconfig +++ b/drivers/iio/common/hid-sensors/Kconfig | |||
@@ -6,7 +6,7 @@ menu "Hid Sensor IIO Common" | |||
6 | config HID_SENSOR_IIO_COMMON | 6 | config HID_SENSOR_IIO_COMMON |
7 | tristate "Common modules for all HID Sensor IIO drivers" | 7 | tristate "Common modules for all HID Sensor IIO drivers" |
8 | depends on HID_SENSOR_HUB | 8 | depends on HID_SENSOR_HUB |
9 | select IIO_TRIGGER if IIO_BUFFER | 9 | select HID_SENSOR_IIO_TRIGGER if IIO_BUFFER |
10 | help | 10 | help |
11 | Say yes here to build support for HID sensor to use | 11 | Say yes here to build support for HID sensor to use |
12 | HID sensor common processing for attributes and IIO triggers. | 12 | HID sensor common processing for attributes and IIO triggers. |
@@ -14,6 +14,17 @@ config HID_SENSOR_IIO_COMMON | |||
14 | HID sensor drivers, this module contains processing for those | 14 | HID sensor drivers, this module contains processing for those |
15 | attributes. | 15 | attributes. |
16 | 16 | ||
17 | config HID_SENSOR_IIO_TRIGGER | ||
18 | tristate "Common module (trigger) for all HID Sensor IIO drivers" | ||
19 | depends on HID_SENSOR_HUB && HID_SENSOR_IIO_COMMON | ||
20 | select IIO_TRIGGER | ||
21 | help | ||
22 | Say yes here to build trigger support for HID sensors. | ||
23 | Triggers will be send if all requested attributes were read. | ||
24 | |||
25 | If this driver is compiled as a module, it will be named | ||
26 | hid-sensor-trigger. | ||
27 | |||
17 | config HID_SENSOR_ENUM_BASE_QUIRKS | 28 | config HID_SENSOR_ENUM_BASE_QUIRKS |
18 | bool "ENUM base quirks for HID Sensor IIO drivers" | 29 | bool "ENUM base quirks for HID Sensor IIO drivers" |
19 | depends on HID_SENSOR_IIO_COMMON | 30 | depends on HID_SENSOR_IIO_COMMON |
diff --git a/drivers/iio/common/hid-sensors/Makefile b/drivers/iio/common/hid-sensors/Makefile index 1f463e00c242..22e7c5a82325 100644 --- a/drivers/iio/common/hid-sensors/Makefile +++ b/drivers/iio/common/hid-sensors/Makefile | |||
@@ -3,4 +3,5 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_HID_SENSOR_IIO_COMMON) += hid-sensor-iio-common.o | 5 | obj-$(CONFIG_HID_SENSOR_IIO_COMMON) += hid-sensor-iio-common.o |
6 | hid-sensor-iio-common-y := hid-sensor-attributes.o hid-sensor-trigger.o | 6 | obj-$(CONFIG_HID_SENSOR_IIO_TRIGGER) += hid-sensor-trigger.o |
7 | hid-sensor-iio-common-y := hid-sensor-attributes.o | ||
diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 14991ac55f26..4aca1895ce52 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c | |||
@@ -406,7 +406,11 @@ static int __devinit ad5380_probe(struct device *dev, struct regmap *regmap, | |||
406 | goto error_free_reg; | 406 | goto error_free_reg; |
407 | } | 407 | } |
408 | 408 | ||
409 | st->vref = regulator_get_voltage(st->vref_reg); | 409 | ret = regulator_get_voltage(st->vref_reg); |
410 | if (ret < 0) | ||
411 | goto error_disable_reg; | ||
412 | |||
413 | st->vref = ret; | ||
410 | } else { | 414 | } else { |
411 | st->vref = st->chip_info->int_vref; | 415 | st->vref = st->chip_info->int_vref; |
412 | ctrl |= AD5380_CTRL_INT_VREF_EN; | 416 | ctrl |= AD5380_CTRL_INT_VREF_EN; |
diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c index 3310cbbd41e7..ecb639540dff 100644 --- a/drivers/iio/dac/ad5446.c +++ b/drivers/iio/dac/ad5446.c | |||
@@ -226,7 +226,11 @@ static int __devinit ad5446_probe(struct device *dev, const char *name, | |||
226 | if (ret) | 226 | if (ret) |
227 | goto error_put_reg; | 227 | goto error_put_reg; |
228 | 228 | ||
229 | voltage_uv = regulator_get_voltage(reg); | 229 | ret = regulator_get_voltage(reg); |
230 | if (ret < 0) | ||
231 | goto error_disable_reg; | ||
232 | |||
233 | voltage_uv = ret; | ||
230 | } | 234 | } |
231 | 235 | ||
232 | indio_dev = iio_device_alloc(sizeof(*st)); | 236 | indio_dev = iio_device_alloc(sizeof(*st)); |
diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index 242bdc7d0044..7f7c026b9d8a 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c | |||
@@ -296,7 +296,11 @@ static int __devinit ad5504_probe(struct spi_device *spi) | |||
296 | if (ret) | 296 | if (ret) |
297 | goto error_put_reg; | 297 | goto error_put_reg; |
298 | 298 | ||
299 | voltage_uv = regulator_get_voltage(reg); | 299 | ret = regulator_get_voltage(reg); |
300 | if (ret < 0) | ||
301 | goto error_disable_reg; | ||
302 | |||
303 | voltage_uv = ret; | ||
300 | } | 304 | } |
301 | 305 | ||
302 | spi_set_drvdata(spi, indio_dev); | 306 | spi_set_drvdata(spi, indio_dev); |
diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c index 6a7d6a48cc6d..14ea3dbf4902 100644 --- a/drivers/iio/dac/ad5624r_spi.c +++ b/drivers/iio/dac/ad5624r_spi.c | |||
@@ -238,7 +238,11 @@ static int __devinit ad5624r_probe(struct spi_device *spi) | |||
238 | if (ret) | 238 | if (ret) |
239 | goto error_put_reg; | 239 | goto error_put_reg; |
240 | 240 | ||
241 | voltage_uv = regulator_get_voltage(st->reg); | 241 | ret = regulator_get_voltage(st->reg); |
242 | if (ret < 0) | ||
243 | goto error_disable_reg; | ||
244 | |||
245 | voltage_uv = ret; | ||
242 | } | 246 | } |
243 | 247 | ||
244 | spi_set_drvdata(spi, indio_dev); | 248 | spi_set_drvdata(spi, indio_dev); |
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index bc92ff9309c2..01eb1d0e4e41 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c | |||
@@ -332,7 +332,11 @@ static int __devinit ad5686_probe(struct spi_device *spi) | |||
332 | if (ret) | 332 | if (ret) |
333 | goto error_put_reg; | 333 | goto error_put_reg; |
334 | 334 | ||
335 | voltage_uv = regulator_get_voltage(st->reg); | 335 | ret = regulator_get_voltage(st->reg); |
336 | if (ret < 0) | ||
337 | goto error_disable_reg; | ||
338 | |||
339 | voltage_uv = ret; | ||
336 | } | 340 | } |
337 | 341 | ||
338 | st->chip_info = | 342 | st->chip_info = |
diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index 2bd2e37280ff..6efe83e32ac6 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c | |||
@@ -365,7 +365,11 @@ static int __devinit ad5791_probe(struct spi_device *spi) | |||
365 | if (ret) | 365 | if (ret) |
366 | goto error_put_reg_pos; | 366 | goto error_put_reg_pos; |
367 | 367 | ||
368 | pos_voltage_uv = regulator_get_voltage(st->reg_vdd); | 368 | ret = regulator_get_voltage(st->reg_vdd); |
369 | if (ret < 0) | ||
370 | goto error_disable_reg_pos; | ||
371 | |||
372 | pos_voltage_uv = ret; | ||
369 | } | 373 | } |
370 | 374 | ||
371 | st->reg_vss = regulator_get(&spi->dev, "vss"); | 375 | st->reg_vss = regulator_get(&spi->dev, "vss"); |
@@ -374,7 +378,11 @@ static int __devinit ad5791_probe(struct spi_device *spi) | |||
374 | if (ret) | 378 | if (ret) |
375 | goto error_put_reg_neg; | 379 | goto error_put_reg_neg; |
376 | 380 | ||
377 | neg_voltage_uv = regulator_get_voltage(st->reg_vss); | 381 | ret = regulator_get_voltage(st->reg_vss); |
382 | if (ret < 0) | ||
383 | goto error_disable_reg_neg; | ||
384 | |||
385 | neg_voltage_uv = ret; | ||
378 | } | 386 | } |
379 | 387 | ||
380 | st->pwr_down = true; | 388 | st->pwr_down = true; |
@@ -428,6 +436,7 @@ error_put_reg_neg: | |||
428 | if (!IS_ERR(st->reg_vss)) | 436 | if (!IS_ERR(st->reg_vss)) |
429 | regulator_put(st->reg_vss); | 437 | regulator_put(st->reg_vss); |
430 | 438 | ||
439 | error_disable_reg_pos: | ||
431 | if (!IS_ERR(st->reg_vdd)) | 440 | if (!IS_ERR(st->reg_vdd)) |
432 | regulator_disable(st->reg_vdd); | 441 | regulator_disable(st->reg_vdd); |
433 | error_put_reg_pos: | 442 | error_put_reg_pos: |
diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index e35bb8f6fe75..c7de8b5a01ff 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c | |||
@@ -173,7 +173,7 @@ static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq) | |||
173 | } while ((st->r1_mod > ADF4350_MAX_MODULUS) && r_cnt); | 173 | } while ((st->r1_mod > ADF4350_MAX_MODULUS) && r_cnt); |
174 | } while (r_cnt == 0); | 174 | } while (r_cnt == 0); |
175 | 175 | ||
176 | tmp = freq * (u64)st->r1_mod + (st->fpfd > 1); | 176 | tmp = freq * (u64)st->r1_mod + (st->fpfd >> 1); |
177 | do_div(tmp, st->fpfd); /* Div round closest (n + d/2)/d */ | 177 | do_div(tmp, st->fpfd); /* Div round closest (n + d/2)/d */ |
178 | st->r0_fract = do_div(tmp, st->r1_mod); | 178 | st->r0_fract = do_div(tmp, st->r1_mod); |
179 | st->r0_int = tmp; | 179 | st->r0_int = tmp; |
diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig index 48ed1483ff27..96b68f63a902 100644 --- a/drivers/iio/gyro/Kconfig +++ b/drivers/iio/gyro/Kconfig | |||
@@ -17,6 +17,7 @@ config HID_SENSOR_GYRO_3D | |||
17 | select IIO_BUFFER | 17 | select IIO_BUFFER |
18 | select IIO_TRIGGERED_BUFFER | 18 | select IIO_TRIGGERED_BUFFER |
19 | select HID_SENSOR_IIO_COMMON | 19 | select HID_SENSOR_IIO_COMMON |
20 | select HID_SENSOR_IIO_TRIGGER | ||
20 | tristate "HID Gyroscope 3D" | 21 | tristate "HID Gyroscope 3D" |
21 | help | 22 | help |
22 | Say yes here to build support for the HID SENSOR | 23 | Say yes here to build support for the HID SENSOR |
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 1763c9bcb98a..dbf80abc834f 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig | |||
@@ -47,6 +47,7 @@ config HID_SENSOR_ALS | |||
47 | select IIO_BUFFER | 47 | select IIO_BUFFER |
48 | select IIO_TRIGGERED_BUFFER | 48 | select IIO_TRIGGERED_BUFFER |
49 | select HID_SENSOR_IIO_COMMON | 49 | select HID_SENSOR_IIO_COMMON |
50 | select HID_SENSOR_IIO_TRIGGER | ||
50 | tristate "HID ALS" | 51 | tristate "HID ALS" |
51 | help | 52 | help |
52 | Say yes here to build support for the HID SENSOR | 53 | Say yes here to build support for the HID SENSOR |
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index c1f0cdd57037..ff11d68225cf 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig | |||
@@ -8,6 +8,7 @@ config HID_SENSOR_MAGNETOMETER_3D | |||
8 | select IIO_BUFFER | 8 | select IIO_BUFFER |
9 | select IIO_TRIGGERED_BUFFER | 9 | select IIO_TRIGGERED_BUFFER |
10 | select HID_SENSOR_IIO_COMMON | 10 | select HID_SENSOR_IIO_COMMON |
11 | select HID_SENSOR_IIO_TRIGGER | ||
11 | tristate "HID Magenetometer 3D" | 12 | tristate "HID Magenetometer 3D" |
12 | help | 13 | help |
13 | Say yes here to build support for the HID SENSOR | 14 | Say yes here to build support for the HID SENSOR |
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 7de2a10213bd..36eec320569c 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig | |||
@@ -444,6 +444,7 @@ config COMEDI_ADQ12B | |||
444 | 444 | ||
445 | config COMEDI_NI_AT_A2150 | 445 | config COMEDI_NI_AT_A2150 |
446 | tristate "NI AT-A2150 ISA card support" | 446 | tristate "NI AT-A2150 ISA card support" |
447 | select COMEDI_FC | ||
447 | depends on VIRT_TO_BUS | 448 | depends on VIRT_TO_BUS |
448 | ---help--- | 449 | ---help--- |
449 | Enable support for National Instruments AT-A2150 cards | 450 | Enable support for National Instruments AT-A2150 cards |
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 2fd577fa941e..cd2c7d40d4db 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c | |||
@@ -1648,6 +1648,7 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, | |||
1648 | { | 1648 | { |
1649 | const unsigned minor = iminor(file->f_dentry->d_inode); | 1649 | const unsigned minor = iminor(file->f_dentry->d_inode); |
1650 | struct comedi_device *dev = comedi_dev_from_minor(minor); | 1650 | struct comedi_device *dev = comedi_dev_from_minor(minor); |
1651 | struct comedi_file_info *info = comedi_file_info_from_minor(minor); | ||
1651 | int rc; | 1652 | int rc; |
1652 | 1653 | ||
1653 | if (!dev) | 1654 | if (!dev) |
@@ -1660,6 +1661,9 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, | |||
1660 | if (cmd == COMEDI_DEVCONFIG) { | 1661 | if (cmd == COMEDI_DEVCONFIG) { |
1661 | rc = do_devconfig_ioctl(dev, | 1662 | rc = do_devconfig_ioctl(dev, |
1662 | (struct comedi_devconfig __user *)arg); | 1663 | (struct comedi_devconfig __user *)arg); |
1664 | if (rc == 0) | ||
1665 | /* Evade comedi_auto_unconfig(). */ | ||
1666 | info->hardware_device = NULL; | ||
1663 | goto done; | 1667 | goto done; |
1664 | } | 1668 | } |
1665 | 1669 | ||
diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c index aaac0b2cc9eb..fd1662b4175d 100644 --- a/drivers/staging/comedi/drivers/ni_pcimio.c +++ b/drivers/staging/comedi/drivers/ni_pcimio.c | |||
@@ -963,7 +963,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
963 | .ao_range_table = &range_ni_M_625x_ao, | 963 | .ao_range_table = &range_ni_M_625x_ao, |
964 | .reg_type = ni_reg_625x, | 964 | .reg_type = ni_reg_625x, |
965 | .ao_unipolar = 0, | 965 | .ao_unipolar = 0, |
966 | .ao_speed = 357, | 966 | .ao_speed = 350, |
967 | .num_p0_dio_channels = 8, | 967 | .num_p0_dio_channels = 8, |
968 | .caldac = {caldac_none}, | 968 | .caldac = {caldac_none}, |
969 | .has_8255 = 0, | 969 | .has_8255 = 0, |
@@ -982,7 +982,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
982 | .ao_range_table = &range_ni_M_625x_ao, | 982 | .ao_range_table = &range_ni_M_625x_ao, |
983 | .reg_type = ni_reg_625x, | 983 | .reg_type = ni_reg_625x, |
984 | .ao_unipolar = 0, | 984 | .ao_unipolar = 0, |
985 | .ao_speed = 357, | 985 | .ao_speed = 350, |
986 | .num_p0_dio_channels = 8, | 986 | .num_p0_dio_channels = 8, |
987 | .caldac = {caldac_none}, | 987 | .caldac = {caldac_none}, |
988 | .has_8255 = 0, | 988 | .has_8255 = 0, |
@@ -1001,7 +1001,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
1001 | .ao_range_table = &range_ni_M_625x_ao, | 1001 | .ao_range_table = &range_ni_M_625x_ao, |
1002 | .reg_type = ni_reg_625x, | 1002 | .reg_type = ni_reg_625x, |
1003 | .ao_unipolar = 0, | 1003 | .ao_unipolar = 0, |
1004 | .ao_speed = 357, | 1004 | .ao_speed = 350, |
1005 | .num_p0_dio_channels = 8, | 1005 | .num_p0_dio_channels = 8, |
1006 | .caldac = {caldac_none}, | 1006 | .caldac = {caldac_none}, |
1007 | .has_8255 = 0, | 1007 | .has_8255 = 0, |
@@ -1037,7 +1037,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
1037 | .ao_range_table = &range_ni_M_625x_ao, | 1037 | .ao_range_table = &range_ni_M_625x_ao, |
1038 | .reg_type = ni_reg_625x, | 1038 | .reg_type = ni_reg_625x, |
1039 | .ao_unipolar = 0, | 1039 | .ao_unipolar = 0, |
1040 | .ao_speed = 357, | 1040 | .ao_speed = 350, |
1041 | .num_p0_dio_channels = 32, | 1041 | .num_p0_dio_channels = 32, |
1042 | .caldac = {caldac_none}, | 1042 | .caldac = {caldac_none}, |
1043 | .has_8255 = 0, | 1043 | .has_8255 = 0, |
@@ -1056,7 +1056,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
1056 | .ao_range_table = &range_ni_M_625x_ao, | 1056 | .ao_range_table = &range_ni_M_625x_ao, |
1057 | .reg_type = ni_reg_625x, | 1057 | .reg_type = ni_reg_625x, |
1058 | .ao_unipolar = 0, | 1058 | .ao_unipolar = 0, |
1059 | .ao_speed = 357, | 1059 | .ao_speed = 350, |
1060 | .num_p0_dio_channels = 32, | 1060 | .num_p0_dio_channels = 32, |
1061 | .caldac = {caldac_none}, | 1061 | .caldac = {caldac_none}, |
1062 | .has_8255 = 0, | 1062 | .has_8255 = 0, |
@@ -1092,7 +1092,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
1092 | .ao_range_table = &range_ni_M_628x_ao, | 1092 | .ao_range_table = &range_ni_M_628x_ao, |
1093 | .reg_type = ni_reg_628x, | 1093 | .reg_type = ni_reg_628x, |
1094 | .ao_unipolar = 1, | 1094 | .ao_unipolar = 1, |
1095 | .ao_speed = 357, | 1095 | .ao_speed = 350, |
1096 | .num_p0_dio_channels = 8, | 1096 | .num_p0_dio_channels = 8, |
1097 | .caldac = {caldac_none}, | 1097 | .caldac = {caldac_none}, |
1098 | .has_8255 = 0, | 1098 | .has_8255 = 0, |
@@ -1111,7 +1111,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
1111 | .ao_range_table = &range_ni_M_628x_ao, | 1111 | .ao_range_table = &range_ni_M_628x_ao, |
1112 | .reg_type = ni_reg_628x, | 1112 | .reg_type = ni_reg_628x, |
1113 | .ao_unipolar = 1, | 1113 | .ao_unipolar = 1, |
1114 | .ao_speed = 357, | 1114 | .ao_speed = 350, |
1115 | .num_p0_dio_channels = 8, | 1115 | .num_p0_dio_channels = 8, |
1116 | .caldac = {caldac_none}, | 1116 | .caldac = {caldac_none}, |
1117 | .has_8255 = 0, | 1117 | .has_8255 = 0, |
@@ -1147,7 +1147,7 @@ static const struct ni_board_struct ni_boards[] = { | |||
1147 | .ao_range_table = &range_ni_M_628x_ao, | 1147 | .ao_range_table = &range_ni_M_628x_ao, |
1148 | .reg_type = ni_reg_628x, | 1148 | .reg_type = ni_reg_628x, |
1149 | .ao_unipolar = 1, | 1149 | .ao_unipolar = 1, |
1150 | .ao_speed = 357, | 1150 | .ao_speed = 350, |
1151 | .num_p0_dio_channels = 32, | 1151 | .num_p0_dio_channels = 32, |
1152 | .caldac = {caldac_none}, | 1152 | .caldac = {caldac_none}, |
1153 | .has_8255 = 0, | 1153 | .has_8255 = 0, |
diff --git a/drivers/staging/fwserial/Kconfig b/drivers/staging/fwserial/Kconfig index 580406cb1808..b2f8331e4acf 100644 --- a/drivers/staging/fwserial/Kconfig +++ b/drivers/staging/fwserial/Kconfig | |||
@@ -3,7 +3,9 @@ config FIREWIRE_SERIAL | |||
3 | depends on FIREWIRE | 3 | depends on FIREWIRE |
4 | help | 4 | help |
5 | This enables TTY over IEEE 1394, providing high-speed serial | 5 | This enables TTY over IEEE 1394, providing high-speed serial |
6 | connectivity to cabled peers. | 6 | connectivity to cabled peers. This driver implements a |
7 | ad-hoc transport protocol and is currently limited to | ||
8 | Linux-to-Linux communication. | ||
7 | 9 | ||
8 | To compile this driver as a module, say M here: the module will | 10 | To compile this driver as a module, say M here: the module will |
9 | be called firewire-serial. | 11 | be called firewire-serial. |
diff --git a/drivers/staging/fwserial/TODO b/drivers/staging/fwserial/TODO index 726900548eae..8dae8fb25223 100644 --- a/drivers/staging/fwserial/TODO +++ b/drivers/staging/fwserial/TODO | |||
@@ -1,5 +1,5 @@ | |||
1 | TODOs | 1 | TODOs prior to this driver moving out of staging |
2 | ----- | 2 | ------------------------------------------------ |
3 | 1. Implement retries for RCODE_BUSY, RCODE_NO_ACK and RCODE_SEND_ERROR | 3 | 1. Implement retries for RCODE_BUSY, RCODE_NO_ACK and RCODE_SEND_ERROR |
4 | - I/O is handled asynchronously which presents some issues when error | 4 | - I/O is handled asynchronously which presents some issues when error |
5 | conditions occur. | 5 | conditions occur. |
@@ -11,17 +11,9 @@ TODOs | |||
11 | -- Issues with firewire stack -- | 11 | -- Issues with firewire stack -- |
12 | 1. This driver uses the same unregistered vendor id that the firewire core does | 12 | 1. This driver uses the same unregistered vendor id that the firewire core does |
13 | (0xd00d1e). Perhaps this could be exposed as a define in | 13 | (0xd00d1e). Perhaps this could be exposed as a define in |
14 | firewire-constants.h? | 14 | firewire.h? |
15 | 2. MAX_ASYNC_PAYLOAD needs to be publicly exposed by core/ohci | ||
16 | - otherwise how will this driver know the max size of address window to | ||
17 | open for one packet write? | ||
18 | 3. Maybe device_max_receive() and link_speed_to_max_payload() should be | 15 | 3. Maybe device_max_receive() and link_speed_to_max_payload() should be |
19 | taken up by the firewire core? | 16 | taken up by the firewire core? |
20 | 4. To avoid dropping rx data while still limiting the maximum buffering, | ||
21 | the size of the AR context must be known. How to expose this to drivers? | ||
22 | 5. Explore if bigger AR context will reduce RCODE_BUSY responses | ||
23 | (or auto-grow to certain max size -- but this would require major surgery | ||
24 | as the current AR is contiguously mapped) | ||
25 | 17 | ||
26 | -- Issues with TTY core -- | 18 | -- Issues with TTY core -- |
27 | 1. Hack for alternate device name scheme | 19 | 1. Hack for alternate device name scheme |
diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c index 61ee29083b26..d03a7f57e8d4 100644 --- a/drivers/staging/fwserial/fwserial.c +++ b/drivers/staging/fwserial/fwserial.c | |||
@@ -179,7 +179,7 @@ static void dump_profile(struct seq_file *m, struct stats *stats) | |||
179 | /* Returns the max receive packet size for the given card */ | 179 | /* Returns the max receive packet size for the given card */ |
180 | static inline int device_max_receive(struct fw_device *fw_device) | 180 | static inline int device_max_receive(struct fw_device *fw_device) |
181 | { | 181 | { |
182 | return 1 << (clamp_t(int, fw_device->max_rec, 8U, 13U) + 1); | 182 | return 1 << (clamp_t(int, fw_device->max_rec, 8U, 11U) + 1); |
183 | } | 183 | } |
184 | 184 | ||
185 | static void fwtty_log_tx_error(struct fwtty_port *port, int rcode) | 185 | static void fwtty_log_tx_error(struct fwtty_port *port, int rcode) |
diff --git a/drivers/staging/fwserial/fwserial.h b/drivers/staging/fwserial/fwserial.h index 8b572edf9563..caa1c1ea82d5 100644 --- a/drivers/staging/fwserial/fwserial.h +++ b/drivers/staging/fwserial/fwserial.h | |||
@@ -374,10 +374,10 @@ static inline void fwtty_bind_console(struct fwtty_port *port, | |||
374 | */ | 374 | */ |
375 | static inline int link_speed_to_max_payload(unsigned speed) | 375 | static inline int link_speed_to_max_payload(unsigned speed) |
376 | { | 376 | { |
377 | static const int max_async[] = { 307, 614, 1229, 2458, 4916, 9832, }; | 377 | static const int max_async[] = { 307, 614, 1229, 2458, }; |
378 | BUILD_BUG_ON(ARRAY_SIZE(max_async) - 1 != SCODE_3200); | 378 | BUILD_BUG_ON(ARRAY_SIZE(max_async) - 1 != SCODE_800); |
379 | 379 | ||
380 | speed = clamp(speed, (unsigned) SCODE_100, (unsigned) SCODE_3200); | 380 | speed = clamp(speed, (unsigned) SCODE_100, (unsigned) SCODE_800); |
381 | if (limit_bw) | 381 | if (limit_bw) |
382 | return max_async[speed]; | 382 | return max_async[speed]; |
383 | else | 383 | else |
diff --git a/drivers/staging/iio/gyro/Kconfig b/drivers/staging/iio/gyro/Kconfig index ea295b25308c..87979a0d03a9 100644 --- a/drivers/staging/iio/gyro/Kconfig +++ b/drivers/staging/iio/gyro/Kconfig | |||
@@ -27,8 +27,8 @@ config ADIS16130 | |||
27 | config ADIS16260 | 27 | config ADIS16260 |
28 | tristate "Analog Devices ADIS16260 Digital Gyroscope Sensor SPI driver" | 28 | tristate "Analog Devices ADIS16260 Digital Gyroscope Sensor SPI driver" |
29 | depends on SPI | 29 | depends on SPI |
30 | select IIO_TRIGGER if IIO_BUFFER | 30 | select IIO_ADIS_LIB |
31 | select IIO_SW_RING if IIO_BUFFER | 31 | select IIO_ADIS_LIB_BUFFER if IIO_BUFFER |
32 | help | 32 | help |
33 | Say yes here to build support for Analog Devices ADIS16260 ADIS16265 | 33 | Say yes here to build support for Analog Devices ADIS16260 ADIS16265 |
34 | ADIS16250 ADIS16255 and ADIS16251 programmable digital gyroscope sensors. | 34 | ADIS16250 ADIS16255 and ADIS16251 programmable digital gyroscope sensors. |
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c index ecf0f44bc70e..cec19f1cf56c 100644 --- a/drivers/staging/imx-drm/imx-drm-core.c +++ b/drivers/staging/imx-drm/imx-drm-core.c | |||
@@ -584,7 +584,6 @@ int imx_drm_add_encoder(struct drm_encoder *encoder, | |||
584 | 584 | ||
585 | ret = imx_drm_encoder_register(imx_drm_encoder); | 585 | ret = imx_drm_encoder_register(imx_drm_encoder); |
586 | if (ret) { | 586 | if (ret) { |
587 | kfree(imx_drm_encoder); | ||
588 | ret = -ENOMEM; | 587 | ret = -ENOMEM; |
589 | goto err_register; | 588 | goto err_register; |
590 | } | 589 | } |
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c index 677e665ca86d..f7059cddd7fd 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c | |||
@@ -1104,7 +1104,9 @@ static int ipu_probe(struct platform_device *pdev) | |||
1104 | if (ret) | 1104 | if (ret) |
1105 | goto out_failed_irq; | 1105 | goto out_failed_irq; |
1106 | 1106 | ||
1107 | ipu_reset(ipu); | 1107 | ret = ipu_reset(ipu); |
1108 | if (ret) | ||
1109 | goto out_failed_reset; | ||
1108 | 1110 | ||
1109 | /* Set MCU_T to divide MCU access window into 2 */ | 1111 | /* Set MCU_T to divide MCU access window into 2 */ |
1110 | ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18), | 1112 | ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18), |
@@ -1129,6 +1131,7 @@ failed_add_clients: | |||
1129 | ipu_submodules_exit(ipu); | 1131 | ipu_submodules_exit(ipu); |
1130 | failed_submodules_init: | 1132 | failed_submodules_init: |
1131 | ipu_irq_exit(ipu); | 1133 | ipu_irq_exit(ipu); |
1134 | out_failed_reset: | ||
1132 | out_failed_irq: | 1135 | out_failed_irq: |
1133 | clk_disable_unprepare(ipu->clk); | 1136 | clk_disable_unprepare(ipu->clk); |
1134 | failed_clk_get: | 1137 | failed_clk_get: |
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c index 1892006526b5..4b3a019409b5 100644 --- a/drivers/staging/imx-drm/ipuv3-crtc.c +++ b/drivers/staging/imx-drm/ipuv3-crtc.c | |||
@@ -452,7 +452,7 @@ static int ipu_get_resources(struct ipu_crtc *ipu_crtc, | |||
452 | int ret; | 452 | int ret; |
453 | 453 | ||
454 | ipu_crtc->ipu_ch = ipu_idmac_get(ipu, pdata->dma[0]); | 454 | ipu_crtc->ipu_ch = ipu_idmac_get(ipu, pdata->dma[0]); |
455 | if (IS_ERR_OR_NULL(ipu_crtc->ipu_ch)) { | 455 | if (IS_ERR(ipu_crtc->ipu_ch)) { |
456 | ret = PTR_ERR(ipu_crtc->ipu_ch); | 456 | ret = PTR_ERR(ipu_crtc->ipu_ch); |
457 | goto err_out; | 457 | goto err_out; |
458 | } | 458 | } |
@@ -472,7 +472,7 @@ static int ipu_get_resources(struct ipu_crtc *ipu_crtc, | |||
472 | if (pdata->dp >= 0) { | 472 | if (pdata->dp >= 0) { |
473 | ipu_crtc->dp = ipu_dp_get(ipu, pdata->dp); | 473 | ipu_crtc->dp = ipu_dp_get(ipu, pdata->dp); |
474 | if (IS_ERR(ipu_crtc->dp)) { | 474 | if (IS_ERR(ipu_crtc->dp)) { |
475 | ret = PTR_ERR(ipu_crtc->ipu_ch); | 475 | ret = PTR_ERR(ipu_crtc->dp); |
476 | goto err_out; | 476 | goto err_out; |
477 | } | 477 | } |
478 | } | 478 | } |
@@ -548,6 +548,8 @@ static int ipu_drm_probe(struct platform_device *pdev) | |||
548 | ipu_crtc->dev = &pdev->dev; | 548 | ipu_crtc->dev = &pdev->dev; |
549 | 549 | ||
550 | ret = ipu_crtc_init(ipu_crtc, pdata); | 550 | ret = ipu_crtc_init(ipu_crtc, pdata); |
551 | if (ret) | ||
552 | return ret; | ||
551 | 553 | ||
552 | platform_set_drvdata(pdev, ipu_crtc); | 554 | platform_set_drvdata(pdev, ipu_crtc); |
553 | 555 | ||
diff --git a/drivers/staging/omapdrm/Makefile b/drivers/staging/omapdrm/Makefile index 1ca0e0016de4..d85e058f2845 100644 --- a/drivers/staging/omapdrm/Makefile +++ b/drivers/staging/omapdrm/Makefile | |||
@@ -5,6 +5,7 @@ | |||
5 | 5 | ||
6 | ccflags-y := -Iinclude/drm -Werror | 6 | ccflags-y := -Iinclude/drm -Werror |
7 | omapdrm-y := omap_drv.o \ | 7 | omapdrm-y := omap_drv.o \ |
8 | omap_irq.o \ | ||
8 | omap_debugfs.o \ | 9 | omap_debugfs.o \ |
9 | omap_crtc.o \ | 10 | omap_crtc.o \ |
10 | omap_plane.o \ | 11 | omap_plane.o \ |
diff --git a/drivers/staging/omapdrm/TODO b/drivers/staging/omapdrm/TODO index 938c7888ca31..abeeb00aaa12 100644 --- a/drivers/staging/omapdrm/TODO +++ b/drivers/staging/omapdrm/TODO | |||
@@ -17,9 +17,6 @@ TODO | |||
17 | . Revisit GEM sync object infrastructure.. TTM has some framework for this | 17 | . Revisit GEM sync object infrastructure.. TTM has some framework for this |
18 | already. Possibly this could be refactored out and made more common? | 18 | already. Possibly this could be refactored out and made more common? |
19 | There should be some way to do this with less wheel-reinvention. | 19 | There should be some way to do this with less wheel-reinvention. |
20 | . Review DSS vs KMS mismatches. The omap_dss_device is sort of part encoder, | ||
21 | part connector. Which results in a bit of duct tape to fwd calls from | ||
22 | encoder to connector. Possibly this could be done a bit better. | ||
23 | . Solve PM sequencing on resume. DMM/TILER must be reloaded before any | 20 | . Solve PM sequencing on resume. DMM/TILER must be reloaded before any |
24 | access is made from any component in the system. Which means on suspend | 21 | access is made from any component in the system. Which means on suspend |
25 | CRTC's should be disabled, and on resume the LUT should be reprogrammed | 22 | CRTC's should be disabled, and on resume the LUT should be reprogrammed |
diff --git a/drivers/staging/omapdrm/omap_connector.c b/drivers/staging/omapdrm/omap_connector.c index 91edb3f96972..4cc9ee733c5f 100644 --- a/drivers/staging/omapdrm/omap_connector.c +++ b/drivers/staging/omapdrm/omap_connector.c | |||
@@ -31,9 +31,10 @@ | |||
31 | struct omap_connector { | 31 | struct omap_connector { |
32 | struct drm_connector base; | 32 | struct drm_connector base; |
33 | struct omap_dss_device *dssdev; | 33 | struct omap_dss_device *dssdev; |
34 | struct drm_encoder *encoder; | ||
34 | }; | 35 | }; |
35 | 36 | ||
36 | static inline void copy_timings_omap_to_drm(struct drm_display_mode *mode, | 37 | void copy_timings_omap_to_drm(struct drm_display_mode *mode, |
37 | struct omap_video_timings *timings) | 38 | struct omap_video_timings *timings) |
38 | { | 39 | { |
39 | mode->clock = timings->pixel_clock; | 40 | mode->clock = timings->pixel_clock; |
@@ -64,7 +65,7 @@ static inline void copy_timings_omap_to_drm(struct drm_display_mode *mode, | |||
64 | mode->flags |= DRM_MODE_FLAG_NVSYNC; | 65 | mode->flags |= DRM_MODE_FLAG_NVSYNC; |
65 | } | 66 | } |
66 | 67 | ||
67 | static inline void copy_timings_drm_to_omap(struct omap_video_timings *timings, | 68 | void copy_timings_drm_to_omap(struct omap_video_timings *timings, |
68 | struct drm_display_mode *mode) | 69 | struct drm_display_mode *mode) |
69 | { | 70 | { |
70 | timings->pixel_clock = mode->clock; | 71 | timings->pixel_clock = mode->clock; |
@@ -96,48 +97,7 @@ static inline void copy_timings_drm_to_omap(struct omap_video_timings *timings, | |||
96 | timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; | 97 | timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; |
97 | } | 98 | } |
98 | 99 | ||
99 | static void omap_connector_dpms(struct drm_connector *connector, int mode) | 100 | static enum drm_connector_status omap_connector_detect( |
100 | { | ||
101 | struct omap_connector *omap_connector = to_omap_connector(connector); | ||
102 | struct omap_dss_device *dssdev = omap_connector->dssdev; | ||
103 | int old_dpms; | ||
104 | |||
105 | DBG("%s: %d", dssdev->name, mode); | ||
106 | |||
107 | old_dpms = connector->dpms; | ||
108 | |||
109 | /* from off to on, do from crtc to connector */ | ||
110 | if (mode < old_dpms) | ||
111 | drm_helper_connector_dpms(connector, mode); | ||
112 | |||
113 | if (mode == DRM_MODE_DPMS_ON) { | ||
114 | /* store resume info for suspended displays */ | ||
115 | switch (dssdev->state) { | ||
116 | case OMAP_DSS_DISPLAY_SUSPENDED: | ||
117 | dssdev->activate_after_resume = true; | ||
118 | break; | ||
119 | case OMAP_DSS_DISPLAY_DISABLED: { | ||
120 | int ret = dssdev->driver->enable(dssdev); | ||
121 | if (ret) { | ||
122 | DBG("%s: failed to enable: %d", | ||
123 | dssdev->name, ret); | ||
124 | dssdev->driver->disable(dssdev); | ||
125 | } | ||
126 | break; | ||
127 | } | ||
128 | default: | ||
129 | break; | ||
130 | } | ||
131 | } else { | ||
132 | /* TODO */ | ||
133 | } | ||
134 | |||
135 | /* from on to off, do from connector to crtc */ | ||
136 | if (mode > old_dpms) | ||
137 | drm_helper_connector_dpms(connector, mode); | ||
138 | } | ||
139 | |||
140 | enum drm_connector_status omap_connector_detect( | ||
141 | struct drm_connector *connector, bool force) | 101 | struct drm_connector *connector, bool force) |
142 | { | 102 | { |
143 | struct omap_connector *omap_connector = to_omap_connector(connector); | 103 | struct omap_connector *omap_connector = to_omap_connector(connector); |
@@ -164,8 +124,6 @@ static void omap_connector_destroy(struct drm_connector *connector) | |||
164 | struct omap_connector *omap_connector = to_omap_connector(connector); | 124 | struct omap_connector *omap_connector = to_omap_connector(connector); |
165 | struct omap_dss_device *dssdev = omap_connector->dssdev; | 125 | struct omap_dss_device *dssdev = omap_connector->dssdev; |
166 | 126 | ||
167 | dssdev->driver->disable(dssdev); | ||
168 | |||
169 | DBG("%s", omap_connector->dssdev->name); | 127 | DBG("%s", omap_connector->dssdev->name); |
170 | drm_sysfs_connector_remove(connector); | 128 | drm_sysfs_connector_remove(connector); |
171 | drm_connector_cleanup(connector); | 129 | drm_connector_cleanup(connector); |
@@ -261,36 +219,12 @@ static int omap_connector_mode_valid(struct drm_connector *connector, | |||
261 | struct drm_encoder *omap_connector_attached_encoder( | 219 | struct drm_encoder *omap_connector_attached_encoder( |
262 | struct drm_connector *connector) | 220 | struct drm_connector *connector) |
263 | { | 221 | { |
264 | int i; | ||
265 | struct omap_connector *omap_connector = to_omap_connector(connector); | 222 | struct omap_connector *omap_connector = to_omap_connector(connector); |
266 | 223 | return omap_connector->encoder; | |
267 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { | ||
268 | struct drm_mode_object *obj; | ||
269 | |||
270 | if (connector->encoder_ids[i] == 0) | ||
271 | break; | ||
272 | |||
273 | obj = drm_mode_object_find(connector->dev, | ||
274 | connector->encoder_ids[i], | ||
275 | DRM_MODE_OBJECT_ENCODER); | ||
276 | |||
277 | if (obj) { | ||
278 | struct drm_encoder *encoder = obj_to_encoder(obj); | ||
279 | struct omap_overlay_manager *mgr = | ||
280 | omap_encoder_get_manager(encoder); | ||
281 | DBG("%s: found %s", omap_connector->dssdev->name, | ||
282 | mgr->name); | ||
283 | return encoder; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | DBG("%s: no encoder", omap_connector->dssdev->name); | ||
288 | |||
289 | return NULL; | ||
290 | } | 224 | } |
291 | 225 | ||
292 | static const struct drm_connector_funcs omap_connector_funcs = { | 226 | static const struct drm_connector_funcs omap_connector_funcs = { |
293 | .dpms = omap_connector_dpms, | 227 | .dpms = drm_helper_connector_dpms, |
294 | .detect = omap_connector_detect, | 228 | .detect = omap_connector_detect, |
295 | .fill_modes = drm_helper_probe_single_connector_modes, | 229 | .fill_modes = drm_helper_probe_single_connector_modes, |
296 | .destroy = omap_connector_destroy, | 230 | .destroy = omap_connector_destroy, |
@@ -302,34 +236,6 @@ static const struct drm_connector_helper_funcs omap_connector_helper_funcs = { | |||
302 | .best_encoder = omap_connector_attached_encoder, | 236 | .best_encoder = omap_connector_attached_encoder, |
303 | }; | 237 | }; |
304 | 238 | ||
305 | /* called from encoder when mode is set, to propagate settings to the dssdev */ | ||
306 | void omap_connector_mode_set(struct drm_connector *connector, | ||
307 | struct drm_display_mode *mode) | ||
308 | { | ||
309 | struct drm_device *dev = connector->dev; | ||
310 | struct omap_connector *omap_connector = to_omap_connector(connector); | ||
311 | struct omap_dss_device *dssdev = omap_connector->dssdev; | ||
312 | struct omap_dss_driver *dssdrv = dssdev->driver; | ||
313 | struct omap_video_timings timings = {0}; | ||
314 | |||
315 | copy_timings_drm_to_omap(&timings, mode); | ||
316 | |||
317 | DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", | ||
318 | omap_connector->dssdev->name, | ||
319 | mode->base.id, mode->name, mode->vrefresh, mode->clock, | ||
320 | mode->hdisplay, mode->hsync_start, | ||
321 | mode->hsync_end, mode->htotal, | ||
322 | mode->vdisplay, mode->vsync_start, | ||
323 | mode->vsync_end, mode->vtotal, mode->type, mode->flags); | ||
324 | |||
325 | if (dssdrv->check_timings(dssdev, &timings)) { | ||
326 | dev_err(dev->dev, "could not set timings\n"); | ||
327 | return; | ||
328 | } | ||
329 | |||
330 | dssdrv->set_timings(dssdev, &timings); | ||
331 | } | ||
332 | |||
333 | /* flush an area of the framebuffer (in case of manual update display that | 239 | /* flush an area of the framebuffer (in case of manual update display that |
334 | * is not automatically flushed) | 240 | * is not automatically flushed) |
335 | */ | 241 | */ |
@@ -344,7 +250,8 @@ void omap_connector_flush(struct drm_connector *connector, | |||
344 | 250 | ||
345 | /* initialize connector */ | 251 | /* initialize connector */ |
346 | struct drm_connector *omap_connector_init(struct drm_device *dev, | 252 | struct drm_connector *omap_connector_init(struct drm_device *dev, |
347 | int connector_type, struct omap_dss_device *dssdev) | 253 | int connector_type, struct omap_dss_device *dssdev, |
254 | struct drm_encoder *encoder) | ||
348 | { | 255 | { |
349 | struct drm_connector *connector = NULL; | 256 | struct drm_connector *connector = NULL; |
350 | struct omap_connector *omap_connector; | 257 | struct omap_connector *omap_connector; |
@@ -360,6 +267,8 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, | |||
360 | } | 267 | } |
361 | 268 | ||
362 | omap_connector->dssdev = dssdev; | 269 | omap_connector->dssdev = dssdev; |
270 | omap_connector->encoder = encoder; | ||
271 | |||
363 | connector = &omap_connector->base; | 272 | connector = &omap_connector->base; |
364 | 273 | ||
365 | drm_connector_init(dev, connector, &omap_connector_funcs, | 274 | drm_connector_init(dev, connector, &omap_connector_funcs, |
diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c index d87bd84257bd..5c6ed6040eff 100644 --- a/drivers/staging/omapdrm/omap_crtc.c +++ b/drivers/staging/omapdrm/omap_crtc.c | |||
@@ -28,19 +28,131 @@ | |||
28 | struct omap_crtc { | 28 | struct omap_crtc { |
29 | struct drm_crtc base; | 29 | struct drm_crtc base; |
30 | struct drm_plane *plane; | 30 | struct drm_plane *plane; |
31 | |||
31 | const char *name; | 32 | const char *name; |
32 | int id; | 33 | int pipe; |
34 | enum omap_channel channel; | ||
35 | struct omap_overlay_manager_info info; | ||
36 | |||
37 | /* | ||
38 | * Temporary: eventually this will go away, but it is needed | ||
39 | * for now to keep the output's happy. (They only need | ||
40 | * mgr->id.) Eventually this will be replaced w/ something | ||
41 | * more common-panel-framework-y | ||
42 | */ | ||
43 | struct omap_overlay_manager mgr; | ||
44 | |||
45 | struct omap_video_timings timings; | ||
46 | bool enabled; | ||
47 | bool full_update; | ||
48 | |||
49 | struct omap_drm_apply apply; | ||
50 | |||
51 | struct omap_drm_irq apply_irq; | ||
52 | struct omap_drm_irq error_irq; | ||
53 | |||
54 | /* list of in-progress apply's: */ | ||
55 | struct list_head pending_applies; | ||
56 | |||
57 | /* list of queued apply's: */ | ||
58 | struct list_head queued_applies; | ||
59 | |||
60 | /* for handling queued and in-progress applies: */ | ||
61 | struct work_struct apply_work; | ||
33 | 62 | ||
34 | /* if there is a pending flip, these will be non-null: */ | 63 | /* if there is a pending flip, these will be non-null: */ |
35 | struct drm_pending_vblank_event *event; | 64 | struct drm_pending_vblank_event *event; |
36 | struct drm_framebuffer *old_fb; | 65 | struct drm_framebuffer *old_fb; |
66 | |||
67 | /* for handling page flips without caring about what | ||
68 | * the callback is called from. Possibly we should just | ||
69 | * make omap_gem always call the cb from the worker so | ||
70 | * we don't have to care about this.. | ||
71 | * | ||
72 | * XXX maybe fold into apply_work?? | ||
73 | */ | ||
74 | struct work_struct page_flip_work; | ||
75 | }; | ||
76 | |||
77 | /* | ||
78 | * Manager-ops, callbacks from output when they need to configure | ||
79 | * the upstream part of the video pipe. | ||
80 | * | ||
81 | * Most of these we can ignore until we add support for command-mode | ||
82 | * panels.. for video-mode the crtc-helpers already do an adequate | ||
83 | * job of sequencing the setup of the video pipe in the proper order | ||
84 | */ | ||
85 | |||
86 | /* we can probably ignore these until we support command-mode panels: */ | ||
87 | static void omap_crtc_start_update(struct omap_overlay_manager *mgr) | ||
88 | { | ||
89 | } | ||
90 | |||
91 | static int omap_crtc_enable(struct omap_overlay_manager *mgr) | ||
92 | { | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static void omap_crtc_disable(struct omap_overlay_manager *mgr) | ||
97 | { | ||
98 | } | ||
99 | |||
100 | static void omap_crtc_set_timings(struct omap_overlay_manager *mgr, | ||
101 | const struct omap_video_timings *timings) | ||
102 | { | ||
103 | struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr); | ||
104 | DBG("%s", omap_crtc->name); | ||
105 | omap_crtc->timings = *timings; | ||
106 | omap_crtc->full_update = true; | ||
107 | } | ||
108 | |||
109 | static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr, | ||
110 | const struct dss_lcd_mgr_config *config) | ||
111 | { | ||
112 | struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr); | ||
113 | DBG("%s", omap_crtc->name); | ||
114 | dispc_mgr_set_lcd_config(omap_crtc->channel, config); | ||
115 | } | ||
116 | |||
117 | static int omap_crtc_register_framedone_handler( | ||
118 | struct omap_overlay_manager *mgr, | ||
119 | void (*handler)(void *), void *data) | ||
120 | { | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static void omap_crtc_unregister_framedone_handler( | ||
125 | struct omap_overlay_manager *mgr, | ||
126 | void (*handler)(void *), void *data) | ||
127 | { | ||
128 | } | ||
129 | |||
130 | static const struct dss_mgr_ops mgr_ops = { | ||
131 | .start_update = omap_crtc_start_update, | ||
132 | .enable = omap_crtc_enable, | ||
133 | .disable = omap_crtc_disable, | ||
134 | .set_timings = omap_crtc_set_timings, | ||
135 | .set_lcd_config = omap_crtc_set_lcd_config, | ||
136 | .register_framedone_handler = omap_crtc_register_framedone_handler, | ||
137 | .unregister_framedone_handler = omap_crtc_unregister_framedone_handler, | ||
37 | }; | 138 | }; |
38 | 139 | ||
140 | /* | ||
141 | * CRTC funcs: | ||
142 | */ | ||
143 | |||
39 | static void omap_crtc_destroy(struct drm_crtc *crtc) | 144 | static void omap_crtc_destroy(struct drm_crtc *crtc) |
40 | { | 145 | { |
41 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 146 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
147 | |||
148 | DBG("%s", omap_crtc->name); | ||
149 | |||
150 | WARN_ON(omap_crtc->apply_irq.registered); | ||
151 | omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); | ||
152 | |||
42 | omap_crtc->plane->funcs->destroy(omap_crtc->plane); | 153 | omap_crtc->plane->funcs->destroy(omap_crtc->plane); |
43 | drm_crtc_cleanup(crtc); | 154 | drm_crtc_cleanup(crtc); |
155 | |||
44 | kfree(omap_crtc); | 156 | kfree(omap_crtc); |
45 | } | 157 | } |
46 | 158 | ||
@@ -48,14 +160,25 @@ static void omap_crtc_dpms(struct drm_crtc *crtc, int mode) | |||
48 | { | 160 | { |
49 | struct omap_drm_private *priv = crtc->dev->dev_private; | 161 | struct omap_drm_private *priv = crtc->dev->dev_private; |
50 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 162 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
163 | bool enabled = (mode == DRM_MODE_DPMS_ON); | ||
51 | int i; | 164 | int i; |
52 | 165 | ||
53 | WARN_ON(omap_plane_dpms(omap_crtc->plane, mode)); | 166 | DBG("%s: %d", omap_crtc->name, mode); |
167 | |||
168 | if (enabled != omap_crtc->enabled) { | ||
169 | omap_crtc->enabled = enabled; | ||
170 | omap_crtc->full_update = true; | ||
171 | omap_crtc_apply(crtc, &omap_crtc->apply); | ||
54 | 172 | ||
55 | for (i = 0; i < priv->num_planes; i++) { | 173 | /* also enable our private plane: */ |
56 | struct drm_plane *plane = priv->planes[i]; | 174 | WARN_ON(omap_plane_dpms(omap_crtc->plane, mode)); |
57 | if (plane->crtc == crtc) | 175 | |
58 | WARN_ON(omap_plane_dpms(plane, mode)); | 176 | /* and any attached overlay planes: */ |
177 | for (i = 0; i < priv->num_planes; i++) { | ||
178 | struct drm_plane *plane = priv->planes[i]; | ||
179 | if (plane->crtc == crtc) | ||
180 | WARN_ON(omap_plane_dpms(plane, mode)); | ||
181 | } | ||
59 | } | 182 | } |
60 | } | 183 | } |
61 | 184 | ||
@@ -73,12 +196,26 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc, | |||
73 | struct drm_framebuffer *old_fb) | 196 | struct drm_framebuffer *old_fb) |
74 | { | 197 | { |
75 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 198 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
76 | struct drm_plane *plane = omap_crtc->plane; | ||
77 | 199 | ||
78 | return omap_plane_mode_set(plane, crtc, crtc->fb, | 200 | mode = adjusted_mode; |
201 | |||
202 | DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", | ||
203 | omap_crtc->name, mode->base.id, mode->name, | ||
204 | mode->vrefresh, mode->clock, | ||
205 | mode->hdisplay, mode->hsync_start, | ||
206 | mode->hsync_end, mode->htotal, | ||
207 | mode->vdisplay, mode->vsync_start, | ||
208 | mode->vsync_end, mode->vtotal, | ||
209 | mode->type, mode->flags); | ||
210 | |||
211 | copy_timings_drm_to_omap(&omap_crtc->timings, mode); | ||
212 | omap_crtc->full_update = true; | ||
213 | |||
214 | return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb, | ||
79 | 0, 0, mode->hdisplay, mode->vdisplay, | 215 | 0, 0, mode->hdisplay, mode->vdisplay, |
80 | x << 16, y << 16, | 216 | x << 16, y << 16, |
81 | mode->hdisplay << 16, mode->vdisplay << 16); | 217 | mode->hdisplay << 16, mode->vdisplay << 16, |
218 | NULL, NULL); | ||
82 | } | 219 | } |
83 | 220 | ||
84 | static void omap_crtc_prepare(struct drm_crtc *crtc) | 221 | static void omap_crtc_prepare(struct drm_crtc *crtc) |
@@ -102,10 +239,11 @@ static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | |||
102 | struct drm_plane *plane = omap_crtc->plane; | 239 | struct drm_plane *plane = omap_crtc->plane; |
103 | struct drm_display_mode *mode = &crtc->mode; | 240 | struct drm_display_mode *mode = &crtc->mode; |
104 | 241 | ||
105 | return plane->funcs->update_plane(plane, crtc, crtc->fb, | 242 | return omap_plane_mode_set(plane, crtc, crtc->fb, |
106 | 0, 0, mode->hdisplay, mode->vdisplay, | 243 | 0, 0, mode->hdisplay, mode->vdisplay, |
107 | x << 16, y << 16, | 244 | x << 16, y << 16, |
108 | mode->hdisplay << 16, mode->vdisplay << 16); | 245 | mode->hdisplay << 16, mode->vdisplay << 16, |
246 | NULL, NULL); | ||
109 | } | 247 | } |
110 | 248 | ||
111 | static void omap_crtc_load_lut(struct drm_crtc *crtc) | 249 | static void omap_crtc_load_lut(struct drm_crtc *crtc) |
@@ -114,63 +252,54 @@ static void omap_crtc_load_lut(struct drm_crtc *crtc) | |||
114 | 252 | ||
115 | static void vblank_cb(void *arg) | 253 | static void vblank_cb(void *arg) |
116 | { | 254 | { |
117 | static uint32_t sequence; | ||
118 | struct drm_crtc *crtc = arg; | 255 | struct drm_crtc *crtc = arg; |
119 | struct drm_device *dev = crtc->dev; | 256 | struct drm_device *dev = crtc->dev; |
120 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 257 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
121 | struct drm_pending_vblank_event *event = omap_crtc->event; | ||
122 | unsigned long flags; | 258 | unsigned long flags; |
123 | struct timeval now; | ||
124 | 259 | ||
125 | WARN_ON(!event); | 260 | spin_lock_irqsave(&dev->event_lock, flags); |
261 | |||
262 | /* wakeup userspace */ | ||
263 | if (omap_crtc->event) | ||
264 | drm_send_vblank_event(dev, omap_crtc->pipe, omap_crtc->event); | ||
126 | 265 | ||
127 | omap_crtc->event = NULL; | 266 | omap_crtc->event = NULL; |
267 | omap_crtc->old_fb = NULL; | ||
128 | 268 | ||
129 | /* wakeup userspace */ | 269 | spin_unlock_irqrestore(&dev->event_lock, flags); |
130 | if (event) { | ||
131 | do_gettimeofday(&now); | ||
132 | |||
133 | spin_lock_irqsave(&dev->event_lock, flags); | ||
134 | /* TODO: we can't yet use the vblank time accounting, | ||
135 | * because omapdss lower layer is the one that knows | ||
136 | * the irq # and registers the handler, which more or | ||
137 | * less defeats how drm_irq works.. for now just fake | ||
138 | * the sequence number and use gettimeofday.. | ||
139 | * | ||
140 | event->event.sequence = drm_vblank_count_and_time( | ||
141 | dev, omap_crtc->id, &now); | ||
142 | */ | ||
143 | event->event.sequence = sequence++; | ||
144 | event->event.tv_sec = now.tv_sec; | ||
145 | event->event.tv_usec = now.tv_usec; | ||
146 | list_add_tail(&event->base.link, | ||
147 | &event->base.file_priv->event_list); | ||
148 | wake_up_interruptible(&event->base.file_priv->event_wait); | ||
149 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
150 | } | ||
151 | } | 270 | } |
152 | 271 | ||
153 | static void page_flip_cb(void *arg) | 272 | static void page_flip_worker(struct work_struct *work) |
154 | { | 273 | { |
155 | struct drm_crtc *crtc = arg; | 274 | struct omap_crtc *omap_crtc = |
156 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 275 | container_of(work, struct omap_crtc, page_flip_work); |
157 | struct drm_framebuffer *old_fb = omap_crtc->old_fb; | 276 | struct drm_crtc *crtc = &omap_crtc->base; |
277 | struct drm_device *dev = crtc->dev; | ||
278 | struct drm_display_mode *mode = &crtc->mode; | ||
158 | struct drm_gem_object *bo; | 279 | struct drm_gem_object *bo; |
159 | 280 | ||
160 | omap_crtc->old_fb = NULL; | 281 | mutex_lock(&dev->mode_config.mutex); |
161 | 282 | omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb, | |
162 | omap_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb); | 283 | 0, 0, mode->hdisplay, mode->vdisplay, |
163 | 284 | crtc->x << 16, crtc->y << 16, | |
164 | /* really we'd like to setup the callback atomically w/ setting the | 285 | mode->hdisplay << 16, mode->vdisplay << 16, |
165 | * new scanout buffer to avoid getting stuck waiting an extra vblank | 286 | vblank_cb, crtc); |
166 | * cycle.. for now go for correctness and later figure out speed.. | 287 | mutex_unlock(&dev->mode_config.mutex); |
167 | */ | ||
168 | omap_plane_on_endwin(omap_crtc->plane, vblank_cb, crtc); | ||
169 | 288 | ||
170 | bo = omap_framebuffer_bo(crtc->fb, 0); | 289 | bo = omap_framebuffer_bo(crtc->fb, 0); |
171 | drm_gem_object_unreference_unlocked(bo); | 290 | drm_gem_object_unreference_unlocked(bo); |
172 | } | 291 | } |
173 | 292 | ||
293 | static void page_flip_cb(void *arg) | ||
294 | { | ||
295 | struct drm_crtc *crtc = arg; | ||
296 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
297 | struct omap_drm_private *priv = crtc->dev->dev_private; | ||
298 | |||
299 | /* avoid assumptions about what ctxt we are called from: */ | ||
300 | queue_work(priv->wq, &omap_crtc->page_flip_work); | ||
301 | } | ||
302 | |||
174 | static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, | 303 | static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, |
175 | struct drm_framebuffer *fb, | 304 | struct drm_framebuffer *fb, |
176 | struct drm_pending_vblank_event *event) | 305 | struct drm_pending_vblank_event *event) |
@@ -179,14 +308,14 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, | |||
179 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 308 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
180 | struct drm_gem_object *bo; | 309 | struct drm_gem_object *bo; |
181 | 310 | ||
182 | DBG("%d -> %d", crtc->fb ? crtc->fb->base.id : -1, fb->base.id); | 311 | DBG("%d -> %d (event=%p)", crtc->fb ? crtc->fb->base.id : -1, |
312 | fb->base.id, event); | ||
183 | 313 | ||
184 | if (omap_crtc->event) { | 314 | if (omap_crtc->old_fb) { |
185 | dev_err(dev->dev, "already a pending flip\n"); | 315 | dev_err(dev->dev, "already a pending flip\n"); |
186 | return -EINVAL; | 316 | return -EINVAL; |
187 | } | 317 | } |
188 | 318 | ||
189 | omap_crtc->old_fb = crtc->fb; | ||
190 | omap_crtc->event = event; | 319 | omap_crtc->event = event; |
191 | crtc->fb = fb; | 320 | crtc->fb = fb; |
192 | 321 | ||
@@ -234,14 +363,244 @@ static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = { | |||
234 | .load_lut = omap_crtc_load_lut, | 363 | .load_lut = omap_crtc_load_lut, |
235 | }; | 364 | }; |
236 | 365 | ||
366 | const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc) | ||
367 | { | ||
368 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
369 | return &omap_crtc->timings; | ||
370 | } | ||
371 | |||
372 | enum omap_channel omap_crtc_channel(struct drm_crtc *crtc) | ||
373 | { | ||
374 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
375 | return omap_crtc->channel; | ||
376 | } | ||
377 | |||
378 | static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus) | ||
379 | { | ||
380 | struct omap_crtc *omap_crtc = | ||
381 | container_of(irq, struct omap_crtc, error_irq); | ||
382 | struct drm_crtc *crtc = &omap_crtc->base; | ||
383 | DRM_ERROR("%s: errors: %08x\n", omap_crtc->name, irqstatus); | ||
384 | /* avoid getting in a flood, unregister the irq until next vblank */ | ||
385 | omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); | ||
386 | } | ||
387 | |||
388 | static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus) | ||
389 | { | ||
390 | struct omap_crtc *omap_crtc = | ||
391 | container_of(irq, struct omap_crtc, apply_irq); | ||
392 | struct drm_crtc *crtc = &omap_crtc->base; | ||
393 | |||
394 | if (!omap_crtc->error_irq.registered) | ||
395 | omap_irq_register(crtc->dev, &omap_crtc->error_irq); | ||
396 | |||
397 | if (!dispc_mgr_go_busy(omap_crtc->channel)) { | ||
398 | struct omap_drm_private *priv = | ||
399 | crtc->dev->dev_private; | ||
400 | DBG("%s: apply done", omap_crtc->name); | ||
401 | omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq); | ||
402 | queue_work(priv->wq, &omap_crtc->apply_work); | ||
403 | } | ||
404 | } | ||
405 | |||
406 | static void apply_worker(struct work_struct *work) | ||
407 | { | ||
408 | struct omap_crtc *omap_crtc = | ||
409 | container_of(work, struct omap_crtc, apply_work); | ||
410 | struct drm_crtc *crtc = &omap_crtc->base; | ||
411 | struct drm_device *dev = crtc->dev; | ||
412 | struct omap_drm_apply *apply, *n; | ||
413 | bool need_apply; | ||
414 | |||
415 | /* | ||
416 | * Synchronize everything on mode_config.mutex, to keep | ||
417 | * the callbacks and list modification all serialized | ||
418 | * with respect to modesetting ioctls from userspace. | ||
419 | */ | ||
420 | mutex_lock(&dev->mode_config.mutex); | ||
421 | dispc_runtime_get(); | ||
422 | |||
423 | /* | ||
424 | * If we are still pending a previous update, wait.. when the | ||
425 | * pending update completes, we get kicked again. | ||
426 | */ | ||
427 | if (omap_crtc->apply_irq.registered) | ||
428 | goto out; | ||
429 | |||
430 | /* finish up previous apply's: */ | ||
431 | list_for_each_entry_safe(apply, n, | ||
432 | &omap_crtc->pending_applies, pending_node) { | ||
433 | apply->post_apply(apply); | ||
434 | list_del(&apply->pending_node); | ||
435 | } | ||
436 | |||
437 | need_apply = !list_empty(&omap_crtc->queued_applies); | ||
438 | |||
439 | /* then handle the next round of of queued apply's: */ | ||
440 | list_for_each_entry_safe(apply, n, | ||
441 | &omap_crtc->queued_applies, queued_node) { | ||
442 | apply->pre_apply(apply); | ||
443 | list_del(&apply->queued_node); | ||
444 | apply->queued = false; | ||
445 | list_add_tail(&apply->pending_node, | ||
446 | &omap_crtc->pending_applies); | ||
447 | } | ||
448 | |||
449 | if (need_apply) { | ||
450 | enum omap_channel channel = omap_crtc->channel; | ||
451 | |||
452 | DBG("%s: GO", omap_crtc->name); | ||
453 | |||
454 | if (dispc_mgr_is_enabled(channel)) { | ||
455 | omap_irq_register(dev, &omap_crtc->apply_irq); | ||
456 | dispc_mgr_go(channel); | ||
457 | } else { | ||
458 | struct omap_drm_private *priv = dev->dev_private; | ||
459 | queue_work(priv->wq, &omap_crtc->apply_work); | ||
460 | } | ||
461 | } | ||
462 | |||
463 | out: | ||
464 | dispc_runtime_put(); | ||
465 | mutex_unlock(&dev->mode_config.mutex); | ||
466 | } | ||
467 | |||
468 | int omap_crtc_apply(struct drm_crtc *crtc, | ||
469 | struct omap_drm_apply *apply) | ||
470 | { | ||
471 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
472 | struct drm_device *dev = crtc->dev; | ||
473 | |||
474 | WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); | ||
475 | |||
476 | /* no need to queue it again if it is already queued: */ | ||
477 | if (apply->queued) | ||
478 | return 0; | ||
479 | |||
480 | apply->queued = true; | ||
481 | list_add_tail(&apply->queued_node, &omap_crtc->queued_applies); | ||
482 | |||
483 | /* | ||
484 | * If there are no currently pending updates, then go ahead and | ||
485 | * kick the worker immediately, otherwise it will run again when | ||
486 | * the current update finishes. | ||
487 | */ | ||
488 | if (list_empty(&omap_crtc->pending_applies)) { | ||
489 | struct omap_drm_private *priv = crtc->dev->dev_private; | ||
490 | queue_work(priv->wq, &omap_crtc->apply_work); | ||
491 | } | ||
492 | |||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | /* called only from apply */ | ||
497 | static void set_enabled(struct drm_crtc *crtc, bool enable) | ||
498 | { | ||
499 | struct drm_device *dev = crtc->dev; | ||
500 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | ||
501 | enum omap_channel channel = omap_crtc->channel; | ||
502 | struct omap_irq_wait *wait = NULL; | ||
503 | |||
504 | if (dispc_mgr_is_enabled(channel) == enable) | ||
505 | return; | ||
506 | |||
507 | /* ignore sync-lost irqs during enable/disable */ | ||
508 | omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); | ||
509 | |||
510 | if (dispc_mgr_get_framedone_irq(channel)) { | ||
511 | if (!enable) { | ||
512 | wait = omap_irq_wait_init(dev, | ||
513 | dispc_mgr_get_framedone_irq(channel), 1); | ||
514 | } | ||
515 | } else { | ||
516 | /* | ||
517 | * When we disable digit output, we need to wait until fields | ||
518 | * are done. Otherwise the DSS is still working, and turning | ||
519 | * off the clocks prevents DSS from going to OFF mode. And when | ||
520 | * enabling, we need to wait for the extra sync losts | ||
521 | */ | ||
522 | wait = omap_irq_wait_init(dev, | ||
523 | dispc_mgr_get_vsync_irq(channel), 2); | ||
524 | } | ||
525 | |||
526 | dispc_mgr_enable(channel, enable); | ||
527 | |||
528 | if (wait) { | ||
529 | int ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100)); | ||
530 | if (ret) { | ||
531 | dev_err(dev->dev, "%s: timeout waiting for %s\n", | ||
532 | omap_crtc->name, enable ? "enable" : "disable"); | ||
533 | } | ||
534 | } | ||
535 | |||
536 | omap_irq_register(crtc->dev, &omap_crtc->error_irq); | ||
537 | } | ||
538 | |||
539 | static void omap_crtc_pre_apply(struct omap_drm_apply *apply) | ||
540 | { | ||
541 | struct omap_crtc *omap_crtc = | ||
542 | container_of(apply, struct omap_crtc, apply); | ||
543 | struct drm_crtc *crtc = &omap_crtc->base; | ||
544 | struct drm_encoder *encoder = NULL; | ||
545 | |||
546 | DBG("%s: enabled=%d, full=%d", omap_crtc->name, | ||
547 | omap_crtc->enabled, omap_crtc->full_update); | ||
548 | |||
549 | if (omap_crtc->full_update) { | ||
550 | struct omap_drm_private *priv = crtc->dev->dev_private; | ||
551 | int i; | ||
552 | for (i = 0; i < priv->num_encoders; i++) { | ||
553 | if (priv->encoders[i]->crtc == crtc) { | ||
554 | encoder = priv->encoders[i]; | ||
555 | break; | ||
556 | } | ||
557 | } | ||
558 | } | ||
559 | |||
560 | if (!omap_crtc->enabled) { | ||
561 | set_enabled(&omap_crtc->base, false); | ||
562 | if (encoder) | ||
563 | omap_encoder_set_enabled(encoder, false); | ||
564 | } else { | ||
565 | if (encoder) { | ||
566 | omap_encoder_set_enabled(encoder, false); | ||
567 | omap_encoder_update(encoder, &omap_crtc->mgr, | ||
568 | &omap_crtc->timings); | ||
569 | omap_encoder_set_enabled(encoder, true); | ||
570 | omap_crtc->full_update = false; | ||
571 | } | ||
572 | |||
573 | dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info); | ||
574 | dispc_mgr_set_timings(omap_crtc->channel, | ||
575 | &omap_crtc->timings); | ||
576 | set_enabled(&omap_crtc->base, true); | ||
577 | } | ||
578 | |||
579 | omap_crtc->full_update = false; | ||
580 | } | ||
581 | |||
582 | static void omap_crtc_post_apply(struct omap_drm_apply *apply) | ||
583 | { | ||
584 | /* nothing needed for post-apply */ | ||
585 | } | ||
586 | |||
587 | static const char *channel_names[] = { | ||
588 | [OMAP_DSS_CHANNEL_LCD] = "lcd", | ||
589 | [OMAP_DSS_CHANNEL_DIGIT] = "tv", | ||
590 | [OMAP_DSS_CHANNEL_LCD2] = "lcd2", | ||
591 | }; | ||
592 | |||
237 | /* initialize crtc */ | 593 | /* initialize crtc */ |
238 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, | 594 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, |
239 | struct omap_overlay *ovl, int id) | 595 | struct drm_plane *plane, enum omap_channel channel, int id) |
240 | { | 596 | { |
241 | struct drm_crtc *crtc = NULL; | 597 | struct drm_crtc *crtc = NULL; |
242 | struct omap_crtc *omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL); | 598 | struct omap_crtc *omap_crtc; |
599 | struct omap_overlay_manager_info *info; | ||
600 | |||
601 | DBG("%s", channel_names[channel]); | ||
243 | 602 | ||
244 | DBG("%s", ovl->name); | 603 | omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL); |
245 | 604 | ||
246 | if (!omap_crtc) { | 605 | if (!omap_crtc) { |
247 | dev_err(dev->dev, "could not allocate CRTC\n"); | 606 | dev_err(dev->dev, "could not allocate CRTC\n"); |
@@ -250,10 +609,40 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, | |||
250 | 609 | ||
251 | crtc = &omap_crtc->base; | 610 | crtc = &omap_crtc->base; |
252 | 611 | ||
253 | omap_crtc->plane = omap_plane_init(dev, ovl, (1 << id), true); | 612 | INIT_WORK(&omap_crtc->page_flip_work, page_flip_worker); |
613 | INIT_WORK(&omap_crtc->apply_work, apply_worker); | ||
614 | |||
615 | INIT_LIST_HEAD(&omap_crtc->pending_applies); | ||
616 | INIT_LIST_HEAD(&omap_crtc->queued_applies); | ||
617 | |||
618 | omap_crtc->apply.pre_apply = omap_crtc_pre_apply; | ||
619 | omap_crtc->apply.post_apply = omap_crtc_post_apply; | ||
620 | |||
621 | omap_crtc->apply_irq.irqmask = pipe2vbl(id); | ||
622 | omap_crtc->apply_irq.irq = omap_crtc_apply_irq; | ||
623 | |||
624 | omap_crtc->error_irq.irqmask = | ||
625 | dispc_mgr_get_sync_lost_irq(channel); | ||
626 | omap_crtc->error_irq.irq = omap_crtc_error_irq; | ||
627 | omap_irq_register(dev, &omap_crtc->error_irq); | ||
628 | |||
629 | omap_crtc->channel = channel; | ||
630 | omap_crtc->plane = plane; | ||
254 | omap_crtc->plane->crtc = crtc; | 631 | omap_crtc->plane->crtc = crtc; |
255 | omap_crtc->name = ovl->name; | 632 | omap_crtc->name = channel_names[channel]; |
256 | omap_crtc->id = id; | 633 | omap_crtc->pipe = id; |
634 | |||
635 | /* temporary: */ | ||
636 | omap_crtc->mgr.id = channel; | ||
637 | |||
638 | dss_install_mgr_ops(&mgr_ops); | ||
639 | |||
640 | /* TODO: fix hard-coded setup.. add properties! */ | ||
641 | info = &omap_crtc->info; | ||
642 | info->default_color = 0x00000000; | ||
643 | info->trans_key = 0x00000000; | ||
644 | info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST; | ||
645 | info->trans_enabled = false; | ||
257 | 646 | ||
258 | drm_crtc_init(dev, crtc, &omap_crtc_funcs); | 647 | drm_crtc_init(dev, crtc, &omap_crtc_funcs); |
259 | drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs); | 648 | drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs); |
diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c index 84943e5ba1d6..ae5ecc2efbc7 100644 --- a/drivers/staging/omapdrm/omap_drv.c +++ b/drivers/staging/omapdrm/omap_drv.c | |||
@@ -74,320 +74,99 @@ static int get_connector_type(struct omap_dss_device *dssdev) | |||
74 | } | 74 | } |
75 | } | 75 | } |
76 | 76 | ||
77 | #if 0 /* enable when dss2 supports hotplug */ | 77 | static int omap_modeset_init(struct drm_device *dev) |
78 | static int omap_drm_notifier(struct notifier_block *nb, | ||
79 | unsigned long evt, void *arg) | ||
80 | { | ||
81 | switch (evt) { | ||
82 | case OMAP_DSS_SIZE_CHANGE: | ||
83 | case OMAP_DSS_HOTPLUG_CONNECT: | ||
84 | case OMAP_DSS_HOTPLUG_DISCONNECT: { | ||
85 | struct drm_device *dev = drm_device; | ||
86 | DBG("hotplug event: evt=%d, dev=%p", evt, dev); | ||
87 | if (dev) | ||
88 | drm_sysfs_hotplug_event(dev); | ||
89 | |||
90 | return NOTIFY_OK; | ||
91 | } | ||
92 | default: /* don't care about other events for now */ | ||
93 | return NOTIFY_DONE; | ||
94 | } | ||
95 | } | ||
96 | #endif | ||
97 | |||
98 | static void dump_video_chains(void) | ||
99 | { | ||
100 | int i; | ||
101 | |||
102 | DBG("dumping video chains: "); | ||
103 | for (i = 0; i < omap_dss_get_num_overlays(); i++) { | ||
104 | struct omap_overlay *ovl = omap_dss_get_overlay(i); | ||
105 | struct omap_overlay_manager *mgr = ovl->manager; | ||
106 | struct omap_dss_device *dssdev = mgr ? | ||
107 | mgr->get_device(mgr) : NULL; | ||
108 | if (dssdev) { | ||
109 | DBG("%d: %s -> %s -> %s", i, ovl->name, mgr->name, | ||
110 | dssdev->name); | ||
111 | } else if (mgr) { | ||
112 | DBG("%d: %s -> %s", i, ovl->name, mgr->name); | ||
113 | } else { | ||
114 | DBG("%d: %s", i, ovl->name); | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | |||
119 | /* create encoders for each manager */ | ||
120 | static int create_encoder(struct drm_device *dev, | ||
121 | struct omap_overlay_manager *mgr) | ||
122 | { | ||
123 | struct omap_drm_private *priv = dev->dev_private; | ||
124 | struct drm_encoder *encoder = omap_encoder_init(dev, mgr); | ||
125 | |||
126 | if (!encoder) { | ||
127 | dev_err(dev->dev, "could not create encoder: %s\n", | ||
128 | mgr->name); | ||
129 | return -ENOMEM; | ||
130 | } | ||
131 | |||
132 | BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders)); | ||
133 | |||
134 | priv->encoders[priv->num_encoders++] = encoder; | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | /* create connectors for each display device */ | ||
140 | static int create_connector(struct drm_device *dev, | ||
141 | struct omap_dss_device *dssdev) | ||
142 | { | 78 | { |
143 | struct omap_drm_private *priv = dev->dev_private; | 79 | struct omap_drm_private *priv = dev->dev_private; |
144 | static struct notifier_block *notifier; | 80 | struct omap_dss_device *dssdev = NULL; |
145 | struct drm_connector *connector; | 81 | int num_ovls = dss_feat_get_num_ovls(); |
146 | int j; | 82 | int id; |
147 | |||
148 | if (!dssdev->driver) { | ||
149 | dev_warn(dev->dev, "%s has no driver.. skipping it\n", | ||
150 | dssdev->name); | ||
151 | return 0; | ||
152 | } | ||
153 | 83 | ||
154 | if (!(dssdev->driver->get_timings || | 84 | drm_mode_config_init(dev); |
155 | dssdev->driver->read_edid)) { | ||
156 | dev_warn(dev->dev, "%s driver does not support " | ||
157 | "get_timings or read_edid.. skipping it!\n", | ||
158 | dssdev->name); | ||
159 | return 0; | ||
160 | } | ||
161 | 85 | ||
162 | connector = omap_connector_init(dev, | 86 | omap_drm_irq_install(dev); |
163 | get_connector_type(dssdev), dssdev); | ||
164 | 87 | ||
165 | if (!connector) { | 88 | /* |
166 | dev_err(dev->dev, "could not create connector: %s\n", | 89 | * Create private planes and CRTCs for the last NUM_CRTCs overlay |
167 | dssdev->name); | 90 | * plus manager: |
168 | return -ENOMEM; | 91 | */ |
169 | } | 92 | for (id = 0; id < min(num_crtc, num_ovls); id++) { |
170 | 93 | struct drm_plane *plane; | |
171 | BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors)); | 94 | struct drm_crtc *crtc; |
172 | 95 | ||
173 | priv->connectors[priv->num_connectors++] = connector; | 96 | plane = omap_plane_init(dev, id, true); |
97 | crtc = omap_crtc_init(dev, plane, pipe2chan(id), id); | ||
174 | 98 | ||
175 | #if 0 /* enable when dss2 supports hotplug */ | 99 | BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); |
176 | notifier = kzalloc(sizeof(struct notifier_block), GFP_KERNEL); | 100 | priv->crtcs[id] = crtc; |
177 | notifier->notifier_call = omap_drm_notifier; | 101 | priv->num_crtcs++; |
178 | omap_dss_add_notify(dssdev, notifier); | ||
179 | #else | ||
180 | notifier = NULL; | ||
181 | #endif | ||
182 | 102 | ||
183 | for (j = 0; j < priv->num_encoders; j++) { | 103 | priv->planes[id] = plane; |
184 | struct omap_overlay_manager *mgr = | 104 | priv->num_planes++; |
185 | omap_encoder_get_manager(priv->encoders[j]); | ||
186 | if (mgr->get_device(mgr) == dssdev) { | ||
187 | drm_mode_connector_attach_encoder(connector, | ||
188 | priv->encoders[j]); | ||
189 | } | ||
190 | } | 105 | } |
191 | 106 | ||
192 | return 0; | 107 | /* |
193 | } | 108 | * Create normal planes for the remaining overlays: |
194 | |||
195 | /* create up to max_overlays CRTCs mapping to overlays.. by default, | ||
196 | * connect the overlays to different managers/encoders, giving priority | ||
197 | * to encoders connected to connectors with a detected connection | ||
198 | */ | ||
199 | static int create_crtc(struct drm_device *dev, struct omap_overlay *ovl, | ||
200 | int *j, unsigned int connected_connectors) | ||
201 | { | ||
202 | struct omap_drm_private *priv = dev->dev_private; | ||
203 | struct omap_overlay_manager *mgr = NULL; | ||
204 | struct drm_crtc *crtc; | ||
205 | |||
206 | /* find next best connector, ones with detected connection first | ||
207 | */ | 109 | */ |
208 | while (*j < priv->num_connectors && !mgr) { | 110 | for (; id < num_ovls; id++) { |
209 | if (connected_connectors & (1 << *j)) { | 111 | struct drm_plane *plane = omap_plane_init(dev, id, false); |
210 | struct drm_encoder *encoder = | ||
211 | omap_connector_attached_encoder( | ||
212 | priv->connectors[*j]); | ||
213 | if (encoder) | ||
214 | mgr = omap_encoder_get_manager(encoder); | ||
215 | 112 | ||
216 | } | 113 | BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); |
217 | (*j)++; | 114 | priv->planes[priv->num_planes++] = plane; |
218 | } | 115 | } |
219 | 116 | ||
220 | /* if we couldn't find another connected connector, lets start | 117 | for_each_dss_dev(dssdev) { |
221 | * looking at the unconnected connectors: | 118 | struct drm_connector *connector; |
222 | * | 119 | struct drm_encoder *encoder; |
223 | * note: it might not be immediately apparent, but thanks to | ||
224 | * the !mgr check in both this loop and the one above, the only | ||
225 | * way to enter this loop is with *j == priv->num_connectors, | ||
226 | * so idx can never go negative. | ||
227 | */ | ||
228 | while (*j < 2 * priv->num_connectors && !mgr) { | ||
229 | int idx = *j - priv->num_connectors; | ||
230 | if (!(connected_connectors & (1 << idx))) { | ||
231 | struct drm_encoder *encoder = | ||
232 | omap_connector_attached_encoder( | ||
233 | priv->connectors[idx]); | ||
234 | if (encoder) | ||
235 | mgr = omap_encoder_get_manager(encoder); | ||
236 | 120 | ||
121 | if (!dssdev->driver) { | ||
122 | dev_warn(dev->dev, "%s has no driver.. skipping it\n", | ||
123 | dssdev->name); | ||
124 | return 0; | ||
237 | } | 125 | } |
238 | (*j)++; | ||
239 | } | ||
240 | |||
241 | crtc = omap_crtc_init(dev, ovl, priv->num_crtcs); | ||
242 | |||
243 | if (!crtc) { | ||
244 | dev_err(dev->dev, "could not create CRTC: %s\n", | ||
245 | ovl->name); | ||
246 | return -ENOMEM; | ||
247 | } | ||
248 | 126 | ||
249 | BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs)); | 127 | if (!(dssdev->driver->get_timings || |
250 | 128 | dssdev->driver->read_edid)) { | |
251 | priv->crtcs[priv->num_crtcs++] = crtc; | 129 | dev_warn(dev->dev, "%s driver does not support " |
252 | 130 | "get_timings or read_edid.. skipping it!\n", | |
253 | return 0; | 131 | dssdev->name); |
254 | } | 132 | return 0; |
255 | |||
256 | static int create_plane(struct drm_device *dev, struct omap_overlay *ovl, | ||
257 | unsigned int possible_crtcs) | ||
258 | { | ||
259 | struct omap_drm_private *priv = dev->dev_private; | ||
260 | struct drm_plane *plane = | ||
261 | omap_plane_init(dev, ovl, possible_crtcs, false); | ||
262 | |||
263 | if (!plane) { | ||
264 | dev_err(dev->dev, "could not create plane: %s\n", | ||
265 | ovl->name); | ||
266 | return -ENOMEM; | ||
267 | } | ||
268 | |||
269 | BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)); | ||
270 | |||
271 | priv->planes[priv->num_planes++] = plane; | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static int match_dev_name(struct omap_dss_device *dssdev, void *data) | ||
277 | { | ||
278 | return !strcmp(dssdev->name, data); | ||
279 | } | ||
280 | |||
281 | static unsigned int detect_connectors(struct drm_device *dev) | ||
282 | { | ||
283 | struct omap_drm_private *priv = dev->dev_private; | ||
284 | unsigned int connected_connectors = 0; | ||
285 | int i; | ||
286 | |||
287 | for (i = 0; i < priv->num_connectors; i++) { | ||
288 | struct drm_connector *connector = priv->connectors[i]; | ||
289 | if (omap_connector_detect(connector, true) == | ||
290 | connector_status_connected) { | ||
291 | connected_connectors |= (1 << i); | ||
292 | } | 133 | } |
293 | } | ||
294 | |||
295 | return connected_connectors; | ||
296 | } | ||
297 | 134 | ||
298 | static int omap_modeset_init(struct drm_device *dev) | 135 | encoder = omap_encoder_init(dev, dssdev); |
299 | { | ||
300 | const struct omap_drm_platform_data *pdata = dev->dev->platform_data; | ||
301 | struct omap_kms_platform_data *kms_pdata = NULL; | ||
302 | struct omap_drm_private *priv = dev->dev_private; | ||
303 | struct omap_dss_device *dssdev = NULL; | ||
304 | int i, j; | ||
305 | unsigned int connected_connectors = 0; | ||
306 | 136 | ||
307 | drm_mode_config_init(dev); | 137 | if (!encoder) { |
308 | 138 | dev_err(dev->dev, "could not create encoder: %s\n", | |
309 | if (pdata && pdata->kms_pdata) { | 139 | dssdev->name); |
310 | kms_pdata = pdata->kms_pdata; | 140 | return -ENOMEM; |
311 | |||
312 | /* if platform data is provided by the board file, use it to | ||
313 | * control which overlays, managers, and devices we own. | ||
314 | */ | ||
315 | for (i = 0; i < kms_pdata->mgr_cnt; i++) { | ||
316 | struct omap_overlay_manager *mgr = | ||
317 | omap_dss_get_overlay_manager( | ||
318 | kms_pdata->mgr_ids[i]); | ||
319 | create_encoder(dev, mgr); | ||
320 | } | ||
321 | |||
322 | for (i = 0; i < kms_pdata->dev_cnt; i++) { | ||
323 | struct omap_dss_device *dssdev = | ||
324 | omap_dss_find_device( | ||
325 | (void *)kms_pdata->dev_names[i], | ||
326 | match_dev_name); | ||
327 | if (!dssdev) { | ||
328 | dev_warn(dev->dev, "no such dssdev: %s\n", | ||
329 | kms_pdata->dev_names[i]); | ||
330 | continue; | ||
331 | } | ||
332 | create_connector(dev, dssdev); | ||
333 | } | 141 | } |
334 | 142 | ||
335 | connected_connectors = detect_connectors(dev); | 143 | connector = omap_connector_init(dev, |
144 | get_connector_type(dssdev), dssdev, encoder); | ||
336 | 145 | ||
337 | j = 0; | 146 | if (!connector) { |
338 | for (i = 0; i < kms_pdata->ovl_cnt; i++) { | 147 | dev_err(dev->dev, "could not create connector: %s\n", |
339 | struct omap_overlay *ovl = | 148 | dssdev->name); |
340 | omap_dss_get_overlay(kms_pdata->ovl_ids[i]); | 149 | return -ENOMEM; |
341 | create_crtc(dev, ovl, &j, connected_connectors); | ||
342 | } | 150 | } |
343 | 151 | ||
344 | for (i = 0; i < kms_pdata->pln_cnt; i++) { | 152 | BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders)); |
345 | struct omap_overlay *ovl = | 153 | BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors)); |
346 | omap_dss_get_overlay(kms_pdata->pln_ids[i]); | ||
347 | create_plane(dev, ovl, (1 << priv->num_crtcs) - 1); | ||
348 | } | ||
349 | } else { | ||
350 | /* otherwise just grab up to CONFIG_DRM_OMAP_NUM_CRTCS and try | ||
351 | * to make educated guesses about everything else | ||
352 | */ | ||
353 | int max_overlays = min(omap_dss_get_num_overlays(), num_crtc); | ||
354 | 154 | ||
355 | for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) | 155 | priv->encoders[priv->num_encoders++] = encoder; |
356 | create_encoder(dev, omap_dss_get_overlay_manager(i)); | 156 | priv->connectors[priv->num_connectors++] = connector; |
357 | |||
358 | for_each_dss_dev(dssdev) { | ||
359 | create_connector(dev, dssdev); | ||
360 | } | ||
361 | 157 | ||
362 | connected_connectors = detect_connectors(dev); | 158 | drm_mode_connector_attach_encoder(connector, encoder); |
363 | 159 | ||
364 | j = 0; | 160 | /* figure out which crtc's we can connect the encoder to: */ |
365 | for (i = 0; i < max_overlays; i++) { | 161 | encoder->possible_crtcs = 0; |
366 | create_crtc(dev, omap_dss_get_overlay(i), | 162 | for (id = 0; id < priv->num_crtcs; id++) { |
367 | &j, connected_connectors); | 163 | enum omap_dss_output_id supported_outputs = |
368 | } | 164 | dss_feat_get_supported_outputs(pipe2chan(id)); |
369 | 165 | if (supported_outputs & dssdev->output->id) | |
370 | /* use any remaining overlays as drm planes */ | 166 | encoder->possible_crtcs |= (1 << id); |
371 | for (; i < omap_dss_get_num_overlays(); i++) { | ||
372 | struct omap_overlay *ovl = omap_dss_get_overlay(i); | ||
373 | create_plane(dev, ovl, (1 << priv->num_crtcs) - 1); | ||
374 | } | 167 | } |
375 | } | 168 | } |
376 | 169 | ||
377 | /* for now keep the mapping of CRTCs and encoders static.. */ | ||
378 | for (i = 0; i < priv->num_encoders; i++) { | ||
379 | struct drm_encoder *encoder = priv->encoders[i]; | ||
380 | struct omap_overlay_manager *mgr = | ||
381 | omap_encoder_get_manager(encoder); | ||
382 | |||
383 | encoder->possible_crtcs = (1 << priv->num_crtcs) - 1; | ||
384 | |||
385 | DBG("%s: possible_crtcs=%08x", mgr->name, | ||
386 | encoder->possible_crtcs); | ||
387 | } | ||
388 | |||
389 | dump_video_chains(); | ||
390 | |||
391 | dev->mode_config.min_width = 32; | 170 | dev->mode_config.min_width = 32; |
392 | dev->mode_config.min_height = 32; | 171 | dev->mode_config.min_height = 32; |
393 | 172 | ||
@@ -450,7 +229,7 @@ static int ioctl_gem_new(struct drm_device *dev, void *data, | |||
450 | struct drm_file *file_priv) | 229 | struct drm_file *file_priv) |
451 | { | 230 | { |
452 | struct drm_omap_gem_new *args = data; | 231 | struct drm_omap_gem_new *args = data; |
453 | DBG("%p:%p: size=0x%08x, flags=%08x", dev, file_priv, | 232 | VERB("%p:%p: size=0x%08x, flags=%08x", dev, file_priv, |
454 | args->size.bytes, args->flags); | 233 | args->size.bytes, args->flags); |
455 | return omap_gem_new_handle(dev, file_priv, args->size, | 234 | return omap_gem_new_handle(dev, file_priv, args->size, |
456 | args->flags, &args->handle); | 235 | args->flags, &args->handle); |
@@ -510,7 +289,7 @@ static int ioctl_gem_info(struct drm_device *dev, void *data, | |||
510 | struct drm_gem_object *obj; | 289 | struct drm_gem_object *obj; |
511 | int ret = 0; | 290 | int ret = 0; |
512 | 291 | ||
513 | DBG("%p:%p: handle=%d", dev, file_priv, args->handle); | 292 | VERB("%p:%p: handle=%d", dev, file_priv, args->handle); |
514 | 293 | ||
515 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | 294 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); |
516 | if (!obj) | 295 | if (!obj) |
@@ -565,14 +344,6 @@ static int dev_load(struct drm_device *dev, unsigned long flags) | |||
565 | 344 | ||
566 | dev->dev_private = priv; | 345 | dev->dev_private = priv; |
567 | 346 | ||
568 | ret = omapdss_compat_init(); | ||
569 | if (ret) { | ||
570 | dev_err(dev->dev, "coult not init omapdss\n"); | ||
571 | dev->dev_private = NULL; | ||
572 | kfree(priv); | ||
573 | return ret; | ||
574 | } | ||
575 | |||
576 | priv->wq = alloc_ordered_workqueue("omapdrm", 0); | 347 | priv->wq = alloc_ordered_workqueue("omapdrm", 0); |
577 | 348 | ||
578 | INIT_LIST_HEAD(&priv->obj_list); | 349 | INIT_LIST_HEAD(&priv->obj_list); |
@@ -584,10 +355,13 @@ static int dev_load(struct drm_device *dev, unsigned long flags) | |||
584 | dev_err(dev->dev, "omap_modeset_init failed: ret=%d\n", ret); | 355 | dev_err(dev->dev, "omap_modeset_init failed: ret=%d\n", ret); |
585 | dev->dev_private = NULL; | 356 | dev->dev_private = NULL; |
586 | kfree(priv); | 357 | kfree(priv); |
587 | omapdss_compat_uninit(); | ||
588 | return ret; | 358 | return ret; |
589 | } | 359 | } |
590 | 360 | ||
361 | ret = drm_vblank_init(dev, priv->num_crtcs); | ||
362 | if (ret) | ||
363 | dev_warn(dev->dev, "could not init vblank\n"); | ||
364 | |||
591 | priv->fbdev = omap_fbdev_init(dev); | 365 | priv->fbdev = omap_fbdev_init(dev); |
592 | if (!priv->fbdev) { | 366 | if (!priv->fbdev) { |
593 | dev_warn(dev->dev, "omap_fbdev_init failed\n"); | 367 | dev_warn(dev->dev, "omap_fbdev_init failed\n"); |
@@ -596,10 +370,6 @@ static int dev_load(struct drm_device *dev, unsigned long flags) | |||
596 | 370 | ||
597 | drm_kms_helper_poll_init(dev); | 371 | drm_kms_helper_poll_init(dev); |
598 | 372 | ||
599 | ret = drm_vblank_init(dev, priv->num_crtcs); | ||
600 | if (ret) | ||
601 | dev_warn(dev->dev, "could not init vblank\n"); | ||
602 | |||
603 | return 0; | 373 | return 0; |
604 | } | 374 | } |
605 | 375 | ||
@@ -609,8 +379,9 @@ static int dev_unload(struct drm_device *dev) | |||
609 | 379 | ||
610 | DBG("unload: dev=%p", dev); | 380 | DBG("unload: dev=%p", dev); |
611 | 381 | ||
612 | drm_vblank_cleanup(dev); | ||
613 | drm_kms_helper_poll_fini(dev); | 382 | drm_kms_helper_poll_fini(dev); |
383 | drm_vblank_cleanup(dev); | ||
384 | omap_drm_irq_uninstall(dev); | ||
614 | 385 | ||
615 | omap_fbdev_free(dev); | 386 | omap_fbdev_free(dev); |
616 | omap_modeset_free(dev); | 387 | omap_modeset_free(dev); |
@@ -619,8 +390,6 @@ static int dev_unload(struct drm_device *dev) | |||
619 | flush_workqueue(priv->wq); | 390 | flush_workqueue(priv->wq); |
620 | destroy_workqueue(priv->wq); | 391 | destroy_workqueue(priv->wq); |
621 | 392 | ||
622 | omapdss_compat_uninit(); | ||
623 | |||
624 | kfree(dev->dev_private); | 393 | kfree(dev->dev_private); |
625 | dev->dev_private = NULL; | 394 | dev->dev_private = NULL; |
626 | 395 | ||
@@ -680,7 +449,9 @@ static void dev_lastclose(struct drm_device *dev) | |||
680 | } | 449 | } |
681 | } | 450 | } |
682 | 451 | ||
452 | mutex_lock(&dev->mode_config.mutex); | ||
683 | ret = drm_fb_helper_restore_fbdev_mode(priv->fbdev); | 453 | ret = drm_fb_helper_restore_fbdev_mode(priv->fbdev); |
454 | mutex_unlock(&dev->mode_config.mutex); | ||
684 | if (ret) | 455 | if (ret) |
685 | DBG("failed to restore crtc mode"); | 456 | DBG("failed to restore crtc mode"); |
686 | } | 457 | } |
@@ -695,60 +466,6 @@ static void dev_postclose(struct drm_device *dev, struct drm_file *file) | |||
695 | DBG("postclose: dev=%p, file=%p", dev, file); | 466 | DBG("postclose: dev=%p, file=%p", dev, file); |
696 | } | 467 | } |
697 | 468 | ||
698 | /** | ||
699 | * enable_vblank - enable vblank interrupt events | ||
700 | * @dev: DRM device | ||
701 | * @crtc: which irq to enable | ||
702 | * | ||
703 | * Enable vblank interrupts for @crtc. If the device doesn't have | ||
704 | * a hardware vblank counter, this routine should be a no-op, since | ||
705 | * interrupts will have to stay on to keep the count accurate. | ||
706 | * | ||
707 | * RETURNS | ||
708 | * Zero on success, appropriate errno if the given @crtc's vblank | ||
709 | * interrupt cannot be enabled. | ||
710 | */ | ||
711 | static int dev_enable_vblank(struct drm_device *dev, int crtc) | ||
712 | { | ||
713 | DBG("enable_vblank: dev=%p, crtc=%d", dev, crtc); | ||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | /** | ||
718 | * disable_vblank - disable vblank interrupt events | ||
719 | * @dev: DRM device | ||
720 | * @crtc: which irq to enable | ||
721 | * | ||
722 | * Disable vblank interrupts for @crtc. If the device doesn't have | ||
723 | * a hardware vblank counter, this routine should be a no-op, since | ||
724 | * interrupts will have to stay on to keep the count accurate. | ||
725 | */ | ||
726 | static void dev_disable_vblank(struct drm_device *dev, int crtc) | ||
727 | { | ||
728 | DBG("disable_vblank: dev=%p, crtc=%d", dev, crtc); | ||
729 | } | ||
730 | |||
731 | static irqreturn_t dev_irq_handler(DRM_IRQ_ARGS) | ||
732 | { | ||
733 | return IRQ_HANDLED; | ||
734 | } | ||
735 | |||
736 | static void dev_irq_preinstall(struct drm_device *dev) | ||
737 | { | ||
738 | DBG("irq_preinstall: dev=%p", dev); | ||
739 | } | ||
740 | |||
741 | static int dev_irq_postinstall(struct drm_device *dev) | ||
742 | { | ||
743 | DBG("irq_postinstall: dev=%p", dev); | ||
744 | return 0; | ||
745 | } | ||
746 | |||
747 | static void dev_irq_uninstall(struct drm_device *dev) | ||
748 | { | ||
749 | DBG("irq_uninstall: dev=%p", dev); | ||
750 | } | ||
751 | |||
752 | static const struct vm_operations_struct omap_gem_vm_ops = { | 469 | static const struct vm_operations_struct omap_gem_vm_ops = { |
753 | .fault = omap_gem_fault, | 470 | .fault = omap_gem_fault, |
754 | .open = drm_gem_vm_open, | 471 | .open = drm_gem_vm_open, |
@@ -778,12 +495,12 @@ static struct drm_driver omap_drm_driver = { | |||
778 | .preclose = dev_preclose, | 495 | .preclose = dev_preclose, |
779 | .postclose = dev_postclose, | 496 | .postclose = dev_postclose, |
780 | .get_vblank_counter = drm_vblank_count, | 497 | .get_vblank_counter = drm_vblank_count, |
781 | .enable_vblank = dev_enable_vblank, | 498 | .enable_vblank = omap_irq_enable_vblank, |
782 | .disable_vblank = dev_disable_vblank, | 499 | .disable_vblank = omap_irq_disable_vblank, |
783 | .irq_preinstall = dev_irq_preinstall, | 500 | .irq_preinstall = omap_irq_preinstall, |
784 | .irq_postinstall = dev_irq_postinstall, | 501 | .irq_postinstall = omap_irq_postinstall, |
785 | .irq_uninstall = dev_irq_uninstall, | 502 | .irq_uninstall = omap_irq_uninstall, |
786 | .irq_handler = dev_irq_handler, | 503 | .irq_handler = omap_irq_handler, |
787 | #ifdef CONFIG_DEBUG_FS | 504 | #ifdef CONFIG_DEBUG_FS |
788 | .debugfs_init = omap_debugfs_init, | 505 | .debugfs_init = omap_debugfs_init, |
789 | .debugfs_cleanup = omap_debugfs_cleanup, | 506 | .debugfs_cleanup = omap_debugfs_cleanup, |
diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h index 1d4aea53b75d..cd1f22b0b124 100644 --- a/drivers/staging/omapdrm/omap_drv.h +++ b/drivers/staging/omapdrm/omap_drv.h | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/platform_data/omap_drm.h> | 28 | #include <linux/platform_data/omap_drm.h> |
29 | #include "omap_drm.h" | 29 | #include "omap_drm.h" |
30 | 30 | ||
31 | |||
31 | #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) | 32 | #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) |
32 | #define VERB(fmt, ...) if (0) DRM_DEBUG(fmt, ##__VA_ARGS__) /* verbose debug */ | 33 | #define VERB(fmt, ...) if (0) DRM_DEBUG(fmt, ##__VA_ARGS__) /* verbose debug */ |
33 | 34 | ||
@@ -39,6 +40,51 @@ | |||
39 | */ | 40 | */ |
40 | #define MAX_MAPPERS 2 | 41 | #define MAX_MAPPERS 2 |
41 | 42 | ||
43 | /* parameters which describe (unrotated) coordinates of scanout within a fb: */ | ||
44 | struct omap_drm_window { | ||
45 | uint32_t rotation; | ||
46 | int32_t crtc_x, crtc_y; /* signed because can be offscreen */ | ||
47 | uint32_t crtc_w, crtc_h; | ||
48 | uint32_t src_x, src_y; | ||
49 | uint32_t src_w, src_h; | ||
50 | }; | ||
51 | |||
52 | /* Once GO bit is set, we can't make further updates to shadowed registers | ||
53 | * until the GO bit is cleared. So various parts in the kms code that need | ||
54 | * to update shadowed registers queue up a pair of callbacks, pre_apply | ||
55 | * which is called before setting GO bit, and post_apply that is called | ||
56 | * after GO bit is cleared. The crtc manages the queuing, and everyone | ||
57 | * else goes thru omap_crtc_apply() using these callbacks so that the | ||
58 | * code which has to deal w/ GO bit state is centralized. | ||
59 | */ | ||
60 | struct omap_drm_apply { | ||
61 | struct list_head pending_node, queued_node; | ||
62 | bool queued; | ||
63 | void (*pre_apply)(struct omap_drm_apply *apply); | ||
64 | void (*post_apply)(struct omap_drm_apply *apply); | ||
65 | }; | ||
66 | |||
67 | /* For transiently registering for different DSS irqs that various parts | ||
68 | * of the KMS code need during setup/configuration. We these are not | ||
69 | * necessarily the same as what drm_vblank_get/put() are requesting, and | ||
70 | * the hysteresis in drm_vblank_put() is not necessarily desirable for | ||
71 | * internal housekeeping related irq usage. | ||
72 | */ | ||
73 | struct omap_drm_irq { | ||
74 | struct list_head node; | ||
75 | uint32_t irqmask; | ||
76 | bool registered; | ||
77 | void (*irq)(struct omap_drm_irq *irq, uint32_t irqstatus); | ||
78 | }; | ||
79 | |||
80 | /* For KMS code that needs to wait for a certain # of IRQs: | ||
81 | */ | ||
82 | struct omap_irq_wait; | ||
83 | struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev, | ||
84 | uint32_t irqmask, int count); | ||
85 | int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, | ||
86 | unsigned long timeout); | ||
87 | |||
42 | struct omap_drm_private { | 88 | struct omap_drm_private { |
43 | uint32_t omaprev; | 89 | uint32_t omaprev; |
44 | 90 | ||
@@ -58,6 +104,7 @@ struct omap_drm_private { | |||
58 | 104 | ||
59 | struct workqueue_struct *wq; | 105 | struct workqueue_struct *wq; |
60 | 106 | ||
107 | /* list of GEM objects: */ | ||
61 | struct list_head obj_list; | 108 | struct list_head obj_list; |
62 | 109 | ||
63 | bool has_dmm; | 110 | bool has_dmm; |
@@ -65,6 +112,11 @@ struct omap_drm_private { | |||
65 | /* properties: */ | 112 | /* properties: */ |
66 | struct drm_property *rotation_prop; | 113 | struct drm_property *rotation_prop; |
67 | struct drm_property *zorder_prop; | 114 | struct drm_property *zorder_prop; |
115 | |||
116 | /* irq handling: */ | ||
117 | struct list_head irq_list; /* list of omap_drm_irq */ | ||
118 | uint32_t vblank_mask; /* irq bits set for userspace vblank */ | ||
119 | struct omap_drm_irq error_handler; | ||
68 | }; | 120 | }; |
69 | 121 | ||
70 | /* this should probably be in drm-core to standardize amongst drivers */ | 122 | /* this should probably be in drm-core to standardize amongst drivers */ |
@@ -75,15 +127,6 @@ struct omap_drm_private { | |||
75 | #define DRM_REFLECT_X 4 | 127 | #define DRM_REFLECT_X 4 |
76 | #define DRM_REFLECT_Y 5 | 128 | #define DRM_REFLECT_Y 5 |
77 | 129 | ||
78 | /* parameters which describe (unrotated) coordinates of scanout within a fb: */ | ||
79 | struct omap_drm_window { | ||
80 | uint32_t rotation; | ||
81 | int32_t crtc_x, crtc_y; /* signed because can be offscreen */ | ||
82 | uint32_t crtc_w, crtc_h; | ||
83 | uint32_t src_x, src_y; | ||
84 | uint32_t src_w, src_h; | ||
85 | }; | ||
86 | |||
87 | #ifdef CONFIG_DEBUG_FS | 130 | #ifdef CONFIG_DEBUG_FS |
88 | int omap_debugfs_init(struct drm_minor *minor); | 131 | int omap_debugfs_init(struct drm_minor *minor); |
89 | void omap_debugfs_cleanup(struct drm_minor *minor); | 132 | void omap_debugfs_cleanup(struct drm_minor *minor); |
@@ -92,23 +135,36 @@ void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m); | |||
92 | void omap_gem_describe_objects(struct list_head *list, struct seq_file *m); | 135 | void omap_gem_describe_objects(struct list_head *list, struct seq_file *m); |
93 | #endif | 136 | #endif |
94 | 137 | ||
138 | int omap_irq_enable_vblank(struct drm_device *dev, int crtc); | ||
139 | void omap_irq_disable_vblank(struct drm_device *dev, int crtc); | ||
140 | irqreturn_t omap_irq_handler(DRM_IRQ_ARGS); | ||
141 | void omap_irq_preinstall(struct drm_device *dev); | ||
142 | int omap_irq_postinstall(struct drm_device *dev); | ||
143 | void omap_irq_uninstall(struct drm_device *dev); | ||
144 | void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq); | ||
145 | void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq); | ||
146 | int omap_drm_irq_uninstall(struct drm_device *dev); | ||
147 | int omap_drm_irq_install(struct drm_device *dev); | ||
148 | |||
95 | struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev); | 149 | struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev); |
96 | void omap_fbdev_free(struct drm_device *dev); | 150 | void omap_fbdev_free(struct drm_device *dev); |
97 | 151 | ||
152 | const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc); | ||
153 | enum omap_channel omap_crtc_channel(struct drm_crtc *crtc); | ||
154 | int omap_crtc_apply(struct drm_crtc *crtc, | ||
155 | struct omap_drm_apply *apply); | ||
98 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, | 156 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, |
99 | struct omap_overlay *ovl, int id); | 157 | struct drm_plane *plane, enum omap_channel channel, int id); |
100 | 158 | ||
101 | struct drm_plane *omap_plane_init(struct drm_device *dev, | 159 | struct drm_plane *omap_plane_init(struct drm_device *dev, |
102 | struct omap_overlay *ovl, unsigned int possible_crtcs, | 160 | int plane_id, bool private_plane); |
103 | bool priv); | ||
104 | int omap_plane_dpms(struct drm_plane *plane, int mode); | 161 | int omap_plane_dpms(struct drm_plane *plane, int mode); |
105 | int omap_plane_mode_set(struct drm_plane *plane, | 162 | int omap_plane_mode_set(struct drm_plane *plane, |
106 | struct drm_crtc *crtc, struct drm_framebuffer *fb, | 163 | struct drm_crtc *crtc, struct drm_framebuffer *fb, |
107 | int crtc_x, int crtc_y, | 164 | int crtc_x, int crtc_y, |
108 | unsigned int crtc_w, unsigned int crtc_h, | 165 | unsigned int crtc_w, unsigned int crtc_h, |
109 | uint32_t src_x, uint32_t src_y, | 166 | uint32_t src_x, uint32_t src_y, |
110 | uint32_t src_w, uint32_t src_h); | 167 | uint32_t src_w, uint32_t src_h, |
111 | void omap_plane_on_endwin(struct drm_plane *plane, | ||
112 | void (*fxn)(void *), void *arg); | 168 | void (*fxn)(void *), void *arg); |
113 | void omap_plane_install_properties(struct drm_plane *plane, | 169 | void omap_plane_install_properties(struct drm_plane *plane, |
114 | struct drm_mode_object *obj); | 170 | struct drm_mode_object *obj); |
@@ -116,21 +172,25 @@ int omap_plane_set_property(struct drm_plane *plane, | |||
116 | struct drm_property *property, uint64_t val); | 172 | struct drm_property *property, uint64_t val); |
117 | 173 | ||
118 | struct drm_encoder *omap_encoder_init(struct drm_device *dev, | 174 | struct drm_encoder *omap_encoder_init(struct drm_device *dev, |
119 | struct omap_overlay_manager *mgr); | 175 | struct omap_dss_device *dssdev); |
120 | struct omap_overlay_manager *omap_encoder_get_manager( | 176 | int omap_encoder_set_enabled(struct drm_encoder *encoder, bool enabled); |
177 | int omap_encoder_update(struct drm_encoder *encoder, | ||
178 | struct omap_overlay_manager *mgr, | ||
179 | struct omap_video_timings *timings); | ||
180 | |||
181 | struct drm_connector *omap_connector_init(struct drm_device *dev, | ||
182 | int connector_type, struct omap_dss_device *dssdev, | ||
121 | struct drm_encoder *encoder); | 183 | struct drm_encoder *encoder); |
122 | struct drm_encoder *omap_connector_attached_encoder( | 184 | struct drm_encoder *omap_connector_attached_encoder( |
123 | struct drm_connector *connector); | 185 | struct drm_connector *connector); |
124 | enum drm_connector_status omap_connector_detect( | ||
125 | struct drm_connector *connector, bool force); | ||
126 | |||
127 | struct drm_connector *omap_connector_init(struct drm_device *dev, | ||
128 | int connector_type, struct omap_dss_device *dssdev); | ||
129 | void omap_connector_mode_set(struct drm_connector *connector, | ||
130 | struct drm_display_mode *mode); | ||
131 | void omap_connector_flush(struct drm_connector *connector, | 186 | void omap_connector_flush(struct drm_connector *connector, |
132 | int x, int y, int w, int h); | 187 | int x, int y, int w, int h); |
133 | 188 | ||
189 | void copy_timings_omap_to_drm(struct drm_display_mode *mode, | ||
190 | struct omap_video_timings *timings); | ||
191 | void copy_timings_drm_to_omap(struct omap_video_timings *timings, | ||
192 | struct drm_display_mode *mode); | ||
193 | |||
134 | uint32_t omap_framebuffer_get_formats(uint32_t *pixel_formats, | 194 | uint32_t omap_framebuffer_get_formats(uint32_t *pixel_formats, |
135 | uint32_t max_formats, enum omap_color_mode supported_modes); | 195 | uint32_t max_formats, enum omap_color_mode supported_modes); |
136 | struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, | 196 | struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, |
@@ -207,6 +267,40 @@ static inline int align_pitch(int pitch, int width, int bpp) | |||
207 | return ALIGN(pitch, 8 * bytespp); | 267 | return ALIGN(pitch, 8 * bytespp); |
208 | } | 268 | } |
209 | 269 | ||
270 | static inline enum omap_channel pipe2chan(int pipe) | ||
271 | { | ||
272 | int num_mgrs = dss_feat_get_num_mgrs(); | ||
273 | |||
274 | /* | ||
275 | * We usually don't want to create a CRTC for each manager, | ||
276 | * at least not until we have a way to expose private planes | ||
277 | * to userspace. Otherwise there would not be enough video | ||
278 | * pipes left for drm planes. The higher #'d managers tend | ||
279 | * to have more features so start in reverse order. | ||
280 | */ | ||
281 | return num_mgrs - pipe - 1; | ||
282 | } | ||
283 | |||
284 | /* map crtc to vblank mask */ | ||
285 | static inline uint32_t pipe2vbl(int crtc) | ||
286 | { | ||
287 | enum omap_channel channel = pipe2chan(crtc); | ||
288 | return dispc_mgr_get_vsync_irq(channel); | ||
289 | } | ||
290 | |||
291 | static inline int crtc2pipe(struct drm_device *dev, struct drm_crtc *crtc) | ||
292 | { | ||
293 | struct omap_drm_private *priv = dev->dev_private; | ||
294 | int i; | ||
295 | |||
296 | for (i = 0; i < ARRAY_SIZE(priv->crtcs); i++) | ||
297 | if (priv->crtcs[i] == crtc) | ||
298 | return i; | ||
299 | |||
300 | BUG(); /* bogus CRTC ptr */ | ||
301 | return -1; | ||
302 | } | ||
303 | |||
210 | /* should these be made into common util helpers? | 304 | /* should these be made into common util helpers? |
211 | */ | 305 | */ |
212 | 306 | ||
diff --git a/drivers/staging/omapdrm/omap_encoder.c b/drivers/staging/omapdrm/omap_encoder.c index 5341d5e3e317..e053160d2db3 100644 --- a/drivers/staging/omapdrm/omap_encoder.c +++ b/drivers/staging/omapdrm/omap_encoder.c | |||
@@ -22,37 +22,56 @@ | |||
22 | #include "drm_crtc.h" | 22 | #include "drm_crtc.h" |
23 | #include "drm_crtc_helper.h" | 23 | #include "drm_crtc_helper.h" |
24 | 24 | ||
25 | #include <linux/list.h> | ||
26 | |||
27 | |||
25 | /* | 28 | /* |
26 | * encoder funcs | 29 | * encoder funcs |
27 | */ | 30 | */ |
28 | 31 | ||
29 | #define to_omap_encoder(x) container_of(x, struct omap_encoder, base) | 32 | #define to_omap_encoder(x) container_of(x, struct omap_encoder, base) |
30 | 33 | ||
34 | /* The encoder and connector both map to same dssdev.. the encoder | ||
35 | * handles the 'active' parts, ie. anything the modifies the state | ||
36 | * of the hw, and the connector handles the 'read-only' parts, like | ||
37 | * detecting connection and reading edid. | ||
38 | */ | ||
31 | struct omap_encoder { | 39 | struct omap_encoder { |
32 | struct drm_encoder base; | 40 | struct drm_encoder base; |
33 | struct omap_overlay_manager *mgr; | 41 | struct omap_dss_device *dssdev; |
34 | }; | 42 | }; |
35 | 43 | ||
36 | static void omap_encoder_destroy(struct drm_encoder *encoder) | 44 | static void omap_encoder_destroy(struct drm_encoder *encoder) |
37 | { | 45 | { |
38 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | 46 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); |
39 | DBG("%s", omap_encoder->mgr->name); | ||
40 | drm_encoder_cleanup(encoder); | 47 | drm_encoder_cleanup(encoder); |
41 | kfree(omap_encoder); | 48 | kfree(omap_encoder); |
42 | } | 49 | } |
43 | 50 | ||
51 | static const struct drm_encoder_funcs omap_encoder_funcs = { | ||
52 | .destroy = omap_encoder_destroy, | ||
53 | }; | ||
54 | |||
55 | /* | ||
56 | * The CRTC drm_crtc_helper_set_mode() doesn't really give us the right | ||
57 | * order.. the easiest way to work around this for now is to make all | ||
58 | * the encoder-helper's no-op's and have the omap_crtc code take care | ||
59 | * of the sequencing and call us in the right points. | ||
60 | * | ||
61 | * Eventually to handle connecting CRTCs to different encoders properly, | ||
62 | * either the CRTC helpers need to change or we need to replace | ||
63 | * drm_crtc_helper_set_mode(), but lets wait until atomic-modeset for | ||
64 | * that. | ||
65 | */ | ||
66 | |||
44 | static void omap_encoder_dpms(struct drm_encoder *encoder, int mode) | 67 | static void omap_encoder_dpms(struct drm_encoder *encoder, int mode) |
45 | { | 68 | { |
46 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | ||
47 | DBG("%s: %d", omap_encoder->mgr->name, mode); | ||
48 | } | 69 | } |
49 | 70 | ||
50 | static bool omap_encoder_mode_fixup(struct drm_encoder *encoder, | 71 | static bool omap_encoder_mode_fixup(struct drm_encoder *encoder, |
51 | const struct drm_display_mode *mode, | 72 | const struct drm_display_mode *mode, |
52 | struct drm_display_mode *adjusted_mode) | 73 | struct drm_display_mode *adjusted_mode) |
53 | { | 74 | { |
54 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | ||
55 | DBG("%s", omap_encoder->mgr->name); | ||
56 | return true; | 75 | return true; |
57 | } | 76 | } |
58 | 77 | ||
@@ -60,47 +79,16 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder, | |||
60 | struct drm_display_mode *mode, | 79 | struct drm_display_mode *mode, |
61 | struct drm_display_mode *adjusted_mode) | 80 | struct drm_display_mode *adjusted_mode) |
62 | { | 81 | { |
63 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | ||
64 | struct drm_device *dev = encoder->dev; | ||
65 | struct omap_drm_private *priv = dev->dev_private; | ||
66 | int i; | ||
67 | |||
68 | mode = adjusted_mode; | ||
69 | |||
70 | DBG("%s: set mode: %dx%d", omap_encoder->mgr->name, | ||
71 | mode->hdisplay, mode->vdisplay); | ||
72 | |||
73 | for (i = 0; i < priv->num_connectors; i++) { | ||
74 | struct drm_connector *connector = priv->connectors[i]; | ||
75 | if (connector->encoder == encoder) | ||
76 | omap_connector_mode_set(connector, mode); | ||
77 | |||
78 | } | ||
79 | } | 82 | } |
80 | 83 | ||
81 | static void omap_encoder_prepare(struct drm_encoder *encoder) | 84 | static void omap_encoder_prepare(struct drm_encoder *encoder) |
82 | { | 85 | { |
83 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | ||
84 | struct drm_encoder_helper_funcs *encoder_funcs = | ||
85 | encoder->helper_private; | ||
86 | DBG("%s", omap_encoder->mgr->name); | ||
87 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF); | ||
88 | } | 86 | } |
89 | 87 | ||
90 | static void omap_encoder_commit(struct drm_encoder *encoder) | 88 | static void omap_encoder_commit(struct drm_encoder *encoder) |
91 | { | 89 | { |
92 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | ||
93 | struct drm_encoder_helper_funcs *encoder_funcs = | ||
94 | encoder->helper_private; | ||
95 | DBG("%s", omap_encoder->mgr->name); | ||
96 | omap_encoder->mgr->apply(omap_encoder->mgr); | ||
97 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); | ||
98 | } | 90 | } |
99 | 91 | ||
100 | static const struct drm_encoder_funcs omap_encoder_funcs = { | ||
101 | .destroy = omap_encoder_destroy, | ||
102 | }; | ||
103 | |||
104 | static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = { | 92 | static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = { |
105 | .dpms = omap_encoder_dpms, | 93 | .dpms = omap_encoder_dpms, |
106 | .mode_fixup = omap_encoder_mode_fixup, | 94 | .mode_fixup = omap_encoder_mode_fixup, |
@@ -109,23 +97,54 @@ static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = { | |||
109 | .commit = omap_encoder_commit, | 97 | .commit = omap_encoder_commit, |
110 | }; | 98 | }; |
111 | 99 | ||
112 | struct omap_overlay_manager *omap_encoder_get_manager( | 100 | /* |
113 | struct drm_encoder *encoder) | 101 | * Instead of relying on the helpers for modeset, the omap_crtc code |
102 | * calls these functions in the proper sequence. | ||
103 | */ | ||
104 | |||
105 | int omap_encoder_set_enabled(struct drm_encoder *encoder, bool enabled) | ||
114 | { | 106 | { |
115 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | 107 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); |
116 | return omap_encoder->mgr; | 108 | struct omap_dss_device *dssdev = omap_encoder->dssdev; |
109 | struct omap_dss_driver *dssdrv = dssdev->driver; | ||
110 | |||
111 | if (enabled) { | ||
112 | return dssdrv->enable(dssdev); | ||
113 | } else { | ||
114 | dssdrv->disable(dssdev); | ||
115 | return 0; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | int omap_encoder_update(struct drm_encoder *encoder, | ||
120 | struct omap_overlay_manager *mgr, | ||
121 | struct omap_video_timings *timings) | ||
122 | { | ||
123 | struct drm_device *dev = encoder->dev; | ||
124 | struct omap_encoder *omap_encoder = to_omap_encoder(encoder); | ||
125 | struct omap_dss_device *dssdev = omap_encoder->dssdev; | ||
126 | struct omap_dss_driver *dssdrv = dssdev->driver; | ||
127 | int ret; | ||
128 | |||
129 | dssdev->output->manager = mgr; | ||
130 | |||
131 | ret = dssdrv->check_timings(dssdev, timings); | ||
132 | if (ret) { | ||
133 | dev_err(dev->dev, "could not set timings: %d\n", ret); | ||
134 | return ret; | ||
135 | } | ||
136 | |||
137 | dssdrv->set_timings(dssdev, timings); | ||
138 | |||
139 | return 0; | ||
117 | } | 140 | } |
118 | 141 | ||
119 | /* initialize encoder */ | 142 | /* initialize encoder */ |
120 | struct drm_encoder *omap_encoder_init(struct drm_device *dev, | 143 | struct drm_encoder *omap_encoder_init(struct drm_device *dev, |
121 | struct omap_overlay_manager *mgr) | 144 | struct omap_dss_device *dssdev) |
122 | { | 145 | { |
123 | struct drm_encoder *encoder = NULL; | 146 | struct drm_encoder *encoder = NULL; |
124 | struct omap_encoder *omap_encoder; | 147 | struct omap_encoder *omap_encoder; |
125 | struct omap_overlay_manager_info info; | ||
126 | int ret; | ||
127 | |||
128 | DBG("%s", mgr->name); | ||
129 | 148 | ||
130 | omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL); | 149 | omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL); |
131 | if (!omap_encoder) { | 150 | if (!omap_encoder) { |
@@ -133,33 +152,14 @@ struct drm_encoder *omap_encoder_init(struct drm_device *dev, | |||
133 | goto fail; | 152 | goto fail; |
134 | } | 153 | } |
135 | 154 | ||
136 | omap_encoder->mgr = mgr; | 155 | omap_encoder->dssdev = dssdev; |
156 | |||
137 | encoder = &omap_encoder->base; | 157 | encoder = &omap_encoder->base; |
138 | 158 | ||
139 | drm_encoder_init(dev, encoder, &omap_encoder_funcs, | 159 | drm_encoder_init(dev, encoder, &omap_encoder_funcs, |
140 | DRM_MODE_ENCODER_TMDS); | 160 | DRM_MODE_ENCODER_TMDS); |
141 | drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs); | 161 | drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs); |
142 | 162 | ||
143 | mgr->get_manager_info(mgr, &info); | ||
144 | |||
145 | /* TODO: fix hard-coded setup.. */ | ||
146 | info.default_color = 0x00000000; | ||
147 | info.trans_key = 0x00000000; | ||
148 | info.trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST; | ||
149 | info.trans_enabled = false; | ||
150 | |||
151 | ret = mgr->set_manager_info(mgr, &info); | ||
152 | if (ret) { | ||
153 | dev_err(dev->dev, "could not set manager info\n"); | ||
154 | goto fail; | ||
155 | } | ||
156 | |||
157 | ret = mgr->apply(mgr); | ||
158 | if (ret) { | ||
159 | dev_err(dev->dev, "could not apply\n"); | ||
160 | goto fail; | ||
161 | } | ||
162 | |||
163 | return encoder; | 163 | return encoder; |
164 | 164 | ||
165 | fail: | 165 | fail: |
diff --git a/drivers/staging/omapdrm/omap_gem_dmabuf.c b/drivers/staging/omapdrm/omap_gem_dmabuf.c index 9a302062b031..eabb8b57f6c3 100644 --- a/drivers/staging/omapdrm/omap_gem_dmabuf.c +++ b/drivers/staging/omapdrm/omap_gem_dmabuf.c | |||
@@ -194,7 +194,7 @@ struct dma_buf_ops omap_dmabuf_ops = { | |||
194 | struct dma_buf *omap_gem_prime_export(struct drm_device *dev, | 194 | struct dma_buf *omap_gem_prime_export(struct drm_device *dev, |
195 | struct drm_gem_object *obj, int flags) | 195 | struct drm_gem_object *obj, int flags) |
196 | { | 196 | { |
197 | return dma_buf_export(obj, &omap_dmabuf_ops, obj->size, 0600); | 197 | return dma_buf_export(obj, &omap_dmabuf_ops, obj->size, flags); |
198 | } | 198 | } |
199 | 199 | ||
200 | struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, | 200 | struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, |
diff --git a/drivers/staging/omapdrm/omap_irq.c b/drivers/staging/omapdrm/omap_irq.c new file mode 100644 index 000000000000..2629ba7be6c8 --- /dev/null +++ b/drivers/staging/omapdrm/omap_irq.c | |||
@@ -0,0 +1,322 @@ | |||
1 | /* | ||
2 | * drivers/staging/omapdrm/omap_irq.c | ||
3 | * | ||
4 | * Copyright (C) 2012 Texas Instruments | ||
5 | * Author: Rob Clark <rob.clark@linaro.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include "omap_drv.h" | ||
21 | |||
22 | static DEFINE_SPINLOCK(list_lock); | ||
23 | |||
24 | static void omap_irq_error_handler(struct omap_drm_irq *irq, | ||
25 | uint32_t irqstatus) | ||
26 | { | ||
27 | DRM_ERROR("errors: %08x\n", irqstatus); | ||
28 | } | ||
29 | |||
30 | /* call with list_lock and dispc runtime held */ | ||
31 | static void omap_irq_update(struct drm_device *dev) | ||
32 | { | ||
33 | struct omap_drm_private *priv = dev->dev_private; | ||
34 | struct omap_drm_irq *irq; | ||
35 | uint32_t irqmask = priv->vblank_mask; | ||
36 | |||
37 | BUG_ON(!spin_is_locked(&list_lock)); | ||
38 | |||
39 | list_for_each_entry(irq, &priv->irq_list, node) | ||
40 | irqmask |= irq->irqmask; | ||
41 | |||
42 | DBG("irqmask=%08x", irqmask); | ||
43 | |||
44 | dispc_write_irqenable(irqmask); | ||
45 | dispc_read_irqenable(); /* flush posted write */ | ||
46 | } | ||
47 | |||
48 | void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq) | ||
49 | { | ||
50 | struct omap_drm_private *priv = dev->dev_private; | ||
51 | unsigned long flags; | ||
52 | |||
53 | dispc_runtime_get(); | ||
54 | spin_lock_irqsave(&list_lock, flags); | ||
55 | |||
56 | if (!WARN_ON(irq->registered)) { | ||
57 | irq->registered = true; | ||
58 | list_add(&irq->node, &priv->irq_list); | ||
59 | omap_irq_update(dev); | ||
60 | } | ||
61 | |||
62 | spin_unlock_irqrestore(&list_lock, flags); | ||
63 | dispc_runtime_put(); | ||
64 | } | ||
65 | |||
66 | void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq) | ||
67 | { | ||
68 | unsigned long flags; | ||
69 | |||
70 | dispc_runtime_get(); | ||
71 | spin_lock_irqsave(&list_lock, flags); | ||
72 | |||
73 | if (!WARN_ON(!irq->registered)) { | ||
74 | irq->registered = false; | ||
75 | list_del(&irq->node); | ||
76 | omap_irq_update(dev); | ||
77 | } | ||
78 | |||
79 | spin_unlock_irqrestore(&list_lock, flags); | ||
80 | dispc_runtime_put(); | ||
81 | } | ||
82 | |||
83 | struct omap_irq_wait { | ||
84 | struct omap_drm_irq irq; | ||
85 | int count; | ||
86 | }; | ||
87 | |||
88 | static DECLARE_WAIT_QUEUE_HEAD(wait_event); | ||
89 | |||
90 | static void wait_irq(struct omap_drm_irq *irq, uint32_t irqstatus) | ||
91 | { | ||
92 | struct omap_irq_wait *wait = | ||
93 | container_of(irq, struct omap_irq_wait, irq); | ||
94 | wait->count--; | ||
95 | wake_up_all(&wait_event); | ||
96 | } | ||
97 | |||
98 | struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev, | ||
99 | uint32_t irqmask, int count) | ||
100 | { | ||
101 | struct omap_irq_wait *wait = kzalloc(sizeof(*wait), GFP_KERNEL); | ||
102 | wait->irq.irq = wait_irq; | ||
103 | wait->irq.irqmask = irqmask; | ||
104 | wait->count = count; | ||
105 | omap_irq_register(dev, &wait->irq); | ||
106 | return wait; | ||
107 | } | ||
108 | |||
109 | int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, | ||
110 | unsigned long timeout) | ||
111 | { | ||
112 | int ret = wait_event_timeout(wait_event, (wait->count <= 0), timeout); | ||
113 | omap_irq_unregister(dev, &wait->irq); | ||
114 | kfree(wait); | ||
115 | if (ret == 0) | ||
116 | return -1; | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | /** | ||
121 | * enable_vblank - enable vblank interrupt events | ||
122 | * @dev: DRM device | ||
123 | * @crtc: which irq to enable | ||
124 | * | ||
125 | * Enable vblank interrupts for @crtc. If the device doesn't have | ||
126 | * a hardware vblank counter, this routine should be a no-op, since | ||
127 | * interrupts will have to stay on to keep the count accurate. | ||
128 | * | ||
129 | * RETURNS | ||
130 | * Zero on success, appropriate errno if the given @crtc's vblank | ||
131 | * interrupt cannot be enabled. | ||
132 | */ | ||
133 | int omap_irq_enable_vblank(struct drm_device *dev, int crtc) | ||
134 | { | ||
135 | struct omap_drm_private *priv = dev->dev_private; | ||
136 | unsigned long flags; | ||
137 | |||
138 | DBG("dev=%p, crtc=%d", dev, crtc); | ||
139 | |||
140 | dispc_runtime_get(); | ||
141 | spin_lock_irqsave(&list_lock, flags); | ||
142 | priv->vblank_mask |= pipe2vbl(crtc); | ||
143 | omap_irq_update(dev); | ||
144 | spin_unlock_irqrestore(&list_lock, flags); | ||
145 | dispc_runtime_put(); | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * disable_vblank - disable vblank interrupt events | ||
152 | * @dev: DRM device | ||
153 | * @crtc: which irq to enable | ||
154 | * | ||
155 | * Disable vblank interrupts for @crtc. If the device doesn't have | ||
156 | * a hardware vblank counter, this routine should be a no-op, since | ||
157 | * interrupts will have to stay on to keep the count accurate. | ||
158 | */ | ||
159 | void omap_irq_disable_vblank(struct drm_device *dev, int crtc) | ||
160 | { | ||
161 | struct omap_drm_private *priv = dev->dev_private; | ||
162 | unsigned long flags; | ||
163 | |||
164 | DBG("dev=%p, crtc=%d", dev, crtc); | ||
165 | |||
166 | dispc_runtime_get(); | ||
167 | spin_lock_irqsave(&list_lock, flags); | ||
168 | priv->vblank_mask &= ~pipe2vbl(crtc); | ||
169 | omap_irq_update(dev); | ||
170 | spin_unlock_irqrestore(&list_lock, flags); | ||
171 | dispc_runtime_put(); | ||
172 | } | ||
173 | |||
174 | irqreturn_t omap_irq_handler(DRM_IRQ_ARGS) | ||
175 | { | ||
176 | struct drm_device *dev = (struct drm_device *) arg; | ||
177 | struct omap_drm_private *priv = dev->dev_private; | ||
178 | struct omap_drm_irq *handler, *n; | ||
179 | unsigned long flags; | ||
180 | unsigned int id; | ||
181 | u32 irqstatus; | ||
182 | |||
183 | irqstatus = dispc_read_irqstatus(); | ||
184 | dispc_clear_irqstatus(irqstatus); | ||
185 | dispc_read_irqstatus(); /* flush posted write */ | ||
186 | |||
187 | VERB("irqs: %08x", irqstatus); | ||
188 | |||
189 | for (id = 0; id < priv->num_crtcs; id++) | ||
190 | if (irqstatus & pipe2vbl(id)) | ||
191 | drm_handle_vblank(dev, id); | ||
192 | |||
193 | spin_lock_irqsave(&list_lock, flags); | ||
194 | list_for_each_entry_safe(handler, n, &priv->irq_list, node) { | ||
195 | if (handler->irqmask & irqstatus) { | ||
196 | spin_unlock_irqrestore(&list_lock, flags); | ||
197 | handler->irq(handler, handler->irqmask & irqstatus); | ||
198 | spin_lock_irqsave(&list_lock, flags); | ||
199 | } | ||
200 | } | ||
201 | spin_unlock_irqrestore(&list_lock, flags); | ||
202 | |||
203 | return IRQ_HANDLED; | ||
204 | } | ||
205 | |||
206 | void omap_irq_preinstall(struct drm_device *dev) | ||
207 | { | ||
208 | DBG("dev=%p", dev); | ||
209 | dispc_runtime_get(); | ||
210 | dispc_clear_irqstatus(0xffffffff); | ||
211 | dispc_runtime_put(); | ||
212 | } | ||
213 | |||
214 | int omap_irq_postinstall(struct drm_device *dev) | ||
215 | { | ||
216 | struct omap_drm_private *priv = dev->dev_private; | ||
217 | struct omap_drm_irq *error_handler = &priv->error_handler; | ||
218 | |||
219 | DBG("dev=%p", dev); | ||
220 | |||
221 | INIT_LIST_HEAD(&priv->irq_list); | ||
222 | |||
223 | error_handler->irq = omap_irq_error_handler; | ||
224 | error_handler->irqmask = DISPC_IRQ_OCP_ERR; | ||
225 | |||
226 | /* for now ignore DISPC_IRQ_SYNC_LOST_DIGIT.. really I think | ||
227 | * we just need to ignore it while enabling tv-out | ||
228 | */ | ||
229 | error_handler->irqmask &= ~DISPC_IRQ_SYNC_LOST_DIGIT; | ||
230 | |||
231 | omap_irq_register(dev, error_handler); | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | void omap_irq_uninstall(struct drm_device *dev) | ||
237 | { | ||
238 | DBG("dev=%p", dev); | ||
239 | // TODO prolly need to call drm_irq_uninstall() somewhere too | ||
240 | } | ||
241 | |||
242 | /* | ||
243 | * We need a special version, instead of just using drm_irq_install(), | ||
244 | * because we need to register the irq via omapdss. Once omapdss and | ||
245 | * omapdrm are merged together we can assign the dispc hwmod data to | ||
246 | * ourselves and drop these and just use drm_irq_{install,uninstall}() | ||
247 | */ | ||
248 | |||
249 | int omap_drm_irq_install(struct drm_device *dev) | ||
250 | { | ||
251 | int ret; | ||
252 | |||
253 | mutex_lock(&dev->struct_mutex); | ||
254 | |||
255 | if (dev->irq_enabled) { | ||
256 | mutex_unlock(&dev->struct_mutex); | ||
257 | return -EBUSY; | ||
258 | } | ||
259 | dev->irq_enabled = 1; | ||
260 | mutex_unlock(&dev->struct_mutex); | ||
261 | |||
262 | /* Before installing handler */ | ||
263 | if (dev->driver->irq_preinstall) | ||
264 | dev->driver->irq_preinstall(dev); | ||
265 | |||
266 | ret = dispc_request_irq(dev->driver->irq_handler, dev); | ||
267 | |||
268 | if (ret < 0) { | ||
269 | mutex_lock(&dev->struct_mutex); | ||
270 | dev->irq_enabled = 0; | ||
271 | mutex_unlock(&dev->struct_mutex); | ||
272 | return ret; | ||
273 | } | ||
274 | |||
275 | /* After installing handler */ | ||
276 | if (dev->driver->irq_postinstall) | ||
277 | ret = dev->driver->irq_postinstall(dev); | ||
278 | |||
279 | if (ret < 0) { | ||
280 | mutex_lock(&dev->struct_mutex); | ||
281 | dev->irq_enabled = 0; | ||
282 | mutex_unlock(&dev->struct_mutex); | ||
283 | dispc_free_irq(dev); | ||
284 | } | ||
285 | |||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | int omap_drm_irq_uninstall(struct drm_device *dev) | ||
290 | { | ||
291 | unsigned long irqflags; | ||
292 | int irq_enabled, i; | ||
293 | |||
294 | mutex_lock(&dev->struct_mutex); | ||
295 | irq_enabled = dev->irq_enabled; | ||
296 | dev->irq_enabled = 0; | ||
297 | mutex_unlock(&dev->struct_mutex); | ||
298 | |||
299 | /* | ||
300 | * Wake up any waiters so they don't hang. | ||
301 | */ | ||
302 | if (dev->num_crtcs) { | ||
303 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | ||
304 | for (i = 0; i < dev->num_crtcs; i++) { | ||
305 | DRM_WAKEUP(&dev->vbl_queue[i]); | ||
306 | dev->vblank_enabled[i] = 0; | ||
307 | dev->last_vblank[i] = | ||
308 | dev->driver->get_vblank_counter(dev, i); | ||
309 | } | ||
310 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
311 | } | ||
312 | |||
313 | if (!irq_enabled) | ||
314 | return -EINVAL; | ||
315 | |||
316 | if (dev->driver->irq_uninstall) | ||
317 | dev->driver->irq_uninstall(dev); | ||
318 | |||
319 | dispc_free_irq(dev); | ||
320 | |||
321 | return 0; | ||
322 | } | ||
diff --git a/drivers/staging/omapdrm/omap_plane.c b/drivers/staging/omapdrm/omap_plane.c index 2a8e5bab49c9..bb989d7f026d 100644 --- a/drivers/staging/omapdrm/omap_plane.c +++ b/drivers/staging/omapdrm/omap_plane.c | |||
@@ -41,12 +41,14 @@ struct callback { | |||
41 | 41 | ||
42 | struct omap_plane { | 42 | struct omap_plane { |
43 | struct drm_plane base; | 43 | struct drm_plane base; |
44 | struct omap_overlay *ovl; | 44 | int id; /* TODO rename omap_plane -> omap_plane_id in omapdss so I can use the enum */ |
45 | const char *name; | ||
45 | struct omap_overlay_info info; | 46 | struct omap_overlay_info info; |
47 | struct omap_drm_apply apply; | ||
46 | 48 | ||
47 | /* position/orientation of scanout within the fb: */ | 49 | /* position/orientation of scanout within the fb: */ |
48 | struct omap_drm_window win; | 50 | struct omap_drm_window win; |
49 | 51 | bool enabled; | |
50 | 52 | ||
51 | /* last fb that we pinned: */ | 53 | /* last fb that we pinned: */ |
52 | struct drm_framebuffer *pinned_fb; | 54 | struct drm_framebuffer *pinned_fb; |
@@ -54,189 +56,15 @@ struct omap_plane { | |||
54 | uint32_t nformats; | 56 | uint32_t nformats; |
55 | uint32_t formats[32]; | 57 | uint32_t formats[32]; |
56 | 58 | ||
57 | /* for synchronizing access to unpins fifo */ | 59 | struct omap_drm_irq error_irq; |
58 | struct mutex unpin_mutex; | ||
59 | 60 | ||
60 | /* set of bo's pending unpin until next END_WIN irq */ | 61 | /* set of bo's pending unpin until next post_apply() */ |
61 | DECLARE_KFIFO_PTR(unpin_fifo, struct drm_gem_object *); | 62 | DECLARE_KFIFO_PTR(unpin_fifo, struct drm_gem_object *); |
62 | int num_unpins, pending_num_unpins; | ||
63 | |||
64 | /* for deferred unpin when we need to wait for scanout complete irq */ | ||
65 | struct work_struct work; | ||
66 | |||
67 | /* callback on next endwin irq */ | ||
68 | struct callback endwin; | ||
69 | }; | ||
70 | 63 | ||
71 | /* map from ovl->id to the irq we are interested in for scanout-done */ | 64 | // XXX maybe get rid of this and handle vblank in crtc too? |
72 | static const uint32_t id2irq[] = { | 65 | struct callback apply_done_cb; |
73 | [OMAP_DSS_GFX] = DISPC_IRQ_GFX_END_WIN, | ||
74 | [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_END_WIN, | ||
75 | [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_END_WIN, | ||
76 | [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_END_WIN, | ||
77 | }; | 66 | }; |
78 | 67 | ||
79 | static void dispc_isr(void *arg, uint32_t mask) | ||
80 | { | ||
81 | struct drm_plane *plane = arg; | ||
82 | struct omap_plane *omap_plane = to_omap_plane(plane); | ||
83 | struct omap_drm_private *priv = plane->dev->dev_private; | ||
84 | |||
85 | omap_dispc_unregister_isr(dispc_isr, plane, | ||
86 | id2irq[omap_plane->ovl->id]); | ||
87 | |||
88 | queue_work(priv->wq, &omap_plane->work); | ||
89 | } | ||
90 | |||
91 | static void unpin_worker(struct work_struct *work) | ||
92 | { | ||
93 | struct omap_plane *omap_plane = | ||
94 | container_of(work, struct omap_plane, work); | ||
95 | struct callback endwin; | ||
96 | |||
97 | mutex_lock(&omap_plane->unpin_mutex); | ||
98 | DBG("unpinning %d of %d", omap_plane->num_unpins, | ||
99 | omap_plane->num_unpins + omap_plane->pending_num_unpins); | ||
100 | while (omap_plane->num_unpins > 0) { | ||
101 | struct drm_gem_object *bo = NULL; | ||
102 | int ret = kfifo_get(&omap_plane->unpin_fifo, &bo); | ||
103 | WARN_ON(!ret); | ||
104 | omap_gem_put_paddr(bo); | ||
105 | drm_gem_object_unreference_unlocked(bo); | ||
106 | omap_plane->num_unpins--; | ||
107 | } | ||
108 | endwin = omap_plane->endwin; | ||
109 | omap_plane->endwin.fxn = NULL; | ||
110 | mutex_unlock(&omap_plane->unpin_mutex); | ||
111 | |||
112 | if (endwin.fxn) | ||
113 | endwin.fxn(endwin.arg); | ||
114 | } | ||
115 | |||
116 | static void install_irq(struct drm_plane *plane) | ||
117 | { | ||
118 | struct omap_plane *omap_plane = to_omap_plane(plane); | ||
119 | struct omap_overlay *ovl = omap_plane->ovl; | ||
120 | int ret; | ||
121 | |||
122 | ret = omap_dispc_register_isr(dispc_isr, plane, id2irq[ovl->id]); | ||
123 | |||
124 | /* | ||
125 | * omapdss has upper limit on # of registered irq handlers, | ||
126 | * which we shouldn't hit.. but if we do the limit should | ||
127 | * be raised or bad things happen: | ||
128 | */ | ||
129 | WARN_ON(ret == -EBUSY); | ||
130 | } | ||
131 | |||
132 | /* push changes down to dss2 */ | ||
133 | static int commit(struct drm_plane *plane) | ||
134 | { | ||
135 | struct drm_device *dev = plane->dev; | ||
136 | struct omap_plane *omap_plane = to_omap_plane(plane); | ||
137 | struct omap_overlay *ovl = omap_plane->ovl; | ||
138 | struct omap_overlay_info *info = &omap_plane->info; | ||
139 | int ret; | ||
140 | |||
141 | DBG("%s", ovl->name); | ||
142 | DBG("%dx%d -> %dx%d (%d)", info->width, info->height, info->out_width, | ||
143 | info->out_height, info->screen_width); | ||
144 | DBG("%d,%d %08x %08x", info->pos_x, info->pos_y, | ||
145 | info->paddr, info->p_uv_addr); | ||
146 | |||
147 | /* NOTE: do we want to do this at all here, or just wait | ||
148 | * for dpms(ON) since other CRTC's may not have their mode | ||
149 | * set yet, so fb dimensions may still change.. | ||
150 | */ | ||
151 | ret = ovl->set_overlay_info(ovl, info); | ||
152 | if (ret) { | ||
153 | dev_err(dev->dev, "could not set overlay info\n"); | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | mutex_lock(&omap_plane->unpin_mutex); | ||
158 | omap_plane->num_unpins += omap_plane->pending_num_unpins; | ||
159 | omap_plane->pending_num_unpins = 0; | ||
160 | mutex_unlock(&omap_plane->unpin_mutex); | ||
161 | |||
162 | /* our encoder doesn't necessarily get a commit() after this, in | ||
163 | * particular in the dpms() and mode_set_base() cases, so force the | ||
164 | * manager to update: | ||
165 | * | ||
166 | * could this be in the encoder somehow? | ||
167 | */ | ||
168 | if (ovl->manager) { | ||
169 | ret = ovl->manager->apply(ovl->manager); | ||
170 | if (ret) { | ||
171 | dev_err(dev->dev, "could not apply settings\n"); | ||
172 | return ret; | ||
173 | } | ||
174 | |||
175 | /* | ||
176 | * NOTE: really this should be atomic w/ mgr->apply() but | ||
177 | * omapdss does not expose such an API | ||
178 | */ | ||
179 | if (omap_plane->num_unpins > 0) | ||
180 | install_irq(plane); | ||
181 | |||
182 | } else { | ||
183 | struct omap_drm_private *priv = dev->dev_private; | ||
184 | queue_work(priv->wq, &omap_plane->work); | ||
185 | } | ||
186 | |||
187 | |||
188 | if (ovl->is_enabled(ovl)) { | ||
189 | omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y, | ||
190 | info->out_width, info->out_height); | ||
191 | } | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | /* when CRTC that we are attached to has potentially changed, this checks | ||
197 | * if we are attached to proper manager, and if necessary updates. | ||
198 | */ | ||
199 | static void update_manager(struct drm_plane *plane) | ||
200 | { | ||
201 | struct omap_drm_private *priv = plane->dev->dev_private; | ||
202 | struct omap_plane *omap_plane = to_omap_plane(plane); | ||
203 | struct omap_overlay *ovl = omap_plane->ovl; | ||
204 | struct omap_overlay_manager *mgr = NULL; | ||
205 | int i; | ||
206 | |||
207 | if (plane->crtc) { | ||
208 | for (i = 0; i < priv->num_encoders; i++) { | ||
209 | struct drm_encoder *encoder = priv->encoders[i]; | ||
210 | if (encoder->crtc == plane->crtc) { | ||
211 | mgr = omap_encoder_get_manager(encoder); | ||
212 | break; | ||
213 | } | ||
214 | } | ||
215 | } | ||
216 | |||
217 | if (ovl->manager != mgr) { | ||
218 | bool enabled = ovl->is_enabled(ovl); | ||
219 | |||
220 | /* don't switch things around with enabled overlays: */ | ||
221 | if (enabled) | ||
222 | omap_plane_dpms(plane, DRM_MODE_DPMS_OFF); | ||
223 | |||
224 | if (ovl->manager) { | ||
225 | DBG("disconnecting %s from %s", ovl->name, | ||
226 | ovl->manager->name); | ||
227 | ovl->unset_manager(ovl); | ||
228 | } | ||
229 | |||
230 | if (mgr) { | ||
231 | DBG("connecting %s to %s", ovl->name, mgr->name); | ||
232 | ovl->set_manager(ovl, mgr); | ||
233 | } | ||
234 | |||
235 | if (enabled && mgr) | ||
236 | omap_plane_dpms(plane, DRM_MODE_DPMS_ON); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | static void unpin(void *arg, struct drm_gem_object *bo) | 68 | static void unpin(void *arg, struct drm_gem_object *bo) |
241 | { | 69 | { |
242 | struct drm_plane *plane = arg; | 70 | struct drm_plane *plane = arg; |
@@ -244,7 +72,6 @@ static void unpin(void *arg, struct drm_gem_object *bo) | |||
244 | 72 | ||
245 | if (kfifo_put(&omap_plane->unpin_fifo, | 73 | if (kfifo_put(&omap_plane->unpin_fifo, |
246 | (const struct drm_gem_object **)&bo)) { | 74 | (const struct drm_gem_object **)&bo)) { |
247 | omap_plane->pending_num_unpins++; | ||
248 | /* also hold a ref so it isn't free'd while pinned */ | 75 | /* also hold a ref so it isn't free'd while pinned */ |
249 | drm_gem_object_reference(bo); | 76 | drm_gem_object_reference(bo); |
250 | } else { | 77 | } else { |
@@ -264,13 +91,19 @@ static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb) | |||
264 | 91 | ||
265 | DBG("%p -> %p", pinned_fb, fb); | 92 | DBG("%p -> %p", pinned_fb, fb); |
266 | 93 | ||
267 | mutex_lock(&omap_plane->unpin_mutex); | 94 | if (fb) |
95 | drm_framebuffer_reference(fb); | ||
96 | |||
268 | ret = omap_framebuffer_replace(pinned_fb, fb, plane, unpin); | 97 | ret = omap_framebuffer_replace(pinned_fb, fb, plane, unpin); |
269 | mutex_unlock(&omap_plane->unpin_mutex); | 98 | |
99 | if (pinned_fb) | ||
100 | drm_framebuffer_unreference(pinned_fb); | ||
270 | 101 | ||
271 | if (ret) { | 102 | if (ret) { |
272 | dev_err(plane->dev->dev, "could not swap %p -> %p\n", | 103 | dev_err(plane->dev->dev, "could not swap %p -> %p\n", |
273 | omap_plane->pinned_fb, fb); | 104 | omap_plane->pinned_fb, fb); |
105 | if (fb) | ||
106 | drm_framebuffer_unreference(fb); | ||
274 | omap_plane->pinned_fb = NULL; | 107 | omap_plane->pinned_fb = NULL; |
275 | return ret; | 108 | return ret; |
276 | } | 109 | } |
@@ -281,31 +114,90 @@ static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb) | |||
281 | return 0; | 114 | return 0; |
282 | } | 115 | } |
283 | 116 | ||
284 | /* update parameters that are dependent on the framebuffer dimensions and | 117 | static void omap_plane_pre_apply(struct omap_drm_apply *apply) |
285 | * position within the fb that this plane scans out from. This is called | ||
286 | * when framebuffer or x,y base may have changed. | ||
287 | */ | ||
288 | static void update_scanout(struct drm_plane *plane) | ||
289 | { | 118 | { |
290 | struct omap_plane *omap_plane = to_omap_plane(plane); | 119 | struct omap_plane *omap_plane = |
291 | struct omap_overlay_info *info = &omap_plane->info; | 120 | container_of(apply, struct omap_plane, apply); |
292 | struct omap_drm_window *win = &omap_plane->win; | 121 | struct omap_drm_window *win = &omap_plane->win; |
122 | struct drm_plane *plane = &omap_plane->base; | ||
123 | struct drm_device *dev = plane->dev; | ||
124 | struct omap_overlay_info *info = &omap_plane->info; | ||
125 | struct drm_crtc *crtc = plane->crtc; | ||
126 | enum omap_channel channel; | ||
127 | bool enabled = omap_plane->enabled && crtc; | ||
128 | bool ilace, replication; | ||
293 | int ret; | 129 | int ret; |
294 | 130 | ||
295 | ret = update_pin(plane, plane->fb); | 131 | DBG("%s, enabled=%d", omap_plane->name, enabled); |
296 | if (ret) { | 132 | |
297 | dev_err(plane->dev->dev, | 133 | /* if fb has changed, pin new fb: */ |
298 | "could not pin fb: %d\n", ret); | 134 | update_pin(plane, enabled ? plane->fb : NULL); |
299 | omap_plane_dpms(plane, DRM_MODE_DPMS_OFF); | 135 | |
136 | if (!enabled) { | ||
137 | dispc_ovl_enable(omap_plane->id, false); | ||
300 | return; | 138 | return; |
301 | } | 139 | } |
302 | 140 | ||
141 | channel = omap_crtc_channel(crtc); | ||
142 | |||
143 | /* update scanout: */ | ||
303 | omap_framebuffer_update_scanout(plane->fb, win, info); | 144 | omap_framebuffer_update_scanout(plane->fb, win, info); |
304 | 145 | ||
305 | DBG("%s: %d,%d: %08x %08x (%d)", omap_plane->ovl->name, | 146 | DBG("%dx%d -> %dx%d (%d)", info->width, info->height, |
306 | win->src_x, win->src_y, | 147 | info->out_width, info->out_height, |
307 | (u32)info->paddr, (u32)info->p_uv_addr, | ||
308 | info->screen_width); | 148 | info->screen_width); |
149 | DBG("%d,%d %08x %08x", info->pos_x, info->pos_y, | ||
150 | info->paddr, info->p_uv_addr); | ||
151 | |||
152 | /* TODO: */ | ||
153 | ilace = false; | ||
154 | replication = false; | ||
155 | |||
156 | /* and finally, update omapdss: */ | ||
157 | ret = dispc_ovl_setup(omap_plane->id, info, | ||
158 | replication, omap_crtc_timings(crtc), false); | ||
159 | if (ret) { | ||
160 | dev_err(dev->dev, "dispc_ovl_setup failed: %d\n", ret); | ||
161 | return; | ||
162 | } | ||
163 | |||
164 | dispc_ovl_enable(omap_plane->id, true); | ||
165 | dispc_ovl_set_channel_out(omap_plane->id, channel); | ||
166 | } | ||
167 | |||
168 | static void omap_plane_post_apply(struct omap_drm_apply *apply) | ||
169 | { | ||
170 | struct omap_plane *omap_plane = | ||
171 | container_of(apply, struct omap_plane, apply); | ||
172 | struct drm_plane *plane = &omap_plane->base; | ||
173 | struct omap_overlay_info *info = &omap_plane->info; | ||
174 | struct drm_gem_object *bo = NULL; | ||
175 | struct callback cb; | ||
176 | |||
177 | cb = omap_plane->apply_done_cb; | ||
178 | omap_plane->apply_done_cb.fxn = NULL; | ||
179 | |||
180 | while (kfifo_get(&omap_plane->unpin_fifo, &bo)) { | ||
181 | omap_gem_put_paddr(bo); | ||
182 | drm_gem_object_unreference_unlocked(bo); | ||
183 | } | ||
184 | |||
185 | if (cb.fxn) | ||
186 | cb.fxn(cb.arg); | ||
187 | |||
188 | if (omap_plane->enabled) { | ||
189 | omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y, | ||
190 | info->out_width, info->out_height); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | static int apply(struct drm_plane *plane) | ||
195 | { | ||
196 | if (plane->crtc) { | ||
197 | struct omap_plane *omap_plane = to_omap_plane(plane); | ||
198 | return omap_crtc_apply(plane->crtc, &omap_plane->apply); | ||
199 | } | ||
200 | return 0; | ||
309 | } | 201 | } |
310 | 202 | ||
311 | int omap_plane_mode_set(struct drm_plane *plane, | 203 | int omap_plane_mode_set(struct drm_plane *plane, |
@@ -313,7 +205,8 @@ int omap_plane_mode_set(struct drm_plane *plane, | |||
313 | int crtc_x, int crtc_y, | 205 | int crtc_x, int crtc_y, |
314 | unsigned int crtc_w, unsigned int crtc_h, | 206 | unsigned int crtc_w, unsigned int crtc_h, |
315 | uint32_t src_x, uint32_t src_y, | 207 | uint32_t src_x, uint32_t src_y, |
316 | uint32_t src_w, uint32_t src_h) | 208 | uint32_t src_w, uint32_t src_h, |
209 | void (*fxn)(void *), void *arg) | ||
317 | { | 210 | { |
318 | struct omap_plane *omap_plane = to_omap_plane(plane); | 211 | struct omap_plane *omap_plane = to_omap_plane(plane); |
319 | struct omap_drm_window *win = &omap_plane->win; | 212 | struct omap_drm_window *win = &omap_plane->win; |
@@ -329,17 +222,20 @@ int omap_plane_mode_set(struct drm_plane *plane, | |||
329 | win->src_w = src_w >> 16; | 222 | win->src_w = src_w >> 16; |
330 | win->src_h = src_h >> 16; | 223 | win->src_h = src_h >> 16; |
331 | 224 | ||
332 | /* note: this is done after this fxn returns.. but if we need | 225 | if (fxn) { |
333 | * to do a commit/update_scanout, etc before this returns we | 226 | /* omap_crtc should ensure that a new page flip |
334 | * need the current value. | 227 | * isn't permitted while there is one pending: |
335 | */ | 228 | */ |
229 | BUG_ON(omap_plane->apply_done_cb.fxn); | ||
230 | |||
231 | omap_plane->apply_done_cb.fxn = fxn; | ||
232 | omap_plane->apply_done_cb.arg = arg; | ||
233 | } | ||
234 | |||
336 | plane->fb = fb; | 235 | plane->fb = fb; |
337 | plane->crtc = crtc; | 236 | plane->crtc = crtc; |
338 | 237 | ||
339 | update_scanout(plane); | 238 | return apply(plane); |
340 | update_manager(plane); | ||
341 | |||
342 | return 0; | ||
343 | } | 239 | } |
344 | 240 | ||
345 | static int omap_plane_update(struct drm_plane *plane, | 241 | static int omap_plane_update(struct drm_plane *plane, |
@@ -349,9 +245,12 @@ static int omap_plane_update(struct drm_plane *plane, | |||
349 | uint32_t src_x, uint32_t src_y, | 245 | uint32_t src_x, uint32_t src_y, |
350 | uint32_t src_w, uint32_t src_h) | 246 | uint32_t src_w, uint32_t src_h) |
351 | { | 247 | { |
352 | omap_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, | 248 | struct omap_plane *omap_plane = to_omap_plane(plane); |
353 | src_x, src_y, src_w, src_h); | 249 | omap_plane->enabled = true; |
354 | return omap_plane_dpms(plane, DRM_MODE_DPMS_ON); | 250 | return omap_plane_mode_set(plane, crtc, fb, |
251 | crtc_x, crtc_y, crtc_w, crtc_h, | ||
252 | src_x, src_y, src_w, src_h, | ||
253 | NULL, NULL); | ||
355 | } | 254 | } |
356 | 255 | ||
357 | static int omap_plane_disable(struct drm_plane *plane) | 256 | static int omap_plane_disable(struct drm_plane *plane) |
@@ -364,48 +263,32 @@ static int omap_plane_disable(struct drm_plane *plane) | |||
364 | static void omap_plane_destroy(struct drm_plane *plane) | 263 | static void omap_plane_destroy(struct drm_plane *plane) |
365 | { | 264 | { |
366 | struct omap_plane *omap_plane = to_omap_plane(plane); | 265 | struct omap_plane *omap_plane = to_omap_plane(plane); |
367 | DBG("%s", omap_plane->ovl->name); | 266 | |
267 | DBG("%s", omap_plane->name); | ||
268 | |||
269 | omap_irq_unregister(plane->dev, &omap_plane->error_irq); | ||
270 | |||
368 | omap_plane_disable(plane); | 271 | omap_plane_disable(plane); |
369 | drm_plane_cleanup(plane); | 272 | drm_plane_cleanup(plane); |
370 | WARN_ON(omap_plane->pending_num_unpins + omap_plane->num_unpins > 0); | 273 | |
274 | WARN_ON(!kfifo_is_empty(&omap_plane->unpin_fifo)); | ||
371 | kfifo_free(&omap_plane->unpin_fifo); | 275 | kfifo_free(&omap_plane->unpin_fifo); |
276 | |||
372 | kfree(omap_plane); | 277 | kfree(omap_plane); |
373 | } | 278 | } |
374 | 279 | ||
375 | int omap_plane_dpms(struct drm_plane *plane, int mode) | 280 | int omap_plane_dpms(struct drm_plane *plane, int mode) |
376 | { | 281 | { |
377 | struct omap_plane *omap_plane = to_omap_plane(plane); | 282 | struct omap_plane *omap_plane = to_omap_plane(plane); |
378 | struct omap_overlay *ovl = omap_plane->ovl; | 283 | bool enabled = (mode == DRM_MODE_DPMS_ON); |
379 | int r; | 284 | int ret = 0; |
380 | 285 | ||
381 | DBG("%s: %d", omap_plane->ovl->name, mode); | 286 | if (enabled != omap_plane->enabled) { |
382 | 287 | omap_plane->enabled = enabled; | |
383 | if (mode == DRM_MODE_DPMS_ON) { | 288 | ret = apply(plane); |
384 | update_scanout(plane); | ||
385 | r = commit(plane); | ||
386 | if (!r) | ||
387 | r = ovl->enable(ovl); | ||
388 | } else { | ||
389 | struct omap_drm_private *priv = plane->dev->dev_private; | ||
390 | r = ovl->disable(ovl); | ||
391 | update_pin(plane, NULL); | ||
392 | queue_work(priv->wq, &omap_plane->work); | ||
393 | } | 289 | } |
394 | 290 | ||
395 | return r; | 291 | return ret; |
396 | } | ||
397 | |||
398 | void omap_plane_on_endwin(struct drm_plane *plane, | ||
399 | void (*fxn)(void *), void *arg) | ||
400 | { | ||
401 | struct omap_plane *omap_plane = to_omap_plane(plane); | ||
402 | |||
403 | mutex_lock(&omap_plane->unpin_mutex); | ||
404 | omap_plane->endwin.fxn = fxn; | ||
405 | omap_plane->endwin.arg = arg; | ||
406 | mutex_unlock(&omap_plane->unpin_mutex); | ||
407 | |||
408 | install_irq(plane); | ||
409 | } | 292 | } |
410 | 293 | ||
411 | /* helper to install properties which are common to planes and crtcs */ | 294 | /* helper to install properties which are common to planes and crtcs */ |
@@ -454,25 +337,13 @@ int omap_plane_set_property(struct drm_plane *plane, | |||
454 | int ret = -EINVAL; | 337 | int ret = -EINVAL; |
455 | 338 | ||
456 | if (property == priv->rotation_prop) { | 339 | if (property == priv->rotation_prop) { |
457 | struct omap_overlay *ovl = omap_plane->ovl; | 340 | DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val); |
458 | |||
459 | DBG("%s: rotation: %02x", ovl->name, (uint32_t)val); | ||
460 | omap_plane->win.rotation = val; | 341 | omap_plane->win.rotation = val; |
461 | 342 | ret = apply(plane); | |
462 | if (ovl->is_enabled(ovl)) | ||
463 | ret = omap_plane_dpms(plane, DRM_MODE_DPMS_ON); | ||
464 | else | ||
465 | ret = 0; | ||
466 | } else if (property == priv->zorder_prop) { | 343 | } else if (property == priv->zorder_prop) { |
467 | struct omap_overlay *ovl = omap_plane->ovl; | 344 | DBG("%s: zorder: %02x", omap_plane->name, (uint32_t)val); |
468 | |||
469 | DBG("%s: zorder: %d", ovl->name, (uint32_t)val); | ||
470 | omap_plane->info.zorder = val; | 345 | omap_plane->info.zorder = val; |
471 | 346 | ret = apply(plane); | |
472 | if (ovl->is_enabled(ovl)) | ||
473 | ret = omap_plane_dpms(plane, DRM_MODE_DPMS_ON); | ||
474 | else | ||
475 | ret = 0; | ||
476 | } | 347 | } |
477 | 348 | ||
478 | return ret; | 349 | return ret; |
@@ -485,20 +356,38 @@ static const struct drm_plane_funcs omap_plane_funcs = { | |||
485 | .set_property = omap_plane_set_property, | 356 | .set_property = omap_plane_set_property, |
486 | }; | 357 | }; |
487 | 358 | ||
359 | static void omap_plane_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus) | ||
360 | { | ||
361 | struct omap_plane *omap_plane = | ||
362 | container_of(irq, struct omap_plane, error_irq); | ||
363 | DRM_ERROR("%s: errors: %08x\n", omap_plane->name, irqstatus); | ||
364 | } | ||
365 | |||
366 | static const char *plane_names[] = { | ||
367 | [OMAP_DSS_GFX] = "gfx", | ||
368 | [OMAP_DSS_VIDEO1] = "vid1", | ||
369 | [OMAP_DSS_VIDEO2] = "vid2", | ||
370 | [OMAP_DSS_VIDEO3] = "vid3", | ||
371 | }; | ||
372 | |||
373 | static const uint32_t error_irqs[] = { | ||
374 | [OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW, | ||
375 | [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW, | ||
376 | [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW, | ||
377 | [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW, | ||
378 | }; | ||
379 | |||
488 | /* initialize plane */ | 380 | /* initialize plane */ |
489 | struct drm_plane *omap_plane_init(struct drm_device *dev, | 381 | struct drm_plane *omap_plane_init(struct drm_device *dev, |
490 | struct omap_overlay *ovl, unsigned int possible_crtcs, | 382 | int id, bool private_plane) |
491 | bool priv) | ||
492 | { | 383 | { |
384 | struct omap_drm_private *priv = dev->dev_private; | ||
493 | struct drm_plane *plane = NULL; | 385 | struct drm_plane *plane = NULL; |
494 | struct omap_plane *omap_plane; | 386 | struct omap_plane *omap_plane; |
387 | struct omap_overlay_info *info; | ||
495 | int ret; | 388 | int ret; |
496 | 389 | ||
497 | DBG("%s: possible_crtcs=%08x, priv=%d", ovl->name, | 390 | DBG("%s: priv=%d", plane_names[id], private_plane); |
498 | possible_crtcs, priv); | ||
499 | |||
500 | /* friendly reminder to update table for future hw: */ | ||
501 | WARN_ON(ovl->id >= ARRAY_SIZE(id2irq)); | ||
502 | 391 | ||
503 | omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); | 392 | omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL); |
504 | if (!omap_plane) { | 393 | if (!omap_plane) { |
@@ -506,47 +395,50 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, | |||
506 | goto fail; | 395 | goto fail; |
507 | } | 396 | } |
508 | 397 | ||
509 | mutex_init(&omap_plane->unpin_mutex); | ||
510 | |||
511 | ret = kfifo_alloc(&omap_plane->unpin_fifo, 16, GFP_KERNEL); | 398 | ret = kfifo_alloc(&omap_plane->unpin_fifo, 16, GFP_KERNEL); |
512 | if (ret) { | 399 | if (ret) { |
513 | dev_err(dev->dev, "could not allocate unpin FIFO\n"); | 400 | dev_err(dev->dev, "could not allocate unpin FIFO\n"); |
514 | goto fail; | 401 | goto fail; |
515 | } | 402 | } |
516 | 403 | ||
517 | INIT_WORK(&omap_plane->work, unpin_worker); | ||
518 | |||
519 | omap_plane->nformats = omap_framebuffer_get_formats( | 404 | omap_plane->nformats = omap_framebuffer_get_formats( |
520 | omap_plane->formats, ARRAY_SIZE(omap_plane->formats), | 405 | omap_plane->formats, ARRAY_SIZE(omap_plane->formats), |
521 | ovl->supported_modes); | 406 | dss_feat_get_supported_color_modes(id)); |
522 | omap_plane->ovl = ovl; | 407 | omap_plane->id = id; |
408 | omap_plane->name = plane_names[id]; | ||
409 | |||
523 | plane = &omap_plane->base; | 410 | plane = &omap_plane->base; |
524 | 411 | ||
525 | drm_plane_init(dev, plane, possible_crtcs, &omap_plane_funcs, | 412 | omap_plane->apply.pre_apply = omap_plane_pre_apply; |
526 | omap_plane->formats, omap_plane->nformats, priv); | 413 | omap_plane->apply.post_apply = omap_plane_post_apply; |
414 | |||
415 | omap_plane->error_irq.irqmask = error_irqs[id]; | ||
416 | omap_plane->error_irq.irq = omap_plane_error_irq; | ||
417 | omap_irq_register(dev, &omap_plane->error_irq); | ||
418 | |||
419 | drm_plane_init(dev, plane, (1 << priv->num_crtcs) - 1, &omap_plane_funcs, | ||
420 | omap_plane->formats, omap_plane->nformats, private_plane); | ||
527 | 421 | ||
528 | omap_plane_install_properties(plane, &plane->base); | 422 | omap_plane_install_properties(plane, &plane->base); |
529 | 423 | ||
530 | /* get our starting configuration, set defaults for parameters | 424 | /* get our starting configuration, set defaults for parameters |
531 | * we don't currently use, etc: | 425 | * we don't currently use, etc: |
532 | */ | 426 | */ |
533 | ovl->get_overlay_info(ovl, &omap_plane->info); | 427 | info = &omap_plane->info; |
534 | omap_plane->info.rotation_type = OMAP_DSS_ROT_DMA; | 428 | info->rotation_type = OMAP_DSS_ROT_DMA; |
535 | omap_plane->info.rotation = OMAP_DSS_ROT_0; | 429 | info->rotation = OMAP_DSS_ROT_0; |
536 | omap_plane->info.global_alpha = 0xff; | 430 | info->global_alpha = 0xff; |
537 | omap_plane->info.mirror = 0; | 431 | info->mirror = 0; |
538 | 432 | ||
539 | /* Set defaults depending on whether we are a CRTC or overlay | 433 | /* Set defaults depending on whether we are a CRTC or overlay |
540 | * layer. | 434 | * layer. |
541 | * TODO add ioctl to give userspace an API to change this.. this | 435 | * TODO add ioctl to give userspace an API to change this.. this |
542 | * will come in a subsequent patch. | 436 | * will come in a subsequent patch. |
543 | */ | 437 | */ |
544 | if (priv) | 438 | if (private_plane) |
545 | omap_plane->info.zorder = 0; | 439 | omap_plane->info.zorder = 0; |
546 | else | 440 | else |
547 | omap_plane->info.zorder = ovl->id; | 441 | omap_plane->info.zorder = id; |
548 | |||
549 | update_manager(plane); | ||
550 | 442 | ||
551 | return plane; | 443 | return plane; |
552 | 444 | ||
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c index ae38475854b5..d10d75e8a33f 100644 --- a/drivers/staging/rtl8187se/r8180_core.c +++ b/drivers/staging/rtl8187se/r8180_core.c | |||
@@ -937,7 +937,8 @@ short alloc_rx_desc_ring(struct net_device *dev, u16 bufsize, int count) | |||
937 | 937 | ||
938 | dma_tmp = pci_map_single(pdev, buf, bufsize * sizeof(u8), | 938 | dma_tmp = pci_map_single(pdev, buf, bufsize * sizeof(u8), |
939 | PCI_DMA_FROMDEVICE); | 939 | PCI_DMA_FROMDEVICE); |
940 | 940 | if (pci_dma_mapping_error(pdev, dma_tmp)) | |
941 | return -1; | ||
941 | if (-1 == buffer_add(&(priv->rxbuffer), buf, dma_tmp, | 942 | if (-1 == buffer_add(&(priv->rxbuffer), buf, dma_tmp, |
942 | &(priv->rxbufferhead))) { | 943 | &(priv->rxbufferhead))) { |
943 | DMESGE("Unable to allocate mem RX buf"); | 944 | DMESGE("Unable to allocate mem RX buf"); |
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 808aab6fa5ef..a9d78e9651c6 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | |||
@@ -1183,6 +1183,8 @@ void rtl8192_tx_fill_desc(struct net_device *dev, struct tx_desc *pdesc, | |||
1183 | pTxFwInfo->TxRate, | 1183 | pTxFwInfo->TxRate, |
1184 | cb_desc); | 1184 | cb_desc); |
1185 | 1185 | ||
1186 | if (pci_dma_mapping_error(priv->pdev, mapping)) | ||
1187 | RT_TRACE(COMP_ERR, "DMA Mapping error\n");; | ||
1186 | if (cb_desc->bAMPDUEnable) { | 1188 | if (cb_desc->bAMPDUEnable) { |
1187 | pTxFwInfo->AllowAggregation = 1; | 1189 | pTxFwInfo->AllowAggregation = 1; |
1188 | pTxFwInfo->RxMF = cb_desc->ampdu_factor; | 1190 | pTxFwInfo->RxMF = cb_desc->ampdu_factor; |
@@ -1280,6 +1282,8 @@ void rtl8192_tx_fill_cmd_desc(struct net_device *dev, | |||
1280 | dma_addr_t mapping = pci_map_single(priv->pdev, skb->data, skb->len, | 1282 | dma_addr_t mapping = pci_map_single(priv->pdev, skb->data, skb->len, |
1281 | PCI_DMA_TODEVICE); | 1283 | PCI_DMA_TODEVICE); |
1282 | 1284 | ||
1285 | if (pci_dma_mapping_error(priv->pdev, mapping)) | ||
1286 | RT_TRACE(COMP_ERR, "DMA Mapping error\n");; | ||
1283 | memset(entry, 0, 12); | 1287 | memset(entry, 0, 12); |
1284 | entry->LINIP = cb_desc->bLastIniPkt; | 1288 | entry->LINIP = cb_desc->bLastIniPkt; |
1285 | entry->FirstSeg = 1; | 1289 | entry->FirstSeg = 1; |
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 1a70f324552f..4ebf99b30975 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c | |||
@@ -2104,7 +2104,10 @@ static short rtl8192_alloc_rx_desc_ring(struct net_device *dev) | |||
2104 | skb_tail_pointer_rsl(skb), | 2104 | skb_tail_pointer_rsl(skb), |
2105 | priv->rxbuffersize, | 2105 | priv->rxbuffersize, |
2106 | PCI_DMA_FROMDEVICE); | 2106 | PCI_DMA_FROMDEVICE); |
2107 | 2107 | if (pci_dma_mapping_error(priv->pdev, *mapping)) { | |
2108 | dev_kfree_skb_any(skb); | ||
2109 | return -1; | ||
2110 | } | ||
2108 | entry->BufferAddress = cpu_to_le32(*mapping); | 2111 | entry->BufferAddress = cpu_to_le32(*mapping); |
2109 | 2112 | ||
2110 | entry->Length = priv->rxbuffersize; | 2113 | entry->Length = priv->rxbuffersize; |
@@ -2397,7 +2400,11 @@ static void rtl8192_rx_normal(struct net_device *dev) | |||
2397 | skb_tail_pointer_rsl(skb), | 2400 | skb_tail_pointer_rsl(skb), |
2398 | priv->rxbuffersize, | 2401 | priv->rxbuffersize, |
2399 | PCI_DMA_FROMDEVICE); | 2402 | PCI_DMA_FROMDEVICE); |
2400 | 2403 | if (pci_dma_mapping_error(priv->pdev, | |
2404 | *((dma_addr_t *)skb->cb))) { | ||
2405 | dev_kfree_skb_any(skb); | ||
2406 | return; | ||
2407 | } | ||
2401 | } | 2408 | } |
2402 | done: | 2409 | done: |
2403 | pdesc->BufferAddress = cpu_to_le32(*((dma_addr_t *)skb->cb)); | 2410 | pdesc->BufferAddress = cpu_to_le32(*((dma_addr_t *)skb->cb)); |
diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c index 6b73843e580a..a96cd06d69dd 100644 --- a/drivers/staging/rtl8712/usb_intf.c +++ b/drivers/staging/rtl8712/usb_intf.c | |||
@@ -63,6 +63,8 @@ static struct usb_device_id rtl871x_usb_id_tbl[] = { | |||
63 | {USB_DEVICE(0x0B05, 0x1791)}, /* 11n mode disable */ | 63 | {USB_DEVICE(0x0B05, 0x1791)}, /* 11n mode disable */ |
64 | /* Belkin */ | 64 | /* Belkin */ |
65 | {USB_DEVICE(0x050D, 0x945A)}, | 65 | {USB_DEVICE(0x050D, 0x945A)}, |
66 | /* ISY IWL - Belkin clone */ | ||
67 | {USB_DEVICE(0x050D, 0x11F1)}, | ||
66 | /* Corega */ | 68 | /* Corega */ |
67 | {USB_DEVICE(0x07AA, 0x0047)}, | 69 | {USB_DEVICE(0x07AA, 0x0047)}, |
68 | /* D-Link */ | 70 | /* D-Link */ |
diff --git a/drivers/staging/sb105x/Kconfig b/drivers/staging/sb105x/Kconfig index ac87c5e38dee..1facad625554 100644 --- a/drivers/staging/sb105x/Kconfig +++ b/drivers/staging/sb105x/Kconfig | |||
@@ -2,6 +2,7 @@ config SB105X | |||
2 | tristate "SystemBase PCI Multiport UART" | 2 | tristate "SystemBase PCI Multiport UART" |
3 | select SERIAL_CORE | 3 | select SERIAL_CORE |
4 | depends on PCI | 4 | depends on PCI |
5 | depends on X86 | ||
5 | help | 6 | help |
6 | A driver for the SystemBase Multi-2/PCI serial card | 7 | A driver for the SystemBase Multi-2/PCI serial card |
7 | 8 | ||
diff --git a/drivers/staging/sb105x/sb_pci_mp.c b/drivers/staging/sb105x/sb_pci_mp.c index edb2a85b9d52..131afd0c460c 100644 --- a/drivers/staging/sb105x/sb_pci_mp.c +++ b/drivers/staging/sb105x/sb_pci_mp.c | |||
@@ -3054,6 +3054,7 @@ static int init_mp_dev(struct pci_dev *pcidev, mppcibrd_t brd) | |||
3054 | sbdev->nr_ports = ((portnum_hex/16)*10) + (portnum_hex % 16); | 3054 | sbdev->nr_ports = ((portnum_hex/16)*10) + (portnum_hex % 16); |
3055 | } | 3055 | } |
3056 | break; | 3056 | break; |
3057 | #ifdef CONFIG_PARPORT | ||
3057 | case PCI_DEVICE_ID_MP2S1P : | 3058 | case PCI_DEVICE_ID_MP2S1P : |
3058 | sbdev->nr_ports = 2; | 3059 | sbdev->nr_ports = 2; |
3059 | 3060 | ||
@@ -3073,6 +3074,7 @@ static int init_mp_dev(struct pci_dev *pcidev, mppcibrd_t brd) | |||
3073 | /* add PC compatible parallel port */ | 3074 | /* add PC compatible parallel port */ |
3074 | parport_pc_probe_port(pcidev->resource[2].start, pcidev->resource[3].start, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &pcidev->dev, 0); | 3075 | parport_pc_probe_port(pcidev->resource[2].start, pcidev->resource[3].start, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &pcidev->dev, 0); |
3075 | break; | 3076 | break; |
3077 | #endif | ||
3076 | } | 3078 | } |
3077 | 3079 | ||
3078 | ret = request_region(sbdev->uart_access_addr, (8*sbdev->nr_ports), sbdev->name); | 3080 | ret = request_region(sbdev->uart_access_addr, (8*sbdev->nr_ports), sbdev->name); |
diff --git a/drivers/staging/speakup/synth.c b/drivers/staging/speakup/synth.c index 59c46a41b5a7..d867dd9109ed 100644 --- a/drivers/staging/speakup/synth.c +++ b/drivers/staging/speakup/synth.c | |||
@@ -342,7 +342,7 @@ int synth_init(char *synth_name) | |||
342 | 342 | ||
343 | mutex_lock(&spk_mutex); | 343 | mutex_lock(&spk_mutex); |
344 | /* First, check if we already have it loaded. */ | 344 | /* First, check if we already have it loaded. */ |
345 | for (i = 0; synths[i] != NULL && i < MAXSYNTHS; i++) | 345 | for (i = 0; i < MAXSYNTHS && synths[i] != NULL; i++) |
346 | if (strcmp(synths[i]->name, synth_name) == 0) | 346 | if (strcmp(synths[i]->name, synth_name) == 0) |
347 | synth = synths[i]; | 347 | synth = synths[i]; |
348 | 348 | ||
@@ -423,7 +423,7 @@ int synth_add(struct spk_synth *in_synth) | |||
423 | int i; | 423 | int i; |
424 | int status = 0; | 424 | int status = 0; |
425 | mutex_lock(&spk_mutex); | 425 | mutex_lock(&spk_mutex); |
426 | for (i = 0; synths[i] != NULL && i < MAXSYNTHS; i++) | 426 | for (i = 0; i < MAXSYNTHS && synths[i] != NULL; i++) |
427 | /* synth_remove() is responsible for rotating the array down */ | 427 | /* synth_remove() is responsible for rotating the array down */ |
428 | if (in_synth == synths[i]) { | 428 | if (in_synth == synths[i]) { |
429 | mutex_unlock(&spk_mutex); | 429 | mutex_unlock(&spk_mutex); |
diff --git a/drivers/staging/tidspbridge/core/_tiomap.h b/drivers/staging/tidspbridge/core/_tiomap.h index 543a127c7d4d..b783bfa59b1c 100644 --- a/drivers/staging/tidspbridge/core/_tiomap.h +++ b/drivers/staging/tidspbridge/core/_tiomap.h | |||
@@ -31,7 +31,7 @@ | |||
31 | * driver should read or write to PRM/CM registers directly; they | 31 | * driver should read or write to PRM/CM registers directly; they |
32 | * should rely on OMAP core code to do this. | 32 | * should rely on OMAP core code to do this. |
33 | */ | 33 | */ |
34 | #include <mach-omap2/cm2xxx_3xxx.h> | 34 | #include <mach-omap2/cm3xxx.h> |
35 | #include <mach-omap2/prm-regbits-34xx.h> | 35 | #include <mach-omap2/prm-regbits-34xx.h> |
36 | #include <mach-omap2/cm-regbits-34xx.h> | 36 | #include <mach-omap2/cm-regbits-34xx.h> |
37 | #include <dspbridge/devdefs.h> | 37 | #include <dspbridge/devdefs.h> |
diff --git a/drivers/staging/tidspbridge/core/dsp-clock.c b/drivers/staging/tidspbridge/core/dsp-clock.c index b647207928b1..2f084e181d39 100644 --- a/drivers/staging/tidspbridge/core/dsp-clock.c +++ b/drivers/staging/tidspbridge/core/dsp-clock.c | |||
@@ -121,9 +121,13 @@ void dsp_clk_exit(void) | |||
121 | for (i = 0; i < DM_TIMER_CLOCKS; i++) | 121 | for (i = 0; i < DM_TIMER_CLOCKS; i++) |
122 | omap_dm_timer_free(timer[i]); | 122 | omap_dm_timer_free(timer[i]); |
123 | 123 | ||
124 | clk_unprepare(iva2_clk); | ||
124 | clk_put(iva2_clk); | 125 | clk_put(iva2_clk); |
126 | clk_unprepare(ssi.sst_fck); | ||
125 | clk_put(ssi.sst_fck); | 127 | clk_put(ssi.sst_fck); |
128 | clk_unprepare(ssi.ssr_fck); | ||
126 | clk_put(ssi.ssr_fck); | 129 | clk_put(ssi.ssr_fck); |
130 | clk_unprepare(ssi.ick); | ||
127 | clk_put(ssi.ick); | 131 | clk_put(ssi.ick); |
128 | } | 132 | } |
129 | 133 | ||
@@ -145,14 +149,21 @@ void dsp_clk_init(void) | |||
145 | iva2_clk = clk_get(&dspbridge_device.dev, "iva2_ck"); | 149 | iva2_clk = clk_get(&dspbridge_device.dev, "iva2_ck"); |
146 | if (IS_ERR(iva2_clk)) | 150 | if (IS_ERR(iva2_clk)) |
147 | dev_err(bridge, "failed to get iva2 clock %p\n", iva2_clk); | 151 | dev_err(bridge, "failed to get iva2 clock %p\n", iva2_clk); |
152 | else | ||
153 | clk_prepare(iva2_clk); | ||
148 | 154 | ||
149 | ssi.sst_fck = clk_get(&dspbridge_device.dev, "ssi_sst_fck"); | 155 | ssi.sst_fck = clk_get(&dspbridge_device.dev, "ssi_sst_fck"); |
150 | ssi.ssr_fck = clk_get(&dspbridge_device.dev, "ssi_ssr_fck"); | 156 | ssi.ssr_fck = clk_get(&dspbridge_device.dev, "ssi_ssr_fck"); |
151 | ssi.ick = clk_get(&dspbridge_device.dev, "ssi_ick"); | 157 | ssi.ick = clk_get(&dspbridge_device.dev, "ssi_ick"); |
152 | 158 | ||
153 | if (IS_ERR(ssi.sst_fck) || IS_ERR(ssi.ssr_fck) || IS_ERR(ssi.ick)) | 159 | if (IS_ERR(ssi.sst_fck) || IS_ERR(ssi.ssr_fck) || IS_ERR(ssi.ick)) { |
154 | dev_err(bridge, "failed to get ssi: sst %p, ssr %p, ick %p\n", | 160 | dev_err(bridge, "failed to get ssi: sst %p, ssr %p, ick %p\n", |
155 | ssi.sst_fck, ssi.ssr_fck, ssi.ick); | 161 | ssi.sst_fck, ssi.ssr_fck, ssi.ick); |
162 | } else { | ||
163 | clk_prepare(ssi.sst_fck); | ||
164 | clk_prepare(ssi.ssr_fck); | ||
165 | clk_prepare(ssi.ick); | ||
166 | } | ||
156 | } | 167 | } |
157 | 168 | ||
158 | /** | 169 | /** |
diff --git a/drivers/staging/tidspbridge/core/wdt.c b/drivers/staging/tidspbridge/core/wdt.c index 1dce36fb828f..7ff0e6c98039 100644 --- a/drivers/staging/tidspbridge/core/wdt.c +++ b/drivers/staging/tidspbridge/core/wdt.c | |||
@@ -63,11 +63,15 @@ int dsp_wdt_init(void) | |||
63 | dsp_wdt.fclk = clk_get(NULL, "wdt3_fck"); | 63 | dsp_wdt.fclk = clk_get(NULL, "wdt3_fck"); |
64 | 64 | ||
65 | if (!IS_ERR(dsp_wdt.fclk)) { | 65 | if (!IS_ERR(dsp_wdt.fclk)) { |
66 | clk_prepare(dsp_wdt.fclk); | ||
67 | |||
66 | dsp_wdt.iclk = clk_get(NULL, "wdt3_ick"); | 68 | dsp_wdt.iclk = clk_get(NULL, "wdt3_ick"); |
67 | if (IS_ERR(dsp_wdt.iclk)) { | 69 | if (IS_ERR(dsp_wdt.iclk)) { |
68 | clk_put(dsp_wdt.fclk); | 70 | clk_put(dsp_wdt.fclk); |
69 | dsp_wdt.fclk = NULL; | 71 | dsp_wdt.fclk = NULL; |
70 | ret = -EFAULT; | 72 | ret = -EFAULT; |
73 | } else { | ||
74 | clk_prepare(dsp_wdt.iclk); | ||
71 | } | 75 | } |
72 | } else | 76 | } else |
73 | ret = -EFAULT; | 77 | ret = -EFAULT; |
@@ -95,10 +99,14 @@ void dsp_wdt_exit(void) | |||
95 | free_irq(INT_34XX_WDT3_IRQ, &dsp_wdt); | 99 | free_irq(INT_34XX_WDT3_IRQ, &dsp_wdt); |
96 | tasklet_kill(&dsp_wdt.wdt3_tasklet); | 100 | tasklet_kill(&dsp_wdt.wdt3_tasklet); |
97 | 101 | ||
98 | if (dsp_wdt.fclk) | 102 | if (dsp_wdt.fclk) { |
103 | clk_unprepare(dsp_wdt.fclk); | ||
99 | clk_put(dsp_wdt.fclk); | 104 | clk_put(dsp_wdt.fclk); |
100 | if (dsp_wdt.iclk) | 105 | } |
106 | if (dsp_wdt.iclk) { | ||
107 | clk_unprepare(dsp_wdt.iclk); | ||
101 | clk_put(dsp_wdt.iclk); | 108 | clk_put(dsp_wdt.iclk); |
109 | } | ||
102 | 110 | ||
103 | dsp_wdt.fclk = NULL; | 111 | dsp_wdt.fclk = NULL; |
104 | dsp_wdt.iclk = NULL; | 112 | dsp_wdt.iclk = NULL; |
diff --git a/drivers/staging/vme/devices/vme_pio2_core.c b/drivers/staging/vme/devices/vme_pio2_core.c index 0331178ca3b3..bf73ba26e88a 100644 --- a/drivers/staging/vme/devices/vme_pio2_core.c +++ b/drivers/staging/vme/devices/vme_pio2_core.c | |||
@@ -162,11 +162,9 @@ static struct vme_driver pio2_driver = { | |||
162 | 162 | ||
163 | static int __init pio2_init(void) | 163 | static int __init pio2_init(void) |
164 | { | 164 | { |
165 | int retval = 0; | ||
166 | |||
167 | if (bus_num == 0) { | 165 | if (bus_num == 0) { |
168 | pr_err("No cards, skipping registration\n"); | 166 | pr_err("No cards, skipping registration\n"); |
169 | goto err_nocard; | 167 | return -ENODEV; |
170 | } | 168 | } |
171 | 169 | ||
172 | if (bus_num > PIO2_CARDS_MAX) { | 170 | if (bus_num > PIO2_CARDS_MAX) { |
@@ -176,15 +174,7 @@ static int __init pio2_init(void) | |||
176 | } | 174 | } |
177 | 175 | ||
178 | /* Register the PIO2 driver */ | 176 | /* Register the PIO2 driver */ |
179 | retval = vme_register_driver(&pio2_driver, bus_num); | 177 | return vme_register_driver(&pio2_driver, bus_num); |
180 | if (retval != 0) | ||
181 | goto err_reg; | ||
182 | |||
183 | return retval; | ||
184 | |||
185 | err_reg: | ||
186 | err_nocard: | ||
187 | return retval; | ||
188 | } | 178 | } |
189 | 179 | ||
190 | static int pio2_match(struct vme_dev *vdev) | 180 | static int pio2_match(struct vme_dev *vdev) |
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c index 18c06a59c091..1d31eab19d16 100644 --- a/drivers/staging/wlan-ng/cfg80211.c +++ b/drivers/staging/wlan-ng/cfg80211.c | |||
@@ -638,8 +638,8 @@ int prism2_leave_ibss(struct wiphy *wiphy, struct net_device *dev) | |||
638 | } | 638 | } |
639 | 639 | ||
640 | 640 | ||
641 | int prism2_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type, | 641 | int prism2_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, |
642 | int mbm) | 642 | enum nl80211_tx_power_setting type, int mbm) |
643 | { | 643 | { |
644 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); | 644 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); |
645 | wlandevice_t *wlandev = priv->wlandev; | 645 | wlandevice_t *wlandev = priv->wlandev; |
@@ -665,7 +665,8 @@ exit: | |||
665 | return err; | 665 | return err; |
666 | } | 666 | } |
667 | 667 | ||
668 | int prism2_get_tx_power(struct wiphy *wiphy, int *dbm) | 668 | int prism2_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, |
669 | int *dbm) | ||
669 | { | 670 | { |
670 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); | 671 | struct prism2_wiphy_private *priv = wiphy_priv(wiphy); |
671 | wlandevice_t *wlandev = priv->wlandev; | 672 | wlandevice_t *wlandev = priv->wlandev; |