From 1e33936d3baee3b688ec12b372534522b9256032 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 28 Jun 2017 04:14:28 -0400 Subject: media: cec-gpio: add HDMI CEC GPIO driver Add a simple HDMI CEC GPIO driver that sits on top of the cec-pin framework. While I have heard of SoCs that use the GPIO pin for CEC (apparently an early RockChip SoC used that), the main use-case of this driver is to function as a debugging tool. By connecting the CEC line to a GPIO pin on a Raspberry Pi 3 for example it turns it into a CEC debugger and protocol analyzer. With 'cec-ctl --monitor-pin' the CEC traffic can be analyzed. But of course it can also be used with any hardware project where the HDMI CEC line is hooked up to a pull-up gpio line. In addition this has (optional) support for tracing HPD changes if the HPD is connected to a GPIO. Signed-off-by: Hans Verkuil Reviewed-by: Linus Walleij Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 10 ++ drivers/media/platform/Makefile | 2 + drivers/media/platform/cec-gpio/Makefile | 1 + drivers/media/platform/cec-gpio/cec-gpio.c | 236 +++++++++++++++++++++++++++++ 4 files changed, 249 insertions(+) create mode 100644 drivers/media/platform/cec-gpio/Makefile create mode 100644 drivers/media/platform/cec-gpio/cec-gpio.c (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 7e7cc49b8674..e4c89a16a3e7 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -553,6 +553,16 @@ config VIDEO_MESON_AO_CEC This is a driver for Amlogic Meson SoCs AO CEC interface. It uses the generic CEC framework interface. CEC bus is present in the HDMI connector and enables communication + +config CEC_GPIO + tristate "Generic GPIO-based CEC driver" + depends on PREEMPT + select CEC_CORE + select CEC_PIN + select GPIOLIB + ---help--- + This is a generic GPIO-based CEC driver. + The CEC bus is present in the HDMI connector and enables communication between compatible devices. config VIDEO_SAMSUNG_S5P_CEC diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index c1ef946bf032..9bf48f118537 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -26,6 +26,8 @@ obj-$(CONFIG_VIDEO_CODA) += coda/ obj-$(CONFIG_VIDEO_SH_VEU) += sh_veu.o +obj-$(CONFIG_CEC_GPIO) += cec-gpio/ + obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE) += m2m-deinterlace.o obj-$(CONFIG_VIDEO_MUX) += video-mux.o diff --git a/drivers/media/platform/cec-gpio/Makefile b/drivers/media/platform/cec-gpio/Makefile new file mode 100644 index 000000000000..e82b258afa55 --- /dev/null +++ b/drivers/media/platform/cec-gpio/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_CEC_GPIO) += cec-gpio.o diff --git a/drivers/media/platform/cec-gpio/cec-gpio.c b/drivers/media/platform/cec-gpio/cec-gpio.c new file mode 100644 index 000000000000..eb982bce99fc --- /dev/null +++ b/drivers/media/platform/cec-gpio/cec-gpio.c @@ -0,0 +1,236 @@ +/* + * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +struct cec_gpio { + struct cec_adapter *adap; + struct device *dev; + + struct gpio_desc *cec_gpio; + int cec_irq; + bool cec_is_low; + bool cec_have_irq; + + struct gpio_desc *hpd_gpio; + int hpd_irq; + bool hpd_is_high; + ktime_t hpd_ts; +}; + +static bool cec_gpio_read(struct cec_adapter *adap) +{ + struct cec_gpio *cec = cec_get_drvdata(adap); + + if (cec->cec_is_low) + return false; + return gpiod_get_value(cec->cec_gpio); +} + +static void cec_gpio_high(struct cec_adapter *adap) +{ + struct cec_gpio *cec = cec_get_drvdata(adap); + + if (!cec->cec_is_low) + return; + cec->cec_is_low = false; + gpiod_set_value(cec->cec_gpio, 1); +} + +static void cec_gpio_low(struct cec_adapter *adap) +{ + struct cec_gpio *cec = cec_get_drvdata(adap); + + if (cec->cec_is_low) + return; + if (WARN_ON_ONCE(cec->cec_have_irq)) + free_irq(cec->cec_irq, cec); + cec->cec_have_irq = false; + cec->cec_is_low = true; + gpiod_set_value(cec->cec_gpio, 0); +} + +static irqreturn_t cec_hpd_gpio_irq_handler_thread(int irq, void *priv) +{ + struct cec_gpio *cec = priv; + + cec_queue_pin_hpd_event(cec->adap, cec->hpd_is_high, cec->hpd_ts); + return IRQ_HANDLED; +} + +static irqreturn_t cec_hpd_gpio_irq_handler(int irq, void *priv) +{ + struct cec_gpio *cec = priv; + + cec->hpd_ts = ktime_get(); + cec->hpd_is_high = gpiod_get_value(cec->hpd_gpio); + return IRQ_WAKE_THREAD; +} + +static irqreturn_t cec_gpio_irq_handler(int irq, void *priv) +{ + struct cec_gpio *cec = priv; + + cec_pin_changed(cec->adap, gpiod_get_value(cec->cec_gpio)); + return IRQ_HANDLED; +} + +static bool cec_gpio_enable_irq(struct cec_adapter *adap) +{ + struct cec_gpio *cec = cec_get_drvdata(adap); + + if (cec->cec_have_irq) + return true; + + if (request_irq(cec->cec_irq, cec_gpio_irq_handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + adap->name, cec)) + return false; + cec->cec_have_irq = true; + return true; +} + +static void cec_gpio_disable_irq(struct cec_adapter *adap) +{ + struct cec_gpio *cec = cec_get_drvdata(adap); + + if (cec->cec_have_irq) + free_irq(cec->cec_irq, cec); + cec->cec_have_irq = false; +} + +static void cec_gpio_status(struct cec_adapter *adap, struct seq_file *file) +{ + struct cec_gpio *cec = cec_get_drvdata(adap); + + seq_printf(file, "mode: %s\n", cec->cec_is_low ? "low-drive" : "read"); + if (cec->cec_have_irq) + seq_printf(file, "using irq: %d\n", cec->cec_irq); + if (cec->hpd_gpio) + seq_printf(file, "hpd: %s\n", + cec->hpd_is_high ? "high" : "low"); +} + +static int cec_gpio_read_hpd(struct cec_adapter *adap) +{ + struct cec_gpio *cec = cec_get_drvdata(adap); + + if (!cec->hpd_gpio) + return -ENOTTY; + return gpiod_get_value(cec->hpd_gpio); +} + +static void cec_gpio_free(struct cec_adapter *adap) +{ + cec_gpio_disable_irq(adap); +} + +static const struct cec_pin_ops cec_gpio_pin_ops = { + .read = cec_gpio_read, + .low = cec_gpio_low, + .high = cec_gpio_high, + .enable_irq = cec_gpio_enable_irq, + .disable_irq = cec_gpio_disable_irq, + .status = cec_gpio_status, + .free = cec_gpio_free, + .read_hpd = cec_gpio_read_hpd, +}; + +static int cec_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct cec_gpio *cec; + int ret; + + cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL); + if (!cec) + return -ENOMEM; + + cec->dev = dev; + + cec->cec_gpio = devm_gpiod_get(dev, "cec", GPIOD_IN); + if (IS_ERR(cec->cec_gpio)) + return PTR_ERR(cec->cec_gpio); + cec->cec_irq = gpiod_to_irq(cec->cec_gpio); + + cec->hpd_gpio = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN); + if (IS_ERR(cec->hpd_gpio)) + return PTR_ERR(cec->hpd_gpio); + + cec->adap = cec_pin_allocate_adapter(&cec_gpio_pin_ops, + cec, pdev->name, CEC_CAP_DEFAULTS | CEC_CAP_PHYS_ADDR | + CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN); + if (IS_ERR(cec->adap)) + return PTR_ERR(cec->adap); + + if (cec->hpd_gpio) { + cec->hpd_irq = gpiod_to_irq(cec->hpd_gpio); + ret = devm_request_threaded_irq(dev, cec->hpd_irq, + cec_hpd_gpio_irq_handler, + cec_hpd_gpio_irq_handler_thread, + IRQF_ONESHOT | + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + "hpd-gpio", cec); + if (ret) + return ret; + } + + ret = cec_register_adapter(cec->adap, &pdev->dev); + if (ret) { + cec_delete_adapter(cec->adap); + return ret; + } + + platform_set_drvdata(pdev, cec); + return 0; +} + +static int cec_gpio_remove(struct platform_device *pdev) +{ + struct cec_gpio *cec = platform_get_drvdata(pdev); + + cec_unregister_adapter(cec->adap); + return 0; +} + +static const struct of_device_id cec_gpio_match[] = { + { + .compatible = "cec-gpio", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, cec_gpio_match); + +static struct platform_driver cec_gpio_pdrv = { + .probe = cec_gpio_probe, + .remove = cec_gpio_remove, + .driver = { + .name = "cec-gpio", + .of_match_table = cec_gpio_match, + }, +}; + +module_platform_driver(cec_gpio_pdrv); + +MODULE_AUTHOR("Hans Verkuil "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("CEC GPIO driver"); -- cgit v1.2.3 From c38e8657a471e9af42b86009e5d3085031b41fda Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 28 Aug 2017 05:46:57 -0400 Subject: media: drivers: delete error messages for failed memory allocation Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. [mchehab@s-opensource.com: fold several similar patches into one] Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/cypress_firmware.c | 4 +--- drivers/media/common/siano/smscoreapi.c | 13 ++++--------- drivers/media/dvb-frontends/as102_fe.c | 5 ++--- drivers/media/dvb-frontends/cx24113.c | 5 ++--- drivers/media/dvb-frontends/cx24116.c | 1 - drivers/media/dvb-frontends/drxd_hard.c | 1 - drivers/media/dvb-frontends/ds3000.c | 8 ++------ drivers/media/dvb-frontends/mb86a20s.c | 5 +---- drivers/media/dvb-frontends/si2168.c | 1 - drivers/media/dvb-frontends/sp2.c | 1 - drivers/media/i2c/adv7604.c | 4 +--- drivers/media/i2c/adv7842.c | 4 +--- drivers/media/pci/cx18/cx18-driver.c | 6 ++---- drivers/media/pci/mantis/hopper_cards.c | 1 - drivers/media/pci/mantis/mantis_cards.c | 4 +--- drivers/media/pci/meye/meye.c | 13 ++++--------- drivers/media/pci/saa7146/hexium_gemini.c | 5 ++--- drivers/media/pci/saa7146/hexium_orion.c | 4 +--- drivers/media/pci/saa7164/saa7164-buffer.c | 4 +--- drivers/media/platform/atmel/atmel-isc.c | 4 +--- drivers/media/platform/atmel/atmel-isi.c | 8 ++------ drivers/media/platform/blackfin/ppi.c | 1 - drivers/media/usb/zr364xx/zr364xx.c | 8 ++------ 23 files changed, 30 insertions(+), 80 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/common/cypress_firmware.c b/drivers/media/common/cypress_firmware.c index 50e3f76d4847..bfe47bc5f716 100644 --- a/drivers/media/common/cypress_firmware.c +++ b/drivers/media/common/cypress_firmware.c @@ -75,10 +75,8 @@ int cypress_load_firmware(struct usb_device *udev, int ret, pos = 0; hx = kmalloc(sizeof(struct hexline), GFP_KERNEL); - if (!hx) { - dev_err(&udev->dev, "%s: kmalloc() failed\n", KBUILD_MODNAME); + if (!hx) return -ENOMEM; - } /* stop the CPU */ hx->data[0] = 1; diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index e7a0d7798d5b..889b486fbc72 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -1301,10 +1301,8 @@ static int smscore_init_device(struct smscore_device_t *coredev, int mode) buffer = kmalloc(sizeof(struct sms_msg_data) + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); - if (!buffer) { - pr_err("Could not allocate buffer for init device message.\n"); + if (!buffer) return -ENOMEM; - } msg = (struct sms_msg_data *)SMS_ALIGN_ADDRESS(buffer); SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ, @@ -1687,10 +1685,9 @@ static int smscore_validate_client(struct smscore_device_t *coredev, return -EEXIST; } listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL); - if (!listentry) { - pr_err("Can't allocate memory for client id.\n"); + if (!listentry) return -ENOMEM; - } + listentry->id = id; listentry->data_type = data_type; list_add_locked(&listentry->entry, &client->idlist, @@ -1725,10 +1722,8 @@ int smscore_register_client(struct smscore_device_t *coredev, } newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL); - if (!newclient) { - pr_err("Failed to allocate memory for client.\n"); + if (!newclient) return -ENOMEM; - } INIT_LIST_HEAD(&newclient->idlist); newclient->coredev = coredev; diff --git a/drivers/media/dvb-frontends/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c index 98d575f2744c..1fb4ab21d786 100644 --- a/drivers/media/dvb-frontends/as102_fe.c +++ b/drivers/media/dvb-frontends/as102_fe.c @@ -456,10 +456,9 @@ struct dvb_frontend *as102_attach(const char *name, struct dvb_frontend *fe; state = kzalloc(sizeof(struct as102_state), GFP_KERNEL); - if (state == NULL) { - pr_err("%s: unable to allocate memory for state\n", __func__); + if (!state) return NULL; - } + fe = &state->frontend; fe->demodulator_priv = state; state->ops = ops; diff --git a/drivers/media/dvb-frontends/cx24113.c b/drivers/media/dvb-frontends/cx24113.c index 0118c2658cf7..8fc7333c76b7 100644 --- a/drivers/media/dvb-frontends/cx24113.c +++ b/drivers/media/dvb-frontends/cx24113.c @@ -555,10 +555,9 @@ struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe, struct cx24113_state *state = kzalloc(sizeof(struct cx24113_state), GFP_KERNEL); int rc; - if (state == NULL) { - cx_err("Unable to kzalloc\n"); + + if (!state) goto error; - } /* setup the state */ state->config = config; diff --git a/drivers/media/dvb-frontends/cx24116.c b/drivers/media/dvb-frontends/cx24116.c index e105532bfba8..96af4ffba0f9 100644 --- a/drivers/media/dvb-frontends/cx24116.c +++ b/drivers/media/dvb-frontends/cx24116.c @@ -227,7 +227,6 @@ static int cx24116_writeregN(struct cx24116_state *state, int reg, buf = kmalloc(len + 1, GFP_KERNEL); if (buf == NULL) { - printk("Unable to kmalloc\n"); ret = -ENOMEM; goto error; } diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index 7d04400b18dd..47b0d37e70ba 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -911,7 +911,6 @@ static int load_firmware(struct drxd_state *state, const char *fw_name) state->microcode = kmemdup(fw->data, fw->size, GFP_KERNEL); if (state->microcode == NULL) { release_firmware(fw); - printk(KERN_ERR "drxd: firmware load failure: no memory\n"); return -ENOMEM; } diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c index 0b17a45c5640..c2959a9695a7 100644 --- a/drivers/media/dvb-frontends/ds3000.c +++ b/drivers/media/dvb-frontends/ds3000.c @@ -277,10 +277,8 @@ static int ds3000_writeFW(struct ds3000_state *state, int reg, u8 *buf; buf = kmalloc(33, GFP_KERNEL); - if (buf == NULL) { - printk(KERN_ERR "Unable to kmalloc\n"); + if (!buf) return -ENOMEM; - } *(buf) = reg; @@ -842,10 +840,8 @@ struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, /* allocate memory for the internal state */ state = kzalloc(sizeof(struct ds3000_state), GFP_KERNEL); - if (state == NULL) { - printk(KERN_ERR "Unable to kmalloc\n"); + if (!state) goto error2; - } state->config = config; state->i2c = i2c; diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index e8ac8c3e2ec0..340984100aec 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -2072,11 +2072,8 @@ struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config, /* allocate memory for the internal state */ state = kzalloc(sizeof(struct mb86a20s_state), GFP_KERNEL); - if (state == NULL) { - dev_err(&i2c->dev, - "%s: unable to allocate memory for state\n", __func__); + if (!state) goto error; - } /* setup the state */ state->config = config; diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 172fc367ccaa..41d9c513b7e8 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -696,7 +696,6 @@ static int si2168_probe(struct i2c_client *client, dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { ret = -ENOMEM; - dev_err(&client->dev, "kzalloc() failed\n"); goto err; } diff --git a/drivers/media/dvb-frontends/sp2.c b/drivers/media/dvb-frontends/sp2.c index 43d47dfcc7b8..d3b4f8822096 100644 --- a/drivers/media/dvb-frontends/sp2.c +++ b/drivers/media/dvb-frontends/sp2.c @@ -384,7 +384,6 @@ static int sp2_probe(struct i2c_client *client, s = kzalloc(sizeof(struct sp2), GFP_KERNEL); if (!s) { ret = -ENOMEM; - dev_err(&client->dev, "kzalloc() failed\n"); goto err; } diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index f289b8aca1da..5217f9ad5e6b 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -3316,10 +3316,8 @@ static int adv76xx_probe(struct i2c_client *client, client->addr << 1); state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); - if (!state) { - v4l_err(client, "Could not allocate adv76xx_state memory!\n"); + if (!state) return -ENOMEM; - } state->i2c_clients[ADV76XX_PAGE_IO] = client; diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 65f34e7e146f..c582bcb782a6 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -3468,10 +3468,8 @@ static int adv7842_probe(struct i2c_client *client, } state = devm_kzalloc(&client->dev, sizeof(struct adv7842_state), GFP_KERNEL); - if (!state) { - v4l_err(client, "Could not allocate adv7842_state memory!\n"); + if (!state) return -ENOMEM; - } /* platform data */ state->pdata = *pdata; diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index 8654710464cc..9e99c6ef1476 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -910,11 +910,9 @@ static int cx18_probe(struct pci_dev *pci_dev, } cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC); - if (cx == NULL) { - printk(KERN_ERR "cx18: cannot manage card %d, out of memory\n", - i); + if (!cx) return -ENOMEM; - } + cx->pci_dev = pci_dev; cx->instance = i; diff --git a/drivers/media/pci/mantis/hopper_cards.c b/drivers/media/pci/mantis/hopper_cards.c index 11e987860b23..0c91df34ec67 100644 --- a/drivers/media/pci/mantis/hopper_cards.c +++ b/drivers/media/pci/mantis/hopper_cards.c @@ -165,7 +165,6 @@ static int hopper_pci_probe(struct pci_dev *pdev, mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); if (mantis == NULL) { - printk(KERN_ERR "%s ERROR: Out of memory\n", __func__); err = -ENOMEM; goto fail0; } diff --git a/drivers/media/pci/mantis/mantis_cards.c b/drivers/media/pci/mantis/mantis_cards.c index adc980d33711..2dba030c7132 100644 --- a/drivers/media/pci/mantis/mantis_cards.c +++ b/drivers/media/pci/mantis/mantis_cards.c @@ -174,10 +174,8 @@ static int mantis_pci_probe(struct pci_dev *pdev, int err = 0; mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); - if (mantis == NULL) { - printk(KERN_ERR "%s ERROR: Out of memory\n", __func__); + if (!mantis) return -ENOMEM; - } drvdata = (void *)pci_id->driver_data; mantis->num = devs; diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index 49e047e4a81e..af9cd02fac0c 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -1626,23 +1626,18 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) meye.mchip_dev = pcidev; meye.grab_temp = vmalloc(MCHIP_NB_PAGES_MJPEG * PAGE_SIZE); - if (!meye.grab_temp) { - v4l2_err(v4l2_dev, "grab buffer allocation failed\n"); + if (!meye.grab_temp) goto outvmalloc; - } spin_lock_init(&meye.grabq_lock); if (kfifo_alloc(&meye.grabq, sizeof(int) * MEYE_MAX_BUFNBRS, - GFP_KERNEL)) { - v4l2_err(v4l2_dev, "fifo allocation failed\n"); + GFP_KERNEL)) goto outkfifoalloc1; - } + spin_lock_init(&meye.doneq_lock); if (kfifo_alloc(&meye.doneq, sizeof(int) * MEYE_MAX_BUFNBRS, - GFP_KERNEL)) { - v4l2_err(v4l2_dev, "fifo allocation failed\n"); + GFP_KERNEL)) goto outkfifoalloc2; - } meye.vdev = meye_template; meye.vdev.v4l2_dev = &meye.v4l2_dev; diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c index f708cab01fef..32c19bad9a17 100644 --- a/drivers/media/pci/saa7146/hexium_gemini.c +++ b/drivers/media/pci/saa7146/hexium_gemini.c @@ -261,10 +261,9 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d DEB_EE("\n"); hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL); - if (NULL == hexium) { - pr_err("not enough kernel memory in hexium_attach()\n"); + if (!hexium) return -ENOMEM; - } + dev->ext_priv = hexium; /* enable i2c-port pins */ diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c index 01f01580c7ca..8d1dc8eea988 100644 --- a/drivers/media/pci/saa7146/hexium_orion.c +++ b/drivers/media/pci/saa7146/hexium_orion.c @@ -220,10 +220,8 @@ static int hexium_probe(struct saa7146_dev *dev) } hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL); - if (NULL == hexium) { - pr_err("hexium_probe: not enough kernel memory\n"); + if (!hexium) return -ENOMEM; - } /* enable i2c-port pins */ saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26)); diff --git a/drivers/media/pci/saa7164/saa7164-buffer.c b/drivers/media/pci/saa7164/saa7164-buffer.c index a0d2129c6ca9..6bd665ea190d 100644 --- a/drivers/media/pci/saa7164/saa7164-buffer.c +++ b/drivers/media/pci/saa7164/saa7164-buffer.c @@ -99,10 +99,8 @@ struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_port *port, } buf = kzalloc(sizeof(struct saa7164_buffer), GFP_KERNEL); - if (!buf) { - log_warn("%s() SAA_ERR_NO_RESOURCES\n", __func__); + if (!buf) goto ret; - } buf->idx = -1; buf->port = port; diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index d7103c5f92c3..db410c558a74 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -1507,10 +1507,8 @@ static int isc_formats_init(struct isc_device *isc) isc->user_formats = devm_kcalloc(isc->dev, num_fmts, sizeof(struct isc_format *), GFP_KERNEL); - if (!isc->user_formats) { - v4l2_err(&isc->v4l2_dev, "could not allocate memory\n"); + if (!isc->user_formats) return -ENOMEM; - } fmt = &isc_formats[0]; for (i = 0, j = 0; i < ARRAY_SIZE(isc_formats); i++) { diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index 891fa2505efa..154e9c39b64f 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -1038,10 +1038,8 @@ static int isi_formats_init(struct atmel_isi *isi) isi->user_formats = devm_kcalloc(isi->dev, num_fmts, sizeof(struct isi_format *), GFP_KERNEL); - if (!isi->user_formats) { - dev_err(isi->dev, "could not allocate memory\n"); + if (!isi->user_formats) return -ENOMEM; - } memcpy(isi->user_formats, isi_fmts, num_fmts * sizeof(struct isi_format *)); @@ -1176,10 +1174,8 @@ static int atmel_isi_probe(struct platform_device *pdev) int ret, i; isi = devm_kzalloc(&pdev->dev, sizeof(struct atmel_isi), GFP_KERNEL); - if (!isi) { - dev_err(&pdev->dev, "Can't allocate interface!\n"); + if (!isi) return -ENOMEM; - } isi->pclk = devm_clk_get(&pdev->dev, "isi_clk"); if (IS_ERR(isi->pclk)) diff --git a/drivers/media/platform/blackfin/ppi.c b/drivers/media/platform/blackfin/ppi.c index 37169054b828..478eb2f7d723 100644 --- a/drivers/media/platform/blackfin/ppi.c +++ b/drivers/media/platform/blackfin/ppi.c @@ -338,7 +338,6 @@ struct ppi_if *ppi_create_instance(struct platform_device *pdev, ppi = kzalloc(sizeof(*ppi), GFP_KERNEL); if (!ppi) { peripheral_free_list(info->pin_req); - dev_err(&pdev->dev, "unable to allocate memory for ppi handle\n"); return NULL; } ppi->ops = &ppi_ops; diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index 4ff8d0aed015..b50cff4ef9eb 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -209,10 +209,8 @@ static int send_control_msg(struct usb_device *udev, u8 request, u16 value, int status; unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL); - if (!transfer_buffer) { - dev_err(&udev->dev, "kmalloc(%d) failed\n", size); + if (!transfer_buffer) return -ENOMEM; - } memcpy(transfer_buffer, cp, size); @@ -1424,10 +1422,8 @@ static int zr364xx_probe(struct usb_interface *intf, le16_to_cpu(udev->descriptor.idProduct)); cam = kzalloc(sizeof(struct zr364xx_camera), GFP_KERNEL); - if (cam == NULL) { - dev_err(&udev->dev, "cam: out of memory !\n"); + if (!cam) return -ENOMEM; - } cam->v4l2_dev.release = zr364xx_release; err = v4l2_device_register(&intf->dev, &cam->v4l2_dev); -- cgit v1.2.3 From 2d3da59ff163b2aa805de0fc65ba933a735b00cd Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 28 Aug 2017 05:55:16 -0400 Subject: media: drivers: improve a size determination Replace the specification of a data structure by a pointer dereference as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. [mchehab@s-opensoure.com: merge similar patches into one] Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil --- drivers/media/common/cypress_firmware.c | 2 +- drivers/media/common/siano/smscoreapi.c | 14 ++++++-------- drivers/media/dvb-frontends/as102_fe.c | 2 +- drivers/media/dvb-frontends/cx24113.c | 3 +-- drivers/media/dvb-frontends/cx24116.c | 2 +- drivers/media/dvb-frontends/ds3000.c | 2 +- drivers/media/dvb-frontends/mb86a20s.c | 2 +- drivers/media/dvb-frontends/sp2.c | 2 +- drivers/media/i2c/adv7842.c | 2 +- drivers/media/pci/cx18/cx18-driver.c | 2 +- drivers/media/pci/mantis/hopper_cards.c | 2 +- drivers/media/pci/mantis/mantis_cards.c | 2 +- drivers/media/pci/saa7146/hexium_gemini.c | 2 +- drivers/media/pci/saa7146/hexium_orion.c | 2 +- drivers/media/pci/saa7164/saa7164-buffer.c | 4 ++-- drivers/media/platform/atmel/atmel-isc.c | 2 +- drivers/media/usb/zr364xx/zr364xx.c | 2 +- 17 files changed, 23 insertions(+), 26 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/common/cypress_firmware.c b/drivers/media/common/cypress_firmware.c index bfe47bc5f716..8895158c1962 100644 --- a/drivers/media/common/cypress_firmware.c +++ b/drivers/media/common/cypress_firmware.c @@ -74,7 +74,7 @@ int cypress_load_firmware(struct usb_device *udev, struct hexline *hx; int ret, pos = 0; - hx = kmalloc(sizeof(struct hexline), GFP_KERNEL); + hx = kmalloc(sizeof(*hx), GFP_KERNEL); if (!hx) return -ENOMEM; diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 889b486fbc72..ad1c41f727b1 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -447,7 +447,7 @@ static struct smscore_registry_entry_t *smscore_find_registry(char *devpath) return entry; } } - entry = kmalloc(sizeof(struct smscore_registry_entry_t), GFP_KERNEL); + entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (entry) { entry->mode = default_mode; strcpy(entry->devpath, devpath); @@ -536,9 +536,7 @@ int smscore_register_hotplug(hotplug_t hotplug) int rc = 0; kmutex_lock(&g_smscore_deviceslock); - - notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t), - GFP_KERNEL); + notifyee = kmalloc(sizeof(*notifyee), GFP_KERNEL); if (notifyee) { /* now notify callback about existing devices */ first = &g_smscore_devices; @@ -627,7 +625,7 @@ smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer, { struct smscore_buffer_t *cb; - cb = kzalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL); + cb = kzalloc(sizeof(*cb), GFP_KERNEL); if (!cb) return NULL; @@ -655,7 +653,7 @@ int smscore_register_device(struct smsdevice_params_t *params, struct smscore_device_t *dev; u8 *buffer; - dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -1684,7 +1682,7 @@ static int smscore_validate_client(struct smscore_device_t *coredev, pr_err("The msg ID already registered to another client.\n"); return -EEXIST; } - listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL); + listentry = kzalloc(sizeof(*listentry), GFP_KERNEL); if (!listentry) return -ENOMEM; @@ -1721,7 +1719,7 @@ int smscore_register_client(struct smscore_device_t *coredev, return -EEXIST; } - newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL); + newclient = kzalloc(sizeof(*newclient), GFP_KERNEL); if (!newclient) return -ENOMEM; diff --git a/drivers/media/dvb-frontends/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c index 1fb4ab21d786..b1c84ee914f0 100644 --- a/drivers/media/dvb-frontends/as102_fe.c +++ b/drivers/media/dvb-frontends/as102_fe.c @@ -455,7 +455,7 @@ struct dvb_frontend *as102_attach(const char *name, struct as102_state *state; struct dvb_frontend *fe; - state = kzalloc(sizeof(struct as102_state), GFP_KERNEL); + state = kzalloc(sizeof(*state), GFP_KERNEL); if (!state) return NULL; diff --git a/drivers/media/dvb-frontends/cx24113.c b/drivers/media/dvb-frontends/cx24113.c index 8fc7333c76b7..2c5502cab5e1 100644 --- a/drivers/media/dvb-frontends/cx24113.c +++ b/drivers/media/dvb-frontends/cx24113.c @@ -552,8 +552,7 @@ struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe, const struct cx24113_config *config, struct i2c_adapter *i2c) { /* allocate memory for the internal state */ - struct cx24113_state *state = - kzalloc(sizeof(struct cx24113_state), GFP_KERNEL); + struct cx24113_state *state = kzalloc(sizeof(*state), GFP_KERNEL); int rc; if (!state) diff --git a/drivers/media/dvb-frontends/cx24116.c b/drivers/media/dvb-frontends/cx24116.c index e5135fbe0297..531c5861a27e 100644 --- a/drivers/media/dvb-frontends/cx24116.c +++ b/drivers/media/dvb-frontends/cx24116.c @@ -1126,7 +1126,7 @@ struct dvb_frontend *cx24116_attach(const struct cx24116_config *config, dprintk("%s\n", __func__); /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct cx24116_state), GFP_KERNEL); + state = kzalloc(sizeof(*state), GFP_KERNEL); if (state == NULL) goto error1; diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c index 293c4103e5ff..3e347d03acb3 100644 --- a/drivers/media/dvb-frontends/ds3000.c +++ b/drivers/media/dvb-frontends/ds3000.c @@ -839,7 +839,7 @@ struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, dprintk("%s\n", __func__); /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct ds3000_state), GFP_KERNEL); + state = kzalloc(sizeof(*state), GFP_KERNEL); if (!state) goto error2; diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 340984100aec..ba7a433dd424 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -2071,7 +2071,7 @@ struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config, dev_dbg(&i2c->dev, "%s called.\n", __func__); /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct mb86a20s_state), GFP_KERNEL); + state = kzalloc(sizeof(*state), GFP_KERNEL); if (!state) goto error; diff --git a/drivers/media/dvb-frontends/sp2.c b/drivers/media/dvb-frontends/sp2.c index d3b4f8822096..dd556012ceb6 100644 --- a/drivers/media/dvb-frontends/sp2.c +++ b/drivers/media/dvb-frontends/sp2.c @@ -381,7 +381,7 @@ static int sp2_probe(struct i2c_client *client, dev_dbg(&client->dev, "\n"); - s = kzalloc(sizeof(struct sp2), GFP_KERNEL); + s = kzalloc(sizeof(*s), GFP_KERNEL); if (!s) { ret = -ENOMEM; goto err; diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index c582bcb782a6..136aa80a834b 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -3467,7 +3467,7 @@ static int adv7842_probe(struct i2c_client *client, return -ENODEV; } - state = devm_kzalloc(&client->dev, sizeof(struct adv7842_state), GFP_KERNEL); + state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); if (!state) return -ENOMEM; diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index 9e99c6ef1476..6efa93168059 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -909,7 +909,7 @@ static int cx18_probe(struct pci_dev *pci_dev, return -ENOMEM; } - cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC); + cx = kzalloc(sizeof(*cx), GFP_ATOMIC); if (!cx) return -ENOMEM; diff --git a/drivers/media/pci/mantis/hopper_cards.c b/drivers/media/pci/mantis/hopper_cards.c index a96ac0144fd2..ecb97dc381fb 100644 --- a/drivers/media/pci/mantis/hopper_cards.c +++ b/drivers/media/pci/mantis/hopper_cards.c @@ -163,7 +163,7 @@ static int hopper_pci_probe(struct pci_dev *pdev, struct mantis_hwconfig *config; int err; - mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); + mantis = kzalloc(sizeof(*mantis), GFP_KERNEL); if (mantis == NULL) { err = -ENOMEM; goto fail0; diff --git a/drivers/media/pci/mantis/mantis_cards.c b/drivers/media/pci/mantis/mantis_cards.c index 9958b6f4405f..4ce8a90d69dc 100644 --- a/drivers/media/pci/mantis/mantis_cards.c +++ b/drivers/media/pci/mantis/mantis_cards.c @@ -173,7 +173,7 @@ static int mantis_pci_probe(struct pci_dev *pdev, struct mantis_hwconfig *config; int err; - mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); + mantis = kzalloc(sizeof(*mantis), GFP_KERNEL); if (!mantis) return -ENOMEM; diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c index 32c19bad9a17..d31a2d4494d1 100644 --- a/drivers/media/pci/saa7146/hexium_gemini.c +++ b/drivers/media/pci/saa7146/hexium_gemini.c @@ -260,7 +260,7 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d DEB_EE("\n"); - hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL); + hexium = kzalloc(sizeof(*hexium), GFP_KERNEL); if (!hexium) return -ENOMEM; diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c index 8d1dc8eea988..7dc182202f8b 100644 --- a/drivers/media/pci/saa7146/hexium_orion.c +++ b/drivers/media/pci/saa7146/hexium_orion.c @@ -219,7 +219,7 @@ static int hexium_probe(struct saa7146_dev *dev) return -EFAULT; } - hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL); + hexium = kzalloc(sizeof(*hexium), GFP_KERNEL); if (!hexium) return -ENOMEM; diff --git a/drivers/media/pci/saa7164/saa7164-buffer.c b/drivers/media/pci/saa7164/saa7164-buffer.c index 6bd665ea190d..c83b2e914dcb 100644 --- a/drivers/media/pci/saa7164/saa7164-buffer.c +++ b/drivers/media/pci/saa7164/saa7164-buffer.c @@ -98,7 +98,7 @@ struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_port *port, goto ret; } - buf = kzalloc(sizeof(struct saa7164_buffer), GFP_KERNEL); + buf = kzalloc(sizeof(*buf), GFP_KERNEL); if (!buf) goto ret; @@ -281,7 +281,7 @@ struct saa7164_user_buffer *saa7164_buffer_alloc_user(struct saa7164_dev *dev, { struct saa7164_user_buffer *buf; - buf = kzalloc(sizeof(struct saa7164_user_buffer), GFP_KERNEL); + buf = kzalloc(sizeof(*buf), GFP_KERNEL); if (!buf) return NULL; diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index db410c558a74..755d2d4dd142 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -1505,7 +1505,7 @@ static int isc_formats_init(struct isc_device *isc) isc->num_user_formats = num_fmts; isc->user_formats = devm_kcalloc(isc->dev, - num_fmts, sizeof(struct isc_format *), + num_fmts, sizeof(*isc->user_formats), GFP_KERNEL); if (!isc->user_formats) return -ENOMEM; diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index b50cff4ef9eb..b3d05027bd9a 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -1421,7 +1421,7 @@ static int zr364xx_probe(struct usb_interface *intf, le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); - cam = kzalloc(sizeof(struct zr364xx_camera), GFP_KERNEL); + cam = kzalloc(sizeof(*cam), GFP_KERNEL); if (!cam) return -ENOMEM; -- cgit v1.2.3 From af28c99628ebfbdc3fff3d92c7044d3a51b7ccea Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 28 Aug 2017 06:50:28 -0400 Subject: media: drivers: Adjust checks for null pointers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The script “checkpatch.pl” pointed information out like the following. Comparison to NULL could be written !… Thus fix the affected source code places. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil --- drivers/media/common/siano/smscoreapi.c | 12 ++++++------ drivers/media/dvb-frontends/drxd_hard.c | 6 +++--- drivers/media/dvb-frontends/sp2.c | 6 +++--- drivers/media/i2c/adv7604.c | 6 +++--- drivers/media/pci/cx18/cx18-driver.c | 20 ++++++++++---------- drivers/media/pci/mantis/hopper_cards.c | 4 ++-- drivers/media/platform/atmel/atmel-isc.c | 6 +++--- drivers/media/platform/atmel/atmel-isi.c | 6 +++--- drivers/media/usb/zr364xx/zr364xx.c | 22 +++++++++++----------- 9 files changed, 44 insertions(+), 44 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index ad1c41f727b1..e4ea2a0c7a24 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -749,7 +749,7 @@ static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev, void *buffer, size_t size, struct completion *completion) { int rc; - if (completion == NULL) + if (!completion) return -EINVAL; init_completion(completion); @@ -1151,8 +1151,8 @@ static int smscore_load_firmware_from_file(struct smscore_device_t *coredev, } pr_debug("Firmware name: %s\n", fw_filename); - if (loadfirmware_handler == NULL && !(coredev->device_flags - & SMS_DEVICE_FAMILY2)) + if (!loadfirmware_handler && + !(coredev->device_flags & SMS_DEVICE_FAMILY2)) return -EINVAL; rc = request_firmware(&fw, fw_filename, coredev->device); @@ -1789,7 +1789,7 @@ int smsclient_sendrequest(struct smscore_client_t *client, struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer; int rc; - if (client == NULL) { + if (!client) { pr_err("Got NULL client\n"); return -EINVAL; } @@ -1797,7 +1797,7 @@ int smsclient_sendrequest(struct smscore_client_t *client, coredev = client->coredev; /* check that no other channel with same id exists */ - if (coredev == NULL) { + if (!coredev) { pr_err("Got NULL coredev\n"); return -EINVAL; } @@ -1954,7 +1954,7 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 pin_num, if (pin_num > MAX_GPIO_PIN_NUMBER) return -EINVAL; - if (p_gpio_config == NULL) + if (!p_gpio_config) return -EINVAL; total_len = sizeof(struct sms_msg_hdr) + (sizeof(u32) * 6); diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index 47b0d37e70ba..3bdf9b1f4e7c 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -328,7 +328,7 @@ static int WriteTable(struct drxd_state *state, u8 * pTable) { int status = 0; - if (pTable == NULL) + if (!pTable) return 0; while (!status) { @@ -909,7 +909,7 @@ static int load_firmware(struct drxd_state *state, const char *fw_name) } state->microcode = kmemdup(fw->data, fw->size, GFP_KERNEL); - if (state->microcode == NULL) { + if (!state->microcode) { release_firmware(fw); return -ENOMEM; } @@ -2629,7 +2629,7 @@ static int DRXD_init(struct drxd_state *state, const u8 *fw, u32 fw_size) break; /* Apply I2c address patch to B1 */ - if (!state->type_A && state->m_HiI2cPatch != NULL) { + if (!state->type_A && state->m_HiI2cPatch) { status = WriteTable(state, state->m_HiI2cPatch); if (status < 0) break; diff --git a/drivers/media/dvb-frontends/sp2.c b/drivers/media/dvb-frontends/sp2.c index dd556012ceb6..53e66c232d3c 100644 --- a/drivers/media/dvb-frontends/sp2.c +++ b/drivers/media/dvb-frontends/sp2.c @@ -357,14 +357,14 @@ static int sp2_exit(struct i2c_client *client) dev_dbg(&client->dev, "\n"); - if (client == NULL) + if (!client) return 0; s = i2c_get_clientdata(client); - if (s == NULL) + if (!s) return 0; - if (s->ca.data == NULL) + if (!s->ca.data) return 0; dvb_ca_en50221_release(&s->ca); diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 5217f9ad5e6b..c786cd125417 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1948,7 +1948,7 @@ static int adv76xx_set_format(struct v4l2_subdev *sd, return -EINVAL; info = adv76xx_format_info(state, format->format.code); - if (info == NULL) + if (!info) info = adv76xx_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8); adv76xx_fill_format(state, &format->format); @@ -2256,7 +2256,7 @@ static int adv76xx_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) return 0; } - if (data == NULL) + if (!data) return -ENODATA; if (edid->start_block >= state->edid.blocks) @@ -3480,7 +3480,7 @@ static int adv76xx_probe(struct i2c_client *client, state->i2c_clients[i] = adv76xx_dummy_client(sd, state->pdata.i2c_addresses[i], 0xf2 + i); - if (state->i2c_clients[i] == NULL) { + if (!state->i2c_clients[i]) { err = -ENOMEM; v4l2_err(sd, "failed to create i2c client %u\n", i); goto err_i2c; diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index 6efa93168059..8f314ca320c7 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -255,7 +255,7 @@ static void request_module_async(struct work_struct *work) request_module("cx18-alsa"); /* Initialize cx18-alsa for this instance of the cx18 device */ - if (cx18_ext_init != NULL) + if (cx18_ext_init) cx18_ext_init(dev); } @@ -291,11 +291,11 @@ int cx18_msleep_timeout(unsigned int msecs, int intr) /* Release ioremapped memory */ static void cx18_iounmap(struct cx18 *cx) { - if (cx == NULL) + if (!cx) return; /* Release io memory */ - if (cx->enc_mem != NULL) { + if (cx->enc_mem) { CX18_DEBUG_INFO("releasing enc_mem\n"); iounmap(cx->enc_mem); cx->enc_mem = NULL; @@ -649,15 +649,15 @@ static void cx18_process_options(struct cx18 *cx) CX18_INFO("User specified %s card\n", cx->card->name); else if (cx->options.cardtype != 0) CX18_ERR("Unknown user specified type, trying to autodetect card\n"); - if (cx->card == NULL) { + if (!cx->card) { if (cx->pci_dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) { cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); CX18_INFO("Autodetected Hauppauge card\n"); } } - if (cx->card == NULL) { + if (!cx->card) { for (i = 0; (cx->card = cx18_get_card(i)); i++) { - if (cx->card->pci_list == NULL) + if (!cx->card->pci_list) continue; for (j = 0; cx->card->pci_list[j].device; j++) { if (cx->pci_dev->device != @@ -676,7 +676,7 @@ static void cx18_process_options(struct cx18 *cx) } done: - if (cx->card == NULL) { + if (!cx->card) { cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); CX18_ERR("Unknown card: vendor/device: [%04x:%04x]\n", cx->pci_dev->vendor, cx->pci_dev->device); @@ -698,7 +698,7 @@ static int cx18_create_in_workq(struct cx18 *cx) snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in", cx->v4l2_dev.name); cx->in_work_queue = alloc_ordered_workqueue("%s", 0, cx->in_workq_name); - if (cx->in_work_queue == NULL) { + if (!cx->in_work_queue) { CX18_ERR("Unable to create incoming mailbox handler thread\n"); return -ENOMEM; } @@ -1254,7 +1254,7 @@ static void cx18_cancel_out_work_orders(struct cx18 *cx) { int i; for (i = 0; i < CX18_MAX_STREAMS; i++) - if (&cx->streams[i].video_dev != NULL) + if (&cx->streams[i].video_dev) cancel_work_sync(&cx->streams[i].out_work_order); } @@ -1299,7 +1299,7 @@ static void cx18_remove(struct pci_dev *pci_dev) pci_disable_device(cx->pci_dev); - if (cx->vbi.sliced_mpeg_data[0] != NULL) + if (cx->vbi.sliced_mpeg_data[0]) for (i = 0; i < CX18_VBI_FRAMES; i++) kfree(cx->vbi.sliced_mpeg_data[i]); diff --git a/drivers/media/pci/mantis/hopper_cards.c b/drivers/media/pci/mantis/hopper_cards.c index ecb97dc381fb..ed855e3df558 100644 --- a/drivers/media/pci/mantis/hopper_cards.c +++ b/drivers/media/pci/mantis/hopper_cards.c @@ -72,7 +72,7 @@ static irqreturn_t hopper_irq_handler(int irq, void *dev_id) struct mantis_ca *ca; mantis = (struct mantis_pci *) dev_id; - if (unlikely(mantis == NULL)) { + if (unlikely(!mantis)) { dprintk(MANTIS_ERROR, 1, "Mantis == NULL"); return IRQ_NONE; } @@ -164,7 +164,7 @@ static int hopper_pci_probe(struct pci_dev *pdev, int err; mantis = kzalloc(sizeof(*mantis), GFP_KERNEL); - if (mantis == NULL) { + if (!mantis) { err = -ENOMEM; goto fail0; } diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 755d2d4dd142..2f8e345d297e 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -1590,7 +1590,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) spin_lock_init(&isc->dma_queue_lock); sd_entity->config = v4l2_subdev_alloc_pad_config(sd_entity->sd); - if (sd_entity->config == NULL) + if (!sd_entity->config) return -ENOMEM; ret = isc_formats_init(isc); @@ -1714,7 +1714,7 @@ static int isc_parse_dt(struct device *dev, struct isc_device *isc) subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity), GFP_KERNEL); - if (subdev_entity == NULL) { + if (!subdev_entity) { of_node_put(rem); ret = -ENOMEM; break; @@ -1722,7 +1722,7 @@ static int isc_parse_dt(struct device *dev, struct isc_device *isc) subdev_entity->asd = devm_kzalloc(dev, sizeof(*subdev_entity->asd), GFP_KERNEL); - if (subdev_entity->asd == NULL) { + if (!subdev_entity->asd) { of_node_put(rem); ret = -ENOMEM; break; diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index 154e9c39b64f..463c0146915e 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -411,7 +411,7 @@ static void buffer_queue(struct vb2_buffer *vb) spin_lock_irqsave(&isi->irqlock, flags); list_add_tail(&buf->list, &isi->video_buffer_list); - if (isi->active == NULL) { + if (!isi->active) { isi->active = buf; if (vb2_is_streaming(vb->vb2_queue)) start_dma(isi, buf); @@ -1141,7 +1141,7 @@ static int isi_graph_init(struct atmel_isi *isi) /* Register the subdevices notifier. */ subdevs = devm_kzalloc(isi->dev, sizeof(*subdevs), GFP_KERNEL); - if (subdevs == NULL) { + if (!subdevs) { of_node_put(isi->entity.node); return -ENOMEM; } @@ -1200,7 +1200,7 @@ static int atmel_isi_probe(struct platform_device *pdev) return ret; isi->vdev = video_device_alloc(); - if (isi->vdev == NULL) { + if (!isi->vdev) { ret = -ENOMEM; goto err_vdev_alloc; } diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index b3d05027bd9a..1d888661fd03 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -385,9 +385,9 @@ static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, vb); int rc; - DBG("%s, field=%d, fmt name = %s\n", __func__, field, cam->fmt != NULL ? - cam->fmt->name : ""); - if (cam->fmt == NULL) + DBG("%s, field=%d, fmt name = %s\n", __func__, field, + cam->fmt ? cam->fmt->name : ""); + if (!cam->fmt) return -EINVAL; buf->vb.size = cam->width * cam->height * (cam->fmt->depth >> 3); @@ -787,7 +787,7 @@ static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct zr364xx_camera *cam = video_drvdata(file); char pixelformat_name[5]; - if (cam == NULL) + if (!cam) return -ENODEV; if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) { @@ -817,7 +817,7 @@ static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv, { struct zr364xx_camera *cam; - if (file == NULL) + if (!file) return -ENODEV; cam = video_drvdata(file); @@ -979,13 +979,13 @@ static void read_pipe_completion(struct urb *purb) pipe_info = purb->context; _DBG("%s %p, status %d\n", __func__, purb, purb->status); - if (pipe_info == NULL) { + if (!pipe_info) { printk(KERN_ERR KBUILD_MODNAME ": no context!\n"); return; } cam = pipe_info->cam; - if (cam == NULL) { + if (!cam) { printk(KERN_ERR KBUILD_MODNAME ": no context!\n"); return; } @@ -1069,7 +1069,7 @@ static void zr364xx_stop_readpipe(struct zr364xx_camera *cam) { struct zr364xx_pipeinfo *pipe_info; - if (cam == NULL) { + if (!cam) { printk(KERN_ERR KBUILD_MODNAME ": invalid device\n"); return; } @@ -1273,7 +1273,7 @@ static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma) struct zr364xx_camera *cam = video_drvdata(file); int ret; - if (cam == NULL) { + if (!cam) { DBG("%s: cam == NULL\n", __func__); return -ENODEV; } @@ -1357,7 +1357,7 @@ static int zr364xx_board_init(struct zr364xx_camera *cam) pipe->transfer_buffer = kzalloc(pipe->transfer_size, GFP_KERNEL); - if (pipe->transfer_buffer == NULL) { + if (!pipe->transfer_buffer) { DBG("out of memory!\n"); return -ENOMEM; } @@ -1373,7 +1373,7 @@ static int zr364xx_board_init(struct zr364xx_camera *cam) DBG("valloc %p, idx %lu, pdata %p\n", &cam->buffer.frame[i], i, cam->buffer.frame[i].lpvbits); - if (cam->buffer.frame[i].lpvbits == NULL) { + if (!cam->buffer.frame[i].lpvbits) { printk(KERN_INFO KBUILD_MODNAME ": out of memory. Using less frames\n"); break; } -- cgit v1.2.3 From 7a6e6c3be88dcc18f592c76f11cf8e7e090dc9dd Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 7 Sep 2017 16:37:16 -0400 Subject: media: davinci: do a couple of checkpatch cleanups - Delete an error message for a failed memory allocation in init_vpbe_layer(); - Replace the specification of data structures by pointer dereferences as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention; - media: DaVinci-VPBE-Display: Improve a size determination in two functions - Adjust 12 checks for null pointers Those issues were pointed by checkpatch.pl and Coccinelle. [mchehab@s-opensource.com: fold three cleanup patches into one] Signed-off-by: Markus Elfring Acked-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpbe_display.c | 37 +++++++++++---------------- 1 file changed, 15 insertions(+), 22 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 13d027031ff0..6aabd21fe69f 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -122,7 +122,7 @@ static irqreturn_t venc_isr(int irq, void *arg) int fid; int i; - if ((NULL == arg) || (NULL == disp_dev->dev[0])) + if (!arg || !disp_dev->dev[0]) return IRQ_HANDLED; if (venc_is_second_field(disp_dev)) @@ -337,10 +337,10 @@ static void vpbe_stop_streaming(struct vb2_queue *vq) vb2_buffer_done(&layer->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); } else { - if (layer->cur_frm != NULL) + if (layer->cur_frm) vb2_buffer_done(&layer->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); - if (layer->next_frm != NULL) + if (layer->next_frm) vb2_buffer_done(&layer->next_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); } @@ -947,7 +947,7 @@ static int vpbe_display_s_std(struct file *file, void *priv, if (vb2_is_busy(&layer->buffer_queue)) return -EBUSY; - if (NULL != vpbe_dev->ops.s_std) { + if (vpbe_dev->ops.s_std) { ret = vpbe_dev->ops.s_std(vpbe_dev, std_id); if (ret) { v4l2_err(&vpbe_dev->v4l2_dev, @@ -1000,8 +1000,7 @@ static int vpbe_display_enum_output(struct file *file, void *priv, v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_OUTPUT\n"); /* Enumerate outputs */ - - if (NULL == vpbe_dev->ops.enum_outputs) + if (!vpbe_dev->ops.enum_outputs) return -EINVAL; ret = vpbe_dev->ops.enum_outputs(vpbe_dev, output); @@ -1030,7 +1029,7 @@ static int vpbe_display_s_output(struct file *file, void *priv, if (vb2_is_busy(&layer->buffer_queue)) return -EBUSY; - if (NULL == vpbe_dev->ops.set_output) + if (!vpbe_dev->ops.set_output) return -EINVAL; ret = vpbe_dev->ops.set_output(vpbe_dev, i); @@ -1077,7 +1076,7 @@ vpbe_display_enum_dv_timings(struct file *file, void *priv, v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_TIMINGS\n"); /* Enumerate outputs */ - if (NULL == vpbe_dev->ops.enum_dv_timings) + if (!vpbe_dev->ops.enum_dv_timings) return -EINVAL; ret = vpbe_dev->ops.enum_dv_timings(vpbe_dev, timings); @@ -1292,7 +1291,7 @@ static int vpbe_device_get(struct device *dev, void *data) if (strcmp("vpbe_controller", pdev->name) == 0) vpbe_disp->vpbe_dev = platform_get_drvdata(pdev); - if (strstr(pdev->name, "vpbe-osd") != NULL) + if (strstr(pdev->name, "vpbe-osd")) vpbe_disp->osd_device = platform_get_drvdata(pdev); return 0; @@ -1305,15 +1304,10 @@ static int init_vpbe_layer(int i, struct vpbe_display *disp_dev, struct video_device *vbd = NULL; /* Allocate memory for four plane display objects */ - - disp_dev->dev[i] = - kzalloc(sizeof(struct vpbe_layer), GFP_KERNEL); - - /* If memory allocation fails, return error */ - if (!disp_dev->dev[i]) { - printk(KERN_ERR "ran out of memory\n"); + disp_dev->dev[i] = kzalloc(sizeof(*disp_dev->dev[i]), GFP_KERNEL); + if (!disp_dev->dev[i]) return -ENOMEM; - } + spin_lock_init(&disp_dev->dev[i]->irqlock); mutex_init(&disp_dev->dev[i]->opslock); @@ -1397,8 +1391,7 @@ static int vpbe_display_probe(struct platform_device *pdev) printk(KERN_DEBUG "vpbe_display_probe\n"); /* Allocate memory for vpbe_display */ - disp_dev = devm_kzalloc(&pdev->dev, sizeof(struct vpbe_display), - GFP_KERNEL); + disp_dev = devm_kzalloc(&pdev->dev, sizeof(*disp_dev), GFP_KERNEL); if (!disp_dev) return -ENOMEM; @@ -1414,7 +1407,7 @@ static int vpbe_display_probe(struct platform_device *pdev) v4l2_dev = &disp_dev->vpbe_dev->v4l2_dev; /* Initialize the vpbe display controller */ - if (NULL != disp_dev->vpbe_dev->ops.initialize) { + if (disp_dev->vpbe_dev->ops.initialize) { err = disp_dev->vpbe_dev->ops.initialize(&pdev->dev, disp_dev->vpbe_dev); if (err) { @@ -1482,7 +1475,7 @@ static int vpbe_display_probe(struct platform_device *pdev) probe_out: for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) { /* Unregister video device */ - if (disp_dev->dev[k] != NULL) { + if (disp_dev->dev[k]) { video_unregister_device(&disp_dev->dev[k]->video_dev); kfree(disp_dev->dev[k]); } @@ -1504,7 +1497,7 @@ static int vpbe_display_remove(struct platform_device *pdev) v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_remove\n"); /* deinitialize the vpbe display controller */ - if (NULL != vpbe_dev->ops.deinitialize) + if (vpbe_dev->ops.deinitialize) vpbe_dev->ops.deinitialize(&pdev->dev, vpbe_dev); /* un-register device */ for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { -- cgit v1.2.3 From 561b29e4ec8d0aac7e094f70d649ee4abccdda03 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 30 Aug 2017 04:47:21 -0400 Subject: media: fix media Kconfig help syntax issues The help text should be indented by at least two spaces after the 'help' separator. This is both good practice and the media_build system for building media drivers makes this assumption. I went through all Kconfigs under drivers/media and fixed any bad help sections. This makes it conform to the common practice and should fix problems with 'make menuconfig' when using media_build. This is due to a "WARNING" message that media_build can insert in the Kconfig and that assumes the help text is indented by at least two spaces. If not, then the Kconfig becomes invalid and 'make menuconfig' fails. Signed-off-by: Hans Verkuil Reported-by: Thomas Kaiser Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/Kconfig | 6 +++--- drivers/media/pci/b2c2/Kconfig | 4 ++-- drivers/media/pci/netup_unidvb/Kconfig | 12 ++++++------ drivers/media/platform/exynos4-is/Kconfig | 2 +- drivers/media/radio/wl128x/Kconfig | 10 +++++----- drivers/media/usb/b2c2/Kconfig | 6 +++--- drivers/media/usb/gspca/Kconfig | 16 ++++++++-------- drivers/media/usb/pvrusb2/Kconfig | 1 - 8 files changed, 28 insertions(+), 29 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 2631d0e0a024..d17722eb4456 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -173,7 +173,7 @@ config DVB_STB6000 tristate "ST STB6000 silicon tuner" depends on DVB_CORE && I2C default m if !MEDIA_SUBDRV_AUTOSELECT - help + help A DVB-S silicon tuner module. Say Y when you want to support this tuner. config DVB_STV0299 @@ -187,7 +187,7 @@ config DVB_STV6110 tristate "ST STV6110 silicon tuner" depends on DVB_CORE && I2C default m if !MEDIA_SUBDRV_AUTOSELECT - help + help A DVB-S silicon tuner module. Say Y when you want to support this tuner. config DVB_STV0900 @@ -902,7 +902,7 @@ config DVB_HELENE depends on DVB_CORE && I2C default m if !MEDIA_SUBDRV_AUTOSELECT help - Say Y when you want to support this frontend. + Say Y when you want to support this frontend. comment "Tools to develop new frontends" diff --git a/drivers/media/pci/b2c2/Kconfig b/drivers/media/pci/b2c2/Kconfig index 58761a21caa0..7b818d445f39 100644 --- a/drivers/media/pci/b2c2/Kconfig +++ b/drivers/media/pci/b2c2/Kconfig @@ -11,5 +11,5 @@ config DVB_B2C2_FLEXCOP_PCI_DEBUG depends on DVB_B2C2_FLEXCOP_PCI select DVB_B2C2_FLEXCOP_DEBUG help - Say Y if you want to enable the module option to control debug messages - of all B2C2 FlexCop drivers. + Say Y if you want to enable the module option to control debug messages + of all B2C2 FlexCop drivers. diff --git a/drivers/media/pci/netup_unidvb/Kconfig b/drivers/media/pci/netup_unidvb/Kconfig index 0ad37714c7fd..b663154d0cc4 100644 --- a/drivers/media/pci/netup_unidvb/Kconfig +++ b/drivers/media/pci/netup_unidvb/Kconfig @@ -1,8 +1,8 @@ config DVB_NETUP_UNIDVB tristate "NetUP Universal DVB card support" depends on DVB_CORE && VIDEO_DEV && PCI && I2C && SPI_MASTER - select VIDEOBUF2_DVB - select VIDEOBUF2_VMALLOC + select VIDEOBUF2_DVB + select VIDEOBUF2_VMALLOC select DVB_HORUS3A if MEDIA_SUBDRV_AUTOSELECT select DVB_ASCOT2E if MEDIA_SUBDRV_AUTOSELECT select DVB_HELENE if MEDIA_SUBDRV_AUTOSELECT @@ -10,8 +10,8 @@ config DVB_NETUP_UNIDVB select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for NetUP PCI express Universal DVB card. - help - Say Y when you want to support NetUP Dual Universal DVB card - Card can receive two independent streams in following standards: + + Say Y when you want to support NetUP Dual Universal DVB card. + Card can receive two independent streams in following standards: DVB-S/S2, T/T2, C/C2 - Two CI slots available for CAM modules. + Two CI slots available for CAM modules. diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig index c480efb755f5..46a7d242a1a5 100644 --- a/drivers/media/platform/exynos4-is/Kconfig +++ b/drivers/media/platform/exynos4-is/Kconfig @@ -76,7 +76,7 @@ config VIDEO_EXYNOS4_ISP_DMA_CAPTURE depends on VIDEO_EXYNOS4_FIMC_IS select VIDEO_EXYNOS4_IS_COMMON default y - help + help This option enables an additional video device node exposing a V4L2 video capture interface for the FIMC-IS ISP raw (Bayer) capture DMA. diff --git a/drivers/media/radio/wl128x/Kconfig b/drivers/media/radio/wl128x/Kconfig index c9e349b169c4..2add222ea346 100644 --- a/drivers/media/radio/wl128x/Kconfig +++ b/drivers/media/radio/wl128x/Kconfig @@ -7,11 +7,11 @@ config RADIO_WL128X depends on VIDEO_V4L2 && RFKILL && TTY && TI_ST depends on GPIOLIB || COMPILE_TEST help - Choose Y here if you have this FM radio chip. + Choose Y here if you have this FM radio chip. - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux 2 API. Information on - this API and pointers to "v4l2" programs may be found at - . + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux 2 API. Information on + this API and pointers to "v4l2" programs may be found at + . endmenu diff --git a/drivers/media/usb/b2c2/Kconfig b/drivers/media/usb/b2c2/Kconfig index 17d35833980c..a620ae42dfc8 100644 --- a/drivers/media/usb/b2c2/Kconfig +++ b/drivers/media/usb/b2c2/Kconfig @@ -10,6 +10,6 @@ config DVB_B2C2_FLEXCOP_USB_DEBUG bool "Enable debug for the B2C2 FlexCop drivers" depends on DVB_B2C2_FLEXCOP_USB select DVB_B2C2_FLEXCOP_DEBUG - help - Say Y if you want to enable the module option to control debug messages - of all B2C2 FlexCop drivers. + help + Say Y if you want to enable the module option to control debug messages + of all B2C2 FlexCop drivers. diff --git a/drivers/media/usb/gspca/Kconfig b/drivers/media/usb/gspca/Kconfig index 3fd94fe7e1eb..d214a21acff7 100644 --- a/drivers/media/usb/gspca/Kconfig +++ b/drivers/media/usb/gspca/Kconfig @@ -204,11 +204,11 @@ config USB_GSPCA_SE401 tristate "SE401 USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the - Endpoints (formerly known as AOX) se401 chip. + Say Y here if you want support for cameras based on the + Endpoints (formerly known as AOX) se401 chip. - To compile this driver as a module, choose M here: the - module will be called gspca_se401. + To compile this driver as a module, choose M here: the + module will be called gspca_se401. config USB_GSPCA_SN9C2028 tristate "SONIX Dual-Mode USB Camera Driver" @@ -224,11 +224,11 @@ config USB_GSPCA_SN9C20X tristate "SN9C20X USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the - sn9c20x chips (SN9C201 and SN9C202). + Say Y here if you want support for cameras based on the + sn9c20x chips (SN9C201 and SN9C202). - To compile this driver as a module, choose M here: the - module will be called gspca_sn9c20x. + To compile this driver as a module, choose M here: the + module will be called gspca_sn9c20x. config USB_GSPCA_SONIXB tristate "SONIX Bayer USB Camera Driver" diff --git a/drivers/media/usb/pvrusb2/Kconfig b/drivers/media/usb/pvrusb2/Kconfig index 60a2604e4cb3..1ad913fc30bf 100644 --- a/drivers/media/usb/pvrusb2/Kconfig +++ b/drivers/media/usb/pvrusb2/Kconfig @@ -44,7 +44,6 @@ config VIDEO_PVRUSB2_DVB select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT ---help--- - This option enables a DVB interface for the pvrusb2 driver. If your device does not support digital television, this feature will have no affect on the driver's operation. -- cgit v1.2.3 From 5dfbf6c51c72ede22975db1e2259c00ee0bfb7ff Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 14 Sep 2017 08:07:27 -0300 Subject: [media] rcar_drif: fix potential uninitialized variable use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Older compilers like gcc-4.6 may run into a case that returns an uninitialized variable from rcar_drif_enable_rx() if that function was ever called with an empty cur_ch_mask: drivers/media/platform/rcar_drif.c:658:2: error: ‘ret’ may be used uninitialized in this function [-Werror=uninitialized] Newer compilers don't have that problem as they optimize the 'ret' variable away and just return zero in that case. This changes the function to return -EINVAL for this particular failure, to make it consistent across all compiler versions. In case gcc gets changed to report a warning for it in the future, it's also a good idea to shut it up now. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82203 Signed-off-by: Arnd Bergmann Acked-by: Ramesh Shanmugasundaram Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar_drif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c index 522364ff0d5d..2c6afd38b78a 100644 --- a/drivers/media/platform/rcar_drif.c +++ b/drivers/media/platform/rcar_drif.c @@ -630,7 +630,7 @@ static int rcar_drif_enable_rx(struct rcar_drif_sdr *sdr) { unsigned int i; u32 ctr; - int ret; + int ret = -EINVAL; /* * When both internal channels are enabled, they can be synchronized -- cgit v1.2.3 From 02005cb27ca98792ac97728811e8dd30b3c1e798 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Sep 2017 11:51:45 -0300 Subject: [media] vivid: add support for Y10 and Y12 Add support for 10 and 12 bit luma formats. Signed-off-by: Hans Verkuil Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-common.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index f0f423c7ca41..a651527d80db 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -188,6 +188,22 @@ struct vivid_fmt vivid_formats[] = { .planes = 1, .buffers = 1, }, + { + .fourcc = V4L2_PIX_FMT_Y10, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .color_enc = TGP_COLOR_ENC_LUMA, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_Y12, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .color_enc = TGP_COLOR_ENC_LUMA, + .planes = 1, + .buffers = 1, + }, { .fourcc = V4L2_PIX_FMT_Y16, .vdownsampling = { 1 }, -- cgit v1.2.3 From 5b2c8da1b040c4608c7cfdc0dd96bcaa190af268 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Sep 2017 05:02:57 -0300 Subject: [media] cec-gpio: don't generate spurious HPD events Only send HPD_LOW/HIGH event if the gpio actually changed value. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/cec-gpio/cec-gpio.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/cec-gpio/cec-gpio.c b/drivers/media/platform/cec-gpio/cec-gpio.c index eb982bce99fc..5debdf08fbe7 100644 --- a/drivers/media/platform/cec-gpio/cec-gpio.c +++ b/drivers/media/platform/cec-gpio/cec-gpio.c @@ -80,9 +80,12 @@ static irqreturn_t cec_hpd_gpio_irq_handler_thread(int irq, void *priv) static irqreturn_t cec_hpd_gpio_irq_handler(int irq, void *priv) { struct cec_gpio *cec = priv; + bool is_high = gpiod_get_value(cec->hpd_gpio); + if (is_high == cec->hpd_is_high) + return IRQ_HANDLED; cec->hpd_ts = ktime_get(); - cec->hpd_is_high = gpiod_get_value(cec->hpd_gpio); + cec->hpd_is_high = is_high; return IRQ_WAKE_THREAD; } -- cgit v1.2.3 From f7e7b48e6d796da85d99b318def20d9313ef61df Mon Sep 17 00:00:00 2001 From: Jacob Chen Date: Wed, 11 Oct 2017 00:29:35 -0700 Subject: [media] rockchip/rga: v4l2 m2m support Rockchip RGA is a separate 2D raster graphic acceleration unit. It accelerates 2D graphics operations, such as point/line drawing, image scaling, rotation, BitBLT, alpha blending and image blur/sharpness The driver supports various operations from the rendering pipeline. - copy - fast solid color fill - rotation - flip - alpha blending The code in rga-hw.c is used to configure regs according to operations The code in rga-buf.c is used to create private mmu table for RGA. Signed-off-by: Jacob Chen Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 15 + drivers/media/platform/Makefile | 2 + drivers/media/platform/rockchip/rga/Makefile | 3 + drivers/media/platform/rockchip/rga/rga-buf.c | 154 ++++ drivers/media/platform/rockchip/rga/rga-hw.c | 421 ++++++++++ drivers/media/platform/rockchip/rga/rga-hw.h | 437 +++++++++++ drivers/media/platform/rockchip/rga/rga.c | 1012 +++++++++++++++++++++++++ drivers/media/platform/rockchip/rga/rga.h | 125 +++ 8 files changed, 2169 insertions(+) create mode 100644 drivers/media/platform/rockchip/rga/Makefile create mode 100644 drivers/media/platform/rockchip/rga/rga-buf.c create mode 100644 drivers/media/platform/rockchip/rga/rga-hw.c create mode 100644 drivers/media/platform/rockchip/rga/rga-hw.h create mode 100644 drivers/media/platform/rockchip/rga/rga.c create mode 100644 drivers/media/platform/rockchip/rga/rga.h (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index e4c89a16a3e7..1bf47e9683ca 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -458,6 +458,21 @@ config VIDEO_RENESAS_VSP1 To compile this driver as a module, choose M here: the module will be called vsp1. +config VIDEO_ROCKCHIP_RGA + tristate "Rockchip Raster 2d Graphic Acceleration Unit" + depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA + depends on ARCH_ROCKCHIP || COMPILE_TEST + select VIDEOBUF2_DMA_SG + select V4L2_MEM2MEM_DEV + default n + ---help--- + This is a v4l2 driver for Rockchip SOC RGA 2d graphics accelerator. + Rockchip RGA is a separate 2D raster graphic acceleration unit. + It accelerates 2D graphics operations, such as point/line drawing, + image scaling, rotation, BitBLT, alpha blending and image blur/sharpness. + + To compile this driver as a module choose m here. + config VIDEO_TI_VPE tristate "TI VPE (Video Processing Engine) driver" depends on VIDEO_DEV && VIDEO_V4L2 diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 9bf48f118537..1530b096db10 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -64,6 +64,8 @@ obj-$(CONFIG_VIDEO_RENESAS_FDP1) += rcar_fdp1.o obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/ +obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip/rga/ + obj-y += omap/ obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/ diff --git a/drivers/media/platform/rockchip/rga/Makefile b/drivers/media/platform/rockchip/rga/Makefile new file mode 100644 index 000000000000..92fe25490ccd --- /dev/null +++ b/drivers/media/platform/rockchip/rga/Makefile @@ -0,0 +1,3 @@ +rockchip-rga-objs := rga.o rga-hw.o rga-buf.o + +obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip-rga.o diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c new file mode 100644 index 000000000000..49cacc7a48d1 --- /dev/null +++ b/drivers/media/platform/rockchip/rga/rga-buf.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2017 Fuzhou Rockchip Electronics Co.Ltd + * Author: Jacob Chen + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +#include +#include +#include +#include +#include + +#include "rga-hw.h" +#include "rga.h" + +static int +rga_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + struct rga_ctx *ctx = vb2_get_drv_priv(vq); + struct rga_frame *f = rga_get_frame(ctx, vq->type); + + if (IS_ERR(f)) + return PTR_ERR(f); + + if (*nplanes) + return sizes[0] < f->size ? -EINVAL : 0; + + sizes[0] = f->size; + *nplanes = 1; + + return 0; +} + +static int rga_buf_prepare(struct vb2_buffer *vb) +{ + struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type); + + if (IS_ERR(f)) + return PTR_ERR(f); + + vb2_set_plane_payload(vb, 0, f->size); + + return 0; +} + +static void rga_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); +} + +static int rga_buf_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct rga_ctx *ctx = vb2_get_drv_priv(q); + struct rockchip_rga *rga = ctx->rga; + int ret, i; + + ret = pm_runtime_get_sync(rga->dev); + + if (!ret) + return 0; + + for (i = 0; i < q->num_buffers; ++i) { + if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) { + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(q->bufs[i]), + VB2_BUF_STATE_QUEUED); + } + } + + return ret; +} + +static void rga_buf_stop_streaming(struct vb2_queue *q) +{ + struct rga_ctx *ctx = vb2_get_drv_priv(q); + struct rockchip_rga *rga = ctx->rga; + struct vb2_v4l2_buffer *vbuf; + + for (;;) { + if (V4L2_TYPE_IS_OUTPUT(q->type)) + vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + else + vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (!vbuf) + break; + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); + } + + pm_runtime_put(rga->dev); +} + +const struct vb2_ops rga_qops = { + .queue_setup = rga_queue_setup, + .buf_prepare = rga_buf_prepare, + .buf_queue = rga_buf_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = rga_buf_start_streaming, + .stop_streaming = rga_buf_stop_streaming, +}; + +/* RGA MMU is a 1-Level MMU, so it can't be used through the IOMMU API. + * We use it more like a scatter-gather list. + */ +void rga_buf_map(struct vb2_buffer *vb) +{ + struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct rockchip_rga *rga = ctx->rga; + struct sg_table *sgt; + struct scatterlist *sgl; + unsigned int *pages; + unsigned int address, len, i, p; + unsigned int mapped_size = 0; + + if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + pages = rga->src_mmu_pages; + else + pages = rga->dst_mmu_pages; + + /* Create local MMU table for RGA */ + sgt = vb2_plane_cookie(vb, 0); + + for_each_sg(sgt->sgl, sgl, sgt->nents, i) { + len = sg_dma_len(sgl) >> PAGE_SHIFT; + address = sg_phys(sgl); + + for (p = 0; p < len; p++) { + dma_addr_t phys = address + (p << PAGE_SHIFT); + + pages[mapped_size + p] = phys; + } + + mapped_size += len; + } + + /* sync local MMU table for RGA */ + dma_sync_single_for_device(rga->dev, virt_to_phys(pages), + 8 * PAGE_SIZE, DMA_BIDIRECTIONAL); +} diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c new file mode 100644 index 000000000000..0645481c9a5e --- /dev/null +++ b/drivers/media/platform/rockchip/rga/rga-hw.c @@ -0,0 +1,421 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Jacob Chen + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +#include "rga-hw.h" +#include "rga.h" + +enum e_rga_start_pos { + LT = 0, + LB = 1, + RT = 2, + RB = 3, +}; + +struct rga_addr_offset { + unsigned int y_off; + unsigned int u_off; + unsigned int v_off; +}; + +struct rga_corners_addr_offset { + struct rga_addr_offset left_top; + struct rga_addr_offset right_top; + struct rga_addr_offset left_bottom; + struct rga_addr_offset right_bottom; +}; + +static unsigned int rga_get_scaling(unsigned int src, unsigned int dst) +{ + /* + * The rga hw scaling factor is a normalized inverse of the + * scaling factor. + * For example: When source width is 100 and destination width is 200 + * (scaling of 2x), then the hw factor is NC * 100 / 200. + * The normalization factor (NC) is 2^16 = 0x10000. + */ + + return (src > dst) ? ((dst << 16) / src) : ((src << 16) / dst); +} + +static struct rga_corners_addr_offset +rga_get_addr_offset(struct rga_frame *frm, unsigned int x, unsigned int y, + unsigned int w, unsigned int h) +{ + struct rga_corners_addr_offset offsets; + struct rga_addr_offset *lt, *lb, *rt, *rb; + unsigned int x_div = 0, + y_div = 0, uv_stride = 0, pixel_width = 0, uv_factor = 0; + + lt = &offsets.left_top; + lb = &offsets.left_bottom; + rt = &offsets.right_top; + rb = &offsets.right_bottom; + + x_div = frm->fmt->x_div; + y_div = frm->fmt->y_div; + uv_factor = frm->fmt->uv_factor; + uv_stride = frm->stride / x_div; + pixel_width = frm->stride / frm->width; + + lt->y_off = y * frm->stride + x * pixel_width; + lt->u_off = + frm->width * frm->height + (y / y_div) * uv_stride + x / x_div; + lt->v_off = lt->u_off + frm->width * frm->height / uv_factor; + + lb->y_off = lt->y_off + (h - 1) * frm->stride; + lb->u_off = lt->u_off + (h / y_div - 1) * uv_stride; + lb->v_off = lt->v_off + (h / y_div - 1) * uv_stride; + + rt->y_off = lt->y_off + (w - 1) * pixel_width; + rt->u_off = lt->u_off + w / x_div - 1; + rt->v_off = lt->v_off + w / x_div - 1; + + rb->y_off = lb->y_off + (w - 1) * pixel_width; + rb->u_off = lb->u_off + w / x_div - 1; + rb->v_off = lb->v_off + w / x_div - 1; + + return offsets; +} + +static struct rga_addr_offset *rga_lookup_draw_pos(struct + rga_corners_addr_offset + * offsets, u32 rotate_mode, + u32 mirr_mode) +{ + static enum e_rga_start_pos rot_mir_point_matrix[4][4] = { + { + LT, RT, LB, RB, + }, + { + RT, LT, RB, LB, + }, + { + RB, LB, RT, LT, + }, + { + LB, RB, LT, RT, + }, + }; + + if (!offsets) + return NULL; + + switch (rot_mir_point_matrix[rotate_mode][mirr_mode]) { + case LT: + return &offsets->left_top; + case LB: + return &offsets->left_bottom; + case RT: + return &offsets->right_top; + case RB: + return &offsets->right_bottom; + } + + return NULL; +} + +static void rga_cmd_set_src_addr(struct rga_ctx *ctx, void *mmu_pages) +{ + struct rockchip_rga *rga = ctx->rga; + u32 *dest = rga->cmdbuf_virt; + unsigned int reg; + + reg = RGA_MMU_SRC_BASE - RGA_MODE_BASE_REG; + dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4; + + reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG; + dest[reg >> 2] |= 0x7; +} + +static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, void *mmu_pages) +{ + struct rockchip_rga *rga = ctx->rga; + u32 *dest = rga->cmdbuf_virt; + unsigned int reg; + + reg = RGA_MMU_SRC1_BASE - RGA_MODE_BASE_REG; + dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4; + + reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG; + dest[reg >> 2] |= 0x7 << 4; +} + +static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, void *mmu_pages) +{ + struct rockchip_rga *rga = ctx->rga; + u32 *dest = rga->cmdbuf_virt; + unsigned int reg; + + reg = RGA_MMU_DST_BASE - RGA_MODE_BASE_REG; + dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4; + + reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG; + dest[reg >> 2] |= 0x7 << 8; +} + +static void rga_cmd_set_trans_info(struct rga_ctx *ctx) +{ + struct rockchip_rga *rga = ctx->rga; + u32 *dest = rga->cmdbuf_virt; + unsigned int scale_dst_w, scale_dst_h; + unsigned int src_h, src_w, src_x, src_y, dst_h, dst_w, dst_x, dst_y; + union rga_src_info src_info; + union rga_dst_info dst_info; + union rga_src_x_factor x_factor; + union rga_src_y_factor y_factor; + union rga_src_vir_info src_vir_info; + union rga_src_act_info src_act_info; + union rga_dst_vir_info dst_vir_info; + union rga_dst_act_info dst_act_info; + + struct rga_addr_offset *dst_offset; + struct rga_corners_addr_offset offsets; + struct rga_corners_addr_offset src_offsets; + + src_h = ctx->in.crop.height; + src_w = ctx->in.crop.width; + src_x = ctx->in.crop.left; + src_y = ctx->in.crop.top; + dst_h = ctx->out.crop.height; + dst_w = ctx->out.crop.width; + dst_x = ctx->out.crop.left; + dst_y = ctx->out.crop.top; + + src_info.val = dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2]; + dst_info.val = dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2]; + x_factor.val = dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2]; + y_factor.val = dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2]; + src_vir_info.val = dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2]; + src_act_info.val = dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2]; + dst_vir_info.val = dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2]; + dst_act_info.val = dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2]; + + src_info.data.format = ctx->in.fmt->hw_format; + src_info.data.swap = ctx->in.fmt->color_swap; + dst_info.data.format = ctx->out.fmt->hw_format; + dst_info.data.swap = ctx->out.fmt->color_swap; + + if (ctx->in.fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) { + if (ctx->out.fmt->hw_format < RGA_COLOR_FMT_YUV422SP) { + switch (ctx->in.colorspace) { + case V4L2_COLORSPACE_REC709: + src_info.data.csc_mode = + RGA_SRC_CSC_MODE_BT709_R0; + break; + default: + src_info.data.csc_mode = + RGA_SRC_CSC_MODE_BT601_R0; + break; + } + } + } + + if (ctx->out.fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) { + switch (ctx->out.colorspace) { + case V4L2_COLORSPACE_REC709: + dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0; + break; + default: + dst_info.data.csc_mode = RGA_DST_CSC_MODE_BT601_R0; + break; + } + } + + if (ctx->vflip) + src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_X; + + if (ctx->hflip) + src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_Y; + + switch (ctx->rotate) { + case 90: + src_info.data.rot_mode = RGA_SRC_ROT_MODE_90_DEGREE; + break; + case 180: + src_info.data.rot_mode = RGA_SRC_ROT_MODE_180_DEGREE; + break; + case 270: + src_info.data.rot_mode = RGA_SRC_ROT_MODE_270_DEGREE; + break; + default: + src_info.data.rot_mode = RGA_SRC_ROT_MODE_0_DEGREE; + break; + } + + /* + * Cacluate the up/down scaling mode/factor. + * + * RGA used to scale the picture first, and then rotate second, + * so we need to swap the w/h when rotate degree is 90/270. + */ + if (src_info.data.rot_mode == RGA_SRC_ROT_MODE_90_DEGREE || + src_info.data.rot_mode == RGA_SRC_ROT_MODE_270_DEGREE) { + if (rga->version.major == 0 || rga->version.minor == 0) { + if (dst_w == src_h) + src_h -= 8; + if (abs(src_w - dst_h) < 16) + src_w -= 16; + } + + scale_dst_h = dst_w; + scale_dst_w = dst_h; + } else { + scale_dst_w = dst_w; + scale_dst_h = dst_h; + } + + if (src_w == scale_dst_w) { + src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_NO; + x_factor.val = 0; + } else if (src_w > scale_dst_w) { + src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_DOWN; + x_factor.data.down_scale_factor = + rga_get_scaling(src_w, scale_dst_w) + 1; + } else { + src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_UP; + x_factor.data.up_scale_factor = + rga_get_scaling(src_w - 1, scale_dst_w - 1); + } + + if (src_h == scale_dst_h) { + src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_NO; + y_factor.val = 0; + } else if (src_h > scale_dst_h) { + src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_DOWN; + y_factor.data.down_scale_factor = + rga_get_scaling(src_h, scale_dst_h) + 1; + } else { + src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_UP; + y_factor.data.up_scale_factor = + rga_get_scaling(src_h - 1, scale_dst_h - 1); + } + + /* + * Cacluate the framebuffer virtual strides and active size, + * note that the step of vir_stride / vir_width is 4 byte words + */ + src_vir_info.data.vir_stride = ctx->in.stride >> 2; + src_vir_info.data.vir_width = ctx->in.stride >> 2; + + src_act_info.data.act_height = src_h - 1; + src_act_info.data.act_width = src_w - 1; + + dst_vir_info.data.vir_stride = ctx->out.stride >> 2; + dst_act_info.data.act_height = dst_h - 1; + dst_act_info.data.act_width = dst_w - 1; + + /* + * Cacluate the source framebuffer base address with offset pixel. + */ + src_offsets = rga_get_addr_offset(&ctx->in, src_x, src_y, + src_w, src_h); + + /* + * Configure the dest framebuffer base address with pixel offset. + */ + offsets = rga_get_addr_offset(&ctx->out, dst_x, dst_y, dst_w, dst_h); + dst_offset = rga_lookup_draw_pos(&offsets, src_info.data.rot_mode, + src_info.data.mir_mode); + + dest[(RGA_SRC_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = + src_offsets.left_top.y_off; + dest[(RGA_SRC_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = + src_offsets.left_top.u_off; + dest[(RGA_SRC_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = + src_offsets.left_top.v_off; + + dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2] = x_factor.val; + dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2] = y_factor.val; + dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = src_vir_info.val; + dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = src_act_info.val; + + dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2] = src_info.val; + + dest[(RGA_DST_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = + dst_offset->y_off; + dest[(RGA_DST_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = + dst_offset->u_off; + dest[(RGA_DST_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = + dst_offset->v_off; + + dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = dst_vir_info.val; + dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = dst_act_info.val; + + dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2] = dst_info.val; +} + +static void rga_cmd_set_mode(struct rga_ctx *ctx) +{ + struct rockchip_rga *rga = ctx->rga; + u32 *dest = rga->cmdbuf_virt; + union rga_mode_ctrl mode; + union rga_alpha_ctrl0 alpha_ctrl0; + union rga_alpha_ctrl1 alpha_ctrl1; + + mode.val = 0; + alpha_ctrl0.val = 0; + alpha_ctrl1.val = 0; + + mode.data.gradient_sat = 1; + mode.data.render = RGA_MODE_RENDER_BITBLT; + mode.data.bitblt = RGA_MODE_BITBLT_MODE_SRC_TO_DST; + + /* disable alpha blending */ + dest[(RGA_ALPHA_CTRL0 - RGA_MODE_BASE_REG) >> 2] = alpha_ctrl0.val; + dest[(RGA_ALPHA_CTRL1 - RGA_MODE_BASE_REG) >> 2] = alpha_ctrl1.val; + + dest[(RGA_MODE_CTRL - RGA_MODE_BASE_REG) >> 2] = mode.val; +} + +void rga_cmd_set(struct rga_ctx *ctx) +{ + struct rockchip_rga *rga = ctx->rga; + + memset(rga->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4); + + rga_cmd_set_src_addr(ctx, rga->src_mmu_pages); + /* + * Due to hardware bug, + * src1 mmu also should be configured when using alpha blending. + */ + rga_cmd_set_src1_addr(ctx, rga->dst_mmu_pages); + + rga_cmd_set_dst_addr(ctx, rga->dst_mmu_pages); + rga_cmd_set_mode(ctx); + + rga_cmd_set_trans_info(ctx); + + rga_write(rga, RGA_CMD_BASE, rga->cmdbuf_phy); + + /* sync CMD buf for RGA */ + dma_sync_single_for_device(rga->dev, rga->cmdbuf_phy, + PAGE_SIZE, DMA_BIDIRECTIONAL); +} + +void rga_hw_start(struct rockchip_rga *rga) +{ + struct rga_ctx *ctx = rga->curr; + + rga_cmd_set(ctx); + + rga_write(rga, RGA_SYS_CTRL, 0x00); + + rga_write(rga, RGA_SYS_CTRL, 0x22); + + rga_write(rga, RGA_INT, 0x600); + + rga_write(rga, RGA_CMD_CTRL, 0x1); +} diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h new file mode 100644 index 000000000000..ca3c204abe42 --- /dev/null +++ b/drivers/media/platform/rockchip/rga/rga-hw.h @@ -0,0 +1,437 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Jacob Chen + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __RGA_HW_H__ +#define __RGA_HW_H__ + +#define RGA_CMDBUF_SIZE 0x20 + +/* Hardware limits */ +#define MAX_WIDTH 8192 +#define MAX_HEIGHT 8192 + +#define MIN_WIDTH 34 +#define MIN_HEIGHT 34 + +#define DEFAULT_WIDTH 100 +#define DEFAULT_HEIGHT 100 + +#define RGA_TIMEOUT 500 + +/* Registers address */ +#define RGA_SYS_CTRL 0x0000 +#define RGA_CMD_CTRL 0x0004 +#define RGA_CMD_BASE 0x0008 +#define RGA_INT 0x0010 +#define RGA_MMU_CTRL0 0x0014 +#define RGA_VERSION_INFO 0x0028 + +#define RGA_MODE_BASE_REG 0x0100 +#define RGA_MODE_MAX_REG 0x017C + +#define RGA_MODE_CTRL 0x0100 +#define RGA_SRC_INFO 0x0104 +#define RGA_SRC_Y_RGB_BASE_ADDR 0x0108 +#define RGA_SRC_CB_BASE_ADDR 0x010c +#define RGA_SRC_CR_BASE_ADDR 0x0110 +#define RGA_SRC1_RGB_BASE_ADDR 0x0114 +#define RGA_SRC_VIR_INFO 0x0118 +#define RGA_SRC_ACT_INFO 0x011c +#define RGA_SRC_X_FACTOR 0x0120 +#define RGA_SRC_Y_FACTOR 0x0124 +#define RGA_SRC_BG_COLOR 0x0128 +#define RGA_SRC_FG_COLOR 0x012c +#define RGA_SRC_TR_COLOR0 0x0130 +#define RGA_SRC_TR_COLOR1 0x0134 + +#define RGA_DST_INFO 0x0138 +#define RGA_DST_Y_RGB_BASE_ADDR 0x013c +#define RGA_DST_CB_BASE_ADDR 0x0140 +#define RGA_DST_CR_BASE_ADDR 0x0144 +#define RGA_DST_VIR_INFO 0x0148 +#define RGA_DST_ACT_INFO 0x014c + +#define RGA_ALPHA_CTRL0 0x0150 +#define RGA_ALPHA_CTRL1 0x0154 +#define RGA_FADING_CTRL 0x0158 +#define RGA_PAT_CON 0x015c +#define RGA_ROP_CON0 0x0160 +#define RGA_ROP_CON1 0x0164 +#define RGA_MASK_BASE 0x0168 + +#define RGA_MMU_CTRL1 0x016C +#define RGA_MMU_SRC_BASE 0x0170 +#define RGA_MMU_SRC1_BASE 0x0174 +#define RGA_MMU_DST_BASE 0x0178 + +/* Registers value */ +#define RGA_MODE_RENDER_BITBLT 0 +#define RGA_MODE_RENDER_COLOR_PALETTE 1 +#define RGA_MODE_RENDER_RECTANGLE_FILL 2 +#define RGA_MODE_RENDER_UPDATE_PALETTE_LUT_RAM 3 + +#define RGA_MODE_BITBLT_MODE_SRC_TO_DST 0 +#define RGA_MODE_BITBLT_MODE_SRC_SRC1_TO_DST 1 + +#define RGA_MODE_CF_ROP4_SOLID 0 +#define RGA_MODE_CF_ROP4_PATTERN 1 + +#define RGA_COLOR_FMT_ABGR8888 0 +#define RGA_COLOR_FMT_XBGR8888 1 +#define RGA_COLOR_FMT_RGB888 2 +#define RGA_COLOR_FMT_BGR565 4 +#define RGA_COLOR_FMT_ABGR1555 5 +#define RGA_COLOR_FMT_ABGR4444 6 +#define RGA_COLOR_FMT_YUV422SP 8 +#define RGA_COLOR_FMT_YUV422P 9 +#define RGA_COLOR_FMT_YUV420SP 10 +#define RGA_COLOR_FMT_YUV420P 11 +/* SRC_COLOR Palette */ +#define RGA_COLOR_FMT_CP_1BPP 12 +#define RGA_COLOR_FMT_CP_2BPP 13 +#define RGA_COLOR_FMT_CP_4BPP 14 +#define RGA_COLOR_FMT_CP_8BPP 15 +#define RGA_COLOR_FMT_MASK 15 + +#define RGA_COLOR_NONE_SWAP 0 +#define RGA_COLOR_RB_SWAP 1 +#define RGA_COLOR_ALPHA_SWAP 2 +#define RGA_COLOR_UV_SWAP 4 + +#define RGA_SRC_CSC_MODE_BYPASS 0 +#define RGA_SRC_CSC_MODE_BT601_R0 1 +#define RGA_SRC_CSC_MODE_BT601_R1 2 +#define RGA_SRC_CSC_MODE_BT709_R0 3 +#define RGA_SRC_CSC_MODE_BT709_R1 4 + +#define RGA_SRC_ROT_MODE_0_DEGREE 0 +#define RGA_SRC_ROT_MODE_90_DEGREE 1 +#define RGA_SRC_ROT_MODE_180_DEGREE 2 +#define RGA_SRC_ROT_MODE_270_DEGREE 3 + +#define RGA_SRC_MIRR_MODE_NO 0 +#define RGA_SRC_MIRR_MODE_X 1 +#define RGA_SRC_MIRR_MODE_Y 2 +#define RGA_SRC_MIRR_MODE_X_Y 3 + +#define RGA_SRC_HSCL_MODE_NO 0 +#define RGA_SRC_HSCL_MODE_DOWN 1 +#define RGA_SRC_HSCL_MODE_UP 2 + +#define RGA_SRC_VSCL_MODE_NO 0 +#define RGA_SRC_VSCL_MODE_DOWN 1 +#define RGA_SRC_VSCL_MODE_UP 2 + +#define RGA_SRC_TRANS_ENABLE_R 1 +#define RGA_SRC_TRANS_ENABLE_G 2 +#define RGA_SRC_TRANS_ENABLE_B 4 +#define RGA_SRC_TRANS_ENABLE_A 8 + +#define RGA_SRC_BIC_COE_SELEC_CATROM 0 +#define RGA_SRC_BIC_COE_SELEC_MITCHELL 1 +#define RGA_SRC_BIC_COE_SELEC_HERMITE 2 +#define RGA_SRC_BIC_COE_SELEC_BSPLINE 3 + +#define RGA_DST_DITHER_MODE_888_TO_666 0 +#define RGA_DST_DITHER_MODE_888_TO_565 1 +#define RGA_DST_DITHER_MODE_888_TO_555 2 +#define RGA_DST_DITHER_MODE_888_TO_444 3 + +#define RGA_DST_CSC_MODE_BYPASS 0 +#define RGA_DST_CSC_MODE_BT601_R0 1 +#define RGA_DST_CSC_MODE_BT601_R1 2 +#define RGA_DST_CSC_MODE_BT709_R0 3 + +#define RGA_ALPHA_ROP_MODE_2 0 +#define RGA_ALPHA_ROP_MODE_3 1 +#define RGA_ALPHA_ROP_MODE_4 2 + +#define RGA_ALPHA_SELECT_ALPHA 0 +#define RGA_ALPHA_SELECT_ROP 1 + +#define RGA_ALPHA_MASK_BIG_ENDIAN 0 +#define RGA_ALPHA_MASK_LITTLE_ENDIAN 1 + +#define RGA_ALPHA_NORMAL 0 +#define RGA_ALPHA_REVERSE 1 + +#define RGA_ALPHA_BLEND_GLOBAL 0 +#define RGA_ALPHA_BLEND_NORMAL 1 +#define RGA_ALPHA_BLEND_MULTIPLY 2 + +#define RGA_ALPHA_CAL_CUT 0 +#define RGA_ALPHA_CAL_NORMAL 1 + +#define RGA_ALPHA_FACTOR_ZERO 0 +#define RGA_ALPHA_FACTOR_ONE 1 +#define RGA_ALPHA_FACTOR_OTHER 2 +#define RGA_ALPHA_FACTOR_OTHER_REVERSE 3 +#define RGA_ALPHA_FACTOR_SELF 4 + +#define RGA_ALPHA_COLOR_NORMAL 0 +#define RGA_ALPHA_COLOR_MULTIPLY_CAL 1 + +/* Registers union */ +union rga_mode_ctrl { + unsigned int val; + struct { + /* [0:2] */ + unsigned int render:3; + /* [3:6] */ + unsigned int bitblt:1; + unsigned int cf_rop4_pat:1; + unsigned int alpha_zero_key:1; + unsigned int gradient_sat:1; + /* [7:31] */ + unsigned int reserved:25; + } data; +}; + +union rga_src_info { + unsigned int val; + struct { + /* [0:3] */ + unsigned int format:4; + /* [4:7] */ + unsigned int swap:3; + unsigned int cp_endian:1; + /* [8:17] */ + unsigned int csc_mode:2; + unsigned int rot_mode:2; + unsigned int mir_mode:2; + unsigned int hscl_mode:2; + unsigned int vscl_mode:2; + /* [18:22] */ + unsigned int trans_mode:1; + unsigned int trans_enable:4; + /* [23:25] */ + unsigned int dither_up_en:1; + unsigned int bic_coe_sel:2; + /* [26:31] */ + unsigned int reserved:6; + } data; +}; + +union rga_src_vir_info { + unsigned int val; + struct { + /* [0:15] */ + unsigned int vir_width:15; + unsigned int reserved:1; + /* [16:25] */ + unsigned int vir_stride:10; + /* [26:31] */ + unsigned int reserved1:6; + } data; +}; + +union rga_src_act_info { + unsigned int val; + struct { + /* [0:15] */ + unsigned int act_width:13; + unsigned int reserved:3; + /* [16:31] */ + unsigned int act_height:13; + unsigned int reserved1:3; + } data; +}; + +union rga_src_x_factor { + unsigned int val; + struct { + /* [0:15] */ + unsigned int down_scale_factor:16; + /* [16:31] */ + unsigned int up_scale_factor:16; + } data; +}; + +union rga_src_y_factor { + unsigned int val; + struct { + /* [0:15] */ + unsigned int down_scale_factor:16; + /* [16:31] */ + unsigned int up_scale_factor:16; + } data; +}; + +/* Alpha / Red / Green / Blue */ +union rga_src_cp_gr_color { + unsigned int val; + struct { + /* [0:15] */ + unsigned int gradient_x:16; + /* [16:31] */ + unsigned int gradient_y:16; + } data; +}; + +union rga_src_transparency_color0 { + unsigned int val; + struct { + /* [0:7] */ + unsigned int trans_rmin:8; + /* [8:15] */ + unsigned int trans_gmin:8; + /* [16:23] */ + unsigned int trans_bmin:8; + /* [24:31] */ + unsigned int trans_amin:8; + } data; +}; + +union rga_src_transparency_color1 { + unsigned int val; + struct { + /* [0:7] */ + unsigned int trans_rmax:8; + /* [8:15] */ + unsigned int trans_gmax:8; + /* [16:23] */ + unsigned int trans_bmax:8; + /* [24:31] */ + unsigned int trans_amax:8; + } data; +}; + +union rga_dst_info { + unsigned int val; + struct { + /* [0:3] */ + unsigned int format:4; + /* [4:6] */ + unsigned int swap:3; + /* [7:9] */ + unsigned int src1_format:3; + /* [10:11] */ + unsigned int src1_swap:2; + /* [12:15] */ + unsigned int dither_up_en:1; + unsigned int dither_down_en:1; + unsigned int dither_down_mode:2; + /* [16:18] */ + unsigned int csc_mode:2; + unsigned int csc_clip:1; + /* [19:31] */ + unsigned int reserved:13; + } data; +}; + +union rga_dst_vir_info { + unsigned int val; + struct { + /* [0:15] */ + unsigned int vir_stride:15; + unsigned int reserved:1; + /* [16:31] */ + unsigned int src1_vir_stride:15; + unsigned int reserved1:1; + } data; +}; + +union rga_dst_act_info { + unsigned int val; + struct { + /* [0:15] */ + unsigned int act_width:12; + unsigned int reserved:4; + /* [16:31] */ + unsigned int act_height:12; + unsigned int reserved1:4; + } data; +}; + +union rga_alpha_ctrl0 { + unsigned int val; + struct { + /* [0:3] */ + unsigned int rop_en:1; + unsigned int rop_select:1; + unsigned int rop_mode:2; + /* [4:11] */ + unsigned int src_fading_val:8; + /* [12:20] */ + unsigned int dst_fading_val:8; + unsigned int mask_endian:1; + /* [21:31] */ + unsigned int reserved:11; + } data; +}; + +union rga_alpha_ctrl1 { + unsigned int val; + struct { + /* [0:1] */ + unsigned int dst_color_m0:1; + unsigned int src_color_m0:1; + /* [2:7] */ + unsigned int dst_factor_m0:3; + unsigned int src_factor_m0:3; + /* [8:9] */ + unsigned int dst_alpha_cal_m0:1; + unsigned int src_alpha_cal_m0:1; + /* [10:13] */ + unsigned int dst_blend_m0:2; + unsigned int src_blend_m0:2; + /* [14:15] */ + unsigned int dst_alpha_m0:1; + unsigned int src_alpha_m0:1; + /* [16:21] */ + unsigned int dst_factor_m1:3; + unsigned int src_factor_m1:3; + /* [22:23] */ + unsigned int dst_alpha_cal_m1:1; + unsigned int src_alpha_cal_m1:1; + /* [24:27] */ + unsigned int dst_blend_m1:2; + unsigned int src_blend_m1:2; + /* [28:29] */ + unsigned int dst_alpha_m1:1; + unsigned int src_alpha_m1:1; + /* [30:31] */ + unsigned int reserved:2; + } data; +}; + +union rga_fading_ctrl { + unsigned int val; + struct { + /* [0:7] */ + unsigned int fading_offset_r:8; + /* [8:15] */ + unsigned int fading_offset_g:8; + /* [16:23] */ + unsigned int fading_offset_b:8; + /* [24:31] */ + unsigned int fading_en:1; + unsigned int reserved:7; + } data; +}; + +union rga_pat_con { + unsigned int val; + struct { + /* [0:7] */ + unsigned int width:8; + /* [8:15] */ + unsigned int height:8; + /* [16:23] */ + unsigned int offset_x:8; + /* [24:31] */ + unsigned int offset_y:8; + } data; +}; + +#endif diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c new file mode 100644 index 000000000000..2cf3bb29a2b3 --- /dev/null +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -0,0 +1,1012 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Jacob Chen + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "rga-hw.h" +#include "rga.h" + +static int debug; +module_param(debug, int, 0644); + +static void job_abort(void *prv) +{ + struct rga_ctx *ctx = prv; + struct rockchip_rga *rga = ctx->rga; + + if (!rga->curr) /* No job currently running */ + return; + + wait_event_timeout(rga->irq_queue, + !rga->curr, msecs_to_jiffies(RGA_TIMEOUT)); +} + +static void device_run(void *prv) +{ + struct rga_ctx *ctx = prv; + struct rockchip_rga *rga = ctx->rga; + struct vb2_buffer *src, *dst; + unsigned long flags; + + spin_lock_irqsave(&rga->ctrl_lock, flags); + + rga->curr = ctx; + + src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + rga_buf_map(src); + rga_buf_map(dst); + + rga_hw_start(rga); + + spin_unlock_irqrestore(&rga->ctrl_lock, flags); +} + +static irqreturn_t rga_isr(int irq, void *prv) +{ + struct rockchip_rga *rga = prv; + int intr; + + intr = rga_read(rga, RGA_INT) & 0xf; + + rga_mod(rga, RGA_INT, intr << 4, 0xf << 4); + + if (intr & 0x04) { + struct vb2_v4l2_buffer *src, *dst; + struct rga_ctx *ctx = rga->curr; + + WARN_ON(!ctx); + + rga->curr = NULL; + + src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + WARN_ON(!src); + WARN_ON(!dst); + + dst->timecode = src->timecode; + dst->vb2_buf.timestamp = src->vb2_buf.timestamp; + dst->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + dst->flags |= src->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + + v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE); + v4l2_m2m_job_finish(rga->m2m_dev, ctx->fh.m2m_ctx); + + wake_up(&rga->irq_queue); + } + + return IRQ_HANDLED; +} + +static struct v4l2_m2m_ops rga_m2m_ops = { + .device_run = device_run, + .job_abort = job_abort, +}; + +static int +queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) +{ + struct rga_ctx *ctx = priv; + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->ops = &rga_qops; + src_vq->mem_ops = &vb2_dma_sg_memops; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &ctx->rga->mutex; + src_vq->dev = ctx->rga->v4l2_dev.dev; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->ops = &rga_qops; + dst_vq->mem_ops = &vb2_dma_sg_memops; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &ctx->rga->mutex; + dst_vq->dev = ctx->rga->v4l2_dev.dev; + + return vb2_queue_init(dst_vq); +} + +static int rga_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct rga_ctx *ctx = container_of(ctrl->handler, struct rga_ctx, + ctrl_handler); + unsigned long flags; + + spin_lock_irqsave(&ctx->rga->ctrl_lock, flags); + switch (ctrl->id) { + case V4L2_CID_HFLIP: + ctx->hflip = ctrl->val; + break; + case V4L2_CID_VFLIP: + ctx->vflip = ctrl->val; + break; + case V4L2_CID_ROTATE: + ctx->rotate = ctrl->val; + break; + case V4L2_CID_BG_COLOR: + ctx->fill_color = ctrl->val; + break; + } + spin_unlock_irqrestore(&ctx->rga->ctrl_lock, flags); + return 0; +} + +static const struct v4l2_ctrl_ops rga_ctrl_ops = { + .s_ctrl = rga_s_ctrl, +}; + +static int rga_setup_ctrls(struct rga_ctx *ctx) +{ + struct rockchip_rga *rga = ctx->rga; + + v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4); + + v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + + v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops, + V4L2_CID_ROTATE, 0, 270, 90, 0); + + v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops, + V4L2_CID_BG_COLOR, 0, 0xffffffff, 1, 0); + + if (ctx->ctrl_handler.error) { + int err = ctx->ctrl_handler.error; + + v4l2_err(&rga->v4l2_dev, "%s failed\n", __func__); + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + return err; + } + + return 0; +} + +struct rga_fmt formats[] = { + { + .fourcc = V4L2_PIX_FMT_ARGB32, + .color_swap = RGA_COLOR_RB_SWAP, + .hw_format = RGA_COLOR_FMT_ABGR8888, + .depth = 32, + .uv_factor = 1, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_XRGB32, + .color_swap = RGA_COLOR_RB_SWAP, + .hw_format = RGA_COLOR_FMT_XBGR8888, + .depth = 32, + .uv_factor = 1, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_ABGR32, + .color_swap = RGA_COLOR_ALPHA_SWAP, + .hw_format = RGA_COLOR_FMT_ABGR8888, + .depth = 32, + .uv_factor = 1, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_XBGR32, + .color_swap = RGA_COLOR_ALPHA_SWAP, + .hw_format = RGA_COLOR_FMT_XBGR8888, + .depth = 32, + .uv_factor = 1, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_RGB24, + .color_swap = RGA_COLOR_NONE_SWAP, + .hw_format = RGA_COLOR_FMT_RGB888, + .depth = 24, + .uv_factor = 1, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_BGR24, + .color_swap = RGA_COLOR_RB_SWAP, + .hw_format = RGA_COLOR_FMT_RGB888, + .depth = 24, + .uv_factor = 1, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB444, + .color_swap = RGA_COLOR_RB_SWAP, + .hw_format = RGA_COLOR_FMT_ABGR4444, + .depth = 16, + .uv_factor = 1, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB555, + .color_swap = RGA_COLOR_RB_SWAP, + .hw_format = RGA_COLOR_FMT_ABGR1555, + .depth = 16, + .uv_factor = 1, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_RGB565, + .color_swap = RGA_COLOR_RB_SWAP, + .hw_format = RGA_COLOR_FMT_BGR565, + .depth = 16, + .uv_factor = 1, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_NV21, + .color_swap = RGA_COLOR_UV_SWAP, + .hw_format = RGA_COLOR_FMT_YUV420SP, + .depth = 12, + .uv_factor = 4, + .y_div = 2, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_NV61, + .color_swap = RGA_COLOR_UV_SWAP, + .hw_format = RGA_COLOR_FMT_YUV422SP, + .depth = 16, + .uv_factor = 2, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_NV12, + .color_swap = RGA_COLOR_NONE_SWAP, + .hw_format = RGA_COLOR_FMT_YUV420SP, + .depth = 12, + .uv_factor = 4, + .y_div = 2, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_NV16, + .color_swap = RGA_COLOR_NONE_SWAP, + .hw_format = RGA_COLOR_FMT_YUV422SP, + .depth = 16, + .uv_factor = 2, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_YUV420, + .color_swap = RGA_COLOR_NONE_SWAP, + .hw_format = RGA_COLOR_FMT_YUV420P, + .depth = 12, + .uv_factor = 4, + .y_div = 2, + .x_div = 2, + }, + { + .fourcc = V4L2_PIX_FMT_YUV422P, + .color_swap = RGA_COLOR_NONE_SWAP, + .hw_format = RGA_COLOR_FMT_YUV422P, + .depth = 16, + .uv_factor = 2, + .y_div = 1, + .x_div = 2, + }, + { + .fourcc = V4L2_PIX_FMT_YVU420, + .color_swap = RGA_COLOR_UV_SWAP, + .hw_format = RGA_COLOR_FMT_YUV420P, + .depth = 12, + .uv_factor = 4, + .y_div = 2, + .x_div = 2, + }, +}; + +#define NUM_FORMATS ARRAY_SIZE(formats) + +struct rga_fmt *rga_fmt_find(struct v4l2_format *f) +{ + unsigned int i; + + for (i = 0; i < NUM_FORMATS; i++) { + if (formats[i].fourcc == f->fmt.pix.pixelformat) + return &formats[i]; + } + return NULL; +} + +static struct rga_frame def_frame = { + .width = DEFAULT_WIDTH, + .height = DEFAULT_HEIGHT, + .colorspace = V4L2_COLORSPACE_DEFAULT, + .crop.left = 0, + .crop.top = 0, + .crop.width = DEFAULT_WIDTH, + .crop.height = DEFAULT_HEIGHT, + .fmt = &formats[0], +}; + +struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return &ctx->in; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &ctx->out; + default: + return ERR_PTR(-EINVAL); + } +} + +static int rga_open(struct file *file) +{ + struct rockchip_rga *rga = video_drvdata(file); + struct rga_ctx *ctx = NULL; + int ret = 0; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + ctx->rga = rga; + /* Set default formats */ + ctx->in = def_frame; + ctx->out = def_frame; + + if (mutex_lock_interruptible(&rga->mutex)) { + kfree(ctx); + return -ERESTARTSYS; + } + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(rga->m2m_dev, ctx, &queue_init); + if (IS_ERR(ctx->fh.m2m_ctx)) { + ret = PTR_ERR(ctx->fh.m2m_ctx); + mutex_unlock(&rga->mutex); + kfree(ctx); + return ret; + } + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + + rga_setup_ctrls(ctx); + + /* Write the default values to the ctx struct */ + v4l2_ctrl_handler_setup(&ctx->ctrl_handler); + + ctx->fh.ctrl_handler = &ctx->ctrl_handler; + mutex_unlock(&rga->mutex); + + return 0; +} + +static int rga_release(struct file *file) +{ + struct rga_ctx *ctx = + container_of(file->private_data, struct rga_ctx, fh); + struct rockchip_rga *rga = ctx->rga; + + mutex_lock(&rga->mutex); + + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); + + mutex_unlock(&rga->mutex); + + return 0; +} + +static const struct v4l2_file_operations rga_fops = { + .owner = THIS_MODULE, + .open = rga_open, + .release = rga_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static int +vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) +{ + strlcpy(cap->driver, RGA_NAME, sizeof(cap->driver)); + strlcpy(cap->card, "rockchip-rga", sizeof(cap->card)); + strlcpy(cap->bus_info, "platform:rga", sizeof(cap->bus_info)); + + return 0; +} + +static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) +{ + struct rga_fmt *fmt; + + if (f->index >= NUM_FORMATS) + return -EINVAL; + + fmt = &formats[f->index]; + f->pixelformat = fmt->fourcc; + + return 0; +} + +static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) +{ + struct rga_ctx *ctx = prv; + struct vb2_queue *vq; + struct rga_frame *frm; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (!vq) + return -EINVAL; + frm = rga_get_frame(ctx, f->type); + if (IS_ERR(frm)) + return PTR_ERR(frm); + + f->fmt.pix.width = frm->width; + f->fmt.pix.height = frm->height; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.pixelformat = frm->fmt->fourcc; + f->fmt.pix.bytesperline = frm->stride; + f->fmt.pix.sizeimage = frm->size; + f->fmt.pix.colorspace = frm->colorspace; + + return 0; +} + +static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) +{ + struct rga_fmt *fmt; + + fmt = rga_fmt_find(f); + if (!fmt) { + fmt = &formats[0]; + f->fmt.pix.pixelformat = fmt->fourcc; + } + + f->fmt.pix.field = V4L2_FIELD_NONE; + + if (f->fmt.pix.width > MAX_WIDTH) + f->fmt.pix.width = MAX_WIDTH; + if (f->fmt.pix.height > MAX_HEIGHT) + f->fmt.pix.height = MAX_HEIGHT; + + if (f->fmt.pix.width < MIN_WIDTH) + f->fmt.pix.width = MIN_WIDTH; + if (f->fmt.pix.height < MIN_HEIGHT) + f->fmt.pix.height = MIN_HEIGHT; + + if (fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) + f->fmt.pix.bytesperline = f->fmt.pix.width; + else + f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; + + f->fmt.pix.sizeimage = + f->fmt.pix.height * (f->fmt.pix.width * fmt->depth) >> 3; + + return 0; +} + +static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) +{ + struct rga_ctx *ctx = prv; + struct rockchip_rga *rga = ctx->rga; + struct vb2_queue *vq; + struct rga_frame *frm; + struct rga_fmt *fmt; + int ret = 0; + + /* Adjust all values accordingly to the hardware capabilities + * and chosen format. + */ + ret = vidioc_try_fmt(file, prv, f); + if (ret) + return ret; + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (vb2_is_busy(vq)) { + v4l2_err(&rga->v4l2_dev, "queue (%d) bust\n", f->type); + return -EBUSY; + } + frm = rga_get_frame(ctx, f->type); + if (IS_ERR(frm)) + return PTR_ERR(frm); + fmt = rga_fmt_find(f); + if (!fmt) + return -EINVAL; + frm->width = f->fmt.pix.width; + frm->height = f->fmt.pix.height; + frm->size = f->fmt.pix.sizeimage; + frm->fmt = fmt; + frm->stride = f->fmt.pix.bytesperline; + frm->colorspace = f->fmt.pix.colorspace; + + /* Reset crop settings */ + frm->crop.left = 0; + frm->crop.top = 0; + frm->crop.width = frm->width; + frm->crop.height = frm->height; + + return 0; +} + +static int vidioc_g_selection(struct file *file, void *prv, + struct v4l2_selection *s) +{ + struct rga_ctx *ctx = prv; + struct rga_frame *f; + bool use_frame = false; + + f = rga_get_frame(ctx, s->type); + if (IS_ERR(f)) + return PTR_ERR(f); + + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + break; + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + break; + case V4L2_SEL_TGT_COMPOSE: + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + use_frame = true; + break; + case V4L2_SEL_TGT_CROP: + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + use_frame = true; + break; + default: + return -EINVAL; + } + + if (use_frame) { + s->r = f->crop; + } else { + s->r.left = 0; + s->r.top = 0; + s->r.width = f->width; + s->r.height = f->height; + } + + return 0; +} + +static int vidioc_s_selection(struct file *file, void *prv, + struct v4l2_selection *s) +{ + struct rga_ctx *ctx = prv; + struct rockchip_rga *rga = ctx->rga; + struct rga_frame *f; + int ret = 0; + + f = rga_get_frame(ctx, s->type); + if (IS_ERR(f)) + return PTR_ERR(f); + + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE: + /* + * COMPOSE target is only valid for capture buffer type, return + * error for output buffer type + */ + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + break; + case V4L2_SEL_TGT_CROP: + /* + * CROP target is only valid for output buffer type, return + * error for capture buffer type + */ + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + break; + /* + * bound and default crop/compose targets are invalid targets to + * try/set + */ + default: + return -EINVAL; + } + + if (s->r.top < 0 || s->r.left < 0) { + v4l2_dbg(debug, 1, &rga->v4l2_dev, + "doesn't support negative values for top & left.\n"); + return -EINVAL; + } + + if (s->r.left + s->r.width > f->width || + s->r.top + s->r.height > f->height || + s->r.width < MIN_WIDTH || s->r.height < MIN_HEIGHT) { + v4l2_dbg(debug, 1, &rga->v4l2_dev, "unsupported crop value.\n"); + return -EINVAL; + } + + f->crop = s->r; + + return ret; +} + +static const struct v4l2_ioctl_ops rga_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt, + + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt, + .vidioc_g_fmt_vid_out = vidioc_g_fmt, + .vidioc_try_fmt_vid_out = vidioc_try_fmt, + .vidioc_s_fmt_vid_out = vidioc_s_fmt, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_g_selection = vidioc_g_selection, + .vidioc_s_selection = vidioc_s_selection, +}; + +static struct video_device rga_videodev = { + .name = "rockchip-rga", + .fops = &rga_fops, + .ioctl_ops = &rga_ioctl_ops, + .minor = -1, + .release = video_device_release, + .vfl_dir = VFL_DIR_M2M, + .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, +}; + +static int rga_enable_clocks(struct rockchip_rga *rga) +{ + int ret; + + ret = clk_prepare_enable(rga->sclk); + if (ret) { + dev_err(rga->dev, "Cannot enable rga sclk: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(rga->aclk); + if (ret) { + dev_err(rga->dev, "Cannot enable rga aclk: %d\n", ret); + goto err_disable_sclk; + } + + ret = clk_prepare_enable(rga->hclk); + if (ret) { + dev_err(rga->dev, "Cannot enable rga hclk: %d\n", ret); + goto err_disable_aclk; + } + + return 0; + +err_disable_sclk: + clk_disable_unprepare(rga->sclk); +err_disable_aclk: + clk_disable_unprepare(rga->aclk); + + return ret; +} + +static void rga_disable_clocks(struct rockchip_rga *rga) +{ + clk_disable_unprepare(rga->sclk); + clk_disable_unprepare(rga->hclk); + clk_disable_unprepare(rga->aclk); +} + +static int rga_parse_dt(struct rockchip_rga *rga) +{ + struct reset_control *core_rst, *axi_rst, *ahb_rst; + + core_rst = devm_reset_control_get(rga->dev, "core"); + if (IS_ERR(core_rst)) { + dev_err(rga->dev, "failed to get core reset controller\n"); + return PTR_ERR(core_rst); + } + + axi_rst = devm_reset_control_get(rga->dev, "axi"); + if (IS_ERR(axi_rst)) { + dev_err(rga->dev, "failed to get axi reset controller\n"); + return PTR_ERR(axi_rst); + } + + ahb_rst = devm_reset_control_get(rga->dev, "ahb"); + if (IS_ERR(ahb_rst)) { + dev_err(rga->dev, "failed to get ahb reset controller\n"); + return PTR_ERR(ahb_rst); + } + + reset_control_assert(core_rst); + udelay(1); + reset_control_deassert(core_rst); + + reset_control_assert(axi_rst); + udelay(1); + reset_control_deassert(axi_rst); + + reset_control_assert(ahb_rst); + udelay(1); + reset_control_deassert(ahb_rst); + + rga->sclk = devm_clk_get(rga->dev, "sclk"); + if (IS_ERR(rga->sclk)) { + dev_err(rga->dev, "failed to get sclk clock\n"); + return PTR_ERR(rga->sclk); + } + + rga->aclk = devm_clk_get(rga->dev, "aclk"); + if (IS_ERR(rga->aclk)) { + dev_err(rga->dev, "failed to get aclk clock\n"); + return PTR_ERR(rga->aclk); + } + + rga->hclk = devm_clk_get(rga->dev, "hclk"); + if (IS_ERR(rga->hclk)) { + dev_err(rga->dev, "failed to get hclk clock\n"); + return PTR_ERR(rga->hclk); + } + + return 0; +} + +static int rga_probe(struct platform_device *pdev) +{ + struct rockchip_rga *rga; + struct video_device *vfd; + struct resource *res; + int ret = 0; + int irq; + + if (!pdev->dev.of_node) + return -ENODEV; + + rga = devm_kzalloc(&pdev->dev, sizeof(*rga), GFP_KERNEL); + if (!rga) + return -ENOMEM; + + rga->dev = &pdev->dev; + spin_lock_init(&rga->ctrl_lock); + mutex_init(&rga->mutex); + + init_waitqueue_head(&rga->irq_queue); + + ret = rga_parse_dt(rga); + if (ret) + dev_err(&pdev->dev, "Unable to parse OF data\n"); + + pm_runtime_enable(rga->dev); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + rga->regs = devm_ioremap_resource(rga->dev, res); + if (IS_ERR(rga->regs)) { + ret = PTR_ERR(rga->regs); + goto err_put_clk; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(rga->dev, "failed to get irq\n"); + ret = irq; + goto err_put_clk; + } + + ret = devm_request_irq(rga->dev, irq, rga_isr, 0, + dev_name(rga->dev), rga); + if (ret < 0) { + dev_err(rga->dev, "failed to request irq\n"); + goto err_put_clk; + } + + ret = v4l2_device_register(&pdev->dev, &rga->v4l2_dev); + if (ret) + goto err_put_clk; + vfd = video_device_alloc(); + if (!vfd) { + v4l2_err(&rga->v4l2_dev, "Failed to allocate video device\n"); + ret = -ENOMEM; + goto unreg_v4l2_dev; + } + *vfd = rga_videodev; + vfd->lock = &rga->mutex; + vfd->v4l2_dev = &rga->v4l2_dev; + + video_set_drvdata(vfd, rga); + snprintf(vfd->name, sizeof(vfd->name), "%s", rga_videodev.name); + rga->vfd = vfd; + + platform_set_drvdata(pdev, rga); + rga->m2m_dev = v4l2_m2m_init(&rga_m2m_ops); + if (IS_ERR(rga->m2m_dev)) { + v4l2_err(&rga->v4l2_dev, "Failed to init mem2mem device\n"); + ret = PTR_ERR(rga->m2m_dev); + goto unreg_video_dev; + } + + pm_runtime_get_sync(rga->dev); + + rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF; + rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F; + + v4l2_info(&rga->v4l2_dev, "HW Version: 0x%02x.%02x\n", + rga->version.major, rga->version.minor); + + pm_runtime_put(rga->dev); + + /* Create CMD buffer */ + rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, RGA_CMDBUF_SIZE, + &rga->cmdbuf_phy, GFP_KERNEL, + DMA_ATTR_WRITE_COMBINE); + + rga->src_mmu_pages = + (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3); + rga->dst_mmu_pages = + (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3); + + def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3; + def_frame.size = def_frame.stride * def_frame.height; + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); + if (ret) { + v4l2_err(&rga->v4l2_dev, "Failed to register video device\n"); + goto rel_vdev; + } + + v4l2_info(&rga->v4l2_dev, "Registered %s as /dev/%s\n", + vfd->name, video_device_node_name(vfd)); + + return 0; + +rel_vdev: + video_device_release(vfd); +unreg_video_dev: + video_unregister_device(rga->vfd); +unreg_v4l2_dev: + v4l2_device_unregister(&rga->v4l2_dev); +err_put_clk: + pm_runtime_disable(rga->dev); + + return ret; +} + +static int rga_remove(struct platform_device *pdev) +{ + struct rockchip_rga *rga = platform_get_drvdata(pdev); + + dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, &rga->cmdbuf_virt, + rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE); + + free_pages((unsigned long)rga->src_mmu_pages, 3); + free_pages((unsigned long)rga->dst_mmu_pages, 3); + + v4l2_info(&rga->v4l2_dev, "Removing\n"); + + v4l2_m2m_release(rga->m2m_dev); + video_unregister_device(rga->vfd); + v4l2_device_unregister(&rga->v4l2_dev); + + pm_runtime_disable(rga->dev); + + return 0; +} + +#ifdef CONFIG_PM +static int rga_runtime_suspend(struct device *dev) +{ + struct rockchip_rga *rga = dev_get_drvdata(dev); + + rga_disable_clocks(rga); + + return 0; +} + +static int rga_runtime_resume(struct device *dev) +{ + struct rockchip_rga *rga = dev_get_drvdata(dev); + + return rga_enable_clocks(rga); +} +#endif + +static const struct dev_pm_ops rga_pm = { + SET_RUNTIME_PM_OPS(rga_runtime_suspend, + rga_runtime_resume, NULL) +}; + +static const struct of_device_id rockchip_rga_match[] = { + { + .compatible = "rockchip,rk3288-rga", + }, + { + .compatible = "rockchip,rk3399-rga", + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, rockchip_rga_match); + +static struct platform_driver rga_pdrv = { + .probe = rga_probe, + .remove = rga_remove, + .driver = { + .name = RGA_NAME, + .pm = &rga_pm, + .of_match_table = rockchip_rga_match, + }, +}; + +module_platform_driver(rga_pdrv); + +MODULE_AUTHOR("Jacob Chen "); +MODULE_DESCRIPTION("Rockchip Raster 2d Graphic Acceleration Unit"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h new file mode 100644 index 000000000000..5d43e7ea88af --- /dev/null +++ b/drivers/media/platform/rockchip/rga/rga.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Jacob Chen + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __RGA_H__ +#define __RGA_H__ + +#include +#include +#include +#include + +#define RGA_NAME "rockchip-rga" + +struct rga_fmt { + u32 fourcc; + int depth; + u8 uv_factor; + u8 y_div; + u8 x_div; + u8 color_swap; + u8 hw_format; +}; + +struct rga_frame { + /* Original dimensions */ + u32 width; + u32 height; + u32 colorspace; + + /* Crop */ + struct v4l2_rect crop; + + /* Image format */ + struct rga_fmt *fmt; + + /* Variables that can calculated once and reused */ + u32 stride; + u32 size; +}; + +struct rockchip_rga_version { + u32 major; + u32 minor; +}; + +struct rga_ctx { + struct v4l2_fh fh; + struct rockchip_rga *rga; + struct rga_frame in; + struct rga_frame out; + struct v4l2_ctrl_handler ctrl_handler; + + /* Control values */ + u32 op; + u32 hflip; + u32 vflip; + u32 rotate; + u32 fill_color; +}; + +struct rockchip_rga { + struct v4l2_device v4l2_dev; + struct v4l2_m2m_dev *m2m_dev; + struct video_device *vfd; + + struct device *dev; + struct regmap *grf; + void __iomem *regs; + struct clk *sclk; + struct clk *aclk; + struct clk *hclk; + struct rockchip_rga_version version; + + /* vfd lock */ + struct mutex mutex; + /* ctrl parm lock */ + spinlock_t ctrl_lock; + + wait_queue_head_t irq_queue; + + struct rga_ctx *curr; + dma_addr_t cmdbuf_phy; + void *cmdbuf_virt; + unsigned int *src_mmu_pages; + unsigned int *dst_mmu_pages; +}; + +struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type); + +/* RGA Buffers Manage */ +extern const struct vb2_ops rga_qops; +void rga_buf_map(struct vb2_buffer *vb); + +/* RGA Hardware */ +static inline void rga_write(struct rockchip_rga *rga, u32 reg, u32 value) +{ + writel(value, rga->regs + reg); +}; + +static inline u32 rga_read(struct rockchip_rga *rga, u32 reg) +{ + return readl(rga->regs + reg); +}; + +static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask) +{ + u32 temp = rga_read(rga, reg) & ~(mask); + + temp |= val & mask; + rga_write(rga, reg, temp); +}; + +void rga_hw_start(struct rockchip_rga *rga); + +#endif -- cgit v1.2.3 From ec8df85f312e299e6d92f7cc3446e67e510ccafb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 16 Oct 2017 16:26:04 -0700 Subject: media: rga: make some functions static drivers/media/platform/rockchip/rga/rga-hw.c:383:6: warning: no previous prototype for 'rga_cmd_set' [-Wmissing-prototypes] void rga_cmd_set(struct rga_ctx *ctx) ^~~~~~~~~~~ drivers/media/platform/rockchip/rga/rga.c:359:17: warning: no previous prototype for 'rga_fmt_find' [-Wmissing-prototypes] struct rga_fmt *rga_fmt_find(struct v4l2_format *f) ^~~~~~~~~~~~ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rga/rga-hw.c | 2 +- drivers/media/platform/rockchip/rga/rga.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c index 0645481c9a5e..96d1b1b3fe8e 100644 --- a/drivers/media/platform/rockchip/rga/rga-hw.c +++ b/drivers/media/platform/rockchip/rga/rga-hw.c @@ -380,7 +380,7 @@ static void rga_cmd_set_mode(struct rga_ctx *ctx) dest[(RGA_MODE_CTRL - RGA_MODE_BASE_REG) >> 2] = mode.val; } -void rga_cmd_set(struct rga_ctx *ctx) +static void rga_cmd_set(struct rga_ctx *ctx) { struct rockchip_rga *rga = ctx->rga; diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 2cf3bb29a2b3..e7d1b34baf1c 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -356,7 +356,7 @@ struct rga_fmt formats[] = { #define NUM_FORMATS ARRAY_SIZE(formats) -struct rga_fmt *rga_fmt_find(struct v4l2_format *f) +static struct rga_fmt *rga_fmt_find(struct v4l2_format *f) { unsigned int i; -- cgit v1.2.3 From a2640560a0e006d037918522f5f33d0aa800680c Mon Sep 17 00:00:00 2001 From: Hoegeun Kwon Date: Wed, 13 Sep 2017 04:41:55 -0700 Subject: media: exynos-gsc: Add hardware rotation limits The hardware rotation limits of gsc depends on SOC (Exynos 5250/5420/5433). Distinguish them and add them to the driver data. [s.nawrocki@samsung.com: corrected num_entities in 5420 variant data] Signed-off-by: Hoegeun Kwon Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 127 +++++++++++++++++++++++++-- 1 file changed, 122 insertions(+), 5 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 43801509dabb..17854a379243 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -958,6 +958,51 @@ static struct gsc_pix_max gsc_v_100_max = { .target_rot_en_h = 2016, }; +static struct gsc_pix_max gsc_v_5250_max = { + .org_scaler_bypass_w = 8192, + .org_scaler_bypass_h = 8192, + .org_scaler_input_w = 4800, + .org_scaler_input_h = 3344, + .real_rot_dis_w = 4800, + .real_rot_dis_h = 3344, + .real_rot_en_w = 2016, + .real_rot_en_h = 2016, + .target_rot_dis_w = 4800, + .target_rot_dis_h = 3344, + .target_rot_en_w = 2016, + .target_rot_en_h = 2016, +}; + +static struct gsc_pix_max gsc_v_5420_max = { + .org_scaler_bypass_w = 8192, + .org_scaler_bypass_h = 8192, + .org_scaler_input_w = 4800, + .org_scaler_input_h = 3344, + .real_rot_dis_w = 4800, + .real_rot_dis_h = 3344, + .real_rot_en_w = 2048, + .real_rot_en_h = 2048, + .target_rot_dis_w = 4800, + .target_rot_dis_h = 3344, + .target_rot_en_w = 2016, + .target_rot_en_h = 2016, +}; + +static struct gsc_pix_max gsc_v_5433_max = { + .org_scaler_bypass_w = 8192, + .org_scaler_bypass_h = 8192, + .org_scaler_input_w = 4800, + .org_scaler_input_h = 3344, + .real_rot_dis_w = 4800, + .real_rot_dis_h = 3344, + .real_rot_en_w = 2047, + .real_rot_en_h = 2047, + .target_rot_dis_w = 4800, + .target_rot_dis_h = 3344, + .target_rot_en_w = 2016, + .target_rot_en_h = 2016, +}; + static struct gsc_pix_min gsc_v_100_min = { .org_w = 64, .org_h = 32, @@ -992,6 +1037,45 @@ static struct gsc_variant gsc_v_100_variant = { .local_sc_down = 2, }; +static struct gsc_variant gsc_v_5250_variant = { + .pix_max = &gsc_v_5250_max, + .pix_min = &gsc_v_100_min, + .pix_align = &gsc_v_100_align, + .in_buf_cnt = 32, + .out_buf_cnt = 32, + .sc_up_max = 8, + .sc_down_max = 16, + .poly_sc_down_max = 4, + .pre_sc_down_max = 4, + .local_sc_down = 2, +}; + +static struct gsc_variant gsc_v_5420_variant = { + .pix_max = &gsc_v_5420_max, + .pix_min = &gsc_v_100_min, + .pix_align = &gsc_v_100_align, + .in_buf_cnt = 32, + .out_buf_cnt = 32, + .sc_up_max = 8, + .sc_down_max = 16, + .poly_sc_down_max = 4, + .pre_sc_down_max = 4, + .local_sc_down = 2, +}; + +static struct gsc_variant gsc_v_5433_variant = { + .pix_max = &gsc_v_5433_max, + .pix_min = &gsc_v_100_min, + .pix_align = &gsc_v_100_align, + .in_buf_cnt = 32, + .out_buf_cnt = 32, + .sc_up_max = 8, + .sc_down_max = 16, + .poly_sc_down_max = 4, + .pre_sc_down_max = 4, + .local_sc_down = 2, +}; + static struct gsc_driverdata gsc_v_100_drvdata = { .variant = { [0] = &gsc_v_100_variant, @@ -1004,11 +1088,33 @@ static struct gsc_driverdata gsc_v_100_drvdata = { .num_clocks = 1, }; +static struct gsc_driverdata gsc_v_5250_drvdata = { + .variant = { + [0] = &gsc_v_5250_variant, + [1] = &gsc_v_5250_variant, + [2] = &gsc_v_5250_variant, + [3] = &gsc_v_5250_variant, + }, + .num_entities = 4, + .clk_names = { "gscl" }, + .num_clocks = 1, +}; + +static struct gsc_driverdata gsc_v_5420_drvdata = { + .variant = { + [0] = &gsc_v_5420_variant, + [1] = &gsc_v_5420_variant, + }, + .num_entities = 2, + .clk_names = { "gscl" }, + .num_clocks = 1, +}; + static struct gsc_driverdata gsc_5433_drvdata = { .variant = { - [0] = &gsc_v_100_variant, - [1] = &gsc_v_100_variant, - [2] = &gsc_v_100_variant, + [0] = &gsc_v_5433_variant, + [1] = &gsc_v_5433_variant, + [2] = &gsc_v_5433_variant, }, .num_entities = 3, .clk_names = { "pclk", "aclk", "aclk_xiu", "aclk_gsclbend" }, @@ -1017,13 +1123,21 @@ static struct gsc_driverdata gsc_5433_drvdata = { static const struct of_device_id exynos_gsc_match[] = { { - .compatible = "samsung,exynos5-gsc", - .data = &gsc_v_100_drvdata, + .compatible = "samsung,exynos5250-gsc", + .data = &gsc_v_5250_drvdata, + }, + { + .compatible = "samsung,exynos5420-gsc", + .data = &gsc_v_5420_drvdata, }, { .compatible = "samsung,exynos5433-gsc", .data = &gsc_5433_drvdata, }, + { + .compatible = "samsung,exynos5-gsc", + .data = &gsc_v_100_drvdata, + }, {}, }; MODULE_DEVICE_TABLE(of, exynos_gsc_match); @@ -1045,6 +1159,9 @@ static int gsc_probe(struct platform_device *pdev) if (ret < 0) return ret; + if (drv_data == &gsc_v_100_drvdata) + dev_info(dev, "compatible 'exynos5-gsc' is deprecated\n"); + gsc->id = ret; if (gsc->id >= drv_data->num_entities) { dev_err(dev, "Invalid platform device id: %d\n", gsc->id); -- cgit v1.2.3 From f6cd32328965232ab1af4fd768999e6a0e351b81 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 8 Sep 2017 13:25:17 -0700 Subject: media: s5p-mfc: Delete an error message for a failed memory allocation Omit an extra message for a memory allocation failure in s5p_mfc_probe() function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 1afde5021ca6..8af45d53846f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1270,10 +1270,8 @@ static int s5p_mfc_probe(struct platform_device *pdev) pr_debug("%s++\n", __func__); dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&pdev->dev, "Not enough memory for MFC device\n"); + if (!dev) return -ENOMEM; - } spin_lock_init(&dev->irqlock); spin_lock_init(&dev->condlock); -- cgit v1.2.3 From d7f15bde0f25ee8a5ea3aad96522ba851a47a0b0 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 8 Sep 2017 13:30:09 -0700 Subject: media: s5p-mfc: Improve a size determination in s5p_mfc_alloc_memdev() Replace the specification of a data structure by a pointer dereference as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 8af45d53846f..abfb70b07032 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1083,7 +1083,7 @@ static struct device *s5p_mfc_alloc_memdev(struct device *dev, struct device *child; int ret; - child = devm_kzalloc(dev, sizeof(struct device), GFP_KERNEL); + child = devm_kzalloc(dev, sizeof(*child), GFP_KERNEL); if (!child) return NULL; -- cgit v1.2.3 From 4449dd0a397536d12c52b599353341135d44b6d0 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 8 Sep 2017 13:37:00 -0700 Subject: media: s5p-mfc: Adjust a null pointer check in four functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The script “checkpatch.pl” pointed information out like the following. Comparison to NULL could be written... Thus fix the affected source code places. Signed-off-by: Markus Elfring Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index abfb70b07032..cf68aed59e0d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -470,7 +470,7 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev, { mfc_err("Interrupt Error: %08x\n", err); - if (ctx != NULL) { + if (ctx) { /* Error recovery is dependent on the state of context */ switch (ctx->state) { case MFCINST_RES_CHANGE_INIT: @@ -508,7 +508,7 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, { struct s5p_mfc_dev *dev; - if (ctx == NULL) + if (!ctx) return; dev = ctx->dev; if (ctx->c_ops->post_seq_start) { @@ -562,7 +562,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *src_buf; struct s5p_mfc_dev *dev; - if (ctx == NULL) + if (!ctx) return; dev = ctx->dev; s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); @@ -1289,7 +1289,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) return PTR_ERR(dev->regs_base); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res == NULL) { + if (!res) { dev_err(&pdev->dev, "failed to get irq resource\n"); return -ENOENT; } -- cgit v1.2.3 From cd1a77e3c9cc6dbb57f02aa50e1740fc144d2dad Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Mon, 9 Oct 2017 14:24:57 +0200 Subject: media: venus: fix wrong size on dma_free This change will fix an issue with dma_free size found with DMA API debug enabled. Signed-off-by: Stanimir Varbanov Signed-off-by: Hans Verkuil Cc: # for v4.13 and up Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/hfi_venus.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c index 1caae8feaa36..734ce11b0ed0 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus.c +++ b/drivers/media/platform/qcom/venus/hfi_venus.c @@ -344,7 +344,7 @@ static int venus_alloc(struct venus_hfi_device *hdev, struct mem_desc *desc, desc->attrs = DMA_ATTR_WRITE_COMBINE; desc->size = ALIGN(size, SZ_4K); - desc->kva = dma_alloc_attrs(dev, size, &desc->da, GFP_KERNEL, + desc->kva = dma_alloc_attrs(dev, desc->size, &desc->da, GFP_KERNEL, desc->attrs); if (!desc->kva) return -ENOMEM; @@ -710,10 +710,8 @@ static int venus_interface_queues_init(struct venus_hfi_device *hdev) if (ret) return ret; - hdev->ifaceq_table.kva = desc.kva; - hdev->ifaceq_table.da = desc.da; - hdev->ifaceq_table.size = IFACEQ_TABLE_SIZE; - offset = hdev->ifaceq_table.size; + hdev->ifaceq_table = desc; + offset = IFACEQ_TABLE_SIZE; for (i = 0; i < IFACEQ_NUM; i++) { queue = &hdev->queues[i]; @@ -755,9 +753,7 @@ static int venus_interface_queues_init(struct venus_hfi_device *hdev) if (ret) { hdev->sfr.da = 0; } else { - hdev->sfr.da = desc.da; - hdev->sfr.kva = desc.kva; - hdev->sfr.size = ALIGNED_SFR_SIZE; + hdev->sfr = desc; sfr = hdev->sfr.kva; sfr->buf_size = ALIGNED_SFR_SIZE; } -- cgit v1.2.3 From cab1dea3be2e51578032c5aee6ac13ff7b4aaeb4 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Tue, 10 Oct 2017 04:46:36 +0200 Subject: media: atmel-isc: Add spin lock for clock enable ops Add the spin lock for the clock enable and disable operations. Signed-off-by: Wenyou Yang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 2f8e345d297e..991f962b7023 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -65,6 +65,7 @@ struct isc_clk { struct clk_hw hw; struct clk *clk; struct regmap *regmap; + spinlock_t lock; u8 id; u8 parent_id; u32 div; @@ -312,26 +313,37 @@ static int isc_clk_enable(struct clk_hw *hw) struct isc_clk *isc_clk = to_isc_clk(hw); u32 id = isc_clk->id; struct regmap *regmap = isc_clk->regmap; + unsigned long flags; + unsigned int status; dev_dbg(isc_clk->dev, "ISC CLK: %s, div = %d, parent id = %d\n", __func__, isc_clk->div, isc_clk->parent_id); + spin_lock_irqsave(&isc_clk->lock, flags); regmap_update_bits(regmap, ISC_CLKCFG, ISC_CLKCFG_DIV_MASK(id) | ISC_CLKCFG_SEL_MASK(id), (isc_clk->div << ISC_CLKCFG_DIV_SHIFT(id)) | (isc_clk->parent_id << ISC_CLKCFG_SEL_SHIFT(id))); regmap_write(regmap, ISC_CLKEN, ISC_CLK(id)); + spin_unlock_irqrestore(&isc_clk->lock, flags); - return 0; + regmap_read(regmap, ISC_CLKSR, &status); + if (status & ISC_CLK(id)) + return 0; + else + return -EINVAL; } static void isc_clk_disable(struct clk_hw *hw) { struct isc_clk *isc_clk = to_isc_clk(hw); u32 id = isc_clk->id; + unsigned long flags; + spin_lock_irqsave(&isc_clk->lock, flags); regmap_write(isc_clk->regmap, ISC_CLKDIS, ISC_CLK(id)); + spin_unlock_irqrestore(&isc_clk->lock, flags); } static int isc_clk_is_enabled(struct clk_hw *hw) @@ -492,6 +504,7 @@ static int isc_clk_register(struct isc_device *isc, unsigned int id) isc_clk->regmap = regmap; isc_clk->id = id; isc_clk->dev = isc->dev; + spin_lock_init(&isc_clk->lock); isc_clk->clk = clk_register(isc->dev, &isc_clk->hw); if (IS_ERR(isc_clk->clk)) { -- cgit v1.2.3 From 64f6306a5af21561ad6b9a3247fc68126b8be88a Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Tue, 10 Oct 2017 04:46:37 +0200 Subject: media: atmel-isc: Add prepare and unprepare ops A software write operation to the ISC_CLKEN or ISC_CLKDIS register requires double clock domain synchronization and is not permitted when the ISC_SR.SIP is asserted. So add the .prepare and .unprepare ops to make sure the ISC_CLKSR.SIP is unasserted before the write operation to the ISC_CLKEN or ISC_CLKDIS register. Signed-off-by: Wenyou Yang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc-regs.h | 1 + drivers/media/platform/atmel/atmel-isc.c | 40 +++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/atmel/atmel-isc-regs.h b/drivers/media/platform/atmel/atmel-isc-regs.h index 6936ac467609..93e58fcf1d5f 100644 --- a/drivers/media/platform/atmel/atmel-isc-regs.h +++ b/drivers/media/platform/atmel/atmel-isc-regs.h @@ -42,6 +42,7 @@ /* ISC Clock Status Register */ #define ISC_CLKSR 0x00000020 +#define ISC_CLKSR_SIP BIT(31) #define ISC_CLK(n) BIT(n) diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 991f962b7023..5f8228fc9c8d 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -308,6 +308,44 @@ module_param(sensor_preferred, uint, 0644); MODULE_PARM_DESC(sensor_preferred, "Sensor is preferred to output the specified format (1-on 0-off), default 1"); +static int isc_wait_clk_stable(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + struct regmap *regmap = isc_clk->regmap; + unsigned long timeout = jiffies + usecs_to_jiffies(1000); + unsigned int status; + + while (time_before(jiffies, timeout)) { + regmap_read(regmap, ISC_CLKSR, &status); + if (!(status & ISC_CLKSR_SIP)) + return 0; + + usleep_range(10, 250); + } + + return -ETIMEDOUT; +} + +static int isc_clk_prepare(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + + if (isc_clk->id == ISC_MCK) + pm_runtime_get_sync(isc_clk->dev); + + return isc_wait_clk_stable(hw); +} + +static void isc_clk_unprepare(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + + isc_wait_clk_stable(hw); + + if (isc_clk->id == ISC_MCK) + pm_runtime_put_sync(isc_clk->dev); +} + static int isc_clk_enable(struct clk_hw *hw) { struct isc_clk *isc_clk = to_isc_clk(hw); @@ -459,6 +497,8 @@ static int isc_clk_set_rate(struct clk_hw *hw, } static const struct clk_ops isc_clk_ops = { + .prepare = isc_clk_prepare, + .unprepare = isc_clk_unprepare, .enable = isc_clk_enable, .disable = isc_clk_disable, .is_enabled = isc_clk_is_enabled, -- cgit v1.2.3 From 01192aa1c5c2a7363cc790ea102c7929ec577240 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Tue, 10 Oct 2017 04:46:38 +0200 Subject: media: atmel-isc: Enable the clocks during probe To meet the relationship, enable the HCLOCK and ispck during the device probe, "isc_pck frequency is less than or equal to isc_ispck, and isc_ispck is greater than or equal to HCLOCK." Meanwhile, call the pm_runtime_enable() in the right place. Signed-off-by: Wenyou Yang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc.c | 34 ++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 5f8228fc9c8d..a44a66ad2c02 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -389,8 +389,14 @@ static int isc_clk_is_enabled(struct clk_hw *hw) struct isc_clk *isc_clk = to_isc_clk(hw); u32 status; + if (isc_clk->id == ISC_MCK) + pm_runtime_get_sync(isc_clk->dev); + regmap_read(isc_clk->regmap, ISC_CLKSR, &status); + if (isc_clk->id == ISC_MCK) + pm_runtime_put_sync(isc_clk->dev); + return status & ISC_CLK(isc_clk->id) ? 1 : 0; } @@ -1866,25 +1872,37 @@ static int atmel_isc_probe(struct platform_device *pdev) return ret; } + ret = clk_prepare_enable(isc->hclock); + if (ret) { + dev_err(dev, "failed to enable hclock: %d\n", ret); + return ret; + } + ret = isc_clk_init(isc); if (ret) { dev_err(dev, "failed to init isc clock: %d\n", ret); - goto clean_isc_clk; + goto unprepare_hclk; } isc->ispck = isc->isc_clks[ISC_ISPCK].clk; + ret = clk_prepare_enable(isc->ispck); + if (ret) { + dev_err(dev, "failed to enable ispck: %d\n", ret); + goto unprepare_hclk; + } + /* ispck should be greater or equal to hclock */ ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock)); if (ret) { dev_err(dev, "failed to set ispck rate: %d\n", ret); - goto clean_isc_clk; + goto unprepare_clk; } ret = v4l2_device_register(dev, &isc->v4l2_dev); if (ret) { dev_err(dev, "unable to register v4l2 device.\n"); - goto clean_isc_clk; + goto unprepare_clk; } ret = isc_parse_dt(dev, isc); @@ -1917,7 +1935,9 @@ static int atmel_isc_probe(struct platform_device *pdev) break; } + pm_runtime_set_active(dev); pm_runtime_enable(dev); + pm_request_idle(dev); return 0; @@ -1927,7 +1947,11 @@ cleanup_subdev: unregister_v4l2_device: v4l2_device_unregister(&isc->v4l2_dev); -clean_isc_clk: +unprepare_clk: + clk_disable_unprepare(isc->ispck); +unprepare_hclk: + clk_disable_unprepare(isc->hclock); + isc_clk_cleanup(isc); return ret; @@ -1938,6 +1962,8 @@ static int atmel_isc_remove(struct platform_device *pdev) struct isc_device *isc = platform_get_drvdata(pdev); pm_runtime_disable(&pdev->dev); + clk_disable_unprepare(isc->ispck); + clk_disable_unprepare(isc->hclock); isc_subdev_cleanup(isc); -- cgit v1.2.3 From b0ea17c589a8b16b4405ab9088d6472cbe08d481 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Tue, 10 Oct 2017 04:46:39 +0200 Subject: media: atmel-isc: Remove unnecessary member Remove the memeber *config from the isc_subdev_entity struct, the member is useless afterward. Signed-off-by: Wenyou Yang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index a44a66ad2c02..29780fcdfc8b 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -83,7 +83,6 @@ struct isc_subdev_entity { struct v4l2_subdev *sd; struct v4l2_async_subdev *asd; struct v4l2_async_notifier notifier; - struct v4l2_subdev_pad_config *config; u32 pfe_cfg0; @@ -1000,6 +999,7 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, { struct isc_format *isc_fmt; struct v4l2_pix_format *pixfmt = &f->fmt.pix; + struct v4l2_subdev_pad_config pad_cfg; struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_TRY, }; @@ -1030,7 +1030,7 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, v4l2_fill_mbus_format(&format.format, pixfmt, mbus_code); ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt, - isc->current_subdev->config, &format); + &pad_cfg, &format); if (ret < 0) return ret; @@ -1495,8 +1495,6 @@ static void isc_async_unbind(struct v4l2_async_notifier *notifier, struct isc_device, v4l2_dev); cancel_work_sync(&isc->awb_work); video_unregister_device(&isc->video_dev); - if (isc->current_subdev->config) - v4l2_subdev_free_pad_config(isc->current_subdev->config); v4l2_ctrl_handler_free(&isc->ctrls.handler); } @@ -1648,10 +1646,6 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) INIT_LIST_HEAD(&isc->dma_queue); spin_lock_init(&isc->dma_queue_lock); - sd_entity->config = v4l2_subdev_alloc_pad_config(sd_entity->sd); - if (!sd_entity->config) - return -ENOMEM; - ret = isc_formats_init(isc); if (ret < 0) { v4l2_err(&isc->v4l2_dev, -- cgit v1.2.3 From f103ea11cd037943b511fa71c852ff14cc6de8ee Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Tue, 10 Oct 2017 04:46:40 +0200 Subject: media: atmel-isc: Rework the format list To improve the readability of code, split the format array into two, one for the format description, other for the register configuration. Meanwhile, add the flag member to indicate the format can be achieved from the sensor or be produced by the controller, and rename members related to the register configuration. Also add more formats support: GREY, ARGB444, ARGB555 and ARGB32. Signed-off-by: Wenyou Yang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc.c | 530 ++++++++++++++++++++++++------- 1 file changed, 411 insertions(+), 119 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 29780fcdfc8b..2c40a7886542 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -89,34 +89,63 @@ struct isc_subdev_entity { struct list_head list; }; +/* Indicate the format is generated by the sensor */ +#define FMT_FLAG_FROM_SENSOR BIT(0) +/* Indicate the format is produced by ISC itself */ +#define FMT_FLAG_FROM_CONTROLLER BIT(1) +/* Indicate a Raw Bayer format */ +#define FMT_FLAG_RAW_FORMAT BIT(2) + +#define FMT_FLAG_RAW_FROM_SENSOR (FMT_FLAG_FROM_SENSOR | \ + FMT_FLAG_RAW_FORMAT) + /* * struct isc_format - ISC media bus format information * @fourcc: Fourcc code for this format * @mbus_code: V4L2 media bus format code. + * flags: Indicate format from sensor or converted by controller * @bpp: Bits per pixel (when stored in memory) - * @reg_bps: reg value for bits per sample * (when transferred over a bus) - * @pipeline: pipeline switch * @sd_support: Subdev supports this format * @isc_support: ISC can convert raw format to this format */ + struct isc_format { u32 fourcc; u32 mbus_code; + u32 flags; u8 bpp; - u32 reg_bps; - u32 reg_bay_cfg; - u32 reg_rlp_mode; - u32 reg_dcfg_imode; - u32 reg_dctrl_dview; - - u32 pipeline; - bool sd_support; bool isc_support; }; +/* Pipeline bitmap */ +#define WB_ENABLE BIT(0) +#define CFA_ENABLE BIT(1) +#define CC_ENABLE BIT(2) +#define GAM_ENABLE BIT(3) +#define GAM_BENABLE BIT(4) +#define GAM_GENABLE BIT(5) +#define GAM_RENABLE BIT(6) +#define CSC_ENABLE BIT(7) +#define CBC_ENABLE BIT(8) +#define SUB422_ENABLE BIT(9) +#define SUB420_ENABLE BIT(10) + +#define GAM_ENABLES (GAM_RENABLE | GAM_GENABLE | GAM_BENABLE | GAM_ENABLE) + +struct fmt_config { + u32 fourcc; + + u32 pfe_cfg0_bps; + u32 cfa_baycfg; + u32 rlp_cfg_mode; + u32 dcfg_imode; + u32 dctrl_dview; + + u32 bits_pipeline; +}; #define HIST_ENTRIES 512 #define HIST_BAYER (ISC_HIS_CFG_MODE_B + 1) @@ -181,80 +210,320 @@ struct isc_device { struct list_head subdev_entities; }; -#define RAW_FMT_IND_START 0 -#define RAW_FMT_IND_END 11 -#define ISC_FMT_IND_START 12 -#define ISC_FMT_IND_END 14 - -static struct isc_format isc_formats[] = { - { V4L2_PIX_FMT_SBGGR8, MEDIA_BUS_FMT_SBGGR8_1X8, 8, - ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT8, - ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - { V4L2_PIX_FMT_SGBRG8, MEDIA_BUS_FMT_SGBRG8_1X8, 8, - ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_GBGB, ISC_RLP_CFG_MODE_DAT8, - ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - { V4L2_PIX_FMT_SGRBG8, MEDIA_BUS_FMT_SGRBG8_1X8, 8, - ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_GRGR, ISC_RLP_CFG_MODE_DAT8, - ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - { V4L2_PIX_FMT_SRGGB8, MEDIA_BUS_FMT_SRGGB8_1X8, 8, - ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_RGRG, ISC_RLP_CFG_MODE_DAT8, - ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - - { V4L2_PIX_FMT_SBGGR10, MEDIA_BUS_FMT_SBGGR10_1X10, 16, - ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT10, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - { V4L2_PIX_FMT_SGBRG10, MEDIA_BUS_FMT_SGBRG10_1X10, 16, - ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_GBGB, ISC_RLP_CFG_MODE_DAT10, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - { V4L2_PIX_FMT_SGRBG10, MEDIA_BUS_FMT_SGRBG10_1X10, 16, - ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_GRGR, ISC_RLP_CFG_MODE_DAT10, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - { V4L2_PIX_FMT_SRGGB10, MEDIA_BUS_FMT_SRGGB10_1X10, 16, - ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_RGRG, ISC_RLP_CFG_MODE_DAT10, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - - { V4L2_PIX_FMT_SBGGR12, MEDIA_BUS_FMT_SBGGR12_1X12, 16, - ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT12, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - { V4L2_PIX_FMT_SGBRG12, MEDIA_BUS_FMT_SGBRG12_1X12, 16, - ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_GBGB, ISC_RLP_CFG_MODE_DAT12, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - { V4L2_PIX_FMT_SGRBG12, MEDIA_BUS_FMT_SGRBG12_1X12, 16, - ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_GRGR, ISC_RLP_CFG_MODE_DAT12, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - { V4L2_PIX_FMT_SRGGB12, MEDIA_BUS_FMT_SRGGB12_1X12, 16, - ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_RGRG, ISC_RLP_CFG_MODE_DAT12, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - - { V4L2_PIX_FMT_YUV420, 0x0, 12, - ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_YYCC, - ISC_DCFG_IMODE_YC420P, ISC_DCTRL_DVIEW_PLANAR, 0x7fb, - false, false }, - { V4L2_PIX_FMT_YUV422P, 0x0, 16, - ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_YYCC, - ISC_DCFG_IMODE_YC422P, ISC_DCTRL_DVIEW_PLANAR, 0x3fb, - false, false }, - { V4L2_PIX_FMT_RGB565, MEDIA_BUS_FMT_RGB565_2X8_LE, 16, - ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_RGB565, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x7b, - false, false }, - - { V4L2_PIX_FMT_YUYV, MEDIA_BUS_FMT_YUYV8_2X8, 16, - ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT8, - ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, +static struct isc_format formats_list[] = { + { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 8, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 8, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 8, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 8, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR12, + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG12, + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG12, + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB12, + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_YUV420, + .mbus_code = 0x0, + .flags = FMT_FLAG_FROM_CONTROLLER, + .bpp = 12, + }, + { + .fourcc = V4L2_PIX_FMT_YUV422P, + .mbus_code = 0x0, + .flags = FMT_FLAG_FROM_CONTROLLER, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_GREY, + .mbus_code = MEDIA_BUS_FMT_Y8_1X8, + .flags = FMT_FLAG_FROM_CONTROLLER | + FMT_FLAG_FROM_SENSOR, + .bpp = 8, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB444, + .mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, + .flags = FMT_FLAG_FROM_CONTROLLER, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB555, + .mbus_code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, + .flags = FMT_FLAG_FROM_CONTROLLER, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_RGB565, + .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .flags = FMT_FLAG_FROM_CONTROLLER, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB32, + .mbus_code = MEDIA_BUS_FMT_ARGB8888_1X32, + .flags = FMT_FLAG_FROM_CONTROLLER, + .bpp = 32, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, + .flags = FMT_FLAG_FROM_CONTROLLER | + FMT_FLAG_FROM_SENSOR, + .bpp = 16, + }, +}; + +struct fmt_config fmt_configs_list[] = { + { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, + .dcfg_imode = ISC_DCFG_IMODE_PACKED8, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_GBGB, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, + .dcfg_imode = ISC_DCFG_IMODE_PACKED8, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_GRGR, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, + .dcfg_imode = ISC_DCFG_IMODE_PACKED8, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_RGRG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, + .dcfg_imode = ISC_DCFG_IMODE_PACKED8, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, + .cfa_baycfg = ISC_BAY_CFG_GBGB, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, + .cfa_baycfg = ISC_BAY_CFG_GRGR, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, + .cfa_baycfg = ISC_BAY_CFG_RGRG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR12, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG12, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, + .cfa_baycfg = ISC_BAY_CFG_GBGB, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0 + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG12, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, + .cfa_baycfg = ISC_BAY_CFG_GRGR, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB12, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, + .cfa_baycfg = ISC_BAY_CFG_RGRG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_YUV420, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC, + .dcfg_imode = ISC_DCFG_IMODE_YC420P, + .dctrl_dview = ISC_DCTRL_DVIEW_PLANAR, + .bits_pipeline = SUB420_ENABLE | SUB422_ENABLE | + CBC_ENABLE | CSC_ENABLE | + GAM_ENABLES | + CFA_ENABLE | WB_ENABLE, + }, + { + .fourcc = V4L2_PIX_FMT_YUV422P, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC, + .dcfg_imode = ISC_DCFG_IMODE_YC422P, + .dctrl_dview = ISC_DCTRL_DVIEW_PLANAR, + .bits_pipeline = SUB422_ENABLE | + CBC_ENABLE | CSC_ENABLE | + GAM_ENABLES | + CFA_ENABLE | WB_ENABLE, + }, + { + .fourcc = V4L2_PIX_FMT_GREY, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY8, + .dcfg_imode = ISC_DCFG_IMODE_PACKED8, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = CBC_ENABLE | CSC_ENABLE | + GAM_ENABLES | + CFA_ENABLE | WB_ENABLE, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB444, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB444, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB555, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB555, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE, + }, + { + .fourcc = V4L2_PIX_FMT_RGB565, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_RGB565, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB32, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB32, + .dcfg_imode = ISC_DCFG_IMODE_PACKED32, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, + .dcfg_imode = ISC_DCFG_IMODE_PACKED8, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0 + }, }; #define GAMMA_MAX 2 @@ -633,11 +902,27 @@ static inline bool sensor_is_preferred(const struct isc_format *isc_fmt) !isc_fmt->isc_support; } +static struct fmt_config *get_fmt_config(u32 fourcc) +{ + struct fmt_config *config; + int i; + + config = &fmt_configs_list[0]; + for (i = 0; i < ARRAY_SIZE(fmt_configs_list); i++) { + if (config->fourcc == fourcc) + return config; + + config++; + } + return NULL; +} + static void isc_start_dma(struct isc_device *isc) { struct regmap *regmap = isc->regmap; struct v4l2_pix_format *pixfmt = &isc->fmt.fmt.pix; u32 sizeimage = pixfmt->sizeimage; + struct fmt_config *config = get_fmt_config(isc->current_fmt->fourcc); u32 dctrl_dview; dma_addr_t addr0; @@ -660,7 +945,7 @@ static void isc_start_dma(struct isc_device *isc) if (sensor_is_preferred(isc->current_fmt)) dctrl_dview = ISC_DCTRL_DVIEW_PACKED; else - dctrl_dview = isc->current_fmt->reg_dctrl_dview; + dctrl_dview = config->dctrl_dview; regmap_write(regmap, ISC_DCTRL, dctrl_dview | ISC_DCTRL_IE_IS); regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE); @@ -670,6 +955,7 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) { struct regmap *regmap = isc->regmap; struct isc_ctrls *ctrls = &isc->ctrls; + struct fmt_config *config = get_fmt_config(isc->raw_fmt->fourcc); u32 val, bay_cfg; const u32 *gamma; unsigned int i; @@ -683,7 +969,7 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) if (!pipeline) return; - bay_cfg = isc->raw_fmt->reg_bay_cfg; + bay_cfg = config->cfa_baycfg; regmap_write(regmap, ISC_WB_CFG, bay_cfg); regmap_write(regmap, ISC_WB_O_RGR, 0x0); @@ -736,11 +1022,13 @@ static void isc_set_histogram(struct isc_device *isc) { struct regmap *regmap = isc->regmap; struct isc_ctrls *ctrls = &isc->ctrls; + struct fmt_config *config = get_fmt_config(isc->raw_fmt->fourcc); if (ctrls->awb && (ctrls->hist_stat != HIST_ENABLED)) { - regmap_write(regmap, ISC_HIS_CFG, ISC_HIS_CFG_MODE_R | - (isc->raw_fmt->reg_bay_cfg << ISC_HIS_CFG_BAYSEL_SHIFT) | - ISC_HIS_CFG_RAR); + regmap_write(regmap, ISC_HIS_CFG, + ISC_HIS_CFG_MODE_R | + (config->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT) | + ISC_HIS_CFG_RAR); regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_EN); regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE); ctrls->hist_id = ISC_HIS_CFG_MODE_R; @@ -757,8 +1045,10 @@ static void isc_set_histogram(struct isc_device *isc) } static inline void isc_get_param(const struct isc_format *fmt, - u32 *rlp_mode, u32 *dcfg) + u32 *rlp_mode, u32 *dcfg) { + struct fmt_config *config = get_fmt_config(fmt->fourcc); + *dcfg = ISC_DCFG_YMBSIZE_BEATS8; switch (fmt->fourcc) { @@ -770,8 +1060,8 @@ static inline void isc_get_param(const struct isc_format *fmt, case V4L2_PIX_FMT_SGBRG12: case V4L2_PIX_FMT_SGRBG12: case V4L2_PIX_FMT_SRGGB12: - *rlp_mode = fmt->reg_rlp_mode; - *dcfg |= fmt->reg_dcfg_imode; + *rlp_mode = config->rlp_cfg_mode; + *dcfg |= config->dcfg_imode; break; default: *rlp_mode = ISC_RLP_CFG_MODE_DAT8; @@ -784,20 +1074,22 @@ static int isc_configure(struct isc_device *isc) { struct regmap *regmap = isc->regmap; const struct isc_format *current_fmt = isc->current_fmt; + struct fmt_config *curfmt_config = get_fmt_config(current_fmt->fourcc); + struct fmt_config *rawfmt_config = get_fmt_config(isc->raw_fmt->fourcc); struct isc_subdev_entity *subdev = isc->current_subdev; u32 pfe_cfg0, rlp_mode, dcfg, mask, pipeline; if (sensor_is_preferred(current_fmt)) { - pfe_cfg0 = current_fmt->reg_bps; + pfe_cfg0 = curfmt_config->pfe_cfg0_bps; pipeline = 0x0; isc_get_param(current_fmt, &rlp_mode, &dcfg); isc->ctrls.hist_stat = HIST_INIT; } else { - pfe_cfg0 = isc->raw_fmt->reg_bps; - pipeline = current_fmt->pipeline; - rlp_mode = current_fmt->reg_rlp_mode; - dcfg = current_fmt->reg_dcfg_imode | ISC_DCFG_YMBSIZE_BEATS8 | - ISC_DCFG_CMBSIZE_BEATS8; + pfe_cfg0 = rawfmt_config->pfe_cfg0_bps; + pipeline = curfmt_config->bits_pipeline; + rlp_mode = curfmt_config->rlp_cfg_mode; + dcfg = curfmt_config->dcfg_imode | + ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8; } pfe_cfg0 |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE; @@ -1382,6 +1674,7 @@ static void isc_awb_work(struct work_struct *w) struct isc_device *isc = container_of(w, struct isc_device, awb_work); struct regmap *regmap = isc->regmap; + struct fmt_config *config = get_fmt_config(isc->raw_fmt->fourcc); struct isc_ctrls *ctrls = &isc->ctrls; u32 hist_id = ctrls->hist_id; u32 baysel; @@ -1399,7 +1692,7 @@ static void isc_awb_work(struct work_struct *w) } ctrls->hist_id = hist_id; - baysel = isc->raw_fmt->reg_bay_cfg << ISC_HIS_CFG_BAYSEL_SHIFT; + baysel = config->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT; pm_runtime_get_sync(isc->dev); @@ -1500,10 +1793,10 @@ static void isc_async_unbind(struct v4l2_async_notifier *notifier, static struct isc_format *find_format_by_code(unsigned int code, int *index) { - struct isc_format *fmt = &isc_formats[0]; + struct isc_format *fmt = &formats_list[0]; unsigned int i; - for (i = 0; i < ARRAY_SIZE(isc_formats); i++) { + for (i = 0; i < ARRAY_SIZE(formats_list); i++) { if (fmt->mbus_code == code) { *index = i; return fmt; @@ -1520,37 +1813,36 @@ static int isc_formats_init(struct isc_device *isc) struct isc_format *fmt; struct v4l2_subdev *subdev = isc->current_subdev->sd; unsigned int num_fmts, i, j; + u32 list_size = ARRAY_SIZE(formats_list); struct v4l2_subdev_mbus_code_enum mbus_code = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; - fmt = &isc_formats[0]; - for (i = 0; i < ARRAY_SIZE(isc_formats); i++) { - fmt->isc_support = false; - fmt->sd_support = false; - - fmt++; - } - while (!v4l2_subdev_call(subdev, pad, enum_mbus_code, NULL, &mbus_code)) { mbus_code.index++; + fmt = find_format_by_code(mbus_code.code, &i); - if (!fmt) + if ((!fmt) || (!(fmt->flags & FMT_FLAG_FROM_SENSOR))) continue; fmt->sd_support = true; - if (i <= RAW_FMT_IND_END) { - for (j = ISC_FMT_IND_START; j <= ISC_FMT_IND_END; j++) - isc_formats[j].isc_support = true; - + if (fmt->flags & FMT_FLAG_RAW_FORMAT) isc->raw_fmt = fmt; - } } - fmt = &isc_formats[0]; - for (i = 0, num_fmts = 0; i < ARRAY_SIZE(isc_formats); i++) { + fmt = &formats_list[0]; + for (i = 0; i < list_size; i++) { + if (fmt->flags & FMT_FLAG_FROM_CONTROLLER) + fmt->isc_support = true; + + fmt++; + } + + fmt = &formats_list[0]; + num_fmts = 0; + for (i = 0; i < list_size; i++) { if (fmt->isc_support || fmt->sd_support) num_fmts++; @@ -1567,8 +1859,8 @@ static int isc_formats_init(struct isc_device *isc) if (!isc->user_formats) return -ENOMEM; - fmt = &isc_formats[0]; - for (i = 0, j = 0; i < ARRAY_SIZE(isc_formats); i++) { + fmt = &formats_list[0]; + for (i = 0, j = 0; i < list_size; i++) { if (fmt->isc_support || fmt->sd_support) isc->user_formats[j++] = fmt; -- cgit v1.2.3 From 5232c37ce244db04fd50d160b92e40d2df46a2e9 Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Tue, 10 Oct 2017 09:52:36 +0200 Subject: media: venus: venc: fix bytesused v4l2_plane field This fixes wrongly filled bytesused field of v4l2_plane structure by include data_offset in the plane, Also fill data_offset and bytesused for capture type of buffers only. Signed-off-by: Stanimir Varbanov Signed-off-by: Hans Verkuil Cc: # for v4.13 and up Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/venc.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 6f123a387cf9..3fcf0e9b7b29 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -963,13 +963,12 @@ static void venc_buf_done(struct venus_inst *inst, unsigned int buf_type, if (!vbuf) return; - vb = &vbuf->vb2_buf; - vb->planes[0].bytesused = bytesused; - vb->planes[0].data_offset = data_offset; - vbuf->flags = flags; if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + vb = &vbuf->vb2_buf; + vb2_set_plane_payload(vb, 0, bytesused + data_offset); + vb->planes[0].data_offset = data_offset; vb->timestamp = timestamp_us * NSEC_PER_USEC; vbuf->sequence = inst->sequence_cap++; } else { -- cgit v1.2.3 From 3863360c15da47e18d894268ad6182fdc7caf0c7 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 11 Oct 2017 13:16:43 +0200 Subject: media: vimc: Fix return value check in vimc_add_subdevs() In case of error, the function platform_device_register_data() returns ERR_PTR() and never returns NULL. The NULL test in the return value check should be replaced with IS_ERR(). Signed-off-by: Wei Yongjun Acked-by: Helen Koike Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vimc/vimc-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/vimc/vimc-core.c b/drivers/media/platform/vimc/vimc-core.c index 51c0eee61ca6..fe088a953860 100644 --- a/drivers/media/platform/vimc/vimc-core.c +++ b/drivers/media/platform/vimc/vimc-core.c @@ -267,11 +267,12 @@ static struct component_match *vimc_add_subdevs(struct vimc_device *vimc) PLATFORM_DEVID_AUTO, &pdata, sizeof(pdata)); - if (!vimc->subdevs[i]) { + if (IS_ERR(vimc->subdevs[i])) { + match = ERR_CAST(vimc->subdevs[i]); while (--i >= 0) platform_device_unregister(vimc->subdevs[i]); - return ERR_PTR(-ENOMEM); + return match; } component_match_add(&vimc->pdev.dev, &match, vimc_comp_compare, -- cgit v1.2.3 From e69b987a97599456b95b5fef4aca8dcdb1505aea Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Fri, 13 Oct 2017 16:13:17 +0200 Subject: media: venus: reimplement decoder stop command This addresses the wrong behavior of decoder stop command by rewriting it. These new implementation enqueue an empty buffer on the decoder input buffer queue to signal end-of-stream. The client should stop queuing buffers on the V4L2 Output queue and continue queuing/dequeuing buffers on Capture queue. This process will continue until the client receives a buffer with V4L2_BUF_FLAG_LAST flag raised, which means that this is last decoded buffer with data. Signed-off-by: Stanimir Varbanov Tested-by: Nicolas Dufresne Signed-off-by: Hans Verkuil Cc: # for v4.13 and up Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/core.h | 2 -- drivers/media/platform/qcom/venus/helpers.c | 7 ------ drivers/media/platform/qcom/venus/hfi.c | 1 + drivers/media/platform/qcom/venus/vdec.c | 34 +++++++++++++++++++---------- 4 files changed, 24 insertions(+), 20 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index cba092bcb76d..a0fe80df0cbd 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -194,7 +194,6 @@ struct venus_buffer { * @fh: a holder of v4l file handle structure * @streamon_cap: stream on flag for capture queue * @streamon_out: stream on flag for output queue - * @cmd_stop: a flag to signal encoder/decoder commands * @width: current capture width * @height: current capture height * @out_width: current output width @@ -258,7 +257,6 @@ struct venus_inst { } controls; struct v4l2_fh fh; unsigned int streamon_cap, streamon_out; - bool cmd_stop; u32 width; u32 height; u32 out_width; diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 9b2a401a4891..0ce9559a2924 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -623,13 +623,6 @@ void venus_helper_vb2_buf_queue(struct vb2_buffer *vb) mutex_lock(&inst->lock); - if (inst->cmd_stop) { - vbuf->flags |= V4L2_BUF_FLAG_LAST; - v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); - inst->cmd_stop = false; - goto unlock; - } - v4l2_m2m_buf_queue(m2m_ctx, vbuf); if (!(inst->streamon_out & inst->streamon_cap)) diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c index c09490876516..ba29fd4d4984 100644 --- a/drivers/media/platform/qcom/venus/hfi.c +++ b/drivers/media/platform/qcom/venus/hfi.c @@ -484,6 +484,7 @@ int hfi_session_process_buf(struct venus_inst *inst, struct hfi_frame_data *fd) return -EINVAL; } +EXPORT_SYMBOL_GPL(hfi_session_process_buf); irqreturn_t hfi_isr_thread(int irq, void *dev_id) { diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index da611a5eb670..c9e9576bb08a 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -469,8 +469,14 @@ static int vdec_subscribe_event(struct v4l2_fh *fh, static int vdec_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) { - if (cmd->cmd != V4L2_DEC_CMD_STOP) + switch (cmd->cmd) { + case V4L2_DEC_CMD_STOP: + if (cmd->flags & V4L2_DEC_CMD_STOP_TO_BLACK) + return -EINVAL; + break; + default: return -EINVAL; + } return 0; } @@ -479,6 +485,7 @@ static int vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) { struct venus_inst *inst = to_inst(file); + struct hfi_frame_data fdata = {0}; int ret; ret = vdec_try_decoder_cmd(file, fh, cmd); @@ -486,12 +493,23 @@ vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) return ret; mutex_lock(&inst->lock); - inst->cmd_stop = true; - mutex_unlock(&inst->lock); - hfi_session_flush(inst); + /* + * Implement V4L2_DEC_CMD_STOP by enqueue an empty buffer on decoder + * input to signal EOS. + */ + if (!(inst->streamon_out & inst->streamon_cap)) + goto unlock; + + fdata.buffer_type = HFI_BUFFER_INPUT; + fdata.flags |= HFI_BUFFERFLAG_EOS; + fdata.device_addr = 0xdeadbeef; - return 0; + ret = hfi_session_process_buf(inst, &fdata); + +unlock: + mutex_unlock(&inst->lock); + return ret; } static const struct v4l2_ioctl_ops vdec_ioctl_ops = { @@ -718,7 +736,6 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count) inst->reconfig = false; inst->sequence_cap = 0; inst->sequence_out = 0; - inst->cmd_stop = false; ret = vdec_init_session(inst); if (ret) @@ -807,11 +824,6 @@ static void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type, vb->timestamp = timestamp_us * NSEC_PER_USEC; vbuf->sequence = inst->sequence_cap++; - if (inst->cmd_stop) { - vbuf->flags |= V4L2_BUF_FLAG_LAST; - inst->cmd_stop = false; - } - if (vbuf->flags & V4L2_BUF_FLAG_LAST) { const struct v4l2_event ev = { .type = V4L2_EVENT_EOS }; -- cgit v1.2.3 From e641e02d78682f7749053d84d1729c5e37655ff9 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 20 Sep 2017 11:40:58 +0200 Subject: media: coda: Handle return value of kasprintf kasprintf() can fail here and we must check its return value. Signed-off-by: Arvind Yadav Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 291c40933935..bfc4ecf6f068 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -417,6 +417,10 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, dev->devtype->product != CODA_DX6) size += ysize / 4; name = kasprintf(GFP_KERNEL, "fb%d", i); + if (!name) { + coda_free_framebuffers(ctx); + return -ENOMEM; + } ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i], size, name); kfree(name); -- cgit v1.2.3 From 9d2d60687c9a0621e0da40338be4cbd7e3783be2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 15 Jul 2017 10:51:00 +0200 Subject: media: tegra-cec: add Tegra HDMI CEC driver This driver adds support for the Tegra CEC IP. It is based on the NVIDIA drivers/misc/tegra-cec driver in their 3.10 kernel. This has been converted to the CEC framework and cleaned up. Tested with my Jetson TK1 board. It has also been tested with the Tegra X1 in an embedded product. Note of warning for the Tegra X2: this SoC supports two HDMI outputs, but only one CEC adapter and the CEC bus is shared between the two outputs. This is a design mistake and the CEC adapter can control only one HDMI output. Never hook up both HDMI outputs to the CEC bus in a hardware design: this is illegal as per the CEC specification. The CEC bus can be shared between multiple inputs and zero or one outputs, but not between multiple outputs. Signed-off-by: Hans Verkuil Acked-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 8 + drivers/media/platform/Kconfig | 11 + drivers/media/platform/Makefile | 2 + drivers/media/platform/tegra-cec/Makefile | 1 + drivers/media/platform/tegra-cec/tegra_cec.c | 501 +++++++++++++++++++++++++++ drivers/media/platform/tegra-cec/tegra_cec.h | 127 +++++++ 6 files changed, 650 insertions(+) create mode 100644 drivers/media/platform/tegra-cec/Makefile create mode 100644 drivers/media/platform/tegra-cec/tegra_cec.c create mode 100644 drivers/media/platform/tegra-cec/tegra_cec.h (limited to 'drivers/media/platform') diff --git a/MAINTAINERS b/MAINTAINERS index dbeaa2c44dcd..adbf69306e9e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1961,6 +1961,14 @@ M: Lennert Buytenhek L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained +ARM/TEGRA HDMI CEC SUBSYSTEM SUPPORT +M: Hans Verkuil +L: linux-tegra@vger.kernel.org +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/platform/tegra-cec/ +F: Documentation/devicetree/bindings/media/tegra-cec.txt + ARM/TETON BGA MACHINE SUPPORT M: "Mark F. Brown" L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 2dc1d8fe4f5f..fd0c99859d6f 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -614,6 +614,17 @@ config VIDEO_STM32_HDMI_CEC CEC bus is present in the HDMI connector and enables communication between compatible devices. +config VIDEO_TEGRA_HDMI_CEC + tristate "Tegra HDMI CEC driver" + depends on ARCH_TEGRA || COMPILE_TEST + select CEC_CORE + select CEC_NOTIFIER + ---help--- + This is a driver for the Tegra HDMI CEC interface. It uses the + generic CEC framework interface. + The CEC bus is present in the HDMI connector and enables communication + between compatible devices. + endif #CEC_PLATFORM_DRIVERS menuconfig SDR_PLATFORM_DRIVERS diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 1530b096db10..012eb4782156 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -48,6 +48,8 @@ obj-$(CONFIG_VIDEO_STI_HDMI_CEC) += sti/cec/ obj-$(CONFIG_VIDEO_STI_DELTA) += sti/delta/ +obj-$(CONFIG_VIDEO_TEGRA_HDMI_CEC) += tegra-cec/ + obj-y += stm32/ obj-y += blackfin/ diff --git a/drivers/media/platform/tegra-cec/Makefile b/drivers/media/platform/tegra-cec/Makefile new file mode 100644 index 000000000000..f3d81127589f --- /dev/null +++ b/drivers/media/platform/tegra-cec/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_VIDEO_TEGRA_HDMI_CEC) += tegra_cec.o diff --git a/drivers/media/platform/tegra-cec/tegra_cec.c b/drivers/media/platform/tegra-cec/tegra_cec.c new file mode 100644 index 000000000000..b53743f555e8 --- /dev/null +++ b/drivers/media/platform/tegra-cec/tegra_cec.c @@ -0,0 +1,501 @@ +/* + * Tegra CEC implementation + * + * The original 3.10 CEC driver using a custom API: + * + * Copyright (c) 2012-2015, NVIDIA CORPORATION. All rights reserved. + * + * Conversion to the CEC framework and to the mainline kernel: + * + * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "tegra_cec.h" + +#define TEGRA_CEC_NAME "tegra-cec" + +struct tegra_cec { + struct cec_adapter *adap; + struct device *dev; + struct clk *clk; + void __iomem *cec_base; + struct cec_notifier *notifier; + int tegra_cec_irq; + bool rx_done; + bool tx_done; + int tx_status; + u8 rx_buf[CEC_MAX_MSG_SIZE]; + u8 rx_buf_cnt; + u32 tx_buf[CEC_MAX_MSG_SIZE]; + u8 tx_buf_cur; + u8 tx_buf_cnt; +}; + +static inline u32 cec_read(struct tegra_cec *cec, u32 reg) +{ + return readl(cec->cec_base + reg); +} + +static inline void cec_write(struct tegra_cec *cec, u32 reg, u32 val) +{ + writel(val, cec->cec_base + reg); +} + +static void tegra_cec_error_recovery(struct tegra_cec *cec) +{ + u32 hw_ctrl; + + hw_ctrl = cec_read(cec, TEGRA_CEC_HW_CONTROL); + cec_write(cec, TEGRA_CEC_HW_CONTROL, 0); + cec_write(cec, TEGRA_CEC_INT_STAT, 0xffffffff); + cec_write(cec, TEGRA_CEC_HW_CONTROL, hw_ctrl); +} + +static irqreturn_t tegra_cec_irq_thread_handler(int irq, void *data) +{ + struct device *dev = data; + struct tegra_cec *cec = dev_get_drvdata(dev); + + if (cec->tx_done) { + cec_transmit_attempt_done(cec->adap, cec->tx_status); + cec->tx_done = false; + } + if (cec->rx_done) { + struct cec_msg msg = {}; + + msg.len = cec->rx_buf_cnt; + memcpy(msg.msg, cec->rx_buf, msg.len); + cec_received_msg(cec->adap, &msg); + cec->rx_done = false; + cec->rx_buf_cnt = 0; + } + return IRQ_HANDLED; +} + +static irqreturn_t tegra_cec_irq_handler(int irq, void *data) +{ + struct device *dev = data; + struct tegra_cec *cec = dev_get_drvdata(dev); + u32 status, mask; + + status = cec_read(cec, TEGRA_CEC_INT_STAT); + mask = cec_read(cec, TEGRA_CEC_INT_MASK); + + status &= mask; + + if (!status) + return IRQ_HANDLED; + + if (status & TEGRA_CEC_INT_STAT_TX_REGISTER_UNDERRUN) { + dev_err(dev, "TX underrun, interrupt timing issue!\n"); + + tegra_cec_error_recovery(cec); + cec_write(cec, TEGRA_CEC_INT_MASK, + mask & ~TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY); + + cec->tx_done = true; + cec->tx_status = CEC_TX_STATUS_ERROR; + return IRQ_WAKE_THREAD; + } + + if ((status & TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED) || + (status & TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED)) { + tegra_cec_error_recovery(cec); + cec_write(cec, TEGRA_CEC_INT_MASK, + mask & ~TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY); + + cec->tx_done = true; + if (status & TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED) + cec->tx_status = CEC_TX_STATUS_LOW_DRIVE; + else + cec->tx_status = CEC_TX_STATUS_ARB_LOST; + return IRQ_WAKE_THREAD; + } + + if (status & TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED) { + cec_write(cec, TEGRA_CEC_INT_STAT, + TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED); + + if (status & TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD) { + tegra_cec_error_recovery(cec); + + cec->tx_done = true; + cec->tx_status = CEC_TX_STATUS_NACK; + } else { + cec->tx_done = true; + cec->tx_status = CEC_TX_STATUS_OK; + } + return IRQ_WAKE_THREAD; + } + + if (status & TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD) + dev_warn(dev, "TX NAKed on the fly!\n"); + + if (status & TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY) { + if (cec->tx_buf_cur == cec->tx_buf_cnt) { + cec_write(cec, TEGRA_CEC_INT_MASK, + mask & ~TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY); + } else { + cec_write(cec, TEGRA_CEC_TX_REGISTER, + cec->tx_buf[cec->tx_buf_cur++]); + cec_write(cec, TEGRA_CEC_INT_STAT, + TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY); + } + } + + if (status & (TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN | + TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED | + TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED | + TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED)) { + cec_write(cec, TEGRA_CEC_INT_STAT, + (TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN | + TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED | + TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED | + TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED)); + } else if (status & TEGRA_CEC_INT_STAT_RX_REGISTER_FULL) { + u32 v; + + cec_write(cec, TEGRA_CEC_INT_STAT, + TEGRA_CEC_INT_STAT_RX_REGISTER_FULL); + v = cec_read(cec, TEGRA_CEC_RX_REGISTER); + if (cec->rx_buf_cnt < CEC_MAX_MSG_SIZE) + cec->rx_buf[cec->rx_buf_cnt++] = v & 0xff; + if (v & TEGRA_CEC_RX_REGISTER_EOM) { + cec->rx_done = true; + return IRQ_WAKE_THREAD; + } + } + + return IRQ_HANDLED; +} + +static int tegra_cec_adap_enable(struct cec_adapter *adap, bool enable) +{ + struct tegra_cec *cec = adap->priv; + + cec->rx_buf_cnt = 0; + cec->tx_buf_cnt = 0; + cec->tx_buf_cur = 0; + + cec_write(cec, TEGRA_CEC_HW_CONTROL, 0); + cec_write(cec, TEGRA_CEC_INT_MASK, 0); + cec_write(cec, TEGRA_CEC_INT_STAT, 0xffffffff); + cec_write(cec, TEGRA_CEC_SW_CONTROL, 0); + + if (!enable) + return 0; + + cec_write(cec, TEGRA_CEC_INPUT_FILTER, (1U << 31) | 0x20); + + cec_write(cec, TEGRA_CEC_RX_TIMING_0, + (0x7a << TEGRA_CEC_RX_TIM0_START_BIT_MAX_LO_TIME_SHIFT) | + (0x6d << TEGRA_CEC_RX_TIM0_START_BIT_MIN_LO_TIME_SHIFT) | + (0x93 << TEGRA_CEC_RX_TIM0_START_BIT_MAX_DURATION_SHIFT) | + (0x86 << TEGRA_CEC_RX_TIM0_START_BIT_MIN_DURATION_SHIFT)); + + cec_write(cec, TEGRA_CEC_RX_TIMING_1, + (0x35 << TEGRA_CEC_RX_TIM1_DATA_BIT_MAX_LO_TIME_SHIFT) | + (0x21 << TEGRA_CEC_RX_TIM1_DATA_BIT_SAMPLE_TIME_SHIFT) | + (0x56 << TEGRA_CEC_RX_TIM1_DATA_BIT_MAX_DURATION_SHIFT) | + (0x40 << TEGRA_CEC_RX_TIM1_DATA_BIT_MIN_DURATION_SHIFT)); + + cec_write(cec, TEGRA_CEC_RX_TIMING_2, + (0x50 << TEGRA_CEC_RX_TIM2_END_OF_BLOCK_TIME_SHIFT)); + + cec_write(cec, TEGRA_CEC_TX_TIMING_0, + (0x74 << TEGRA_CEC_TX_TIM0_START_BIT_LO_TIME_SHIFT) | + (0x8d << TEGRA_CEC_TX_TIM0_START_BIT_DURATION_SHIFT) | + (0x08 << TEGRA_CEC_TX_TIM0_BUS_XITION_TIME_SHIFT) | + (0x71 << TEGRA_CEC_TX_TIM0_BUS_ERROR_LO_TIME_SHIFT)); + + cec_write(cec, TEGRA_CEC_TX_TIMING_1, + (0x2f << TEGRA_CEC_TX_TIM1_LO_DATA_BIT_LO_TIME_SHIFT) | + (0x13 << TEGRA_CEC_TX_TIM1_HI_DATA_BIT_LO_TIME_SHIFT) | + (0x4b << TEGRA_CEC_TX_TIM1_DATA_BIT_DURATION_SHIFT) | + (0x21 << TEGRA_CEC_TX_TIM1_ACK_NAK_BIT_SAMPLE_TIME_SHIFT)); + + cec_write(cec, TEGRA_CEC_TX_TIMING_2, + (0x07 << TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_ADDITIONAL_FRAME_SHIFT) | + (0x05 << TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_NEW_FRAME_SHIFT) | + (0x03 << TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_RETRY_FRAME_SHIFT)); + + cec_write(cec, TEGRA_CEC_INT_MASK, + TEGRA_CEC_INT_MASK_TX_REGISTER_UNDERRUN | + TEGRA_CEC_INT_MASK_TX_FRAME_OR_BLOCK_NAKD | + TEGRA_CEC_INT_MASK_TX_ARBITRATION_FAILED | + TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED | + TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED | + TEGRA_CEC_INT_MASK_RX_REGISTER_FULL | + TEGRA_CEC_INT_MASK_RX_REGISTER_OVERRUN); + + cec_write(cec, TEGRA_CEC_HW_CONTROL, TEGRA_CEC_HWCTRL_TX_RX_MODE); + return 0; +} + +static int tegra_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr) +{ + struct tegra_cec *cec = adap->priv; + u32 state = cec_read(cec, TEGRA_CEC_HW_CONTROL); + + if (logical_addr == CEC_LOG_ADDR_INVALID) + state &= ~TEGRA_CEC_HWCTRL_RX_LADDR_MASK; + else + state |= TEGRA_CEC_HWCTRL_RX_LADDR((1 << logical_addr)); + + cec_write(cec, TEGRA_CEC_HW_CONTROL, state); + return 0; +} + +static int tegra_cec_adap_monitor_all_enable(struct cec_adapter *adap, + bool enable) +{ + struct tegra_cec *cec = adap->priv; + u32 reg = cec_read(cec, TEGRA_CEC_HW_CONTROL); + + if (enable) + reg |= TEGRA_CEC_HWCTRL_RX_SNOOP; + else + reg &= ~TEGRA_CEC_HWCTRL_RX_SNOOP; + cec_write(cec, TEGRA_CEC_HW_CONTROL, reg); + return 0; +} + +static int tegra_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time_ms, struct cec_msg *msg) +{ + bool retry_xfer = signal_free_time_ms == CEC_SIGNAL_FREE_TIME_RETRY; + struct tegra_cec *cec = adap->priv; + unsigned int i; + u32 mode = 0; + u32 mask; + + if (cec_msg_is_broadcast(msg)) + mode = TEGRA_CEC_TX_REG_BCAST; + + cec->tx_buf_cur = 0; + cec->tx_buf_cnt = msg->len; + + for (i = 0; i < msg->len; i++) { + cec->tx_buf[i] = mode | msg->msg[i]; + if (i == 0) + cec->tx_buf[i] |= TEGRA_CEC_TX_REG_START_BIT; + if (i == msg->len - 1) + cec->tx_buf[i] |= TEGRA_CEC_TX_REG_EOM; + if (i == 0 && retry_xfer) + cec->tx_buf[i] |= TEGRA_CEC_TX_REG_RETRY; + } + + mask = cec_read(cec, TEGRA_CEC_INT_MASK); + cec_write(cec, TEGRA_CEC_INT_MASK, + mask | TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY); + + return 0; +} + +static const struct cec_adap_ops tegra_cec_ops = { + .adap_enable = tegra_cec_adap_enable, + .adap_log_addr = tegra_cec_adap_log_addr, + .adap_transmit = tegra_cec_adap_transmit, + .adap_monitor_all_enable = tegra_cec_adap_monitor_all_enable, +}; + +static int tegra_cec_probe(struct platform_device *pdev) +{ + struct platform_device *hdmi_dev; + struct device_node *np; + struct tegra_cec *cec; + struct resource *res; + int ret = 0; + + np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0); + + if (!np) { + dev_err(&pdev->dev, "Failed to find hdmi node in device tree\n"); + return -ENODEV; + } + hdmi_dev = of_find_device_by_node(np); + if (hdmi_dev == NULL) + return -EPROBE_DEFER; + + cec = devm_kzalloc(&pdev->dev, sizeof(struct tegra_cec), GFP_KERNEL); + + if (!cec) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!res) { + dev_err(&pdev->dev, + "Unable to allocate resources for device\n"); + ret = -EBUSY; + goto cec_error; + } + + if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), + pdev->name)) { + dev_err(&pdev->dev, + "Unable to request mem region for device\n"); + ret = -EBUSY; + goto cec_error; + } + + cec->tegra_cec_irq = platform_get_irq(pdev, 0); + + if (cec->tegra_cec_irq <= 0) { + ret = -EBUSY; + goto cec_error; + } + + cec->cec_base = devm_ioremap_nocache(&pdev->dev, res->start, + resource_size(res)); + + if (!cec->cec_base) { + dev_err(&pdev->dev, "Unable to grab IOs for device\n"); + ret = -EBUSY; + goto cec_error; + } + + cec->clk = devm_clk_get(&pdev->dev, "cec"); + + if (IS_ERR_OR_NULL(cec->clk)) { + dev_err(&pdev->dev, "Can't get clock for CEC\n"); + ret = -ENOENT; + goto clk_error; + } + + clk_prepare_enable(cec->clk); + + /* set context info. */ + cec->dev = &pdev->dev; + + platform_set_drvdata(pdev, cec); + + ret = devm_request_threaded_irq(&pdev->dev, cec->tegra_cec_irq, + tegra_cec_irq_handler, tegra_cec_irq_thread_handler, + 0, "cec_irq", &pdev->dev); + + if (ret) { + dev_err(&pdev->dev, + "Unable to request interrupt for device\n"); + goto cec_error; + } + + cec->notifier = cec_notifier_get(&hdmi_dev->dev); + if (!cec->notifier) { + ret = -ENOMEM; + goto cec_error; + } + + cec->adap = cec_allocate_adapter(&tegra_cec_ops, cec, TEGRA_CEC_NAME, + CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL, + CEC_MAX_LOG_ADDRS); + if (IS_ERR(cec->adap)) { + ret = -ENOMEM; + dev_err(&pdev->dev, "Couldn't create cec adapter\n"); + goto cec_error; + } + ret = cec_register_adapter(cec->adap, &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Couldn't register device\n"); + goto cec_error; + } + + cec_register_cec_notifier(cec->adap, cec->notifier); + + return 0; + +cec_error: + if (cec->notifier) + cec_notifier_put(cec->notifier); + cec_delete_adapter(cec->adap); + clk_disable_unprepare(cec->clk); +clk_error: + return ret; +} + +static int tegra_cec_remove(struct platform_device *pdev) +{ + struct tegra_cec *cec = platform_get_drvdata(pdev); + + clk_disable_unprepare(cec->clk); + + cec_unregister_adapter(cec->adap); + cec_notifier_put(cec->notifier); + + return 0; +} + +#ifdef CONFIG_PM +static int tegra_cec_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct tegra_cec *cec = platform_get_drvdata(pdev); + + clk_disable_unprepare(cec->clk); + + dev_notice(&pdev->dev, "suspended\n"); + return 0; +} + +static int tegra_cec_resume(struct platform_device *pdev) +{ + struct tegra_cec *cec = platform_get_drvdata(pdev); + + dev_notice(&pdev->dev, "Resuming\n"); + + clk_prepare_enable(cec->clk); + + return 0; +} +#endif + +static const struct of_device_id tegra_cec_of_match[] = { + { .compatible = "nvidia,tegra114-cec", }, + { .compatible = "nvidia,tegra124-cec", }, + { .compatible = "nvidia,tegra210-cec", }, + {}, +}; + +static struct platform_driver tegra_cec_driver = { + .driver = { + .name = TEGRA_CEC_NAME, + .of_match_table = of_match_ptr(tegra_cec_of_match), + }, + .probe = tegra_cec_probe, + .remove = tegra_cec_remove, + +#ifdef CONFIG_PM + .suspend = tegra_cec_suspend, + .resume = tegra_cec_resume, +#endif +}; + +module_platform_driver(tegra_cec_driver); diff --git a/drivers/media/platform/tegra-cec/tegra_cec.h b/drivers/media/platform/tegra-cec/tegra_cec.h new file mode 100644 index 000000000000..e301513daa87 --- /dev/null +++ b/drivers/media/platform/tegra-cec/tegra_cec.h @@ -0,0 +1,127 @@ +/* + * Tegra CEC register definitions + * + * The original 3.10 CEC driver using a custom API: + * + * Copyright (c) 2012-2015, NVIDIA CORPORATION. All rights reserved. + * + * Conversion to the CEC framework and to the mainline kernel: + * + * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TEGRA_CEC_H +#define TEGRA_CEC_H + +/* CEC registers */ +#define TEGRA_CEC_SW_CONTROL 0x000 +#define TEGRA_CEC_HW_CONTROL 0x004 +#define TEGRA_CEC_INPUT_FILTER 0x008 +#define TEGRA_CEC_TX_REGISTER 0x010 +#define TEGRA_CEC_RX_REGISTER 0x014 +#define TEGRA_CEC_RX_TIMING_0 0x018 +#define TEGRA_CEC_RX_TIMING_1 0x01c +#define TEGRA_CEC_RX_TIMING_2 0x020 +#define TEGRA_CEC_TX_TIMING_0 0x024 +#define TEGRA_CEC_TX_TIMING_1 0x028 +#define TEGRA_CEC_TX_TIMING_2 0x02c +#define TEGRA_CEC_INT_STAT 0x030 +#define TEGRA_CEC_INT_MASK 0x034 +#define TEGRA_CEC_HW_DEBUG_RX 0x038 +#define TEGRA_CEC_HW_DEBUG_TX 0x03c + +#define TEGRA_CEC_HWCTRL_RX_LADDR_MASK 0x7fff +#define TEGRA_CEC_HWCTRL_RX_LADDR(x) \ + ((x) & TEGRA_CEC_HWCTRL_RX_LADDR_MASK) +#define TEGRA_CEC_HWCTRL_RX_SNOOP (1 << 15) +#define TEGRA_CEC_HWCTRL_RX_NAK_MODE (1 << 16) +#define TEGRA_CEC_HWCTRL_TX_NAK_MODE (1 << 24) +#define TEGRA_CEC_HWCTRL_FAST_SIM_MODE (1 << 30) +#define TEGRA_CEC_HWCTRL_TX_RX_MODE (1 << 31) + +#define TEGRA_CEC_INPUT_FILTER_MODE (1 << 31) +#define TEGRA_CEC_INPUT_FILTER_FIFO_LENGTH_SHIFT 0 + +#define TEGRA_CEC_TX_REG_DATA_SHIFT 0 +#define TEGRA_CEC_TX_REG_EOM (1 << 8) +#define TEGRA_CEC_TX_REG_BCAST (1 << 12) +#define TEGRA_CEC_TX_REG_START_BIT (1 << 16) +#define TEGRA_CEC_TX_REG_RETRY (1 << 17) + +#define TEGRA_CEC_RX_REGISTER_SHIFT 0 +#define TEGRA_CEC_RX_REGISTER_EOM (1 << 8) +#define TEGRA_CEC_RX_REGISTER_ACK (1 << 9) + +#define TEGRA_CEC_RX_TIM0_START_BIT_MAX_LO_TIME_SHIFT 0 +#define TEGRA_CEC_RX_TIM0_START_BIT_MIN_LO_TIME_SHIFT 8 +#define TEGRA_CEC_RX_TIM0_START_BIT_MAX_DURATION_SHIFT 16 +#define TEGRA_CEC_RX_TIM0_START_BIT_MIN_DURATION_SHIFT 24 + +#define TEGRA_CEC_RX_TIM1_DATA_BIT_MAX_LO_TIME_SHIFT 0 +#define TEGRA_CEC_RX_TIM1_DATA_BIT_SAMPLE_TIME_SHIFT 8 +#define TEGRA_CEC_RX_TIM1_DATA_BIT_MAX_DURATION_SHIFT 16 +#define TEGRA_CEC_RX_TIM1_DATA_BIT_MIN_DURATION_SHIFT 24 + +#define TEGRA_CEC_RX_TIM2_END_OF_BLOCK_TIME_SHIFT 0 + +#define TEGRA_CEC_TX_TIM0_START_BIT_LO_TIME_SHIFT 0 +#define TEGRA_CEC_TX_TIM0_START_BIT_DURATION_SHIFT 8 +#define TEGRA_CEC_TX_TIM0_BUS_XITION_TIME_SHIFT 16 +#define TEGRA_CEC_TX_TIM0_BUS_ERROR_LO_TIME_SHIFT 24 + +#define TEGRA_CEC_TX_TIM1_LO_DATA_BIT_LO_TIME_SHIFT 0 +#define TEGRA_CEC_TX_TIM1_HI_DATA_BIT_LO_TIME_SHIFT 8 +#define TEGRA_CEC_TX_TIM1_DATA_BIT_DURATION_SHIFT 16 +#define TEGRA_CEC_TX_TIM1_ACK_NAK_BIT_SAMPLE_TIME_SHIFT 24 + +#define TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_ADDITIONAL_FRAME_SHIFT 0 +#define TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_NEW_FRAME_SHIFT 4 +#define TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_RETRY_FRAME_SHIFT 8 + +#define TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY (1 << 0) +#define TEGRA_CEC_INT_STAT_TX_REGISTER_UNDERRUN (1 << 1) +#define TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD (1 << 2) +#define TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED (1 << 3) +#define TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED (1 << 4) +#define TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED (1 << 5) +#define TEGRA_CEC_INT_STAT_RX_REGISTER_FULL (1 << 8) +#define TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN (1 << 9) +#define TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED (1 << 10) +#define TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED (1 << 11) +#define TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED (1 << 12) +#define TEGRA_CEC_INT_STAT_FILTERED_RX_DATA_PIN_TRANSITION_H2L (1 << 13) +#define TEGRA_CEC_INT_STAT_FILTERED_RX_DATA_PIN_TRANSITION_L2H (1 << 14) + +#define TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY (1 << 0) +#define TEGRA_CEC_INT_MASK_TX_REGISTER_UNDERRUN (1 << 1) +#define TEGRA_CEC_INT_MASK_TX_FRAME_OR_BLOCK_NAKD (1 << 2) +#define TEGRA_CEC_INT_MASK_TX_ARBITRATION_FAILED (1 << 3) +#define TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED (1 << 4) +#define TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED (1 << 5) +#define TEGRA_CEC_INT_MASK_RX_REGISTER_FULL (1 << 8) +#define TEGRA_CEC_INT_MASK_RX_REGISTER_OVERRUN (1 << 9) +#define TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED (1 << 10) +#define TEGRA_CEC_INT_MASK_RX_BUS_ANOMALY_DETECTED (1 << 11) +#define TEGRA_CEC_INT_MASK_RX_BUS_ERROR_DETECTED (1 << 12) +#define TEGRA_CEC_INT_MASK_FILTERED_RX_DATA_PIN_TRANSITION_H2L (1 << 13) +#define TEGRA_CEC_INT_MASK_FILTERED_RX_DATA_PIN_TRANSITION_L2H (1 << 14) + +#define TEGRA_CEC_HW_DEBUG_TX_DURATION_COUNT_SHIFT 0 +#define TEGRA_CEC_HW_DEBUG_TX_TXBIT_COUNT_SHIFT 17 +#define TEGRA_CEC_HW_DEBUG_TX_STATE_SHIFT 21 +#define TEGRA_CEC_HW_DEBUG_TX_FORCELOOUT (1 << 25) +#define TEGRA_CEC_HW_DEBUG_TX_TXDATABIT_SAMPLE_TIMER (1 << 26) + +#endif /* TEGRA_CEC_H */ -- cgit v1.2.3 From ec62464e83beacd8b8856e8313a4cae4a91ea90b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 31 Oct 2017 05:32:02 -0400 Subject: media: atmel-isc: get rid of an unused var drivers/media/platform/atmel/atmel-isc.c: In function 'isc_async_complete': drivers/media/platform/atmel/atmel-isc.c:1900:28: warning: variable 'sd_entity' set but not used [-Wunused-but-set-variable] struct isc_subdev_entity *sd_entity; ^~~~~~~~~ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 2c40a7886542..8b37656f035d 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -1897,7 +1897,6 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) { struct isc_device *isc = container_of(notifier->v4l2_dev, struct isc_device, v4l2_dev); - struct isc_subdev_entity *sd_entity; struct video_device *vdev = &isc->video_dev; struct vb2_queue *q = &isc->vb2_vidq; int ret; @@ -1910,8 +1909,6 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) isc->current_subdev = container_of(notifier, struct isc_subdev_entity, notifier); - sd_entity = isc->current_subdev; - mutex_init(&isc->lock); init_completion(&isc->comp); -- cgit v1.2.3 From bfba2b3e21b9426c0f9aca00f3cad8631b2da170 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 24 Sep 2017 05:00:57 -0400 Subject: media: omap_vout: Fix a possible null pointer dereference in omap_vout_open() Move a debug message so that a null pointer access can not happen for the variable "vout" in this function. Fixes: 5c7ab6348e7b3fcca2b8ee548306c774472971e2 ("V4L/DVB: V4L2: Add support for OMAP2/3 V4L2 display driver on top of DSS2") Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap/omap_vout.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index 4d29860d27b4..6f1b0c799e58 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -1004,11 +1004,12 @@ static int omap_vout_open(struct file *file) struct omap_vout_device *vout = NULL; vout = video_drvdata(file); - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__); if (vout == NULL) return -ENODEV; + v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__); + /* for now, we only support single open */ if (vout->opened) return -EBUSY; -- cgit v1.2.3 From 1e6be014466e07d3ba95b396d0ea64d11ac0a79d Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Tue, 17 Oct 2017 08:27:24 -0400 Subject: media: davinci: make function arguments const Make the function arguments of functions vpfe_{register/unregister}_ccdc_device const as the pointer dev does not modify the fields of the structure it points to. Also, declare the variable ccdc_dev const as it points to the same structure as dev but it does not modify the fields as well. Signed-off-by: Bhumika Goyal Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/ccdc_hw_device.h | 4 ++-- drivers/media/platform/davinci/vpfe_capture.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/davinci/ccdc_hw_device.h b/drivers/media/platform/davinci/ccdc_hw_device.h index f1b521045d64..3482178cbf01 100644 --- a/drivers/media/platform/davinci/ccdc_hw_device.h +++ b/drivers/media/platform/davinci/ccdc_hw_device.h @@ -82,8 +82,8 @@ struct ccdc_hw_device { }; /* Used by CCDC module to register & unregister with vpfe capture driver */ -int vpfe_register_ccdc_device(struct ccdc_hw_device *dev); -void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev); +int vpfe_register_ccdc_device(const struct ccdc_hw_device *dev); +void vpfe_unregister_ccdc_device(const struct ccdc_hw_device *dev); #endif #endif diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 6792da16d9c7..7b3f6f8e3dc8 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -115,7 +115,7 @@ static struct vpfe_config_params config_params = { }; /* ccdc device registered */ -static struct ccdc_hw_device *ccdc_dev; +static const struct ccdc_hw_device *ccdc_dev; /* lock for accessing ccdc information */ static DEFINE_MUTEX(ccdc_lock); /* ccdc configuration */ @@ -203,7 +203,7 @@ static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format) * vpfe_register_ccdc_device. CCDC module calls this to * register with vpfe capture */ -int vpfe_register_ccdc_device(struct ccdc_hw_device *dev) +int vpfe_register_ccdc_device(const struct ccdc_hw_device *dev) { int ret = 0; printk(KERN_NOTICE "vpfe_register_ccdc_device: %s\n", dev->name); @@ -259,7 +259,7 @@ EXPORT_SYMBOL(vpfe_register_ccdc_device); * vpfe_unregister_ccdc_device. CCDC module calls this to * unregister with vpfe capture */ -void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev) +void vpfe_unregister_ccdc_device(const struct ccdc_hw_device *dev) { if (!dev) { printk(KERN_ERR "invalid ccdc device ptr\n"); -- cgit v1.2.3 From 0cba3f438cd6154621a3b4d66e0875ba213cd7ab Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Tue, 17 Oct 2017 08:27:25 -0400 Subject: media: davinci: make ccdc_hw_device structures const Make these structures const as they are only getting passed to the functions vpfe_{register/unregister}_ccdc_device having the argument as const. Structures found using Coccinelle and changes done by hand. Signed-off-by: Bhumika Goyal Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/dm355_ccdc.c | 2 +- drivers/media/platform/davinci/dm644x_ccdc.c | 2 +- drivers/media/platform/davinci/isif.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/davinci/dm355_ccdc.c b/drivers/media/platform/davinci/dm355_ccdc.c index 6d492dc4c3a9..89cb3094d7e6 100644 --- a/drivers/media/platform/davinci/dm355_ccdc.c +++ b/drivers/media/platform/davinci/dm355_ccdc.c @@ -841,7 +841,7 @@ static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) return 0; } -static struct ccdc_hw_device ccdc_hw_dev = { +static const struct ccdc_hw_device ccdc_hw_dev = { .name = "DM355 CCDC", .owner = THIS_MODULE, .hw_ops = { diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c index 3b2d8a9317b8..5fa0a1f32536 100644 --- a/drivers/media/platform/davinci/dm644x_ccdc.c +++ b/drivers/media/platform/davinci/dm644x_ccdc.c @@ -776,7 +776,7 @@ static void ccdc_restore_context(void) regw(ccdc_ctx[CCDC_VP_OUT >> 2], CCDC_VP_OUT); regw(ccdc_ctx[CCDC_PCR >> 2], CCDC_PCR); } -static struct ccdc_hw_device ccdc_hw_dev = { +static const struct ccdc_hw_device ccdc_hw_dev = { .name = "DM6446 CCDC", .owner = THIS_MODULE, .hw_ops = { diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c index 5813b49391ed..d5ff58494c1e 100644 --- a/drivers/media/platform/davinci/isif.c +++ b/drivers/media/platform/davinci/isif.c @@ -1000,7 +1000,7 @@ static int isif_close(struct device *device) return 0; } -static struct ccdc_hw_device isif_hw_dev = { +static const struct ccdc_hw_device isif_hw_dev = { .name = "ISIF", .owner = THIS_MODULE, .hw_ops = { -- cgit v1.2.3 From 94b28441c9c7168bfdef932703f968a43ba77f97 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 19 Oct 2017 05:30:34 -0400 Subject: media: rockchip/rga: annotate PM functions as __maybe_unused The newly added driver has incorrect #ifdef annotations on its PM functions, leading to a harmless compile-time warning when CONFIG_PM is disabled: drivers/media/platform/rockchip/rga/rga.c:760:13: error: 'rga_disable_clocks' defined but not used [-Werror=unused-function] static void rga_disable_clocks(struct rockchip_rga *rga) ^~~~~~~~~~~~~~~~~~ drivers/media/platform/rockchip/rga/rga.c:728:12: error: 'rga_enable_clocks' defined but not used [-Werror=unused-function] This removes the #ifdef and marks the functions as __maybe_unused, so gcc can silently drop all the unused code. Fixes: f7e7b48e6d79 ("[media] rockchip/rga: v4l2 m2m support") Signed-off-by: Arnd Bergmann Acked-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rga/rga.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index e7d1b34baf1c..89296de9cf4a 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -960,8 +960,7 @@ static int rga_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int rga_runtime_suspend(struct device *dev) +static int __maybe_unused rga_runtime_suspend(struct device *dev) { struct rockchip_rga *rga = dev_get_drvdata(dev); @@ -970,13 +969,12 @@ static int rga_runtime_suspend(struct device *dev) return 0; } -static int rga_runtime_resume(struct device *dev) +static int __maybe_unused rga_runtime_resume(struct device *dev) { struct rockchip_rga *rga = dev_get_drvdata(dev); return rga_enable_clocks(rga); } -#endif static const struct dev_pm_ops rga_pm = { SET_RUNTIME_PM_OPS(rga_runtime_suspend, -- cgit v1.2.3 From 3ddad1ae10c23a700e060edab11eb13ec01ea380 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 21 Oct 2017 04:37:49 -0400 Subject: media: tegra-cec: fix messy probe() cleanup The probe() cleanup code ('goto foo_error') was very messy. It appears that this code wasn't updated when I switched to the devm_ functions in an earlier version. Update the code to use 'return error' where it can and do proper cleanup where it needs to. Note that the original code wasn't buggy, it was just messy. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/tegra-cec/tegra_cec.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/tegra-cec/tegra_cec.c b/drivers/media/platform/tegra-cec/tegra_cec.c index b53743f555e8..807c94c70049 100644 --- a/drivers/media/platform/tegra-cec/tegra_cec.c +++ b/drivers/media/platform/tegra-cec/tegra_cec.c @@ -356,40 +356,34 @@ static int tegra_cec_probe(struct platform_device *pdev) if (!res) { dev_err(&pdev->dev, "Unable to allocate resources for device\n"); - ret = -EBUSY; - goto cec_error; + return -EBUSY; } if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), pdev->name)) { dev_err(&pdev->dev, "Unable to request mem region for device\n"); - ret = -EBUSY; - goto cec_error; + return -EBUSY; } cec->tegra_cec_irq = platform_get_irq(pdev, 0); - if (cec->tegra_cec_irq <= 0) { - ret = -EBUSY; - goto cec_error; - } + if (cec->tegra_cec_irq <= 0) + return -EBUSY; cec->cec_base = devm_ioremap_nocache(&pdev->dev, res->start, - resource_size(res)); + resource_size(res)); if (!cec->cec_base) { dev_err(&pdev->dev, "Unable to grab IOs for device\n"); - ret = -EBUSY; - goto cec_error; + return -EBUSY; } cec->clk = devm_clk_get(&pdev->dev, "cec"); if (IS_ERR_OR_NULL(cec->clk)) { dev_err(&pdev->dev, "Can't get clock for CEC\n"); - ret = -ENOENT; - goto clk_error; + return -ENOENT; } clk_prepare_enable(cec->clk); @@ -406,13 +400,13 @@ static int tegra_cec_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "Unable to request interrupt for device\n"); - goto cec_error; + goto clk_error; } cec->notifier = cec_notifier_get(&hdmi_dev->dev); if (!cec->notifier) { ret = -ENOMEM; - goto cec_error; + goto clk_error; } cec->adap = cec_allocate_adapter(&tegra_cec_ops, cec, TEGRA_CEC_NAME, @@ -437,8 +431,8 @@ cec_error: if (cec->notifier) cec_notifier_put(cec->notifier); cec_delete_adapter(cec->adap); - clk_disable_unprepare(cec->clk); clk_error: + clk_disable_unprepare(cec->clk); return ret; } -- cgit v1.2.3 From da6a7a7806dfec0d7358bba474084abba03046a3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 28 Oct 2017 05:19:50 -0400 Subject: media: camss-video.c: drop unused header Drop unused vb1 header. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss-8x16/camss-video.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/qcom/camss-8x16/camss-video.c b/drivers/media/platform/qcom/camss-8x16/camss-video.c index cf4219e871bd..ffaa2849e0c1 100644 --- a/drivers/media/platform/qcom/camss-8x16/camss-video.c +++ b/drivers/media/platform/qcom/camss-8x16/camss-video.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include "camss-video.h" -- cgit v1.2.3 From bf3881707b6f6350c3f8f8ff15524b6d719847bc Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 29 Oct 2017 09:43:39 -0400 Subject: media: bdisp: remove redundant assignment to pix Pointer pix is being initialized to a value and a little later being assigned the same value again. Remove the initial assignment to avoid a duplicate assignment. Cleans up the clang warning: drivers/media/platform/sti/bdisp/bdisp-v4l2.c:726:26: warning: Value stored to 'pix' during its initialization is never read Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/bdisp/bdisp-v4l2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c index 939da6da7644..7e9ed9c7b3e1 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c @@ -723,7 +723,7 @@ static int bdisp_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) static int bdisp_g_fmt(struct file *file, void *fh, struct v4l2_format *f) { struct bdisp_ctx *ctx = fh_to_ctx(fh); - struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_pix_format *pix; struct bdisp_frame *frame = ctx_get_frame(ctx, f->type); if (IS_ERR(frame)) { -- cgit v1.2.3 From d7ca1c9c15e309344e8dcd19826434359dff33b7 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Sun, 29 Oct 2017 20:46:50 -0400 Subject: media: atmel-isc: Fix clock ID for clk_prepare/unprepare Fix the clock ID to do the runtime pm should be ISC_ISPCK, instead of ISC_MCK in clk_prepare(), clk_unprepare() and isc_clk_is_enabled(). Signed-off-by: Wenyou Yang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 8b37656f035d..30f2867c2932 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -598,7 +598,7 @@ static int isc_clk_prepare(struct clk_hw *hw) { struct isc_clk *isc_clk = to_isc_clk(hw); - if (isc_clk->id == ISC_MCK) + if (isc_clk->id == ISC_ISPCK) pm_runtime_get_sync(isc_clk->dev); return isc_wait_clk_stable(hw); @@ -610,7 +610,7 @@ static void isc_clk_unprepare(struct clk_hw *hw) isc_wait_clk_stable(hw); - if (isc_clk->id == ISC_MCK) + if (isc_clk->id == ISC_ISPCK) pm_runtime_put_sync(isc_clk->dev); } @@ -657,12 +657,12 @@ static int isc_clk_is_enabled(struct clk_hw *hw) struct isc_clk *isc_clk = to_isc_clk(hw); u32 status; - if (isc_clk->id == ISC_MCK) + if (isc_clk->id == ISC_ISPCK) pm_runtime_get_sync(isc_clk->dev); regmap_read(isc_clk->regmap, ISC_CLKSR, &status); - if (isc_clk->id == ISC_MCK) + if (isc_clk->id == ISC_ISPCK) pm_runtime_put_sync(isc_clk->dev); return status & ISC_CLK(isc_clk->id) ? 1 : 0; -- cgit v1.2.3 From 3fa013be95bb046490d3b11d546bf06d73c7e0e3 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 30 Oct 2017 00:18:47 -0400 Subject: media: st-hva: hva-h264: use swap macro in hva_h264_encode Make use of the swap macro and remove unnecessary variable tmp_frame. This makes the code easier to read and maintain. This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/hva/hva-h264.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sti/hva/hva-h264.c b/drivers/media/platform/sti/hva/hva-h264.c index e6f247a983c7..a7e5eed17ada 100644 --- a/drivers/media/platform/sti/hva/hva-h264.c +++ b/drivers/media/platform/sti/hva/hva-h264.c @@ -999,7 +999,6 @@ static int hva_h264_encode(struct hva_ctx *pctx, struct hva_frame *frame, { struct hva_h264_ctx *ctx = (struct hva_h264_ctx *)pctx->priv; struct hva_h264_task *task = (struct hva_h264_task *)ctx->task->vaddr; - struct hva_buffer *tmp_frame; u32 stuffing_bytes = 0; int ret = 0; @@ -1023,9 +1022,7 @@ static int hva_h264_encode(struct hva_ctx *pctx, struct hva_frame *frame, &stream->bytesused); /* switch reference & reconstructed frame */ - tmp_frame = ctx->ref_frame; - ctx->ref_frame = ctx->rec_frame; - ctx->rec_frame = tmp_frame; + swap(ctx->ref_frame, ctx->rec_frame); return 0; err: -- cgit v1.2.3 From df4975663f2002f6e6ce9a203f63bfcc51742732 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 1 Sep 2017 17:56:32 -0400 Subject: media: omap3isp: Use generic parser for parsing fwnode endpoints Instead of using a custom driver implementation, use v4l2_async_notifier_parse_fwnode_endpoints() to parse the fwnode endpoints of the device. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Reviewed-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 121 +++++++++++----------------------- drivers/media/platform/omap3isp/isp.h | 5 +- 2 files changed, 40 insertions(+), 86 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 1a428fe9f070..97a5206b6ddc 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -2001,6 +2001,7 @@ static int isp_remove(struct platform_device *pdev) __omap3isp_put(isp, false); media_entity_enum_cleanup(&isp->crashed); + v4l2_async_notifier_cleanup(&isp->notifier); return 0; } @@ -2011,44 +2012,41 @@ enum isp_of_phy { ISP_OF_PHY_CSIPHY2, }; -static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode, - struct isp_async_subdev *isd) +static int isp_fwnode_parse(struct device *dev, + struct v4l2_fwnode_endpoint *vep, + struct v4l2_async_subdev *asd) { + struct isp_async_subdev *isd = + container_of(asd, struct isp_async_subdev, asd); struct isp_bus_cfg *buscfg = &isd->bus; - struct v4l2_fwnode_endpoint vep; - unsigned int i; - int ret; bool csi1 = false; - - ret = v4l2_fwnode_endpoint_parse(fwnode, &vep); - if (ret) - return ret; + unsigned int i; dev_dbg(dev, "parsing endpoint %pOF, interface %u\n", - to_of_node(fwnode), vep.base.port); + to_of_node(vep->base.local_fwnode), vep->base.port); - switch (vep.base.port) { + switch (vep->base.port) { case ISP_OF_PHY_PARALLEL: buscfg->interface = ISP_INTERFACE_PARALLEL; buscfg->bus.parallel.data_lane_shift = - vep.bus.parallel.data_shift; + vep->bus.parallel.data_shift; buscfg->bus.parallel.clk_pol = - !!(vep.bus.parallel.flags + !!(vep->bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_FALLING); buscfg->bus.parallel.hs_pol = - !!(vep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW); + !!(vep->bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW); buscfg->bus.parallel.vs_pol = - !!(vep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW); + !!(vep->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW); buscfg->bus.parallel.fld_pol = - !!(vep.bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW); + !!(vep->bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW); buscfg->bus.parallel.data_pol = - !!(vep.bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW); - buscfg->bus.parallel.bt656 = vep.bus_type == V4L2_MBUS_BT656; + !!(vep->bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW); + buscfg->bus.parallel.bt656 = vep->bus_type == V4L2_MBUS_BT656; break; case ISP_OF_PHY_CSIPHY1: case ISP_OF_PHY_CSIPHY2: - switch (vep.bus_type) { + switch (vep->bus_type) { case V4L2_MBUS_CCP2: case V4L2_MBUS_CSI1: dev_dbg(dev, "CSI-1/CCP-2 configuration\n"); @@ -2060,11 +2058,11 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode, break; default: dev_err(dev, "unsupported bus type %u\n", - vep.bus_type); + vep->bus_type); return -EINVAL; } - switch (vep.base.port) { + switch (vep->base.port) { case ISP_OF_PHY_CSIPHY1: if (csi1) buscfg->interface = ISP_INTERFACE_CCP2B_PHY1; @@ -2080,47 +2078,47 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode, } if (csi1) { buscfg->bus.ccp2.lanecfg.clk.pos = - vep.bus.mipi_csi1.clock_lane; + vep->bus.mipi_csi1.clock_lane; buscfg->bus.ccp2.lanecfg.clk.pol = - vep.bus.mipi_csi1.lane_polarity[0]; + vep->bus.mipi_csi1.lane_polarity[0]; dev_dbg(dev, "clock lane polarity %u, pos %u\n", buscfg->bus.ccp2.lanecfg.clk.pol, buscfg->bus.ccp2.lanecfg.clk.pos); buscfg->bus.ccp2.lanecfg.data[0].pos = - vep.bus.mipi_csi1.data_lane; + vep->bus.mipi_csi1.data_lane; buscfg->bus.ccp2.lanecfg.data[0].pol = - vep.bus.mipi_csi1.lane_polarity[1]; + vep->bus.mipi_csi1.lane_polarity[1]; dev_dbg(dev, "data lane polarity %u, pos %u\n", buscfg->bus.ccp2.lanecfg.data[0].pol, buscfg->bus.ccp2.lanecfg.data[0].pos); buscfg->bus.ccp2.strobe_clk_pol = - vep.bus.mipi_csi1.clock_inv; - buscfg->bus.ccp2.phy_layer = vep.bus.mipi_csi1.strobe; + vep->bus.mipi_csi1.clock_inv; + buscfg->bus.ccp2.phy_layer = vep->bus.mipi_csi1.strobe; buscfg->bus.ccp2.ccp2_mode = - vep.bus_type == V4L2_MBUS_CCP2; + vep->bus_type == V4L2_MBUS_CCP2; buscfg->bus.ccp2.vp_clk_pol = 1; buscfg->bus.ccp2.crc = 1; } else { buscfg->bus.csi2.lanecfg.clk.pos = - vep.bus.mipi_csi2.clock_lane; + vep->bus.mipi_csi2.clock_lane; buscfg->bus.csi2.lanecfg.clk.pol = - vep.bus.mipi_csi2.lane_polarities[0]; + vep->bus.mipi_csi2.lane_polarities[0]; dev_dbg(dev, "clock lane polarity %u, pos %u\n", buscfg->bus.csi2.lanecfg.clk.pol, buscfg->bus.csi2.lanecfg.clk.pos); buscfg->bus.csi2.num_data_lanes = - vep.bus.mipi_csi2.num_data_lanes; + vep->bus.mipi_csi2.num_data_lanes; for (i = 0; i < buscfg->bus.csi2.num_data_lanes; i++) { buscfg->bus.csi2.lanecfg.data[i].pos = - vep.bus.mipi_csi2.data_lanes[i]; + vep->bus.mipi_csi2.data_lanes[i]; buscfg->bus.csi2.lanecfg.data[i].pol = - vep.bus.mipi_csi2.lane_polarities[i + 1]; + vep->bus.mipi_csi2.lane_polarities[i + 1]; dev_dbg(dev, "data lane %u polarity %u, pos %u\n", i, buscfg->bus.csi2.lanecfg.data[i].pol, @@ -2137,57 +2135,13 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode, default: dev_warn(dev, "%pOF: invalid interface %u\n", - to_of_node(fwnode), vep.base.port); + to_of_node(vep->base.local_fwnode), vep->base.port); return -EINVAL; } return 0; } -static int isp_fwnodes_parse(struct device *dev, - struct v4l2_async_notifier *notifier) -{ - struct fwnode_handle *fwnode = NULL; - - notifier->subdevs = devm_kcalloc( - dev, ISP_MAX_SUBDEVS, sizeof(*notifier->subdevs), GFP_KERNEL); - if (!notifier->subdevs) - return -ENOMEM; - - while (notifier->num_subdevs < ISP_MAX_SUBDEVS && - (fwnode = fwnode_graph_get_next_endpoint( - of_fwnode_handle(dev->of_node), fwnode))) { - struct isp_async_subdev *isd; - - isd = devm_kzalloc(dev, sizeof(*isd), GFP_KERNEL); - if (!isd) - goto error; - - if (isp_fwnode_parse(dev, fwnode, isd)) { - devm_kfree(dev, isd); - continue; - } - - notifier->subdevs[notifier->num_subdevs] = &isd->asd; - - isd->asd.match.fwnode.fwnode = - fwnode_graph_get_remote_port_parent(fwnode); - if (!isd->asd.match.fwnode.fwnode) { - dev_warn(dev, "bad remote port parent\n"); - goto error; - } - - isd->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; - notifier->num_subdevs++; - } - - return notifier->num_subdevs; - -error: - fwnode_handle_put(fwnode); - return -EINVAL; -} - static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async) { struct isp_device *isp = container_of(async, struct isp_device, @@ -2256,15 +2210,17 @@ static int isp_probe(struct platform_device *pdev) if (ret) return ret; - ret = isp_fwnodes_parse(&pdev->dev, &isp->notifier); - if (ret < 0) - return ret; - isp->autoidle = autoidle; mutex_init(&isp->isp_mutex); spin_lock_init(&isp->stat_lock); + ret = v4l2_async_notifier_parse_fwnode_endpoints( + &pdev->dev, &isp->notifier, sizeof(struct isp_async_subdev), + isp_fwnode_parse); + if (ret < 0) + goto error; + isp->dev = &pdev->dev; isp->ref_count = 0; @@ -2406,6 +2362,7 @@ error_isp: isp_xclk_cleanup(isp); __omap3isp_put(isp, false); error: + v4l2_async_notifier_cleanup(&isp->notifier); mutex_destroy(&isp->isp_mutex); return ret; diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index e528df6efc09..8b9043db94b3 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h @@ -220,14 +220,11 @@ struct isp_device { unsigned int sbl_resources; unsigned int subclk_resources; - -#define ISP_MAX_SUBDEVS 8 - struct v4l2_subdev *subdevs[ISP_MAX_SUBDEVS]; }; struct isp_async_subdev { - struct isp_bus_cfg bus; struct v4l2_async_subdev asd; + struct isp_bus_cfg bus; }; #define v4l2_subdev_to_bus_cfg(sd) \ -- cgit v1.2.3 From 85999e8ec0ee7cf1039152b34a3fc3d91e7e27c3 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 1 Sep 2017 18:41:19 -0400 Subject: media: rcar-vin: Use generic parser for parsing fwnode endpoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using a custom driver implementation, use v4l2_async_notifier_parse_fwnode_endpoints() to parse the fwnode endpoints of the device. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Niklas Söderlund Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 107 +++++++++------------------- drivers/media/platform/rcar-vin/rcar-dma.c | 10 +-- drivers/media/platform/rcar-vin/rcar-v4l2.c | 14 ++-- drivers/media/platform/rcar-vin/rcar-vin.h | 4 +- 4 files changed, 46 insertions(+), 89 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 142de447aaaa..380288658601 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -21,6 +21,7 @@ #include #include +#include #include #include "rcar-vin.h" @@ -77,14 +78,14 @@ static int rvin_digital_notify_complete(struct v4l2_async_notifier *notifier) int ret; /* Verify subdevices mbus format */ - if (!rvin_mbus_supported(&vin->digital)) { + if (!rvin_mbus_supported(vin->digital)) { vin_err(vin, "Unsupported media bus format for %s\n", - vin->digital.subdev->name); + vin->digital->subdev->name); return -EINVAL; } vin_dbg(vin, "Found media bus format for %s: %d\n", - vin->digital.subdev->name, vin->digital.code); + vin->digital->subdev->name, vin->digital->code); ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev); if (ret < 0) { @@ -103,7 +104,7 @@ static void rvin_digital_notify_unbind(struct v4l2_async_notifier *notifier, vin_dbg(vin, "unbind digital subdev %s\n", subdev->name); rvin_v4l2_remove(vin); - vin->digital.subdev = NULL; + vin->digital->subdev = NULL; } static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier, @@ -120,117 +121,71 @@ static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier, ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SOURCE); if (ret < 0) return ret; - vin->digital.source_pad = ret; + vin->digital->source_pad = ret; ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SINK); - vin->digital.sink_pad = ret < 0 ? 0 : ret; + vin->digital->sink_pad = ret < 0 ? 0 : ret; - vin->digital.subdev = subdev; + vin->digital->subdev = subdev; vin_dbg(vin, "bound subdev %s source pad: %u sink pad: %u\n", - subdev->name, vin->digital.source_pad, - vin->digital.sink_pad); + subdev->name, vin->digital->source_pad, + vin->digital->sink_pad); return 0; } -static int rvin_digitial_parse_v4l2(struct rvin_dev *vin, - struct device_node *ep, - struct v4l2_mbus_config *mbus_cfg) +static int rvin_digital_parse_v4l2(struct device *dev, + struct v4l2_fwnode_endpoint *vep, + struct v4l2_async_subdev *asd) { - struct v4l2_fwnode_endpoint v4l2_ep; - int ret; + struct rvin_dev *vin = dev_get_drvdata(dev); + struct rvin_graph_entity *rvge = + container_of(asd, struct rvin_graph_entity, asd); - ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &v4l2_ep); - if (ret) { - vin_err(vin, "Could not parse v4l2 endpoint\n"); - return -EINVAL; - } + if (vep->base.port || vep->base.id) + return -ENOTCONN; - mbus_cfg->type = v4l2_ep.bus_type; + rvge->mbus_cfg.type = vep->bus_type; - switch (mbus_cfg->type) { + switch (rvge->mbus_cfg.type) { case V4L2_MBUS_PARALLEL: vin_dbg(vin, "Found PARALLEL media bus\n"); - mbus_cfg->flags = v4l2_ep.bus.parallel.flags; + rvge->mbus_cfg.flags = vep->bus.parallel.flags; break; case V4L2_MBUS_BT656: vin_dbg(vin, "Found BT656 media bus\n"); - mbus_cfg->flags = 0; + rvge->mbus_cfg.flags = 0; break; default: vin_err(vin, "Unknown media bus type\n"); return -EINVAL; } - return 0; -} - -static int rvin_digital_graph_parse(struct rvin_dev *vin) -{ - struct device_node *ep, *np; - int ret; - - vin->digital.asd.match.fwnode.fwnode = NULL; - vin->digital.subdev = NULL; - - /* - * Port 0 id 0 is local digital input, try to get it. - * Not all instances can or will have this, that is OK - */ - ep = of_graph_get_endpoint_by_regs(vin->dev->of_node, 0, 0); - if (!ep) - return 0; - - np = of_graph_get_remote_port_parent(ep); - if (!np) { - vin_err(vin, "No remote parent for digital input\n"); - of_node_put(ep); - return -EINVAL; - } - of_node_put(np); - - ret = rvin_digitial_parse_v4l2(vin, ep, &vin->digital.mbus_cfg); - of_node_put(ep); - if (ret) - return ret; - - vin->digital.asd.match.fwnode.fwnode = of_fwnode_handle(np); - vin->digital.asd.match_type = V4L2_ASYNC_MATCH_FWNODE; + vin->digital = rvge; return 0; } static int rvin_digital_graph_init(struct rvin_dev *vin) { - struct v4l2_async_subdev **subdevs = NULL; int ret; - ret = rvin_digital_graph_parse(vin); + ret = v4l2_async_notifier_parse_fwnode_endpoints( + vin->dev, &vin->notifier, + sizeof(struct rvin_graph_entity), rvin_digital_parse_v4l2); if (ret) return ret; - if (!vin->digital.asd.match.fwnode.fwnode) { - vin_dbg(vin, "No digital subdevice found\n"); + if (!vin->digital) return -ENODEV; - } - - /* Register the subdevices notifier. */ - subdevs = devm_kzalloc(vin->dev, sizeof(*subdevs), GFP_KERNEL); - if (subdevs == NULL) - return -ENOMEM; - - subdevs[0] = &vin->digital.asd; vin_dbg(vin, "Found digital subdevice %pOF\n", - to_of_node(subdevs[0]->match.fwnode.fwnode)); + to_of_node(vin->digital->asd.match.fwnode.fwnode)); - vin->notifier.num_subdevs = 1; - vin->notifier.subdevs = subdevs; vin->notifier.bound = rvin_digital_notify_bound; vin->notifier.unbind = rvin_digital_notify_unbind; vin->notifier.complete = rvin_digital_notify_complete; - ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier); if (ret < 0) { vin_err(vin, "Notifier registration failed\n"); @@ -290,6 +245,8 @@ static int rcar_vin_probe(struct platform_device *pdev) if (ret) return ret; + platform_set_drvdata(pdev, vin); + ret = rvin_digital_graph_init(vin); if (ret < 0) goto error; @@ -297,11 +254,10 @@ static int rcar_vin_probe(struct platform_device *pdev) pm_suspend_ignore_children(&pdev->dev, true); pm_runtime_enable(&pdev->dev); - platform_set_drvdata(pdev, vin); - return 0; error: rvin_dma_remove(vin); + v4l2_async_notifier_cleanup(&vin->notifier); return ret; } @@ -313,6 +269,7 @@ static int rcar_vin_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); v4l2_async_notifier_unregister(&vin->notifier); + v4l2_async_notifier_cleanup(&vin->notifier); rvin_dma_remove(vin); diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index b136844499f6..23fdff7a7370 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -183,7 +183,7 @@ static int rvin_setup(struct rvin_dev *vin) /* * Input interface */ - switch (vin->digital.code) { + switch (vin->digital->code) { case MEDIA_BUS_FMT_YUYV8_1X16: /* BT.601/BT.1358 16bit YCbCr422 */ vnmc |= VNMC_INF_YUV16; @@ -191,7 +191,7 @@ static int rvin_setup(struct rvin_dev *vin) break; case MEDIA_BUS_FMT_UYVY8_2X8: /* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */ - vnmc |= vin->digital.mbus_cfg.type == V4L2_MBUS_BT656 ? + vnmc |= vin->digital->mbus_cfg.type == V4L2_MBUS_BT656 ? VNMC_INF_YUV8_BT656 : VNMC_INF_YUV8_BT601; input_is_yuv = true; break; @@ -200,7 +200,7 @@ static int rvin_setup(struct rvin_dev *vin) break; case MEDIA_BUS_FMT_UYVY10_2X10: /* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */ - vnmc |= vin->digital.mbus_cfg.type == V4L2_MBUS_BT656 ? + vnmc |= vin->digital->mbus_cfg.type == V4L2_MBUS_BT656 ? VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601; input_is_yuv = true; break; @@ -212,11 +212,11 @@ static int rvin_setup(struct rvin_dev *vin) dmr2 = VNDMR2_FTEV | VNDMR2_VLV(1); /* Hsync Signal Polarity Select */ - if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) + if (!(vin->digital->mbus_cfg.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) dmr2 |= VNDMR2_HPS; /* Vsync Signal Polarity Select */ - if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) + if (!(vin->digital->mbus_cfg.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) dmr2 |= VNDMR2_VPS; /* diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index dd37ea811680..b479b882da12 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -111,7 +111,7 @@ static int rvin_reset_format(struct rvin_dev *vin) struct v4l2_mbus_framefmt *mf = &fmt.format; int ret; - fmt.pad = vin->digital.source_pad; + fmt.pad = vin->digital->source_pad; ret = v4l2_subdev_call(vin_to_source(vin), pad, get_fmt, NULL, &fmt); if (ret) @@ -172,13 +172,13 @@ static int __rvin_try_format_source(struct rvin_dev *vin, sd = vin_to_source(vin); - v4l2_fill_mbus_format(&format.format, pix, vin->digital.code); + v4l2_fill_mbus_format(&format.format, pix, vin->digital->code); pad_cfg = v4l2_subdev_alloc_pad_config(sd); if (pad_cfg == NULL) return -ENOMEM; - format.pad = vin->digital.source_pad; + format.pad = vin->digital->source_pad; field = pix->field; @@ -555,7 +555,7 @@ static int rvin_enum_dv_timings(struct file *file, void *priv_fh, if (timings->pad) return -EINVAL; - timings->pad = vin->digital.sink_pad; + timings->pad = vin->digital->sink_pad; ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings); @@ -607,7 +607,7 @@ static int rvin_dv_timings_cap(struct file *file, void *priv_fh, if (cap->pad) return -EINVAL; - cap->pad = vin->digital.sink_pad; + cap->pad = vin->digital->sink_pad; ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap); @@ -625,7 +625,7 @@ static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid) if (edid->pad) return -EINVAL; - edid->pad = vin->digital.sink_pad; + edid->pad = vin->digital->sink_pad; ret = v4l2_subdev_call(sd, pad, get_edid, edid); @@ -643,7 +643,7 @@ static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid) if (edid->pad) return -EINVAL; - edid->pad = vin->digital.sink_pad; + edid->pad = vin->digital->sink_pad; ret = v4l2_subdev_call(sd, pad, set_edid, edid); diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index 9bfb5a7c4dc4..5382078143fb 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -126,7 +126,7 @@ struct rvin_dev { struct v4l2_device v4l2_dev; struct v4l2_ctrl_handler ctrl_handler; struct v4l2_async_notifier notifier; - struct rvin_graph_entity digital; + struct rvin_graph_entity *digital; struct mutex lock; struct vb2_queue queue; @@ -145,7 +145,7 @@ struct rvin_dev { struct v4l2_rect compose; }; -#define vin_to_source(vin) vin->digital.subdev +#define vin_to_source(vin) ((vin)->digital->subdev) /* Debug */ #define vin_dbg(d, fmt, arg...) dev_dbg(d->dev, fmt, ##arg) -- cgit v1.2.3 From eae4cf8f262e35b60928058e36ce1e841a2ab917 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 1 Sep 2017 19:42:05 -0400 Subject: media: omap3isp: Fix check for our own sub-devices We only want to link sub-devices that were bound to the async notifier the isp driver registered but there may be other sub-devices in the v4l2_device as well. Check for the correct async notifier. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Pavel Machek Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 97a5206b6ddc..4afd7ba4fad6 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -2155,7 +2155,7 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async) return ret; list_for_each_entry(sd, &v4l2_dev->subdevs, list) { - if (!sd->asd) + if (sd->notifier != &isp->notifier) continue; ret = isp_link_entity(isp, &sd->entity, -- cgit v1.2.3 From bce9e317cec9c4ffff3dde1170c0ad70f5e690c8 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 1 Sep 2017 19:43:31 -0400 Subject: media: omap3isp: Print the name of the entity where no source pads could be found If no source pads are found in an entity, print the name of the entity. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Pavel Machek Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 4afd7ba4fad6..35687c9707e0 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -1669,8 +1669,8 @@ static int isp_link_entity( break; } if (i == entity->num_pads) { - dev_err(isp->dev, "%s: no source pad in external entity\n", - __func__); + dev_err(isp->dev, "%s: no source pad in external entity %s\n", + __func__, entity->name); return -EINVAL; } -- cgit v1.2.3 From b6ee3f0dcf43dc3e8dbbe9be9c4e728c8d52f1ba Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 30 Aug 2017 13:18:04 -0400 Subject: media: v4l: async: Move async subdev notifier operations to a separate structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The async subdev notifier .bound(), .unbind() and .complete() operations are function pointers stored directly in the v4l2_async_subdev structure. As the structure isn't immutable, this creates a potential security risk as the function pointers are mutable. To fix this, move the function pointers to a new v4l2_async_subdev_operations structure that can be made const in drivers. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Acked-by: Niklas Söderlund Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/am437x/am437x-vpfe.c | 8 +++++-- drivers/media/platform/atmel/atmel-isc.c | 10 ++++++--- drivers/media/platform/atmel/atmel-isi.c | 10 ++++++--- drivers/media/platform/davinci/vpif_capture.c | 8 +++++-- drivers/media/platform/davinci/vpif_display.c | 8 +++++-- drivers/media/platform/exynos4-is/media-dev.c | 8 +++++-- drivers/media/platform/omap3isp/isp.c | 6 +++++- drivers/media/platform/pxa_camera.c | 8 +++++-- drivers/media/platform/qcom/camss-8x16/camss.c | 8 +++++-- drivers/media/platform/rcar-vin/rcar-core.c | 10 ++++++--- drivers/media/platform/rcar_drif.c | 10 ++++++--- drivers/media/platform/soc_camera/soc_camera.c | 14 ++++++------ drivers/media/platform/stm32/stm32-dcmi.c | 10 ++++++--- drivers/media/platform/ti-vpe/cal.c | 8 +++++-- drivers/media/platform/xilinx/xilinx-vipp.c | 8 +++++-- drivers/media/v4l2-core/v4l2-async.c | 30 ++++++++++++-------------- drivers/staging/media/imx/imx-media-dev.c | 8 +++++-- include/media/v4l2-async.h | 29 ++++++++++++++++--------- 18 files changed, 135 insertions(+), 66 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index dfcc484cab89..0997c640191d 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -2417,6 +2417,11 @@ static int vpfe_async_complete(struct v4l2_async_notifier *notifier) return vpfe_probe_complete(vpfe); } +static const struct v4l2_async_notifier_operations vpfe_async_ops = { + .bound = vpfe_async_bound, + .complete = vpfe_async_complete, +}; + static struct vpfe_config * vpfe_get_pdata(struct platform_device *pdev) { @@ -2590,8 +2595,7 @@ static int vpfe_probe(struct platform_device *pdev) vpfe->notifier.subdevs = vpfe->cfg->asd; vpfe->notifier.num_subdevs = ARRAY_SIZE(vpfe->cfg->asd); - vpfe->notifier.bound = vpfe_async_bound; - vpfe->notifier.complete = vpfe_async_complete; + vpfe->notifier.ops = &vpfe_async_ops; ret = v4l2_async_notifier_register(&vpfe->v4l2_dev, &vpfe->notifier); if (ret) { diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 30f2867c2932..13f1c1c797b0 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -1979,6 +1979,12 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) return 0; } +static const struct v4l2_async_notifier_operations isc_async_ops = { + .bound = isc_async_bound, + .unbind = isc_async_unbind, + .complete = isc_async_complete, +}; + static void isc_subdev_cleanup(struct isc_device *isc) { struct isc_subdev_entity *subdev_entity; @@ -2203,9 +2209,7 @@ static int atmel_isc_probe(struct platform_device *pdev) list_for_each_entry(subdev_entity, &isc->subdev_entities, list) { subdev_entity->notifier.subdevs = &subdev_entity->asd; subdev_entity->notifier.num_subdevs = 1; - subdev_entity->notifier.bound = isc_async_bound; - subdev_entity->notifier.unbind = isc_async_unbind; - subdev_entity->notifier.complete = isc_async_complete; + subdev_entity->notifier.ops = &isc_async_ops; ret = v4l2_async_notifier_register(&isc->v4l2_dev, &subdev_entity->notifier); diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index 463c0146915e..e900995143a3 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -1103,6 +1103,12 @@ static int isi_graph_notify_bound(struct v4l2_async_notifier *notifier, return 0; } +static const struct v4l2_async_notifier_operations isi_graph_notify_ops = { + .bound = isi_graph_notify_bound, + .unbind = isi_graph_notify_unbind, + .complete = isi_graph_notify_complete, +}; + static int isi_graph_parse(struct atmel_isi *isi, struct device_node *node) { struct device_node *ep = NULL; @@ -1150,9 +1156,7 @@ static int isi_graph_init(struct atmel_isi *isi) isi->notifier.subdevs = subdevs; isi->notifier.num_subdevs = 1; - isi->notifier.bound = isi_graph_notify_bound; - isi->notifier.unbind = isi_graph_notify_unbind; - isi->notifier.complete = isi_graph_notify_complete; + isi->notifier.ops = &isi_graph_notify_ops; ret = v4l2_async_notifier_register(&isi->v4l2_dev, &isi->notifier); if (ret < 0) { diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 0ef36cec21d1..a89367ab1e06 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1500,6 +1500,11 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier) return vpif_probe_complete(); } +static const struct v4l2_async_notifier_operations vpif_async_ops = { + .bound = vpif_async_bound, + .complete = vpif_async_complete, +}; + static struct vpif_capture_config * vpif_capture_get_pdata(struct platform_device *pdev) { @@ -1691,8 +1696,7 @@ static __init int vpif_probe(struct platform_device *pdev) } else { vpif_obj.notifier.subdevs = vpif_obj.config->asd; vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0]; - vpif_obj.notifier.bound = vpif_async_bound; - vpif_obj.notifier.complete = vpif_async_complete; + vpif_obj.notifier.ops = &vpif_async_ops; err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev, &vpif_obj.notifier); if (err) { diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 56fe4e5b396e..ff2f75a328c9 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -1232,6 +1232,11 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier) return vpif_probe_complete(); } +static const struct v4l2_async_notifier_operations vpif_async_ops = { + .bound = vpif_async_bound, + .complete = vpif_async_complete, +}; + /* * vpif_probe: This function creates device entries by register itself to the * V4L2 driver and initializes fields of each channel objects @@ -1313,8 +1318,7 @@ static __init int vpif_probe(struct platform_device *pdev) } else { vpif_obj.notifier.subdevs = vpif_obj.config->asd; vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0]; - vpif_obj.notifier.bound = vpif_async_bound; - vpif_obj.notifier.complete = vpif_async_complete; + vpif_obj.notifier.ops = &vpif_async_ops; err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev, &vpif_obj.notifier); if (err) { diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index d4656d5175d7..c15596b56dc9 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -1405,6 +1405,11 @@ unlock: return media_device_register(&fmd->media_dev); } +static const struct v4l2_async_notifier_operations subdev_notifier_ops = { + .bound = subdev_notifier_bound, + .complete = subdev_notifier_complete, +}; + static int fimc_md_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1479,8 +1484,7 @@ static int fimc_md_probe(struct platform_device *pdev) if (fmd->num_sensors > 0) { fmd->subdev_notifier.subdevs = fmd->async_subdevs; fmd->subdev_notifier.num_subdevs = fmd->num_sensors; - fmd->subdev_notifier.bound = subdev_notifier_bound; - fmd->subdev_notifier.complete = subdev_notifier_complete; + fmd->subdev_notifier.ops = &subdev_notifier_ops; fmd->num_sensors = 0; ret = v4l2_async_notifier_register(&fmd->v4l2_dev, diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 35687c9707e0..b7ff3842afc0 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -2171,6 +2171,10 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async) return media_device_register(&isp->media_dev); } +static const struct v4l2_async_notifier_operations isp_subdev_notifier_ops = { + .complete = isp_subdev_notifier_complete, +}; + /* * isp_probe - Probe ISP platform device * @pdev: Pointer to ISP platform device @@ -2341,7 +2345,7 @@ static int isp_probe(struct platform_device *pdev) if (ret < 0) goto error_register_entities; - isp->notifier.complete = isp_subdev_notifier_complete; + isp->notifier.ops = &isp_subdev_notifier_ops; ret = v4l2_async_notifier_register(&isp->v4l2_dev, &isp->notifier); if (ret) diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c index edca993c2b1f..9d3f0cb1d95a 100644 --- a/drivers/media/platform/pxa_camera.c +++ b/drivers/media/platform/pxa_camera.c @@ -2221,6 +2221,11 @@ static void pxa_camera_sensor_unbind(struct v4l2_async_notifier *notifier, mutex_unlock(&pcdev->mlock); } +static const struct v4l2_async_notifier_operations pxa_camera_sensor_ops = { + .bound = pxa_camera_sensor_bound, + .unbind = pxa_camera_sensor_unbind, +}; + /* * Driver probe, remove, suspend and resume operations */ @@ -2489,8 +2494,7 @@ static int pxa_camera_probe(struct platform_device *pdev) pcdev->asds[0] = &pcdev->asd; pcdev->notifier.subdevs = pcdev->asds; pcdev->notifier.num_subdevs = 1; - pcdev->notifier.bound = pxa_camera_sensor_bound; - pcdev->notifier.unbind = pxa_camera_sensor_unbind; + pcdev->notifier.ops = &pxa_camera_sensor_ops; if (!of_have_populated_dt()) pcdev->asd.match_type = V4L2_ASYNC_MATCH_I2C; diff --git a/drivers/media/platform/qcom/camss-8x16/camss.c b/drivers/media/platform/qcom/camss-8x16/camss.c index a3760b5dd1d1..390a42c17b66 100644 --- a/drivers/media/platform/qcom/camss-8x16/camss.c +++ b/drivers/media/platform/qcom/camss-8x16/camss.c @@ -601,6 +601,11 @@ static int camss_subdev_notifier_complete(struct v4l2_async_notifier *async) return media_device_register(&camss->media_dev); } +static const struct v4l2_async_notifier_operations camss_subdev_notifier_ops = { + .bound = camss_subdev_notifier_bound, + .complete = camss_subdev_notifier_complete, +}; + static const struct media_device_ops camss_media_ops = { .link_notify = v4l2_pipeline_link_notify, }; @@ -655,8 +660,7 @@ static int camss_probe(struct platform_device *pdev) goto err_register_entities; if (camss->notifier.num_subdevs) { - camss->notifier.bound = camss_subdev_notifier_bound; - camss->notifier.complete = camss_subdev_notifier_complete; + camss->notifier.ops = &camss_subdev_notifier_ops; ret = v4l2_async_notifier_register(&camss->v4l2_dev, &camss->notifier); diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 380288658601..108d776f3265 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -134,6 +134,12 @@ static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier, return 0; } +static const struct v4l2_async_notifier_operations rvin_digital_notify_ops = { + .bound = rvin_digital_notify_bound, + .unbind = rvin_digital_notify_unbind, + .complete = rvin_digital_notify_complete, +}; + static int rvin_digital_parse_v4l2(struct device *dev, struct v4l2_fwnode_endpoint *vep, @@ -183,9 +189,7 @@ static int rvin_digital_graph_init(struct rvin_dev *vin) vin_dbg(vin, "Found digital subdevice %pOF\n", to_of_node(vin->digital->asd.match.fwnode.fwnode)); - vin->notifier.bound = rvin_digital_notify_bound; - vin->notifier.unbind = rvin_digital_notify_unbind; - vin->notifier.complete = rvin_digital_notify_complete; + vin->notifier.ops = &rvin_digital_notify_ops; ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier); if (ret < 0) { vin_err(vin, "Notifier registration failed\n"); diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c index 2c6afd38b78a..63c94f4028a7 100644 --- a/drivers/media/platform/rcar_drif.c +++ b/drivers/media/platform/rcar_drif.c @@ -1185,6 +1185,12 @@ error: return ret; } +static const struct v4l2_async_notifier_operations rcar_drif_notify_ops = { + .bound = rcar_drif_notify_bound, + .unbind = rcar_drif_notify_unbind, + .complete = rcar_drif_notify_complete, +}; + /* Read endpoint properties */ static void rcar_drif_get_ep_properties(struct rcar_drif_sdr *sdr, struct fwnode_handle *fwnode) @@ -1347,9 +1353,7 @@ static int rcar_drif_sdr_probe(struct rcar_drif_sdr *sdr) if (ret) goto error; - sdr->notifier.bound = rcar_drif_notify_bound; - sdr->notifier.unbind = rcar_drif_notify_unbind; - sdr->notifier.complete = rcar_drif_notify_complete; + sdr->notifier.ops = &rcar_drif_notify_ops; /* Register notifier */ ret = v4l2_async_notifier_register(&sdr->v4l2_dev, &sdr->notifier); diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 1f3c450c7a69..916ff68b73d4 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -1391,6 +1391,12 @@ static int soc_camera_async_complete(struct v4l2_async_notifier *notifier) return 0; } +static const struct v4l2_async_notifier_operations soc_camera_async_ops = { + .bound = soc_camera_async_bound, + .unbind = soc_camera_async_unbind, + .complete = soc_camera_async_complete, +}; + static int scan_async_group(struct soc_camera_host *ici, struct v4l2_async_subdev **asd, unsigned int size) { @@ -1437,9 +1443,7 @@ static int scan_async_group(struct soc_camera_host *ici, sasc->notifier.subdevs = asd; sasc->notifier.num_subdevs = size; - sasc->notifier.bound = soc_camera_async_bound; - sasc->notifier.unbind = soc_camera_async_unbind; - sasc->notifier.complete = soc_camera_async_complete; + sasc->notifier.ops = &soc_camera_async_ops; icd->sasc = sasc; icd->parent = ici->v4l2_dev.dev; @@ -1537,9 +1541,7 @@ static int soc_of_bind(struct soc_camera_host *ici, sasc->notifier.subdevs = &info->subdev; sasc->notifier.num_subdevs = 1; - sasc->notifier.bound = soc_camera_async_bound; - sasc->notifier.unbind = soc_camera_async_unbind; - sasc->notifier.complete = soc_camera_async_complete; + sasc->notifier.ops = &soc_camera_async_ops; icd->sasc = sasc; icd->parent = ici->v4l2_dev.dev; diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index 35ba6f211b79..ac4c450a6c7d 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -1495,6 +1495,12 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier, return 0; } +static const struct v4l2_async_notifier_operations dcmi_graph_notify_ops = { + .bound = dcmi_graph_notify_bound, + .unbind = dcmi_graph_notify_unbind, + .complete = dcmi_graph_notify_complete, +}; + static int dcmi_graph_parse(struct stm32_dcmi *dcmi, struct device_node *node) { struct device_node *ep = NULL; @@ -1542,9 +1548,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) dcmi->notifier.subdevs = subdevs; dcmi->notifier.num_subdevs = 1; - dcmi->notifier.bound = dcmi_graph_notify_bound; - dcmi->notifier.unbind = dcmi_graph_notify_unbind; - dcmi->notifier.complete = dcmi_graph_notify_complete; + dcmi->notifier.ops = &dcmi_graph_notify_ops; ret = v4l2_async_notifier_register(&dcmi->v4l2_dev, &dcmi->notifier); if (ret < 0) { diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 42e383a48ffe..8b586c864524 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -1522,6 +1522,11 @@ static int cal_async_complete(struct v4l2_async_notifier *notifier) return 0; } +static const struct v4l2_async_notifier_operations cal_async_ops = { + .bound = cal_async_bound, + .complete = cal_async_complete, +}; + static int cal_complete_ctx(struct cal_ctx *ctx) { struct video_device *vfd; @@ -1736,8 +1741,7 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst) ctx->asd_list[0] = asd; ctx->notifier.subdevs = ctx->asd_list; ctx->notifier.num_subdevs = 1; - ctx->notifier.bound = cal_async_bound; - ctx->notifier.complete = cal_async_complete; + ctx->notifier.ops = &cal_async_ops; ret = v4l2_async_notifier_register(&ctx->v4l2_dev, &ctx->notifier); if (ret) { diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c index ebfdf334d99c..d881cf09876d 100644 --- a/drivers/media/platform/xilinx/xilinx-vipp.c +++ b/drivers/media/platform/xilinx/xilinx-vipp.c @@ -351,6 +351,11 @@ static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier, return -EINVAL; } +static const struct v4l2_async_notifier_operations xvip_graph_notify_ops = { + .bound = xvip_graph_notify_bound, + .complete = xvip_graph_notify_complete, +}; + static int xvip_graph_parse_one(struct xvip_composite_device *xdev, struct device_node *node) { @@ -548,8 +553,7 @@ static int xvip_graph_init(struct xvip_composite_device *xdev) xdev->notifier.subdevs = subdevs; xdev->notifier.num_subdevs = num_subdevs; - xdev->notifier.bound = xvip_graph_notify_bound; - xdev->notifier.complete = xvip_graph_notify_complete; + xdev->notifier.ops = &xvip_graph_notify_ops; ret = v4l2_async_notifier_register(&xdev->v4l2_dev, &xdev->notifier); if (ret < 0) { diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 46aebfc75e43..9d6fc5f25619 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -102,16 +102,16 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, { int ret; - if (notifier->bound) { - ret = notifier->bound(notifier, sd, asd); + if (notifier->ops->bound) { + ret = notifier->ops->bound(notifier, sd, asd); if (ret < 0) return ret; } ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd); if (ret < 0) { - if (notifier->unbind) - notifier->unbind(notifier, sd, asd); + if (notifier->ops->unbind) + notifier->ops->unbind(notifier, sd, asd); return ret; } @@ -140,9 +140,8 @@ static void v4l2_async_notifier_unbind_all_subdevs( struct v4l2_subdev *sd, *tmp; list_for_each_entry_safe(sd, tmp, ¬ifier->done, async_list) { - if (notifier->unbind) - notifier->unbind(notifier, sd, sd->asd); - + if (notifier->ops->unbind) + notifier->ops->unbind(notifier, sd, sd->asd); v4l2_async_cleanup(sd); list_move(&sd->async_list, &subdev_list); @@ -199,8 +198,8 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, } } - if (list_empty(¬ifier->waiting) && notifier->complete) { - ret = notifier->complete(notifier); + if (list_empty(¬ifier->waiting) && notifier->ops->complete) { + ret = notifier->ops->complete(notifier); if (ret) goto err_complete; } @@ -297,10 +296,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) if (ret) goto err_unlock; - if (!list_empty(¬ifier->waiting) || !notifier->complete) + if (!list_empty(¬ifier->waiting) || !notifier->ops->complete) goto out_unlock; - ret = notifier->complete(notifier); + ret = notifier->ops->complete(notifier); if (ret) goto err_cleanup; @@ -316,9 +315,8 @@ out_unlock: return 0; err_cleanup: - if (notifier->unbind) - notifier->unbind(notifier, sd, sd->asd); - + if (notifier->ops->unbind) + notifier->ops->unbind(notifier, sd, sd->asd); v4l2_async_cleanup(sd); err_unlock: @@ -337,8 +335,8 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) list_add(&sd->asd->list, ¬ifier->waiting); - if (notifier->unbind) - notifier->unbind(notifier, sd, sd->asd); + if (notifier->ops->unbind) + notifier->ops->unbind(notifier, sd, sd->asd); } v4l2_async_cleanup(sd); diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c index b55e5ebba8b4..47c4c954fed5 100644 --- a/drivers/staging/media/imx/imx-media-dev.c +++ b/drivers/staging/media/imx/imx-media-dev.c @@ -440,6 +440,11 @@ unlock: return media_device_register(&imxmd->md); } +static const struct v4l2_async_notifier_operations imx_media_subdev_ops = { + .bound = imx_media_subdev_bound, + .complete = imx_media_probe_complete, +}; + /* * adds controls to a video device from an entity subdevice. * Continues upstream from the entity's sink pads. @@ -608,8 +613,7 @@ static int imx_media_probe(struct platform_device *pdev) /* prepare the async subdev notifier and register it */ imxmd->subdev_notifier.subdevs = imxmd->async_ptrs; - imxmd->subdev_notifier.bound = imx_media_subdev_bound; - imxmd->subdev_notifier.complete = imx_media_probe_complete; + imxmd->subdev_notifier.ops = &imx_media_subdev_ops; ret = v4l2_async_notifier_register(&imxmd->v4l2_dev, &imxmd->subdev_notifier); if (ret) { diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h index 329aeebd1a80..68606afb5ef9 100644 --- a/include/media/v4l2-async.h +++ b/include/media/v4l2-async.h @@ -18,6 +18,7 @@ struct device; struct device_node; struct v4l2_device; struct v4l2_subdev; +struct v4l2_async_notifier; /* A random max subdevice number, used to allocate an array on stack */ #define V4L2_MAX_SUBDEVS 128U @@ -78,9 +79,26 @@ struct v4l2_async_subdev { struct list_head list; }; +/** + * struct v4l2_async_notifier_operations - Asynchronous V4L2 notifier operations + * @bound: a subdevice driver has successfully probed one of the subdevices + * @complete: all subdevices have been probed successfully + * @unbind: a subdevice is leaving + */ +struct v4l2_async_notifier_operations { + int (*bound)(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd); + int (*complete)(struct v4l2_async_notifier *notifier); + void (*unbind)(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd); +}; + /** * struct v4l2_async_notifier - v4l2_device notifier data * + * @ops: notifier operations * @num_subdevs: number of subdevices used in the subdevs array * @max_subdevs: number of subdevices allocated in the subdevs array * @subdevs: array of pointers to subdevice descriptors @@ -88,11 +106,9 @@ struct v4l2_async_subdev { * @waiting: list of struct v4l2_async_subdev, waiting for their drivers * @done: list of struct v4l2_subdev, already probed * @list: member in a global list of notifiers - * @bound: a subdevice driver has successfully probed one of subdevices - * @complete: all subdevices have been probed successfully - * @unbind: a subdevice is leaving */ struct v4l2_async_notifier { + const struct v4l2_async_notifier_operations *ops; unsigned int num_subdevs; unsigned int max_subdevs; struct v4l2_async_subdev **subdevs; @@ -100,13 +116,6 @@ struct v4l2_async_notifier { struct list_head waiting; struct list_head done; struct list_head list; - int (*bound)(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *subdev, - struct v4l2_async_subdev *asd); - int (*complete)(struct v4l2_async_notifier *notifier); - void (*unbind)(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *subdev, - struct v4l2_async_subdev *asd); }; /** -- cgit v1.2.3 From 9917fbcfa20ab987d6381fd0365665e5c1402d75 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 1 Nov 2017 08:09:59 -0400 Subject: media: camss-vfe: always initialize reg at vfe_set_xbar_cfg() if output->wm_num is bigger than 2, the value for reg is not initialized, as warned by smatch: drivers/media/platform/qcom/camss-8x16/camss-vfe.c:633 vfe_set_xbar_cfg() error: uninitialized symbol 'reg'. drivers/media/platform/qcom/camss-8x16/camss-vfe.c:637 vfe_set_xbar_cfg() error: uninitialized symbol 'reg'. That shouldn't happen in practice, so add a logic that will break the loop if i > 1, fixing the warnings. Signed-off-by: Mauro Carvalho Chehab Acked-by: Todor Tomov --- drivers/media/platform/qcom/camss-8x16/camss-vfe.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/qcom/camss-8x16/camss-vfe.c b/drivers/media/platform/qcom/camss-8x16/camss-vfe.c index b22d2dfcd3c2..55232a912950 100644 --- a/drivers/media/platform/qcom/camss-8x16/camss-vfe.c +++ b/drivers/media/platform/qcom/camss-8x16/camss-vfe.c @@ -622,6 +622,9 @@ static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output, reg = VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN; if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV16) reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA; + } else { + /* On current devices output->wm_num is always <= 2 */ + break; } if (output->wm_idx[i] % 2 == 1) -- cgit v1.2.3 From 55a839a09395aaa21646cea328fb9afd7342dce6 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Mon, 30 Oct 2017 17:04:57 -0400 Subject: media: s5p-mfc: fix lockdep warning The driver mmap functions shouldn't take lock when calling vb2_mmap(). Fix it to not take the lock. The following lockdep warning is fixed with this change. [ 2106.181412] ====================================================== [ 2106.187563] WARNING: possible circular locking dependency detected [ 2106.193718] 4.14.0-rc2-00002-gfab205f-dirty #4 Not tainted [ 2106.199175] ------------------------------------------------------ [ 2106.205328] qtdemux0:sink/2614 is trying to acquire lock: [ 2106.210701] (&dev->mfc_mutex){+.+.}, at: [] s5p_mfc_mmap+0x28/0xd4 [s5p_mfc] [ 2106.218672] [ 2106.218672] but task is already holding lock: [ 2106.224477] (&mm->mmap_sem){++++}, at: [] vm_mmap_pgoff+0x44/0xb8 [ 2106.231497] [ 2106.231497] which lock already depends on the new lock. [ 2106.231497] [ 2106.239642] [ 2106.239642] the existing dependency chain (in reverse order) is: [ 2106.247095] [ 2106.247095] -> #1 (&mm->mmap_sem){++++}: [ 2106.252473] __might_fault+0x80/0xb0 [ 2106.256567] video_usercopy+0x1cc/0x510 [videodev] [ 2106.261845] v4l2_ioctl+0xa4/0xdc [videodev] [ 2106.266596] do_vfs_ioctl+0xa0/0xa18 [ 2106.270667] SyS_ioctl+0x34/0x5c [ 2106.274395] ret_fast_syscall+0x0/0x28 [ 2106.278637] [ 2106.278637] -> #0 (&dev->mfc_mutex){+.+.}: [ 2106.284186] lock_acquire+0x6c/0x88 [ 2106.288173] __mutex_lock+0x68/0xa34 [ 2106.292244] mutex_lock_interruptible_nested+0x1c/0x24 [ 2106.297893] s5p_mfc_mmap+0x28/0xd4 [s5p_mfc] [ 2106.302747] v4l2_mmap+0x54/0x88 [videodev] [ 2106.307409] mmap_region+0x3a8/0x638 [ 2106.311480] do_mmap+0x330/0x3a4 [ 2106.315207] vm_mmap_pgoff+0x90/0xb8 [ 2106.319279] SyS_mmap_pgoff+0x90/0xc0 [ 2106.323439] ret_fast_syscall+0x0/0x28 [ 2106.327683] [ 2106.327683] other info that might help us debug this: [ 2106.327683] [ 2106.335656] Possible unsafe locking scenario: [ 2106.335656] [ 2106.341548] CPU0 CPU1 [ 2106.346053] ---- ---- [ 2106.350559] lock(&mm->mmap_sem); [ 2106.353939] lock(&dev->mfc_mutex); [ 2106.353939] lock(&dev->mfc_mutex); [ 2106.365897] lock(&dev->mfc_mutex); [ 2106.369450] [ 2106.369450] *** DEADLOCK *** [ 2106.369450] [ 2106.375344] 1 lock held by qtdemux0:sink/2614: [ 2106.379762] #0: (&mm->mmap_sem){++++}, at: [] vm_mmap_pgoff+0x44/0xb8 [ 2106.387214] [ 2106.387214] stack backtrace: [ 2106.391550] CPU: 7 PID: 2614 Comm: qtdemux0:sink Not tainted 4.14.0-rc2-00002-gfab205f-dirty #4 [ 2106.400213] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [ 2106.406285] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 2106.413995] [] (show_stack) from [] (dump_stack+0x98/0xc4) [ 2106.421187] [] (dump_stack) from [] (print_circular_bug+0x254/0x410) [ 2106.429245] [] (print_circular_bug) from [] (check_prev_add+0x468/0x938) [ 2106.437651] [] (check_prev_add) from [] (__lock_acquire+0x1314/0x14fc) [ 2106.445883] [] (__lock_acquire) from [] (lock_acquire+0x6c/0x88) [ 2106.453596] [] (lock_acquire) from [] (__mutex_lock+0x68/0xa34) [ 2106.461221] [] (__mutex_lock) from [] (mutex_lock_interruptible_nested+0x1c/0x24) [ 2106.470425] [] (mutex_lock_interruptible_nested) from [] (s5p_mfc_mmap+0x28/0xd4 [s5p_mfc]) [ 2106.480494] [] (s5p_mfc_mmap [s5p_mfc]) from [] (v4l2_mmap+0x54/0x88 [videodev]) [ 2106.489575] [] (v4l2_mmap [videodev]) from [] (mmap_region+0x3a8/0x638) [ 2106.497875] [] (mmap_region) from [] (do_mmap+0x330/0x3a4) [ 2106.505068] [] (do_mmap) from [] (vm_mmap_pgoff+0x90/0xb8) [ 2106.512260] [] (vm_mmap_pgoff) from [] (SyS_mmap_pgoff+0x90/0xc0) [ 2106.520059] [] (SyS_mmap_pgoff) from [] (ret_fast_syscall+0x0/0x28) Signed-off-by: Shuah Khan Suggested-by: Hans Verkuil Acked-by: Marek Szyprowski Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index cf68aed59e0d..1839a86cc2a5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1043,12 +1043,9 @@ end: static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma) { struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); - struct s5p_mfc_dev *dev = ctx->dev; unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; int ret; - if (mutex_lock_interruptible(&dev->mfc_mutex)) - return -ERESTARTSYS; if (offset < DST_QUEUE_OFF_BASE) { mfc_debug(2, "mmaping source\n"); ret = vb2_mmap(&ctx->vq_src, vma); @@ -1057,7 +1054,6 @@ static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT); ret = vb2_mmap(&ctx->vq_dst, vma); } - mutex_unlock(&dev->mfc_mutex); return ret; } -- cgit v1.2.3